Metadata and text providers

https://fedorahosted.org/freeipa/ticket/3235
This commit is contained in:
Petr Vobornik 2013-04-03 15:12:42 +02:00
parent 1b90b3b65e
commit 13e34216eb
7 changed files with 459 additions and 90 deletions

View File

@ -0,0 +1,220 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Value provider.
*
* It search source or child providers for value defined by key.
*
* Key consists of code and path.
*
* Code defines the type of resource. Provider's handles() method tells whether
* it can handle this type of resource.
*
* Path is a plain object path within a source.
*
* Ie. if source is {
* foo: {
* bar: {
* a: 'val'
* }
* }
* }
*
* path: 'foo.bar.a' would return 'val'
*
*/
define(['dojo/_base/declare','dojo/_base/lang'], function(declare, lang) {
var undefined;
var Provider = declare(null, {
/**
* Array of other providers
* @type Provider[]
*/
providers: null,
/**
* Source object or a function which returns source object.
* @type {Function|Object|Provider}
*/
source: null,
/**
* Path within a source.
*
* When defined, all lookups in source are based on the object
* defined by this path within a source.
* @type String
*/
path: null,
/**
* Value which is returned if no value nor alternative is found
*/
null_value: null,
/**
* Specifies which type should be returned. Limited to output of
* typeof operator.
* @type String
*/
required_type: null,
_code: null,
_code_length: null,
_handling_provider: null,
_set_code: function(code) {
this._code = code;
if (code) this._code_length = code.length;
},
_get_source: function() {
var source;
var type = typeof this.source;
if (type === 'function') {
source = this.source.call(this);
} else if (type === 'object') {
source = this.source;
// if source is another provider, use its source as this source
if (source.isInstanceOf && source.isInstanceOf(Provider) &&
source.source) {
source = source._get_source();
}
}
if (this.path) {
source = lang.getObject(this.path, false, source);
}
return source;
},
_handles: function(key) {
if (!this._code) return false;
if (typeof key !== 'string') return false;
if (key[0] !== '@') return false;
var code = key.substring(0, this._code_length);
var handles = code === this._code;
return handles;
},
_handle_children: function(key) {
var handles = false;
this._handling_provider = null;
for (var i=0; i< this.providers.length; i++) {
handles = this.providers[i].handles(key);
if (handles) {
this._handling_provider = this.providers[i];
break;
}
}
return handles;
},
/**
* Get's value from this provider's source
* @protected
*/
_get: function(key) {
var property = key.substring(this._code_length);
var value = lang.getObject(property, false, this._get_source());
return value;
},
/**
* Finds out whether this or some of its children handles given key.
*/
handles: function(key) {
var handles = this._handles(key);
handles = handles || this._handle_children(key);
return handles;
},
/**
* Gets value.
*
* @param {String|Object} Key or value
* @param {Object} Alternate value
*/
get: function(key, alternate) {
var value = key;
if (key !== undefined) {
if (this._handles(key)) {
value = this._get(key);
} else if(this._handle_children(key)) {
value = this._handling_provider.get(key);
} else {
// Return key as value when it's not a proper key.
window.console.log('Using key as value:'+key);
}
}
var ret = value || alternate;
if (!ret) {
window.console.log('No value for:'+key);
}
if ((this.required_type && typeof ret !== this.required_type) ||
ret === null ||
ret === undefined){
ret = this.null_value;
}
return ret;
},
/**
* Finds object with attr_name === value in array defined by key.
*/
find: function(key, attr_name, value) {
var arr = this.get(key);
if (!lang.isArrayLike(arr)) return null;
for (var i=0; i<arr.length; i++) {
if (arr[i][attr_name] === value) {
return arr[i];
}
}
return null;
},
constructor: function(spec) {
spec = spec || {};
this.source = spec.source || {};
this.path = spec.path || null;
this.providers = spec.providers || [];
if (spec.null_value !== undefined) {
this.null_value = spec.null_value;
}
this.required_type = spec.required_type;
if (spec.code) {
this._set_code(spec.code);
}
}
});
return Provider;
});

View File

@ -0,0 +1,111 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Search value providers.
*
* Serves for searching for values within a array in a source.
*
* Path has following formats:
* * key1:key2:key3
* * key1:key2
* * key2
*
* base_query: '%1.takes_params'
* array_attr: 'name'
*
* It translates into following query:
* %key1.takes_params[name=%key2].$key3
*
* In a future we should support defining generic queries and thus not be
* limited to simple search.
*
*/
define(['dojo/_base/declare','dojo/_base/lang', './Provider'],
function(declare, lang, Provider) {
var Search_provider = declare([Provider], {
base_query: null,
array_attr: null,
_get: function(key) {
var search_keys = key.substring(this._code_length);
search_keys = search_keys.split(':');
var count = search_keys.length;
if (count < 1 || count > 3) return null;
var key1, key2, key3;
if (count === 1) {
key2 = search_keys[0];
} else if (count === 2) {
key1 = search_keys[0];
key2 = search_keys[1];
} else {
key1 = search_keys[0];
key2 = search_keys[1];
key3 = search_keys[2];
}
var arr;
var source = arr = this._get_source();
if (key1) {
var property = this.base_query.replace('%1', search_keys[0]);
arr = lang.getObject(property, false, source);
}
var ret = this._find(arr, this.array_attr, key2, false);
if (ret && key3) {
ret = lang.getObject(key3, false, ret);
}
return ret;
},
/**
* Finds object with attr_name === value in array defined by key.
*/
_find: function(array, attr, value, all) {
var vals = [];
if (!lang.isArrayLike(array)) return null;
for (var i=0; i<array.length; i++) {
if (array[i][attr] === value) {
vals.push(array[i]);
if (!all) break;
}
}
if (!all) return vals[0] || null;
return vals;
},
constructor: function(spec) {
spec = spec || {};
this.base_query = spec.base_query || '%1';
this.array_attr = spec.array_attr || 'name';
}
});
return Search_provider;
});

View File

@ -18,40 +18,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define(['dojo/_base/lang', '../ipa'], function(lang, IPA) {
/**
* Gets translated message.
*
* If a message starts with @i18n: it tries to get the message from
* message object. If it doesn't contain a string with
* the key it returns alternate string.
*
* It all other cases the message itself or empty string is returned.
*/
define(['dojo/_base/lang', './Provider'], function(lang, Provider) {
var i18n = {
/**
* Gets translated message.
*
* If a message starts with @i18n: it tries to get the message from
* IPA.messages. If IPA messages doesn't contain a string with
* the key it returns alternate string or the part after @i18n.
*
* When IPA.messages doesn't exist alternate string is returned.
* It all other cases the message itself is returned.
*
* @param {String} Message key
* @param {String} Alternate message.
* @returns {String} Translated message
*/
message: function(message, alternate) {
if (!message) return '';
if (message.substring(0, 6) === '@i18n:') {
var key = message.substring(6);
if(!IPA.messages) return alternate || key;
var string = lang.getObject(key, false, IPA.messages);
// don't return objecs
if (typeof string !== 'string') string = null;
return string || alternate || key;
}
return alternate || message;
}
};
var i18n = new Provider({
code: '@i18n:',
null_value: '',
required_type: 'string'
});
return i18n;
});

View File

@ -0,0 +1,62 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define(['dojo/_base/lang', './Provider', './Search_provider'],
function(lang, Provider, Search_provider) {
var metadata = new Provider({
code: '@m:'
});
var objects = new Provider({
code: '@mo:',
source: metadata,
path: 'objects'
});
var commmads = new Provider({
code: '@mc:',
source: metadata,
path: 'commmads'
});
var object_param = new Search_provider({
code: '@mo-param:',
source: metadata,
path: 'objects',
base_query: '%1.takes_params',
array_attr: 'name'
});
var cmd_arg = new Search_provider({
code: '@mc-arg:',
source: metadata,
path: 'commands',
base_query: '%1.takes_args',
array_attr: 'name'
});
var cmd_option = new Search_provider({
code: '@mc-opt:',
source: metadata,
path: 'commands',
base_query: '%1.takes_options',
array_attr: 'name'
});
metadata.providers.push(objects, commmads, object_param, cmd_arg, cmd_option);
return metadata;
});

View File

@ -22,7 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define(['./jquery', './json2'], function($, JSON) {
define(['./jquery', './json2','./_base/i18n', './_base/metadata_provider'], function($, JSON, i18n, metadata_provider) {
var IPA = function() {
@ -42,6 +42,7 @@ var IPA = function() {
};
that.metadata = {};
metadata_provider.source = that.metadata;
that.messages = {};
that.whoami = {};
@ -111,6 +112,7 @@ var IPA = function() {
method: 'i18n_messages',
on_success: function(data, text_status, xhr) {
that.messages = data.texts;
i18n.source = that.messages;
}
}));
@ -1268,71 +1270,23 @@ IPA.default_factory = function(spec) {
/* helper function used to retrieve information about an attribute */
IPA.get_entity_param = function(entity_name, name) {
var metadata = IPA.metadata.objects[entity_name];
if (!metadata) {
return null;
}
var params = metadata.takes_params;
if (!params) {
return null;
}
for (var i=0; i<params.length; i++) {
if (params[i].name === name) {
return params[i];
}
}
return null;
return metadata_provider.get(['@mo-param', entity_name, name].join(':'));
};
IPA.get_command_arg = function(command_name, arg_name) {
var metadata = IPA.metadata.commands[command_name];
if (!metadata) {
return null;
}
var args = metadata.takes_args;
if (!args) {
return null;
}
for (var i=0; i<args.length; i++) {
if (args[i].name === arg_name) {
return args[i];
}
}
return null;
return metadata_provider.get(['@mc-arg', command_name, arg_name].join(':'));
};
IPA.get_command_option = function(command_name, option_name) {
var metadata = IPA.metadata.commands[command_name];
if (!metadata) {
return null;
}
var options = metadata.takes_options;
if (!options) {
return null;
}
for (var i=0; i<options.length; i++) {
if (options[i].name === option_name) {
return options[i];
}
}
return null;
return metadata_provider.get(['@mc-opt', command_name, option_name].join(':'));
};
/* helper function used to retrieve attr name with members of type `member` */
IPA.get_member_attribute = function(obj_name, member) {
var obj = IPA.metadata.objects[obj_name];
var obj = metadata_provider.get('@mo:'+obj_name);
if (!obj) {
return null;
}

View File

@ -25,9 +25,9 @@ define(['dojo/_base/declare',
'dojo/_base/lang',
'dojo/store/Observable',
'dojo/Evented',
'../_base/i18n',
'../text',
'../ipa' // TODO: remove dependance
], function(declare, Memory_store, array, lang, Observable, Evented, i18n, IPA) {
], function(declare, Memory_store, array, lang, Observable, Evented, text, IPA) {
/**
* Menu store
@ -109,8 +109,8 @@ return declare([Evented], {
// FIXME: consider to move entity and facet stuff outside of this object
item.name = item.name || item.facet || item.entity;
if (!name) throw 'Missing menu item property: name';
if (item.label) item.label = i18n.message(item.label);
if (item.title) item.title = i18n.message(item.title);
if (item.label) item.label = text.get(item.label);
if (item.title) item.title = text.get(item.title);
if (item.entity) {
// FIXME: replace with 'entities' module in future

View File

@ -0,0 +1,40 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Text provider
*
* Serves for returning labels, titles, messages from various providers.
* Other providers can extends functionality.
*/
define(['./_base/Provider', './_base/i18n', './_base/metadata_provider'],
function(Provider, i18n, metadata) {
var text = new Provider({
providers: [
i18n,
metadata
],
null_value: '',
required_type: 'string'
});
return text;
});