summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/ui/src/freeipa/Application_controller.js13
-rw-r--r--install/ui/src/freeipa/_base/Builder.js118
-rw-r--r--install/ui/src/freeipa/_base/Construct_registry.js62
-rw-r--r--install/ui/src/freeipa/_base/Phase_controller.js89
-rw-r--r--install/ui/src/freeipa/_base/Provider.js30
-rw-r--r--install/ui/src/freeipa/_base/Search_provider.js25
-rw-r--r--install/ui/src/freeipa/_base/Singleton_registry.js35
-rw-r--r--install/ui/src/freeipa/_base/Spec_mod.js31
-rw-r--r--install/ui/src/freeipa/_base/construct.js35
-rw-r--r--install/ui/src/freeipa/_base/i18n.js5
-rw-r--r--install/ui/src/freeipa/aci.js60
-rw-r--r--install/ui/src/freeipa/add.js55
-rw-r--r--install/ui/src/freeipa/app.js11
-rw-r--r--install/ui/src/freeipa/association.js68
-rw-r--r--install/ui/src/freeipa/builder.js28
-rw-r--r--install/ui/src/freeipa/config.js9
-rw-r--r--install/ui/src/freeipa/details.js819
-rw-r--r--install/ui/src/freeipa/dialog.js306
-rw-r--r--install/ui/src/freeipa/entity.js398
-rw-r--r--install/ui/src/freeipa/facet.js1331
-rw-r--r--install/ui/src/freeipa/field.js568
-rw-r--r--install/ui/src/freeipa/hbac.js1
-rw-r--r--install/ui/src/freeipa/ipa.js675
-rw-r--r--install/ui/src/freeipa/menu.js31
-rw-r--r--install/ui/src/freeipa/metadata.js16
-rw-r--r--install/ui/src/freeipa/navigation.js46
-rw-r--r--install/ui/src/freeipa/navigation/Menu.js65
-rw-r--r--install/ui/src/freeipa/navigation/MenuItem.js98
-rw-r--r--install/ui/src/freeipa/navigation/Router.js31
-rw-r--r--install/ui/src/freeipa/navigation/menu_spec.js11
-rw-r--r--install/ui/src/freeipa/netgroup.js1
-rw-r--r--install/ui/src/freeipa/ordered-map.js1
-rw-r--r--install/ui/src/freeipa/phases.js28
-rw-r--r--install/ui/src/freeipa/plugin_loader.js23
-rw-r--r--install/ui/src/freeipa/reg.js30
-rw-r--r--install/ui/src/freeipa/selinux.js1
-rw-r--r--install/ui/src/freeipa/spec_util.js7
-rw-r--r--install/ui/src/freeipa/sudo.js1
-rw-r--r--install/ui/src/freeipa/text.js20
-rw-r--r--install/ui/src/freeipa/user.js7
-rw-r--r--install/ui/src/freeipa/widget.js817
-rw-r--r--install/ui/src/freeipa/widgets/App.js3
-rw-r--r--install/ui/src/freeipa/widgets/Menu.js41
43 files changed, 5571 insertions, 479 deletions
diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js
index 4c1007b7b..4bde1238c 100644
--- a/install/ui/src/freeipa/Application_controller.js
+++ b/install/ui/src/freeipa/Application_controller.js
@@ -18,12 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Application controller
- *
- * Controls interaction between navigation, menu and facets.
- */
-
define([
'dojo/_base/declare',
'dojo/_base/lang',
@@ -44,10 +38,11 @@ define([
JSON, App_widget, IPA, Menu, Router, menu_spec) {
/**
- * Main application
+ * Application controller
+ *
+ * Controls interaction between navigation, menu and facets.
*
- * This class serves as top level widget. It creates basic UI: controls
- * rendering of header, footer and placeholder for facets.
+ * @class Application_controller
*/
var App = declare(null, {
diff --git a/install/ui/src/freeipa/_base/Builder.js b/install/ui/src/freeipa/_base/Builder.js
index e4669ed9e..e487aa542 100644
--- a/install/ui/src/freeipa/_base/Builder.js
+++ b/install/ui/src/freeipa/_base/Builder.js
@@ -28,35 +28,51 @@ define(['dojo/_base/declare',
var undefined;
+ /**
+ * Builder
+ *
+ * Builds objects based on their specification.
+ * @class _base.Builder
+ */
var Builder = declare(null, {
/**
- * Builds objects based on specication.
- *
- * @class
- * @name Builder
- */
-
- /**
* Construct registry
- * @property ./Construct_registry
+ * @property {_base.Construct_registry}
*/
registry: null,
/**
* Specification modifier
+ * @property {_base.Spec_mod}
*/
spec_mod: null,
+ /**
+ * Default factory
+ * @property {Function|null}
+ */
factory: null,
+ /**
+ * Default constructor
+ * @property {Function|null}
+ */
ctor: null,
/**
* Array of spec modifiers.
*
- * Spec modifier is a function which is called before build.
- * takes params: spec, context
- * returns spec
+ * Are applied before build on spec object.
+ *
+ * Spec modifier can be:
+ *
+ * - a function which is called before build
+ * - takes params: spec, context
+ * - returns spec
+ * - an object which is mixed in into spec
+ * - an object with properties for Spec_mod
+ *
+ * @property {Array|null}
*/
pre_ops: null,
@@ -64,55 +80,59 @@ define(['dojo/_base/declare',
* Array of object modifiers.
*
* Object modifier is a function which is after build.
- * takes params: built object, spec, context
- * returns object
+ *
+ * - takes params: built object, spec, context
+ * - returns object
+ * @property {Array|null}
*/
post_ops: null,
/**
* Controls what builder do when spec is a string. Possible values:
- * * 'type'
- * * 'property'
- * Type:
- * Spec is type. Queries registry for obtaining construction spec.
*
- * Property:
- * Spec is a property of spec, name of property is set in
- * `string_property`. This mode should be combined with default
- * factory or ctor otherwise the build will fail.
+ * - 'type'
+ * - 'property'
+ *
+ * ##Type
+ * Spec is type. Queries registry for obtaining construction spec.
+ *
+ * ##Property
+ * Spec is a property of spec, name of property is set in
+ * `string_property`. This mode should be combined with default
+ * factory or ctor otherwise the build will fail.
*
- * @type {String}
+ * @property {string}
*/
string_mode: 'type',
/**
* Property name for `string_mode` == `property`
- * @type {String}
+ * @property {string}
*/
string_property: '',
/**
* Build object based on spec.
*
- * @param {String|Function|Object|Array} Build spec
- * @param {Object} build context
- * @param {Object} overrides
+ * @param {string|Function|Object|Array} spec Build spec
*
- * String: type name, queries registry
- * Function: factory or ctor
- * Object: spec object
- * Array: array of spec objects
+ * - **String**: type name, queries registry
+ * - **Function**: factory or ctor
+ * - **Object**: spec object
+ * - **Array**: array of spec objects
*
- * Build control properies of spec object:
- * $ctor: Function
- * $factory: Function
- * $mixim_spec: Boolean
- * $type: String
- * $pre_ops: []
- * $post_ops: []
+ * Build control properties of spec object:
*
- * All other properties will be passed to object construction method.
+ * - $ctor: Function
+ * - $factory: Function
+ * - $mixim_spec: boolean
+ * - $type: string
+ * - $pre_ops: []
+ * - $post_ops: []
*
+ * All other properties will be passed to object construction method.
+ * @param {Object} context build context
+ * @param {Object} overrides
* Builder default factory and ctor is overridden by those specified
* in overrides when overrides are set.
*/
@@ -167,12 +187,20 @@ define(['dojo/_base/declare',
return objects;
},
+ /**
+ * Build single object
+ * @protected
+ */
_build: function(spec, context) {
var cs = this._get_construction_spec(spec);
var obj = this._build_core(cs, context);
return obj;
},
+ /**
+ * Normalizes construction specification
+ * @protected
+ */
_get_construction_spec: function(spec) {
var cs = {};
@@ -235,6 +263,7 @@ define(['dojo/_base/declare',
/**
* Queries registry and returns copy of construction specification
+ * @protected
*/
_query_registry: function(type) {
@@ -253,6 +282,7 @@ define(['dojo/_base/declare',
/**
* Get cs from string according to string mode
+ * @protected
*/
_get_cs_string: function(spec) {
@@ -267,6 +297,10 @@ define(['dojo/_base/declare',
return cs;
},
+ /**
+ * Core build method
+ * @protected
+ */
_build_core: function(construction_spec, context) {
var cs = construction_spec,
@@ -318,6 +352,10 @@ define(['dojo/_base/declare',
return obj;
},
+ /**
+ * Apply pre_ops
+ * @protected
+ */
_run_preops: function(pre_ops, spec, context) {
for (var i=0; i<pre_ops.length; i++) {
var preop = pre_ops[i];
@@ -334,6 +372,10 @@ define(['dojo/_base/declare',
return spec;
},
+ /**
+ * Apply post_ops
+ * @protected
+ */
_run_post_ops: function(post_ops, obj, spec, context) {
for (var i=0; i<post_ops.length; i++) {
var postop = post_ops[i];
diff --git a/install/ui/src/freeipa/_base/Construct_registry.js b/install/ui/src/freeipa/_base/Construct_registry.js
index d9489add3..934af6ef1 100644
--- a/install/ui/src/freeipa/_base/Construct_registry.js
+++ b/install/ui/src/freeipa/_base/Construct_registry.js
@@ -24,12 +24,12 @@ define(['dojo/_base/declare',
'./construct'
], function(declare, array, lang, construct) {
+ /**
+ * Registry for storing construction specification.
+ * @class _base.Construct_registry
+ */
var Construct_registry = declare(null, {
- /**
- * Registry for storing construction specification.
- * @class
- * @name Construct_registry
- */
+
/**
* Internal map for construction specifications.
@@ -40,27 +40,25 @@ define(['dojo/_base/declare',
/**
* Registers construction specification
*
- * @param type {String|Object} type or construction spec
- * @param func {Function} ctor or factory function
- * @param [default_spec] {Object} default spec object for given type
- *
- * @returns Object
+ * // May be defined by single construction spec object:
+ * var construction_spec = {
+ * type: String,
+ * factory: Function,
+ * ctor: Function,
+ * spec: Object,
+ * pre_ops: [],
+ * post_ops: []
+ * };
+ * register(construction_spec);
*
- * Examples:
+ * // or by defining them separately as params:
+ * register(type, factory|ctor, spec);
*
- * May be defined by single construction spec object:
- * var construction_spec = {
- * type: String,
- * factory: Function,
- * ctor: Function,
- * spec: Object,
- * pre_ops: [],
- * post_ops: []
- * };
- * register(construction_spec);
+ * @param {string|Object} type type or construction spec
+ * @param {Function} func ctor or factory function
+ * @param {Object} [default_spec] default spec object for given type
*
- * or by defining them separately as params:
- * register(type, factory|ctor, spec);
+ * @returns {Object}
*/
register: function(type, func, default_spec) {
@@ -91,9 +89,9 @@ define(['dojo/_base/declare',
* Makes a copy of construct specification of original type. Extends
* it with values in supplied construct specification.
*
- * @param {String} Original type
- * @param {String} New type
- * @param {Object} Construction specification
+ * @param {string} org_type Original type
+ * @param {string} new_type New type
+ * @param {Object} construct_spec Construction specification
*/
copy: function(org_type, new_type, construct_spec) {
@@ -128,9 +126,9 @@ define(['dojo/_base/declare',
*
* When op is Object, the object gets mixed in into spec.
*
- * @param {type} type
+ * @param {string} type
* @param {Function|Object} op
- * @param {Boolean} move op to first position
+ * @param {boolean} move op to first position
*/
register_pre_op: function(type, op, first) {
@@ -150,9 +148,9 @@ define(['dojo/_base/declare',
* When op is Object, the object gets mixed in into built object. Use
* with caution.
*
- * @param {type} type
+ * @param {string} type
* @param {Function|Object} op
- * @param {Boolean} move op to first position
+ * @param {boolean} first move op to first position
*/
register_post_op: function(type, op, first) {
@@ -164,8 +162,8 @@ define(['dojo/_base/declare',
/**
* Gets construction specification for given type.
*
- * @param type {String} Type name
- * @returns Object|null
+ * @param {string} string Type name
+ * @returns {Object|null}
*/
get: function(type) {
return this._map[type] || null;
diff --git a/install/ui/src/freeipa/_base/Phase_controller.js b/install/ui/src/freeipa/_base/Phase_controller.js
index 095b90241..9147f201a 100644
--- a/install/ui/src/freeipa/_base/Phase_controller.js
+++ b/install/ui/src/freeipa/_base/Phase_controller.js
@@ -28,17 +28,66 @@ define([
'../ordered-map'
], function(lang, array, declare, Deferred, all, topic, ordered_map) {
+
+ /**
+ * Phase
+ *
+ * This class does not exist, it's only for documentation purposes.
+ *
+ * @class _base.Phase_controller.phase
+ * @abstract
+ */
+ /**
+ * Name
+ * @property {string} name
+ */
+ /**
+ * Tasks
+ * @property {Array.<_base.Phase_controller.task>} tasks
+ */
+
+ /**
+ * Phase task
+ *
+ * This class does not exist, it's only for documentation purposes.
+ *
+ * @class _base.Phase_controller.task
+ * @abstract
+ */
+ /**
+ * Name
+ * @property {number} priority
+ */
+ /**
+ * Tasks
+ * @property {Function} handler
+ */
+
+ /**
+ * Phase Controller
+ *
+ * Creates synchronization points - phases - in application life cycle.
+ *
+ * Phases:
+ *
+ * - are ordered
+ * - consist of task
+ * - phase finishes when all task finishes
+ * - new phases can be added at runtime
+ *
+ * @class _base.Phase_controller
+ */
var Phase_controller = declare(null, {
/**
* Phases
- * @type ordered_map[name, phase]
+ * @property {ordered_map.<string, _base.Phase_controller.phase>}
*/
phases: null,
/**
* Current phase name
- * @type String
+ * @property {string}
*/
current: null,
@@ -57,13 +106,14 @@ define([
/**
* Runs phase
- * 1) Sorts tasks of the phase based on their priority.
- * 2) Runs all task sequentially.
- * 3) Waits for all tasks to complete (in case of asynchronous ones)
- * 4) Optionally runs next phase
*
- * @param {phase} Phase to runs
- * @param {Boolean} Whether to run next phase when current finishes
+ * 1. Sorts tasks of the phase based on their priority.
+ * 2. Runs all task sequentially.
+ * 3. Waits for all tasks to complete (in case of asynchronous ones)
+ * 4. Optionally runs next phase
+ *
+ * @param {_base.Phase_controller.phase} phase Phase to run
+ * @param {boolean} next_phase Whether to run next phase when current finishes
*/
_run_phase: function(phase, next_phase) {
@@ -104,7 +154,7 @@ define([
/**
* Selects next phase and then runs it.
*
- * @param {Boolen} Whether to run phases continuously
+ * @param {boolean} continuous Whether to run phases continuously
*/
next_phase: function(continuous) {
var phase;
@@ -125,9 +175,9 @@ define([
* At phase execution, tasks are sorted by priority and executed in
* that order.
*
- * @param {String} Name of associated phase
- * @param {Function} Task handler. Should return promise if async.
- * @param {Number} Priority of task. Default 10.
+ * @param {string} phase_name Name of associated phase
+ * @param {Function} handler Task handler. Should return promise if async.
+ * @param {number} [priority=10] Priority of task.
*/
add_task: function(phase_name, handler, priority) {
@@ -150,12 +200,13 @@ define([
* Adds a phase
*
* Possible options:
- * before: 'name-of-phase'
- * after: 'name-of-phase'
- * position: 'position for new phase'
*
- * @param {String} phase name
- * @param {Array} tasks
+ * - before: 'name-of-phase'
+ * - after: 'name-of-phase'
+ * - position: 'position for new phase'
+ *
+ * @param {string} phase name
+ * @param {Array.<_base.Phase_controller.task>} tasks
* @param {Object} options
*/
add_phase: function(name, tasks, options) {
@@ -184,8 +235,8 @@ define([
/**
* Checks if phases with given name exists
*
- * @param {String} name
- * @return {Boolean}
+ * @param {string} name
+ * @return {boolean}
*/
exists: function(name) {
return !!this.phases.get(name);
diff --git a/install/ui/src/freeipa/_base/Provider.js b/install/ui/src/freeipa/_base/Provider.js
index 8d769a2eb..b2e55aed3 100644
--- a/install/ui/src/freeipa/_base/Provider.js
+++ b/install/ui/src/freeipa/_base/Provider.js
@@ -30,15 +30,18 @@
*
* Path is a plain object path within a source.
*
- * Ie. if source is {
- * foo: {
- * bar: {
- * a: 'val'
- * }
- * }
- * }
+ * // if source is
+ * {
+ * foo: {
+ * bar: {
+ * a: 'val'
+ * }
+ * }
+ * }
*
- * path: 'foo.bar.a' would return 'val'
+ * // path: `foo.bar.a` would return `val`
+ *
+ * @class _base.Provider
*
*/
define(['dojo/_base/declare','dojo/_base/lang'], function(declare, lang) {
@@ -48,13 +51,13 @@ define(['dojo/_base/declare','dojo/_base/lang'], function(declare, lang) {
/**
* Array of other providers
- * @type Provider[]
+ * @property {_base.Provider[]}
*/
providers: null,
/**
* Source object or a function which returns source object.
- * @type {Function|Object|Provider}
+ * @property {Function|Object|_base.Provider}
*/
source: null,
@@ -63,19 +66,20 @@ define(['dojo/_base/declare','dojo/_base/lang'], function(declare, lang) {
*
* When defined, all lookups in source are based on the object
* defined by this path within a source.
- * @type String
+ * @property {string}
*/
path: null,
/**
* Value which is returned if no value nor alternative is found
+ * @property {Mixed}
*/
null_value: null,
/**
* Specifies which type should be returned. Limited to output of
* typeof operator.
- * @type String
+ * @property {string}
*/
required_type: null,
@@ -153,7 +157,7 @@ define(['dojo/_base/declare','dojo/_base/lang'], function(declare, lang) {
/**
* Gets value.
*
- * @param {String|Object} Key or value
+ * @param {string|Object} Key or value
* @param {Object} Alternate value
*/
get: function(key, alternate) {
diff --git a/install/ui/src/freeipa/_base/Search_provider.js b/install/ui/src/freeipa/_base/Search_provider.js
index fcd2b0ff7..10ef1562e 100644
--- a/install/ui/src/freeipa/_base/Search_provider.js
+++ b/install/ui/src/freeipa/_base/Search_provider.js
@@ -19,24 +19,30 @@
*/
/**
- * Search value providers.
+ * Search value provider
*
- * Serves for searching for values within a array in a source.
+ * Serves for searching for values within an array in a source object.
+ *
+ * Path has input formats as follows:
*
- * Path has following formats:
* * key1:key2:key3
* * key1:key2
* * key2
*
- * base_query: '%1.takes_params'
- * array_attr: 'name'
+ * With:
+ *
+ * * base_query: `%1.takes_params`
+ * * array_attr: `name`
+ *
+ * Such path is translates into query:
*
- * It translates into following query:
- * %key1.takes_params[name=%key2].$key3
+ * * `%key1.takes_params[name=%key2].$key3`
*
* In a future we should support defining generic queries and thus not be
* limited to simple search.
*
+ * @class _base.Search_provider
+ * @extends _base.Provider
*/
define(['dojo/_base/declare','dojo/_base/lang', './Provider'],
function(declare, lang, Provider) {
@@ -46,6 +52,10 @@ define(['dojo/_base/declare','dojo/_base/lang', './Provider'],
base_query: null,
array_attr: null,
+ /**
+ * @inheritDoc
+ * @protected
+ */
_get: function(key) {
var search_keys = key.substring(this._code_length);
search_keys = search_keys.split(':');
@@ -80,6 +90,7 @@ define(['dojo/_base/declare','dojo/_base/lang', './Provider'],
/**
* Finds object with attr_name === value in array defined by key.
+ * @protected
*/
_find: function(array, attr, value, all) {
diff --git a/install/ui/src/freeipa/_base/Singleton_registry.js b/install/ui/src/freeipa/_base/Singleton_registry.js
index a3427d7e0..e0c55ca14 100644
--- a/install/ui/src/freeipa/_base/Singleton_registry.js
+++ b/install/ui/src/freeipa/_base/Singleton_registry.js
@@ -26,26 +26,25 @@ define(['dojo/_base/declare',
'./Construct_registry'
], function(declare, array, lang, construct, Builder, Construct_registry) {
+ /**
+ * Registry for storing singleton instances of various items based
+ * on their type.
+ *
+ * @class _base.Singleton_registry
+ */
var Singleton_registry = declare(null, {
- /**
- * Registry for storing singleton instances of various items based
- * on their type.
- *
- * @class
- * @name Singleton_registry
- */
/**
* Internal map for instances
* @protected
- * @type Object
+ * @property {Object}
*/
_map: {},
/**
* Builder used for building new instances. Builder has to have a
* Constructor registry set.
- * @type Builder
+ * @property {_base.Builder}
*/
builder: null,
@@ -55,8 +54,8 @@ define(['dojo/_base/declare',
*
* When an object is passed in, the function returns it.
*
- * @param type {String|Object} Type's name. Or the the object itself.
- * @returns Object|null
+ * @param {string|Object} type Type's name. Or the the object itself.
+ * @return {Object|null}
*/
get: function(type) {
@@ -79,8 +78,8 @@ define(['dojo/_base/declare',
/**
* Set object of given type - overwrites existing
*
- * @param {String} type
- * @param {anything} object
+ * @param {string} type
+ * @param {Mixed} object
*/
set: function (type, obj) {
this._map[type] = obj;
@@ -89,7 +88,7 @@ define(['dojo/_base/declare',
/**
* Removes object of given type from registry
*
- * @param {String} type
+ * @param {string} type
*/
remove: function(type) {
@@ -100,11 +99,11 @@ define(['dojo/_base/declare',
/**
* Registers construction specification
*
- * @param type {String|Object} type or construction spec
- * @param func {Function} ctor or factory function
- * @param [default_spec] {Object} default spec object for given type
+ * @param {string|Object} type type or construction spec
+ * @param {Function} func ctor or factory function
+ * @param {Object} [default_spec] default spec object for given type
*
- * @returns Object
+ * @return {Object}
*/
register: function(type, func, default_spec) {
if (!lang.exists('builder.registry', this)) {
diff --git a/install/ui/src/freeipa/_base/Spec_mod.js b/install/ui/src/freeipa/_base/Spec_mod.js
index 60d4b9229..34f79f726 100644
--- a/install/ui/src/freeipa/_base/Spec_mod.js
+++ b/install/ui/src/freeipa/_base/Spec_mod.js
@@ -22,16 +22,23 @@ define(['dojo/_base/declare',
'dojo/_base/lang'
], function(declare, lang) {
+ /**
+ * Utility for common modification of specification objects
+ *
+ * @class _base.Spec_mod
+ */
var Spec_mod = declare(null, {
/**
* Modifies spec according to rules defined in diff object.
*
- * Diff should have following structure: {
- * $add: array of add rules
- * $del: array of del rules
- * $set: array of set rules
- * }
+ * Diff should have structure as follows:
+ *
+ * {
+ * $add: array of add rules
+ * $del: array of del rules
+ * $set: array of set rules
+ * }
*
* The order of modification is del, add, set.
*
@@ -54,8 +61,10 @@ define(['dojo/_base/declare',
* Adds objects according to rules to array.
*
* A rule is a triple of path and a object and position to add:
- * ['path.to.spec.array', {}, position]
*
+ * ['path.to.spec.array', {}, position]
+ * @param {Object} spec
+ * @param {Array} rules
*/
add: function(spec, rules) {
@@ -66,9 +75,11 @@ define(['dojo/_base/declare',
* Deletes objects according to rules from an array.
*
* A rule is a pair of path and delete conditions:
- * ['path.to.spec.array', [ { name: 'foo'}, { name: 'baz'} ]]
*
- * Deletes all objects with name 'baz' or 'foo'.
+ * ['path.to.spec.array', [ { name: 'foo'}, { name: 'baz'} ]]
+ * // Deletes all objects with name 'baz' or 'foo'.
+ * @param {Object} spec
+ * @param {Array} rules
*/
del: function(spec, rules) {
@@ -77,7 +88,10 @@ define(['dojo/_base/declare',
/**
* A rule is a pair of path and a object to set.
+ *
* ['path.to.spec.property', {}]
+ * @param {Object} spec
+ * @param {Array} rules
*/
set: function(spec, rules) {
@@ -86,6 +100,7 @@ define(['dojo/_base/declare',
/**
* Removes all rule props
+ * @param {Object} diff
*/
del_rules: function(diff) {
delete diff.$add;
diff --git a/install/ui/src/freeipa/_base/construct.js b/install/ui/src/freeipa/_base/construct.js
index 960596da2..ce675e588 100644
--- a/install/ui/src/freeipa/_base/construct.js
+++ b/install/ui/src/freeipa/_base/construct.js
@@ -23,14 +23,17 @@ define(['dojo/_base/declare',
'dojo/_base/lang'
], function(declare, array, lang) {
+ /**
+ * Helper module
+ * @class _base.construct
+ * @singleton
+ */
var construct = {
- /**
- * Helper modules
- */
/**
- * Checks if supplied object is a construtor function.
- * It can recognize only classes declared by ''dojo/_base/declare''.
+ * Checks if supplied object is a constructor function.
+ * It can recognize only classes declared by `dojo/_base/declare`.
+ * @param {Object} obj
*/
is_ctor: function(obj) {
@@ -38,13 +41,14 @@ define(['dojo/_base/declare',
},
/**
- * Finds out if object is a spec object.
+ * Finds out if object is a spec object.
*
- * Object is not a spec object when any of following applies:
- * * has __fw_obj === true
- * * has isInstanceOf function - basically tells if it's a instance of
- * dojo-based class
+ * Object is not a spec object when any of following applies:
*
+ * - has `__fw_obj === true`
+ * - has `isInstanceOf` function - basically tells if it's a instance of
+ * dojo-based class
+ * @param {Object} obj
*/
is_spec: function(obj) {
var ret = false;
@@ -56,13 +60,14 @@ define(['dojo/_base/declare',
},
/**
- * Deep clone.
- * - does not clone framework objects
- * - fails on cyclic non-framework objects
+ * Deep clone
+ *
+ * - does not clone framework objects
+ * - fails on cyclic non-framework objects
*
- * based on dojo/_base/lang.clone
+ * based on `dojo/_base/lang.clone`
*
- * @param {anything} object to clone
+ * @param {Mixed} src object to clone
*/
clone: function(src) {
diff --git a/install/ui/src/freeipa/_base/i18n.js b/install/ui/src/freeipa/_base/i18n.js
index 970705bba..ae9b40bca 100644
--- a/install/ui/src/freeipa/_base/i18n.js
+++ b/install/ui/src/freeipa/_base/i18n.js
@@ -21,11 +21,14 @@
/**
* Gets translated message.
*
-* If a message starts with @i18n: it tries to get the message from
+* 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.
+* @class _base.i18n
+* @extends _base.Provider
+* @singleton
*/
define(['dojo/_base/lang', './Provider'], function(lang, Provider) {
diff --git a/install/ui/src/freeipa/aci.js b/install/ui/src/freeipa/aci.js
index 3ca10dbfb..67dc46e3e 100644
--- a/install/ui/src/freeipa/aci.js
+++ b/install/ui/src/freeipa/aci.js
@@ -32,6 +32,16 @@ define([
'./entity'],
function(metadata_provider, IPA, $, phases, reg, text) {
+/**
+ * Widgets, entities and fields related to Access Control that means
+ * Permissions, Privilege, Role, Delegation and Self-service.
+ *
+ * When loaded, this module is also accessible as `IPA.aci`.
+ *
+ * @class aci
+ * @alternateClassName IPA.aci
+ * @singleton
+ */
var exp = IPA.aci = {};
var make_permission_spec = function() {
@@ -231,6 +241,10 @@ return {
}
};};
+/**
+ * @class aci.permission_details_facet
+ * @extends details.details_facet
+ */
IPA.aci.permission_details_facet = function(spec) {
var that = IPA.details_facet(spec);
@@ -463,7 +477,10 @@ return {
}
};};
-
+/**
+ * @class IPA.attributes_widget
+ * @extends IPA.checkboxes_widget
+ */
IPA.attributes_widget = function(spec) {
spec = spec || {};
@@ -609,6 +626,10 @@ IPA.attributes_widget = function(spec) {
return that;
};
+/**
+ * @class IPA.rights_widget
+ * @extends IPA.checkboxes_widget
+ */
IPA.rights_widget = function(spec) {
var that = IPA.checkboxes_widget(spec);
@@ -622,6 +643,10 @@ IPA.rights_widget = function(spec) {
return that;
};
+/**
+ * @class IPA.permission_target_widget
+ * @extends IPA.details_table_section_nc
+ */
IPA.permission_target_widget = function(spec) {
spec = spec || {};
@@ -737,6 +762,11 @@ IPA.permission_target_widget = function(spec) {
return that;
};
+/**
+ * Permission target policy
+ * @class IPA.permission_target_policy
+ * @extends IPA.facet_policy
+ */
IPA.permission_target_policy = function (spec) {
var that = IPA.facet_policy();
@@ -894,12 +924,40 @@ IPA.permission_target_policy = function (spec) {
return that;
};
+/**
+ * Permission entity spec
+ * @member aci
+ */
exp.permission_entity_spec = make_permission_spec();
+
+/**
+ * Privilege entity spec
+ * @member aci
+ */
exp.privilege_entity_spec = make_privilege_spec();
+
+/**
+ * Role entity spec
+ * @member aci
+ */
exp.role_entity_spec = make_role_spec();
+
+/**
+ * Self-service entity spec
+ * @member aci
+ */
exp.selfservice_entity_spec = make_selfservice_spec();
+
+/**
+ * Delegation entity spec
+ * @member aci
+ */
exp.delegation_entity_spec = make_delegation_spec();
+/**
+ * Register entities, widgets and fields to global registers.
+ * @member aci
+ */
exp.register = function() {
var e = reg.entity;
var w = reg.widget;
diff --git a/install/ui/src/freeipa/add.js b/install/ui/src/freeipa/add.js
index eb7ce38dc..00d499da5 100644
--- a/install/ui/src/freeipa/add.js
+++ b/install/ui/src/freeipa/add.js
@@ -22,6 +22,12 @@
define(['./ipa', './jquery', './navigation', './text', './field', './widget', './dialog'],
function(IPA, $, navigation, text) {
+/**
+ * Entity adder dialog
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
+ */
IPA.entity_adder_dialog = function(spec) {
spec = spec || {};
@@ -32,14 +38,34 @@ IPA.entity_adder_dialog = function(spec) {
IPA.confirm_mixin().apply(that);
+ /** @property {string} method="add" API method for add command */
that.method = spec.method || 'add';
+ /** @property {Function} on_error Custom add error handler */
that.on_error = spec.on_error ;
+ /** @property {boolean} retry=true Allow retry on error (same as in IPA.command)*/
that.retry = typeof spec.retry !== 'undefined' ? spec.retry : true;
+ /**
+ * Add command
+ * @property {IPA.command}
+ * @protected
+ */
that.command = null;
+ /** @property {IPA.observer} added Added event */
that.added = IPA.observer();
+ /** @property {string} subject Name of added subject (usually entity label) */
that.subject = spec.subject || that.entity.metadata.label_singular;
+ /**
+ * Pkeys of containing entities to use in add command when adding nested entity
+ * @property {string[]}
+ */
that.pkey_prefix = spec.pkey_prefix || [];
+ /**
+ * Custom logic for navigation to edit page in case of 'Add and Edit'
+ * @property {Function}
+ * @param {entity.entity} entity
+ * @param {Object} result
+ */
that.show_edit_page = spec.show_edit_page || show_edit_page;
var init = function() {
@@ -94,6 +120,10 @@ IPA.entity_adder_dialog = function(spec) {
});
};
+ /**
+ * Invokes simple add
+ * @protected
+ */
that.on_add = function() {
that.hide_message();
@@ -106,15 +136,29 @@ IPA.entity_adder_dialog = function(spec) {
that.on_error);
};
+ /**
+ * Confirm handler
+ * @protected
+ */
that.on_confirm = function() {
that.on_add();
};
+ /**
+ * Get success notification message text
+ * @protected
+ * @param {Object} data Add command result
+ */
that.get_success_message = function(data) {
var message = text.get('@i18n:dialogs.add_confirmation');
return message.replace('${entity}', that.subject);
};
+ /**
+ * Show success notification
+ * @protected
+ * @param {Object} data Add command result
+ */
that.notify_success = function(data) {
IPA.notify_success(that.get_success_message(data));
};
@@ -131,6 +175,11 @@ IPA.entity_adder_dialog = function(spec) {
navigation.show_entity(that.entity.name, 'default', pkeys);
}
+ /**
+ * Create add command
+ * @protected
+ * @param {Object} record Saved data
+ */
that.create_add_command = function(record) {
var pkey_name = that.entity.metadata.primary_key;
@@ -163,6 +212,11 @@ IPA.entity_adder_dialog = function(spec) {
return command;
};
+ /**
+ * Execute add command
+ * @param {Function} on_success
+ * @param {Function} on_error
+ */
that.add = function(on_success, on_error) {
if (!that.validate()) return;
@@ -177,6 +231,7 @@ IPA.entity_adder_dialog = function(spec) {
that.command.execute();
};
+ /** @inheritDoc */
that.create = function() {
that.dialog_create();
diff --git a/install/ui/src/freeipa/app.js b/install/ui/src/freeipa/app.js
index 37c4c08a8..2fbe0775c 100644
--- a/install/ui/src/freeipa/app.js
+++ b/install/ui/src/freeipa/app.js
@@ -18,9 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Application wrapper
- */
define([
//core
'dojo/_base/lang',
@@ -56,6 +53,14 @@ define([
'dojo/domReady!'
],function(lang, Deferred, when, plugin_loader, phases, Application_controller, exports) {
+ /**
+ * Application wrapper
+ *
+ * Prepares application controller and registers phases.
+ *
+ * @class app
+ * @singleton
+ */
var app = {
/**
diff --git a/install/ui/src/freeipa/association.js b/install/ui/src/freeipa/association.js
index ad427d66b..8709b9045 100644
--- a/install/ui/src/freeipa/association.js
+++ b/install/ui/src/freeipa/association.js
@@ -38,8 +38,17 @@ define([
function(Deferred, metadata_provider, IPA, $, navigation,
phases, reg, su, text) {
+/**
+ * Association module
+ * @class association
+ * @singleton
+ */
var exp = {};
+/**
+ * Associator base class
+ * @class
+ */
IPA.associator = function (spec) {
spec = spec || {};
@@ -65,7 +74,10 @@ IPA.associator = function (spec) {
/**
+ * Serial associator
* This associator is built for the case where each association requires a separate rpc
+ * @class
+ * @extends IPA.associator
*/
IPA.serial_associator = function(spec) {
@@ -112,6 +124,7 @@ IPA.serial_associator = function(spec) {
/**
* This associator is for the common case where all the asociations can be sent
* in a single rpc
+ * @class
*/
IPA.bulk_associator = function(spec) {
@@ -148,6 +161,8 @@ IPA.bulk_associator = function(spec) {
/**
* This dialog is for adding value of multivalued attribute which behaves like
* association attribute.
+ * @class
+ * @extends IPA.entity_adder_dialog
*/
IPA.attribute_adder_dialog = function(spec) {
@@ -206,6 +221,8 @@ IPA.attribute_adder_dialog = function(spec) {
/**
* This dialog is used for adding associations between two entities.
+ * @class
+ * @extends IPA.adder_dialog
*/
IPA.association_adder_dialog = function(spec) {
@@ -310,6 +327,8 @@ IPA.association_adder_dialog = function(spec) {
/**
* This dialog is used for removing associations between two entities.
+ * @class
+ * @extends IPA.deleter_dialog
*/
IPA.association_deleter_dialog = function (spec) {
@@ -347,7 +366,10 @@ IPA.association_deleter_dialog = function (spec) {
return that;
};
-
+/**
+ * Association config
+ * @class
+ */
IPA.association_config = function (spec) {
spec = spec || {};
@@ -362,6 +384,11 @@ IPA.association_config = function (spec) {
return that;
};
+/**
+ * Association table widget
+ * @class
+ * @extends IPA.table_widget
+ */
IPA.association_table_widget = function (spec) {
spec = spec || {};
@@ -735,6 +762,11 @@ IPA.association_table_widget = function (spec) {
return that;
};
+/**
+ * Association table field
+ * @class
+ * @extends IPA.field
+ */
IPA.association_table_field = function (spec) {
spec = spec || {};
@@ -771,6 +803,10 @@ IPA.association_table_field = function (spec) {
return that;
};
+/**
+ * Association facet pre-op
+ * @member association
+ */
exp.association_facet_pre_op = function(spec, context) {
var has_indirect_attribute_member = function(spec) {
@@ -880,6 +916,12 @@ exp.association_facet_pre_op = function(spec, context) {
return spec;
};
+/**
+ * Association facet
+ * @class association.association_facet
+ * @alternateClassName IPA.association_facet
+ * @extends facet.table_facet
+ */
exp.association_facet = IPA.association_facet = function (spec, no_init) {
spec = spec || {};
@@ -1223,6 +1265,10 @@ exp.association_facet = IPA.association_facet = function (spec, no_init) {
return that;
};
+/**
+ * Attribute facet pre-op
+ * @member association
+ */
exp.attribute_facet_pre_op = function(spec, context) {
var entity = context.entity;
@@ -1295,6 +1341,12 @@ exp.attribute_facet_pre_op = function(spec, context) {
return spec;
};
+/**
+ * Association facet
+ * @class association.attribute_facet
+ * @alternateClassName IPA.attribute_facet
+ * @extends facet.table_facet
+ */
exp.attribute_facet = IPA.attribute_facet = function(spec, no_init) {
spec = spec || {};
@@ -1455,7 +1507,13 @@ exp.attribute_facet = IPA.attribute_facet = function(spec, no_init) {
return that;
};
-IPA.sid_facet = function(spec, no_init) {
+/**
+ * SID facet
+ * @class association.sid_facet
+ * @alternateClassName IPA.sid_facet
+ * @extends association.attribute_facet
+ */
+exp.sid_facet = IPA.sid_facet = function(spec, no_init) {
spec.name = spec.name || 'sid_facet';
@@ -1501,7 +1559,11 @@ IPA.sid_facet = function(spec, no_init) {
return that;
};
-
+/**
+ * Attriute read-only evaluator
+ * @class IPA.attr_read_only_evaluator
+ * @extends IPA.state_evaluator
+ */
IPA.attr_read_only_evaluator = function(spec) {
spec.name = spec.name || 'attr_read_only_evaluator';
diff --git a/install/ui/src/freeipa/builder.js b/install/ui/src/freeipa/builder.js
index 0a8c39921..6d2086917 100644
--- a/install/ui/src/freeipa/builder.js
+++ b/install/ui/src/freeipa/builder.js
@@ -18,12 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Global builder interface.
- *
- * Contains a map of builders for a specific object type.
- *
- */
define(['dojo/_base/declare',
'dojo/_base/array',
'dojo/_base/lang',
@@ -34,13 +28,25 @@ define(['dojo/_base/declare',
var builder_registry = new Singleton_registry();
builder_registry.builder.ctor = Builder;
+ /**
+ * Global builder interface.
+ *
+ * Contains a map of builders for a specific object type.
+ *
+ * @class builder
+ * @singleton
+ */
var exp = {
+ /**
+ * Registry of builders
+ * @property {_base.Singleton_registry}
+ */
builders: builder_registry,
/**
* Get builder for object type
*
- * @param {String} object type
+ * @param {string} object type
*/
get: function(obj_type) {
return this.builders.get(obj_type);
@@ -49,8 +55,8 @@ define(['dojo/_base/declare',
/**
* Set builder for object type.
*
- * @param {String} object type
- * @param {Builder} builder
+ * @param {string} object type
+ * @param {_base.Builder} builder
*/
set: function(obj_type, builder) {
this.builders.set(obj_type, builder);
@@ -59,8 +65,8 @@ define(['dojo/_base/declare',
/**
* Build object by builder for given object type.
*
- * @param {String} object type. Uses generic builder if empty string.
- * @param {String|Object|Function} spec
+ * @param {string} object type. Uses generic builder if empty string.
+ * @param {string|Object|Function} spec
* @param {Object|null} context
* @param {Object|null} build overrides
*/
diff --git a/install/ui/src/freeipa/config.js b/install/ui/src/freeipa/config.js
index 8aa222cfd..632bc136d 100644
--- a/install/ui/src/freeipa/config.js
+++ b/install/ui/src/freeipa/config.js
@@ -18,12 +18,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Application configuration
- */
+
define([], function() {
+ /**
+ * Application configuration
+ * @class config
+ * @singleton
+ */
var config = {
/**
diff --git a/install/ui/src/freeipa/details.js b/install/ui/src/freeipa/details.js
index 149a04e43..687926c8c 100644
--- a/install/ui/src/freeipa/details.js
+++ b/install/ui/src/freeipa/details.js
@@ -21,8 +21,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* IPA Object Details - populating definiton lists from entry data */
-
define([
'dojo/_base/lang',
'./builder',
@@ -36,22 +34,75 @@ define([
'./add'],
function(lang, builder, IPA, $, phases, reg, su, text) {
+/**
+ * Details module
+ *
+ * @class details
+ * @singleton
+ */
var exp = {};
+/**
+ * Name of expanded icon
+ * @member details
+ */
exp.expanded_icon = IPA.expanded_icon = 'expanded-icon';
+
+/**
+ * Name of collapsed icon
+ * @member details
+ */
exp.collapsed_icon = IPA.collapsed_icon = 'collapsed-icon';
+/**
+ * Details builder
+ *
+ * Processes containers spec and builds sections, widget and fields according
+ * to that spec. Container is usually a details facet or a dialog. For its task
+ * it uses `section_builder`, `widget_builder` and `field_builder` each
+ * builder can be configured. Otherwise it uses default builders.
+ *
+ * @class details.details_builder
+ * @alternateClassName IPA.details_builder
+ */
exp.details_builder = IPA.details_builder = function(spec) {
var that = IPA.object();
+ /**
+ * Container's widget collection
+ * @protected
+ */
that.widgets = spec.container.widgets;
+
+ /**
+ * Container's field collection
+ * @protected
+ */
that.fields = spec.container.fields;
+ /**
+ * Widget builder
+ * @property {IPA.widget_builder}
+ */
that.widget_builder = spec.widget_builder || IPA.widget_builder();
+
+ /**
+ * Fields builder
+ * @property {IPA.field_builder}
+ */
that.field_builder = spec.field_builder || IPA.field_builder();
+
+ /**
+ * Section builder
+ * @property {details.section_builder}
+ */
that.section_builder = spec.section_builder || IPA.section_builder();
+ /**
+ * Build single widget according to its spec and add it to widget collection.
+ * @param {Object} spec widget spec
+ */
that.build_widget = function(spec) {
if (!spec) return;
@@ -59,6 +110,10 @@ exp.details_builder = IPA.details_builder = function(spec) {
that.widget_builder.build_widget(spec, that.widgets);
};
+ /**
+ * Build multiple widgets and add them to widget collection.
+ * @param {Array.<Object>} specs widget specs
+ */
that.build_widgets = function(specs) {
if (!specs) return;
@@ -66,6 +121,10 @@ exp.details_builder = IPA.details_builder = function(spec) {
that.widget_builder.build_widgets(specs, that.widgets);
};
+ /**
+ * Build single field and add it to field collection.
+ * @param {Object} spec field spec
+ */
that.build_field = function(spec) {
if (!spec) return;
@@ -73,6 +132,10 @@ exp.details_builder = IPA.details_builder = function(spec) {
that.field_builder.build_field(spec, that.fields);
};
+ /**
+ * Build multiple fields and add them to field collection.
+ * @param {Array.<Object>} specs field spec
+ */
that.build_fields = function(specs) {
if (!specs) return;
@@ -80,6 +143,10 @@ exp.details_builder = IPA.details_builder = function(spec) {
that.field_builder.build_fields(specs, that.fields);
};
+ /**
+ * Build sections
+ * @param {Array.<Object>} specs section specs
+ */
that.build_sections = function(specs) {
if (!specs) return;
@@ -87,6 +154,10 @@ exp.details_builder = IPA.details_builder = function(spec) {
that.section_builder.build_sections(specs);
};
+ /**
+ * Build section, fields and widgets.
+ * @param {Object} spec facet or dialog spec
+ */
that.build = function(spec) {
if (spec.sections) {
@@ -111,18 +182,50 @@ exp.details_builder = IPA.details_builder = function(spec) {
return that;
};
+/**
+ * Section builder
+ *
+ * Section is a layout unit of details facet or a dialog.
+ *
+ * @class details.section_builder
+ * @alternateClassName IPA.section_builder
+ */
exp.section_builder = IPA.section_builder = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Container
+ * @property {IPA.facet|IPA.dialog}
+ */
that.container = spec.container;
+
+ /**
+ * Default section factory
+ *
+ * TODO: should be modified so it can be a class too
+ * @property {IPA.composite_widget}
+ */
that.section_factory = spec.section_factory || IPA.details_table_section;
+ /**
+ * Field builder
+ * @property {IPA.field_builder}
+ */
that.field_builder = spec.field_builder;
+
+ /**
+ * Widget builder
+ * @property {IPA.widget_builder}
+ */
that.widget_builder = spec.widget_builder;
+ /**
+ * Build multiple sections
+ * @param {Array.<Object>} sections section specs
+ */
that.build_sections = function(sections) {
if(!sections) return;
@@ -132,6 +235,12 @@ exp.section_builder = IPA.section_builder = function(spec) {
}
};
+ /**
+ * Build single section
+ * @param {Object} section_spec
+ * @param {number|string} index value which is used in section name if name
+ * is not specified in spec
+ */
that.build_section = function(section_spec, index) {
section_spec.entity = that.container.entity;
section_spec.facet = that.container;
@@ -152,13 +261,23 @@ exp.section_builder = IPA.section_builder = function(spec) {
that.create_fields(section, section_spec.fields);
};
- that.create_fields = function(section, fields_spec) {
+ /**
+ * Create fields and associated widgets
+ * @param {IPA.composite_widget} section
+ * @param {Array.<Object>} field_specs
+ */
+ that.create_fields = function(section, fields_specs) {
- for (var i=0; i < fields_spec.length; i++) {
- that.create_field(section, fields_spec[i]);
+ for (var i=0; i < fields_specs.length; i++) {
+ that.create_field(section, fields_specs[i]);
}
};
+ /**
+ * Create field and associated widget
+ * @param {IPA.composite_widget} section
+ * @param {Object} field_spec
+ */
that.create_field = function(section, field_spec) {
var widget = that.widget_builder.build_widget(field_spec, section.widgets);
@@ -176,35 +295,89 @@ exp.section_builder = IPA.section_builder = function(spec) {
return that;
};
+/**
+ * Facet policy
+ *
+ * Object which extends container's (facet or dialog) logic.
+ *
+ * @class details.facet_policy
+ * @alternateClassName IPA.facet_policy
+ */
exp.facet_policy = IPA.facet_policy = function() {
var that = IPA.object();
+ /**
+ * Container
+ * @property {IPA.facet|IPA.dialog}
+ */
+ that.container = null;
+
+ /**
+ * Init handler.
+ *
+ * Should be executed in container's init.
+ */
that.init = function() {
};
+ /**
+ * Post Create Handler
+ *
+ * Should be executed at the end of container's create
+ */
that.post_create = function() {
};
+ /**
+ * Post Load Handler
+ *
+ * Should be executed at the end of container's load
+ * @param {Object} data
+ */
that.post_load = function(data) {
};
return that;
};
+/**
+ * Facet policy collection
+ *
+ * @class details.facet_policies
+ * @alternateClassName IPA.facet_policies
+ */
exp.facet_policies = IPA.facet_policies = function(spec) {
var that = IPA.object();
+ /**
+ * Container
+ * @property {IPA.facet|IPA.dialog}
+ */
that.container = spec.container;
+
+ /**
+ * Facet Policies
+ * @readonly
+ * @property {Array.<details.facet_policy>}
+ */
that.policies = [];
+ /**
+ * Add policy
+ * @param {details.facet_policy} policy
+ */
that.add_policy = function(policy) {
policy.container = that.container;
that.policies.push(policy);
};
+ /**
+ * Add multiple policies
+ * @param {Array.<details.facet_policy>} policies
+ */
that.add_policies = function(policies) {
if (!policies) return;
@@ -214,6 +387,11 @@ exp.facet_policies = IPA.facet_policies = function(spec) {
}
};
+ /**
+ * Init handler
+ *
+ * Calls init handlers of all policies
+ */
that.init = function() {
for (var i=0; i<that.policies.length; i++) {
@@ -221,6 +399,11 @@ exp.facet_policies = IPA.facet_policies = function(spec) {
}
};
+ /**
+ * Post Create handler
+ *
+ * Calls post create handlers of all policies
+ */
that.post_create = function() {
for (var i=0; i<that.policies.length; i++) {
@@ -228,6 +411,11 @@ exp.facet_policies = IPA.facet_policies = function(spec) {
}
};
+ /**
+ * Post Load handler
+ *
+ * Calls post load handlers of all policies
+ */
that.post_load = function(data) {
for (var i=0; i<that.policies.length; i++) {
@@ -242,6 +430,19 @@ exp.facet_policies = IPA.facet_policies = function(spec) {
return that;
};
+/**
+ * Details facet build pre_op
+ *
+ * It
+ * - sets name, title, label if not present
+ * - adds default actions and related buttons
+ * - refresh
+ * - reset
+ * - update
+ * - adds dirty state evaluator
+ *
+ * @member details
+ */
exp.details_facet_pre_op = function(spec, context) {
var entity = context.entity;
@@ -286,22 +487,81 @@ exp.details_facet_pre_op = function(spec, context) {
return spec;
};
+/**
+ * Details facet
+ * @class details.details_facet
+ * @alternateClassName IPA.details_facet
+ * @extends facet.facet
+ */
exp.details_facet = IPA.details_facet = function(spec, no_init) {
spec = spec || {};
var that = IPA.facet(spec, true);
+ /**
+ * Entity
+ * @property {IPA.entity}
+ */
that.entity = IPA.get_entity(spec.entity);
+
+ /**
+ * Name of update command
+ *
+ * - defaults to 'mod'
+ * @property {string}
+ */
that.update_command_name = spec.update_command_name || 'mod';
+
+ /**
+ * Command mode
+ * Command mode determines how update information on update is collected.
+ * There are two modes:
+ *
+ * - `save` this uses field's `save()` method
+ * - `info` works with `details.update_info`. Update info is collected by
+ * `get_update_info()` method.
+ * @property {string}
+ */
that.command_mode = spec.command_mode || 'save'; // [save, info]
+
+ /**
+ * Check rights
+ *
+ * Controls obtaining of attribute level rights on refresh and update
+ *
+ * @property {boolean}
+ */
that.check_rights = spec.check_rights !== undefined ? spec.check_rights : true;
+ /**
+ * Facet label
+ * @property {string}
+ */
that.label = text.get(spec.label) || text.get('facets.details');
+
+ /**
+ * Facet group
+ * @property {string}
+ */
that.facet_group = spec.facet_group || 'settings';
+ /**
+ * Widgets
+ * @property {IPA.widget_container}
+ */
that.widgets = IPA.widget_container();
+
+ /**
+ * Fields
+ * @property {IPA.field_container}
+ */
that.fields = IPA.field_container({ container: that });
+
+ /**
+ * Policies
+ * @property {IPA.facet_policies}
+ */
that.policies = IPA.facet_policies({
container: that,
policies: spec.policies
@@ -315,9 +575,23 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
that.fields.container_add_field(field);
};
+ /**
+ * Dirty
+ *
+ * - true if any field is dirty
+ * @property {boolean}
+ */
that.dirty = false;
+
+ /**
+ * Dirty changed
+ * @event
+ */
that.dirty_changed = IPA.observer();
+ /**
+ * @inheritDoc
+ */
that.create = function(container) {
if (that.entity.facets.length == 1) {
if (that.disable_breadcrumb === undefined) {
@@ -332,11 +606,19 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
that.policies.post_create();
};
+ /**
+ * Create header controls
+ *
+ * - ie control buttons
+ */
that.create_controls = function() {
that.create_control_buttons(that.controls);
};
+ /**
+ * @inheritDoc
+ */
that.create_header = function(container) {
that.facet_create_header(container);
@@ -389,6 +671,9 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
container.append('<hr/>');
};
+ /**
+ * @inheritDoc
+ */
that.create_content = function(container) {
that.content = $('<div/>', {
@@ -403,12 +688,23 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
}).appendTo(container);
};
+ /**
+ * @inheritDoc
+ */
that.show = function() {
that.facet_show();
var pkey = that.get_pkey();
that.header.set_pkey(pkey);
};
+ /**
+ * Field's dirty event handler
+ *
+ * Sets this dirty state
+ *
+ * @protected
+ * @param {boolean} dirty
+ */
that.field_dirty_changed = function(dirty) {
var old_dirty = that.dirty;
@@ -424,6 +720,12 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
}
};
+ /**
+ * Evaluates if facet is dirty.
+ *
+ * Facet is dirty if any child widget is dirty.
+ * @return {boolean} dirty
+ */
that.is_dirty = function() {
var fields = that.fields.get_fields();
for (var i=0; i<fields.length; i++) {
@@ -434,6 +736,9 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return false;
};
+ /**
+ * @inheritDoc
+ */
that.load = function(data) {
that.facet_load(data);
@@ -447,6 +752,10 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
that.clear_expired_flag();
};
+ /**
+ * Save fields' values into record
+ * @param {Object} record
+ */
that.save = function(record) {
var fields = that.fields.get_fields();
for (var i=0; i<fields.length; i++) {
@@ -455,6 +764,19 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
}
};
+ /**
+ * Creates update info
+ *
+ * - used when in 'save' command mode
+ *
+ * This update info consists of fields' update information
+ *
+ * @param {boolean} [only_dirty=false] collect update information only from
+ * dirty fields
+ * @param {boolean} [require_value=false] collect update information from
+ * fields which has value
+ * @return {details.update_info}
+ */
that.save_as_update_info = function(only_dirty, require_value) {
var record = {};
@@ -477,6 +799,9 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return update_info;
};
+ /**
+ * Reset facet
+ */
that.reset = function() {
var fields = that.fields.get_fields();
for (var i=0; i<fields.length; i++) {
@@ -485,7 +810,10 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
}
};
-
+ /**
+ * Validate all fields
+ * @return {boolean} all fields are valid
+ */
that.validate = function() {
var valid = true;
var fields = that.fields.get_fields();
@@ -496,6 +824,10 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return valid;
};
+ /**
+ * Notifies successful update
+ * @protected
+ */
that.nofify_update_success = function() {
var msg = text.get('@i18n:details.updated');
var key = that.get_pkey();
@@ -504,16 +836,45 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
IPA.notify_success(msg);
};
-
+ /**
+ * Update success handler
+ *
+ * Invokes Load by default.
+ *
+ * This is the method to override if different actions need to be taken
+ * on update success.
+ *
+ * @protected
+ * @param {Object} data
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ */
that.update_on_success = function(data, text_status, xhr) {
that.load(data);
that.on_update.notify();
that.nofify_update_success();
};
+ /**
+ * Update error handler
+ *
+ * This is the method to override if different actions need to be taken
+ * on update error.
+ *
+ * @protected
+ * @param {XMLHttpRequest} xhr
+ * @param {string} text_status
+ * @param {Object} error_thrown
+ */
that.update_on_error = function(xhr, text_status, error_thrown) {
};
+ /**
+ * Adds update info as command options
+ * @protected
+ * @param {details.update_info} update_info
+ * @param {IPA.command} command
+ */
that.add_fields_to_command = function(update_info, command) {
for (var i=0; i < update_info.fields.length; i++) {
@@ -527,6 +888,12 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
}
};
+ /**
+ * Create update command based on field part of update info
+ * @protected
+ * @param {details.update_info} update_info
+ * @return {IPA.command}
+ */
that.create_fields_update_command = function(update_info) {
var args = that.get_pkeys();
@@ -547,6 +914,15 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return command;
};
+ /**
+ * Create batch command from update info
+ *
+ * Created batch command consists of update info's commands and a mod command
+ * to reflect field part of update info (if present).
+ * @protected
+ * @param {details.update_info} update_info
+ * @return {IPA.batch_command}
+ */
that.create_batch_update_command = function(update_info) {
var batch = IPA.batch_command({
@@ -571,6 +947,10 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return batch;
};
+ /**
+ * Show validation error
+ * @protected
+ */
that.show_validation_error = function() {
var dialog = IPA.message_dialog({
name: 'validation_error',
@@ -580,6 +960,11 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
dialog.open();
};
+ /**
+ * Create update command
+ * @protected
+ * @return {IPA.command/IPA.batch_command}
+ */
that.create_update_command = function() {
var command, update_info;
@@ -601,6 +986,14 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return command;
};
+ /**
+ * Perform update operation
+ *
+ * Update reflects current state into data store.
+ *
+ * @param {Function} on_success success handler
+ * @param {Function} on_error error handler
+ */
that.update = function(on_success, on_error) {
var command = that.create_update_command();
@@ -618,10 +1011,20 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
command.execute();
};
+ /**
+ * Get refresh command name
+ * @protected
+ * @return {string}
+ */
that.get_refresh_command_name = function() {
return that.entity.name+'_show';
};
+ /**
+ * Create refresh command
+ * @protected
+ * @return {IPA.command}
+ */
that.create_refresh_command = function() {
var options = { all: true };
@@ -641,16 +1044,33 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return command;
};
+ /**
+ * Refresh success handler
+ * @protected
+ * @param {Object} data
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ */
that.refresh_on_success = function(data, text_status, xhr) {
that.load(data);
that.show_content();
};
+ /**
+ * Refresh error handler
+ * @protected
+ * @param {XMLHttpRequest} xhr
+ * @param {string} text_status
+ * @param {Object} error_thrown
+ */
that.refresh_on_error = function(xhr, text_status, error_thrown) {
that.redirect_error(error_thrown);
that.report_error(error_thrown);
};
+ /**
+ * @inheritDoc
+ */
that.refresh = function(on_success, on_error) {
if (!that.get_pkey() && that.entity.redirect_facet) {
@@ -673,12 +1093,22 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
command.execute();
};
+ /**
+ * @inheritDoc
+ */
that.clear = function() {
that.header.clear();
that.widgets.clear();
};
+ /**
+ * Create update info
+ *
+ * - used in `update_info` command mode
+ * @protected
+ * @return {details.update_info}
+ */
that.get_update_info = function() {
var update_info = IPA.update_info_builder.new_update_info();
@@ -695,6 +1125,10 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return update_info;
};
+ /**
+ * Create builders needed for initialization
+ * @protected
+ */
that.create_builder = function() {
var widget_builder = IPA.widget_builder({
@@ -723,6 +1157,13 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
});
};
+ /**
+ * Initialize details facet
+ *
+ * - called automatically if `no_init==true` is not present
+ *
+ * @protected
+ */
that.init_details_facet = function() {
that.init_facet();
@@ -743,18 +1184,42 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) {
return that;
};
+/**
+ * Update info
+ * @class details.update_info
+ * @alternateClassName IPA.update_info
+ */
exp.update_info = IPA.update_info = function(spec) {
var that = IPA.object();
+ /**
+ * Fields update info
+ * @property {Array.<details.field_info>}
+ */
that.fields = spec.fields || [];
+
+ /**
+ * Update commands info
+ * @property {Array.<details.command_info>}
+ */
that.commands = spec.commands || [];
+ /**
+ * Create new field info and add it to collection
+ * @param {IPA.field} field
+ * @param {Object} value field's value
+ */
that.append_field = function(field, value) {
var field_info = IPA.update_info_builder.new_field_info(field, value);
that.fields.push(field_info);
};
+ /**
+ * Create new command info and add it to collection
+ * @param {IPA.command} command
+ * @param {number} priority
+ */
that.append_command = function (command, priority) {
var command_info = IPA.update_info_builder.new_command_info(command, priority);
that.commands.push(command_info);
@@ -763,30 +1228,72 @@ exp.update_info = IPA.update_info = function(spec) {
return that;
};
+/**
+ * Command info
+ * @class details.command_info
+ * @alternateClassName IPA.command_info
+ */
exp.command_info = IPA.command_info = function(spec) {
var that = IPA.object();
+ /**
+ * Command
+ * @property {IPA.command}
+ */
that.command = spec.command;
+
+ /**
+ * Priority
+ *
+ * - controls command execution order
+ * @property {number}
+ */
that.priority = spec.priority || IPA.config.default_priority;
return that;
};
+/**
+ * Field update info
+ * @class details.field_info
+ * @alternateClassName IPA.field_info
+ */
exp.field_info = IPA.field_info = function(spec) {
var that = IPA.object();
+ /**
+ * Field
+ * @property {IPA.field}
+ */
that.field = spec.field;
+
+ /**
+ * Value
+ * @property {Object}
+ */
that.value = spec.value;
return that;
};
+/**
+ * Update info builder
+ * @class details.update_info_builder
+ * @alternateClassName IPA.update_info_builder
+ * @singleton
+ */
exp.update_info_builder = IPA.update_info_builder = function() {
var that = IPA.object();
+ /**
+ * Create update info from field and command infos
+ * @param {Array.<details.field_info>} fields
+ * @param {Array.<details.command_info>} commands
+ * @return {details.update_info}
+ */
that.new_update_info = function (fields, commands) {
return IPA.update_info({
fields: fields,
@@ -794,6 +1301,12 @@ exp.update_info_builder = IPA.update_info_builder = function() {
});
};
+ /**
+ * Create field info
+ * @param {details.field_info} field
+ * @param {Object} value
+ * @return {details.field_info}
+ */
that.new_field_info = function(field, value) {
return IPA.field_info({
field: field,
@@ -801,6 +1314,12 @@ exp.update_info_builder = IPA.update_info_builder = function() {
});
};
+ /**
+ * Create new command info
+ * @param {IPA.command} command
+ * @param {number} priority
+ * @return {details.command_info}
+ */
that.new_command_info = function(command, priority) {
return IPA.command_info({
command: command,
@@ -808,12 +1327,23 @@ exp.update_info_builder = IPA.update_info_builder = function() {
});
};
+ /**
+ * Merge two commands info into new one
+ * @param {details.command_info} a
+ * @param {details.command_info} b
+ * @return {details.command_info}
+ */
that.merge = function(a, b) {
return that.new_update_info(
a.fields.concat(b.fields),
a.commands.concat(b.commands));
};
+ /**
+ * Create copy of command info
+ * @param {details.command_info} original
+ * @return {details.command_info} copy
+ */
that.copy = function(original) {
return that.new_update_info(
original.fields.concat([]),
@@ -823,10 +1353,23 @@ exp.update_info_builder = IPA.update_info_builder = function() {
return that;
}();
+/**
+ * Field add/mod command builder
+ *
+ * @class details.command_builder
+ * @alternateClassName IPA.command_builder
+ * @singleton
+ */
exp.command_builder = IPA.command_builder = function() {
var that = IPA.object();
+ /**
+ * Add option to command with field values
+ * @param {IPA.command} command
+ * @param {IPA.field} field
+ * @param {Array} values
+ */
that.add_field_option = function(command, field, values) {
if (!field || !values) return;
@@ -854,6 +1397,12 @@ exp.command_builder = IPA.command_builder = function() {
return that;
}();
+/**
+ * No-op action which serves only for displaying label
+ * @class details.select_action
+ * @alternateClassName IPA.select_action
+ * @extends facet.action
+ */
exp.select_action = IPA.select_action = function(spec) {
spec = spec || {};
@@ -868,6 +1417,12 @@ exp.select_action = IPA.select_action = function(spec) {
return that;
};
+/**
+ * Invokes `facet.refresh`
+ * @class details.refresh_action
+ * @alternateClassName IPA.refresh_action
+ * @extends facet.action
+ */
exp.refresh_action = IPA.refresh_action = function(spec) {
spec = spec || {};
@@ -883,6 +1438,12 @@ exp.refresh_action = IPA.refresh_action = function(spec) {
return that;
};
+/**
+ * Invokes `facet.reset`
+ * @class details.reset_action
+ * @alternateClassName IPA.reset_action
+ * @extends facet.action
+ */
exp.reset_action = IPA.reset_action = function(spec) {
spec = spec || {};
@@ -899,6 +1460,12 @@ exp.reset_action = IPA.reset_action = function(spec) {
return that;
};
+/**
+ * Invokes validation and then `facet.update`
+ * @class details.update_action
+ * @alternateClassName IPA.update_action
+ * @extends facet.action
+ */
exp.update_action = IPA.update_action = function(spec) {
spec = spec || {};
@@ -922,6 +1489,14 @@ exp.update_action = IPA.update_action = function(spec) {
return that;
};
+/**
+ * Sets state based on value of loaded boolean attribute.
+ * - evaluated on post load by default
+ *
+ * @class details.boolean_state_evaluator
+ * @alternateClassName IPA.boolean_state_evaluator
+ * @extends facet.state_evaluator
+ */
exp.boolean_state_evaluator = IPA.boolean_state_evaluator = function(spec) {
spec = spec || {};
@@ -930,23 +1505,56 @@ exp.boolean_state_evaluator = IPA.boolean_state_evaluator = function(spec) {
var that = IPA.state_evaluator(spec);
+ /**
+ * @inheritDoc
+ */
that.name = spec.name || 'boolean_state_evaluator';
- that.field = spec.field;
+
+ /**
+ * Attribute's name
+ *
+ * - spec name: `field`
+ * @property {string}
+ */
+ that.field_name = spec.field;
+
+ /**
+ * State to set when value is `true`
+ * @property {string}
+ */
that.true_state = spec.true_state || that.field_name + '-true';
+
+ /**
+ * State to set when value is `false`
+ * @property {string}
+ */
that.false_state = spec.false_state || that.field_name + '-false';
+
+ /**
+ * Inverted logic
+ * @property {boolean}
+ */
that.invert_value = spec.invert_value;
+
+ /**
+ * Value parser
+ * @property {IPA.boolean_formatter}
+ */
that.parser = IPA.build({
$factory: spec.parser || IPA.boolean_formatter,
invert_value: that.invert_value
});
+ /**
+ * @inheritDoc
+ */
that.on_event = function(data) {
var old_state = that.state;
var record = data.result.result;
that.state = [];
- var value = that.parser.parse(record[that.field]);
+ var value = that.parser.parse(record[that.field_name]);
if (value === true) {
that.state.push(that.true_state);
@@ -960,6 +1568,21 @@ exp.boolean_state_evaluator = IPA.boolean_state_evaluator = function(spec) {
return that;
};
+/**
+ * Evaluates enabled/disabled state
+ *
+ * // in facet spec
+ * evaluators: [
+ * {
+ * $factory: IPA.enable_state_evaluator,
+ * field: 'ipaenabledflag'
+ * }
+ * ],
+ *
+ * @class details.enable_state_evaluator
+ * @alternateClassName IPA.enable_state_evaluator
+ * @extends details.boolean_state_evaluator
+ */
exp.enable_state_evaluator = IPA.enable_state_evaluator = function(spec) {
spec = spec || {};
@@ -972,14 +1595,31 @@ exp.enable_state_evaluator = IPA.enable_state_evaluator = function(spec) {
return that;
};
+/**
+ * Create state for each attribute level right user has for specific attribute
+ *
+ * - on post load
+ * - state value is $(ATTR_NAME)_$(RIGHT) where right is a letter (one of 'rscwo')
+ *
+ * @class details.acl_state_evaluator
+ * @alternateClassName IPA.acl_state_evaluator
+ * @extends facet.state_evaluator
+ */
exp.acl_state_evaluator = IPA.acl_state_evaluator = function(spec) {
spec.name = spec.name || 'acl_state_evaluator';
spec.event = spec.event || 'post_load';
var that = IPA.state_evaluator(spec);
+ /**
+ * Attribute name
+ * @property {string}
+ */
that.attribute = spec.attribute;
+ /**
+ * @inheritDoc
+ */
that.on_event = function(data) {
var old_state, record, rights, i, state;
@@ -1008,16 +1648,45 @@ exp.acl_state_evaluator = IPA.acl_state_evaluator = function(spec) {
return that;
};
+/**
+ * Evaluator which sets state when loaded value of specific attribute is equal
+ * to desired value.
+ *
+ * @class details.value_state_evaluator
+ * @alternateClassName IPA.value_state_evaluator
+ * @extends facet.state_evaluator
+ */
exp.value_state_evaluator = IPA.value_state_evaluator = function(spec) {
spec.name = spec.name || 'value_state_evaluator';
spec.event = spec.event || 'post_load';
var that = IPA.state_evaluator(spec);
+
+ /**
+ * Attribute name
+ * @property {string}
+ */
that.attribute = spec.attribute;
+
+ /**
+ * Desired value
+ * @property {Mixed}
+ */
that.value = spec.value;
+
+ /**
+ * State to set
+ *
+ * If not set, state is created from attribute name and value:
+ * `$(ATTR_NAME)_$(VALUE)`
+ * @property {string}
+ */
that.representation = spec.representation;
+ /**
+ * @inheritDoc
+ */
that.on_event = function(data) {
var old_state, record, state, value, loaded_value;
@@ -1037,6 +1706,15 @@ exp.value_state_evaluator = IPA.value_state_evaluator = function(spec) {
that.notify_on_change(old_state);
};
+ /**
+ * Normalize value
+ *
+ * - it's expected that value will be in array (to work with multivalued
+ * attributes)
+ * - override point
+ * @protected
+ * @return {Mixed} value
+ */
that.normalize_value = function(original) {
var value = original;
@@ -1047,6 +1725,16 @@ exp.value_state_evaluator = IPA.value_state_evaluator = function(spec) {
return value;
};
+ /**
+ * Create state
+ *
+ * If `representation` is not set, state is created from attribute name
+ * and value:
+ * `$(ATTR_NAME)_$(VALUE)`
+ *
+ * @protected
+ * @return {string} state
+ */
that.get_state_text = function() {
var representation, value;
@@ -1064,6 +1752,17 @@ exp.value_state_evaluator = IPA.value_state_evaluator = function(spec) {
return that;
};
+/**
+ * Object class evaluator
+ *
+ * Set state for each object class which loaded record has.
+ *
+ * State name is `oc_$(class)`
+ *
+ * @class details.object_class_evaluator
+ * @alternateClassName IPA.object_class_evaluator
+ * @extends facet.state_evaluator
+ */
exp.object_class_evaluator = IPA.object_class_evaluator = function(spec) {
spec.name = spec.name || 'object_class_evaluator';
@@ -1072,6 +1771,9 @@ exp.object_class_evaluator = IPA.object_class_evaluator = function(spec) {
var that = IPA.state_evaluator(spec);
+ /**
+ * @inheritDoc
+ */
that.on_event = function(data) {
var old_state, classes, i;
@@ -1091,16 +1793,42 @@ exp.object_class_evaluator = IPA.object_class_evaluator = function(spec) {
return that;
};
+/**
+ * Base class for executing specific entity methods
+ * - command options can be set
+ * - facet pkeys are set as command arguments
+ * - entity is fetched from facet
+ * @class details.object_action
+ * @alternateClassName IPA.object_action
+ * @extends facet.action
+ */
exp.object_action = IPA.object_action = function(spec) {
spec = spec || {};
var that = IPA.action(spec);
+ /**
+ * Method name
+ * @property {string}
+ */
that.method = spec.method;
+
+ /**
+ * @inheritDoc
+ */
that.confirm_msg = text.get(spec.confirm_msg || '@i18n:actions.confirm');
+
+ /**
+ * Command options
+ * @property {Object}
+ */
that.options = spec.options || {};
+ /**
+ * @protected
+ * @inheritDoc
+ */
that.execute_action = function(facet, on_success, on_error) {
var entity_name = facet.entity.name;
@@ -1116,6 +1844,14 @@ exp.object_action = IPA.object_action = function(spec) {
}).execute();
};
+ /**
+ * Command success handler
+ * @protected
+ * @param {facet.facet} facet
+ * @param {Object} data
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ */
that.on_success = function(facet, data, text_status, xhr) {
IPA.notify_success(data.result.summary);
@@ -1123,10 +1859,25 @@ exp.object_action = IPA.object_action = function(spec) {
facet.refresh();
};
+ /**
+ * Command error handler
+ * @protected
+ * @param {facet.facet} facet
+ * @param {XMLHttpRequest} xhr
+ * @param {string} text_status
+ * @param {Object} error_thrown
+ */
that.on_error = function(facet, xhr, text_status, error_thrown) {
facet.refresh();
};
+ /**
+ * Combines given success handler with action success handler so both
+ * can be called.
+ * @protected
+ * @param {facet.facet} facet
+ * @param {Function} on_success success handler
+ */
that.get_on_success = function(facet, on_success) {
return function(data, text_status, xhr) {
that.on_success(facet, data, text_status, xhr);
@@ -1134,6 +1885,13 @@ exp.object_action = IPA.object_action = function(spec) {
};
};
+ /**
+ * Combines given error handler with action error handler so both
+ * can be called.
+ * @protected
+ * @param {facet.facet} facet
+ * @param {Function} on_error error handler
+ */
that.get_on_error = function(facet, on_error) {
return function(xhr, text_status, error_thrown) {
that.on_error(facet, xhr, text_status, error_thrown);
@@ -1141,6 +1899,10 @@ exp.object_action = IPA.object_action = function(spec) {
};
};
+ /**
+ * @protected
+ * @inheritDoc
+ */
that.get_confirm_message = function(facet) {
var pkey = that.get_pkey();
var msg = that.confirm_msg.replace('${object}', pkey);
@@ -1152,6 +1914,12 @@ exp.object_action = IPA.object_action = function(spec) {
return that;
};
+/**
+ * Call 'enable' method of current entity
+ * @class details.enable_action
+ * @alternateClassName IPA.enable_action
+ * @extends details.object_action
+ */
exp.enable_action = IPA.enable_action = function(spec) {
spec = spec || {};
@@ -1166,6 +1934,12 @@ exp.enable_action = IPA.enable_action = function(spec) {
return that;
};
+/**
+ * Call 'disable' method of current entity
+ * @class details.disable_action
+ * @alternateClassName IPA.disable_action
+ * @extends details.object_action
+ */
exp.disable_action = IPA.disable_action = function(spec) {
spec = spec || {};
@@ -1180,6 +1954,15 @@ exp.disable_action = IPA.disable_action = function(spec) {
return that;
};
+/**
+ * Call 'delete' method of current entity
+ *
+ * Redirects to facet's redirect target on success by default.
+ *
+ * @class details.delete_action
+ * @alternateClassName IPA.delete_action
+ * @extends details.object_action
+ */
exp.delete_action = IPA.delete_action = function(spec) {
spec = spec || {};
@@ -1207,7 +1990,12 @@ exp.delete_action = IPA.delete_action = function(spec) {
return that;
};
-
+/**
+ * Summary condition for 'enabled' state
+ *
+ * @class details.enabled_summary_cond
+ * @alternateClassName IPA.enabled_summary_cond
+ */
exp.enabled_summary_cond = IPA.enabled_summary_cond = function() {
var that = IPA.object();
@@ -1220,6 +2008,12 @@ exp.enabled_summary_cond = IPA.enabled_summary_cond = function() {
return that;
};
+/**
+ * Summary condition for 'disabled' state
+ *
+ * @class details.disabled_summary_cond
+ * @alternateClassName IPA.disabled_summary_cond
+ */
exp.disabled_summary_cond = IPA.disabled_summary_cond = function() {
var that = IPA.object();
lang.mixin(that, {
@@ -1231,6 +2025,11 @@ exp.disabled_summary_cond = IPA.disabled_summary_cond = function() {
return that;
};
+/**
+ * Register facet and actions.
+ *
+ * @member details
+ */
exp.register = function() {
var a = reg.action;
var f = reg.facet;
diff --git a/install/ui/src/freeipa/dialog.js b/install/ui/src/freeipa/dialog.js
index d1428fecd..a31c9f453 100644
--- a/install/ui/src/freeipa/dialog.js
+++ b/install/ui/src/freeipa/dialog.js
@@ -22,16 +22,25 @@
define(['./ipa', './jquery', './text', './field', './widget'], function(IPA, $, text) {
+/**
+ * Opened dialogs
+ *
+ * @class
+ * @singleton
+ */
IPA.opened_dialogs = {
+ /** Opened dialogs */
dialogs: [],
+ /** Get top dialog */
top_dialog: function() {
var top = null;
if (this.dialogs.length) top = this.dialogs[this.dialogs.length - 1];
return top;
},
+ /** Focus to dialog */
focus_top: function() {
var top = this.top_dialog();
if (top) {
@@ -40,30 +49,44 @@ IPA.opened_dialogs = {
}
},
+ /** Add dialog */
add_dialog: function(dialog) {
this.dialogs.push(dialog);
},
+ /** Remove dialog */
remove_dialog: function(dialog) {
var index = this.dialogs.indexOf(dialog);
if (index > -1) this.dialogs.splice(index, 1);
}
};
+/**
+ * Dialog button
+ * @class
+ */
IPA.dialog_button = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /** @property {string} name Name */
that.name = spec.name;
+ /** @property {string} label Label */
that.label = text.get(spec.label || spec.name);
+ /** @property {Function} click Click handler */
that.click = spec.click || click;
+ /** @property {boolean} visible=true Button should be visible */
that.visible = spec.visible !== undefined ? spec.visible : true;
function click() {
}
+ /**
+ * Enabled setter
+ * @param {boolean} enabled
+ */
that.set_enabled = function(enabled) {
if (enabled) {
that.element.removeClass('ui-state-disabled');
@@ -72,6 +95,10 @@ IPA.dialog_button = function(spec) {
}
};
+ /**
+ * Enabled getter
+ * @return {boolean}
+ */
that.is_enabled = function() {
return !that.element.hasClass('ui-state-disabled');
};
@@ -81,6 +108,7 @@ IPA.dialog_button = function(spec) {
/**
* This is a base class for dialog boxes.
+ * @class
*/
IPA.dialog = function(spec) {
@@ -88,28 +116,48 @@ IPA.dialog = function(spec) {
var that = IPA.object();
+ /** @property {entity.entity} entity Entity */
that.entity = IPA.get_entity(spec.entity);
+ /** @property {string} name="dialog" Name */
that.name = spec.name || 'dialog';
+ /** @property {string} id ID */
that.id = spec.id;
+ /** @property {string} title Dialog title */
that.title = text.get(spec.title);
+ /** @property {number} width=500 Dialog width */
that.width = spec.width || 500;
+ /** @property {number} height Dialog height */
that.height = spec.height;
+
+ /**
+ * Close dialog on Escape key press
+ * @property {boolean} close_on_escape=true
+ */
that.close_on_escape = spec.close_on_escape !== undefined ?
spec.close_on_escape : true;
// FIXME: remove facet reference
// Purpose of facet reference is to obtain pkeys or ability to reload
// facet. Such usage makes the code more spaghetti. It should be replaced.
+ /**
+ * Facet
+ * @property {facet.facet}
+ */
that.facet = spec.facet;
+ /** @property {IPA.widget_container} widgets Widgets */
that.widgets = IPA.widget_container();
+ /** @property {IPA.field_container} fields Fields */
that.fields = IPA.field_container({ container: that });
+ /** @property {ordered_map} buttons Buttons */
that.buttons = $.ordered_map();
+ /** @property {details.facet_policies} policies Policies */
that.policies = IPA.facet_policies({
container: that,
policies: spec.policies
});
+ /** Create and add button */
that.create_button = function(spec) {
var factory = spec.$factory || IPA.dialog_button;
var button = factory(spec);
@@ -117,19 +165,32 @@ IPA.dialog = function(spec) {
return button;
};
+ /**
+ * Add button
+ * @param {IPA.dialog_button} button
+ */
that.add_button = function(button) {
that.buttons.put(button.name, button);
};
+ /**
+ * Get button
+ * @param {string} name
+ */
that.get_button = function(name) {
return that.buttons.get(name);
};
+ /**
+ * Add field
+ * @param {IPA.field} field
+ */
that.field = function(field) {
that.fields.add_field(field);
return that;
};
+ /** Validate dialog fields */
that.validate = function() {
var valid = true;
var fields = that.fields.get_fields();
@@ -140,6 +201,7 @@ IPA.dialog = function(spec) {
return valid;
};
+ /** Get ID */
that.get_id = function() {
if (that.id) return that.id;
if (that.name) return that.name;
@@ -172,17 +234,23 @@ IPA.dialog = function(spec) {
that.policies.post_create();
};
+ /**
+ * Show message in dialog's message container
+ * @param {string} message
+ */
that.show_message = function(message) {
that.message_container.text(message);
that.message_container.css('display', '');
};
+ /** Hide dialog message */
that.hide_message = function() {
that.message_container.css('display', 'none');
};
/**
* Open dialog
+ * @param {jQuery} container
*/
that.open = function(container) {
@@ -217,9 +285,11 @@ IPA.dialog = function(spec) {
that.focus_first_element();
};
+ /**
+ * Set focus to the first tabbable element in the content area or the first button.
+ * If there are no tabbable elements, set focus on the dialog itself.
+ */
that.focus_first_element = function() {
- // set focus to the first tabbable element in the content area or the first button
- // if there are no tabbable elements, set focus on the dialog itself
var element = that.container;
var ui_dialog = that.container.parent('.ui-dialog'); // jq dialog div
@@ -230,10 +300,20 @@ IPA.dialog = function(spec) {
ui_dialog.get()))).eq(0).focus();
};
+ /**
+ * Set jQuery dialog option
+ * @protected
+ * @param {string} name
+ * @param {Mixed} value
+ */
that.option = function(name, value) {
that.container.dialog('option', name, value);
};
+ /**
+ * Set dialog buttons as jQuery dialog buttons
+ * @protected
+ */
that.set_buttons = function() {
// create a map of button labels and handlers
@@ -258,6 +338,10 @@ IPA.dialog = function(spec) {
});
};
+ /**
+ * Make buttons visible
+ * @param {string[]} names button names
+ */
that.display_buttons = function(names) {
for (var i=0; i<that.buttons.values.length; i++) {
@@ -268,6 +352,10 @@ IPA.dialog = function(spec) {
that.set_buttons();
};
+ /**
+ * Save fields' values into record object
+ * @param {Object} record
+ */
that.save = function(record) {
var fields = that.fields.get_fields();
for (var i=0; i<fields.length; i++) {
@@ -276,6 +364,9 @@ IPA.dialog = function(spec) {
}
};
+ /**
+ * Close dialog
+ */
that.close = function() {
that.container.dialog('destroy');
that.container.remove();
@@ -284,6 +375,9 @@ IPA.dialog = function(spec) {
IPA.opened_dialogs.focus_top();
};
+ /**
+ * Reset dialog's fields
+ */
that.reset = function() {
var fields = that.fields.get_fields();
for (var i=0; i<fields.length; i++) {
@@ -291,9 +385,27 @@ IPA.dialog = function(spec) {
}
};
+ /**
+ * Called when dialog is opened.
+ *
+ * - override point
+ * @protected
+ */
that.register_listeners = function() {};
+
+ /**
+ * Called when dialog is closed.
+ *
+ * - override point
+ * @protected
+ */
that.remove_listeners = function() {};
+ /**
+ * Create builder(s) which should build dialog's content (fields,
+ * widgets...)
+ * @protected
+ */
that.create_builder = function() {
var widget_builder = IPA.widget_builder({
@@ -324,6 +436,10 @@ IPA.dialog = function(spec) {
});
};
+ /**
+ * Initializes dialog object
+ * @protected
+ */
that.init = function() {
that.create_builder();
@@ -345,8 +461,18 @@ IPA.dialog = function(spec) {
};
/**
+ * Adder dialog
* This dialog provides an interface for searching and selecting
* values from the available results.
+ *
+ * It has two tables:
+ *
+ * - available, contains values to choose from
+ * - selected, contains chosen values
+ *
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
*/
IPA.adder_dialog = function(spec) {
@@ -358,8 +484,17 @@ IPA.adder_dialog = function(spec) {
IPA.confirm_mixin().apply(that);
+ /**
+ * External value can be added.
+ *
+ * In general external member doesn't represent any entity.
+ * @property {boolean} external=undefined
+ */
that.external = spec.external;
+
+ /** @property {number} width=600 Width */
that.width = spec.width || 600;
+ /** @property {number} height=300 Height */
that.height = spec.height || 360;
if (!that.entity) {
@@ -390,19 +525,32 @@ IPA.adder_dialog = function(spec) {
}
};
+ /**
+ * Get column
+ * @param {string} name
+ */
that.get_column = function(name) {
return that.available_table.get_column(name);
};
+ /** Get all columns */
that.get_columns = function() {
return that.available_table.get_columns();
};
+ /**
+ * Add column to both tables.
+ * @param {IPA.column} column
+ */
that.add_column = function(column) {
that.available_table.add_column(column);
that.selected_table.add_column(column);
};
+ /**
+ * Replace columns in both tables
+ * @param {IPA.column[]} columns New columns
+ */
that.set_columns = function(columns) {
that.clear_columns();
for (var i=0; i<columns.length; i++) {
@@ -410,11 +558,19 @@ IPA.adder_dialog = function(spec) {
}
};
+ /**
+ * Clear all columns in both tables.
+ */
that.clear_columns = function() {
that.available_table.clear_columns();
that.selected_table.clear_columns();
};
+ /**
+ * Create column from spec
+ * @param {Object} spec
+ * @return {IPA.column}
+ */
that.create_column = function(spec) {
spec.entity = that.entity;
var column = IPA.column(spec);
@@ -422,6 +578,9 @@ IPA.adder_dialog = function(spec) {
return column;
};
+ /**
+ * @inheritDoc
+ */
that.create = function() {
// do not call that.dialog_create();
@@ -555,6 +714,7 @@ IPA.adder_dialog = function(spec) {
that.search();
};
+ /** @inheritDoc */
that.open = function(container) {
var add_button = that.create_button({
@@ -579,16 +739,26 @@ IPA.adder_dialog = function(spec) {
that.update_buttons();
};
+ /**
+ * Move selected values in 'available' table to 'selected' table
+ */
that.add = function() {
var rows = that.available_table.remove_selected_rows();
that.selected_table.add_rows(rows);
};
+ /**
+ * Move selected values in 'selected' table to 'available' table
+ */
that.remove = function() {
var rows = that.selected_table.remove_selected_rows();
that.available_table.add_rows(rows);
};
+ /**
+ * Update button state based on selection
+ * @protected
+ */
that.update_buttons = function() {
var values = that.selected_table.save();
@@ -597,29 +767,55 @@ IPA.adder_dialog = function(spec) {
button.set_enabled(values && values.length);
};
+ /**
+ * Get value of 'available' filter
+ * @return {string}
+ */
that.get_filter = function() {
return that.filter_field.val();
};
+ /**
+ * Clear rows in available table
+ */
that.clear_available_values = function() {
that.available_table.empty();
};
+ /**
+ * Clear rows in selected table
+ */
that.clear_selected_values = function() {
that.selected_table.empty();
};
+ /**
+ * Add record to available table
+ * @param {Object} record
+ */
that.add_available_value = function(record) {
that.available_table.add_record(record);
};
+ /**
+ * Get values in 'selected' table
+ */
that.get_selected_values = function() {
return that.selected_table.save();
};
+ /**
+ * Operation which has to be executed after selection confirmation
+ *
+ * - override point
+ */
that.execute = function() {
};
+ /**
+ * Confirm handler
+ * @protected
+ */
that.on_confirm = function() {
var add_button = that.get_button('add');
@@ -636,7 +832,12 @@ IPA.adder_dialog = function(spec) {
};
/**
- * This dialog displays the values to be deleted.
+ * Deletion confirmation dialog
+ *
+ * - displays the values to be deleted.
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
*/
IPA.deleter_dialog = function (spec) {
@@ -648,19 +849,35 @@ IPA.deleter_dialog = function (spec) {
spec.ok_label = spec.ok_label || '@i18n:buttons.remove';
var that = IPA.confirm_dialog(spec);
+
+ /**
+ * Values to be deleted
+ * @property {string[]} values
+ */
that.values = spec.values || [];
+
+ /** Positive confirmation handler */
that.on_ok = spec.on_ok || function() {
that.execute();
};
+ /**
+ * Add value
+ * @param {string} value
+ */
that.add_value = function(value) {
that.values.push(value);
};
+ /**
+ * Replace values
+ * @param {string[]} values
+ */
that.set_values = function(values) {
that.values = values;
};
+ /** @inheritDoc */
that.create = function() {
$('<p/>', {
@@ -702,6 +919,13 @@ IPA.deleter_dialog = function (spec) {
return that;
};
+/**
+ * Message dialog
+ *
+ * Displays a message.
+ * @class
+ * @extends IPA.confirm_dialog
+ */
IPA.message_dialog = function(spec) {
spec = spec || {};
@@ -710,6 +934,7 @@ IPA.message_dialog = function(spec) {
var that = IPA.confirm_dialog(spec);
+ /** @inheritDoc */
that.open = function(container) {
that.confirm_dialog_open(container);
@@ -723,6 +948,19 @@ IPA.message_dialog = function(spec) {
return that;
};
+/**
+ * Confirmation dialog
+ *
+ * Presents user a proposal(message). User then decides whether he would accept or
+ * decline the proposal.
+ *
+ * Acceptation is done by clicking on 'OK' button or hitting 'ENTER' key,
+ * refusal by clicking on 'Cancel' button or hitting 'ESCAPE' key.
+ *
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
+ */
IPA.confirm_dialog = function(spec) {
spec = spec || {};
@@ -732,20 +970,42 @@ IPA.confirm_dialog = function(spec) {
var that = IPA.dialog(spec);
IPA.confirm_mixin().apply(that);
+ /** @property {string} message Confirmation message */
that.message = text.get(spec.message);
+
+ /** @property {Function} on_ok OK handler */
that.on_ok = spec.on_ok;
+
+ /** @property {Function} on_cancel Cancel handler */
that.on_cancel = spec.on_cancel;
+
+ /** @property {Function} ok_label OK button label */
that.ok_label = text.get(spec.ok_label || '@i18n:buttons.ok');
+
+ /** @property {Function} cancel_label Cancel button label */
that.cancel_label = text.get(spec.cancel_label || '@i18n:buttons.cancel');
+
+ /**
+ * Dialog is confirmed
+ * @protected
+ * @property {boolean}
+ */
that.confirmed = false;
+
+ /**
+ * Dialog can be confirmed by hitting 'ENTER' key
+ * @property {boolean} confirm_on_enter=true
+ */
that.confirm_on_enter = spec.confirm_on_enter !== undefined ? spec.confirm_on_enter : true;
+ /** @inheritDoc */
that.create = function() {
$('<p/>', {
'text': that.message
}).appendTo(that.container);
};
+ /** @inheritDoc */
that.close = function() {
that.dialog_close();
@@ -761,17 +1021,22 @@ IPA.confirm_dialog = function(spec) {
}
};
+ /** @inheritDoc */
that.open = function(container) {
that.confirmed = false;
that.dialog_open(container);
};
+ /**
+ * Confirm handler
+ */
that.on_confirm = function() {
that.confirmed = true;
that.close();
};
+ /** Create buttons */
that.create_buttons = function() {
that.create_button({
@@ -801,16 +1066,40 @@ IPA.confirm_dialog = function(spec) {
return that;
};
+/**
+ * Confirm mixin
+ *
+ * Can extend a dialog by confirmation by keyboard functionality. When applied
+ * dialog can be:
+ *
+ * - confirmed by 'ENTER' key
+ * - declined by 'ESCAPE' key
+ *
+ * To apply:
+ *
+ * IPA.confirm_mixin().apply(dialog);
+ *
+ * @class
+ */
IPA.confirm_mixin = function() {
return {
mixin: {
+ /**
+ * Elements (tag names) or node types which should be ignored as
+ * confirmation event sources.
+ */
ignore_enter_rules: {
src_elements: ['a', 'button'],
src_types: ['textarea', 'select-one']
},
+ /**
+ * Test if event is confirmation event
+ * @param {Event} event
+ * @return {boolean}
+ */
test_ignore: function(event) {
var ir = this.ignore_enter_rules,
@@ -822,6 +1111,9 @@ IPA.confirm_mixin = function() {
return ignore;
},
+ /**
+ * Registration of keyboard event handlers
+ */
register_listeners: function() {
var self = this;
this._on_key_up_listener = function(e) { self.on_key_up(e); };
@@ -829,11 +1121,19 @@ IPA.confirm_mixin = function() {
dialog_container.bind('keyup', this._on_key_up_listener);
},
+ /**
+ * Removal of registered event handlers
+ */
remove_listeners: function() {
var dialog_container = this.container.parent('.ui-dialog');
dialog_container.unbind('keyup', this._on_key_up_listener);
},
+ /**
+ * Test if confirmation happened
+ * If so call dialog's `on_confirm` or `on_cancel` method.
+ * @param {Event} event
+ */
on_key_up: function(event) {
if (event.keyCode === $.ui.keyCode.ENTER &&
!this.test_ignore(event) &&
diff --git a/install/ui/src/freeipa/entity.js b/install/ui/src/freeipa/entity.js
index eef58d1a4..eb2d98a55 100644
--- a/install/ui/src/freeipa/entity.js
+++ b/install/ui/src/freeipa/entity.js
@@ -34,8 +34,22 @@ define([
function(lang, metadata_provider, Singleton_registry, builder,
IPA, $, reg, text) {
+/**
+ * Entity module
+ *
+ * @class entity
+ * @singleton
+ */
var exp = {};
+/**
+ * Entity
+ *
+ * Represents a business logic object type, ie. user. Maintains
+ * information related to that object.
+ * @class entity.entity
+ * @alternateClassName IPA.entity
+ */
exp.entity = IPA.entity = function(spec) {
spec = spec || {};
@@ -47,34 +61,113 @@ exp.entity = IPA.entity = function(spec) {
var that = IPA.object();
+ /**
+ * Name
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+ /**
+ * Entity has primary key(s)
+ * @property {boolean} defines_key=true
+ */
that.defines_key = spec.defines_key !== undefined ? spec.defines_key : true;
+ /**
+ * Metadata
+ * @property {Object}
+ */
that.metadata = spec.metadata;
+ /**
+ * Dialogs
+ * @protected
+ * @property {ordered_map}
+ */
that.dialogs = $.ordered_map();
+
+ /**
+ * Dialog specifications
+ * @property {Array.<Object>}
+ */
that.dialog_specs = spec.dialogs || [];
+
+ /**
+ * Dialogs defined in `dialog_specs` were created -> `dialogs` is populated.
+ * @property {boolean}
+ */
that.dialogs_created = false;
+ /**
+ * Entity policies
+ * @property {IPA.entity_policies}
+ */
that.policies = IPA.entity_policies({
entity: that,
policies: spec.policies
});
+
+ /**
+ * Facets
+ * @protected
+ * @property {ordered_map}
+ */
that.facets = $.ordered_map();
+
+ /**
+ * Facet groups
+ * @property {ordered_map}
+ */
that.facet_groups = $.ordered_map();
+
+ /**
+ * Facet group object specifications
+ * @property {Array.<Object>}
+ */
that.facet_group_specs = spec.facet_groups;
+
+ /**
+ * Facet object specifications
+ * @property {Array.<Object>}
+ */
that.facet_specs = spec.facets || [];
+
+ /**
+ * Facets and facet groups were created
+ * @property {boolean}
+ */
that.facets_created = false;
- // current facet
+ /**
+ * Current facet
+ * @property {IPA.facet}
+ */
that.facet = null;
+ /**
+ * Name of facet to which other facets should redirect in case of unexpected
+ * event.
+ * @property {string}
+ */
that.redirect_facet = spec.redirect_facet;
+
+ /**
+ * Containing entity in case if this is a nested entity
+ * @property {entity.entity}
+ */
that.containing_entity = null;
+ /**
+ * Initialize entity.
+ * Should be called by builder if used.
+ */
that.init = function() {
if (!that.metadata) {
that.metadata = that.get_default_metadata();
@@ -88,14 +181,28 @@ exp.entity = IPA.entity = function(spec) {
that.label = text.get(that.label) || that.metadata.label || that.name;
};
+ /**
+ * Initialize entity.
+ * Should be called by builder if used.
+ * @return Metadata
+ */
that.get_default_metadata = function() {
return metadata_provider.get('@mo:'+that.name);
};
+ /**
+ * Getter for `containing_entity`
+ * @return {entity.entity}
+ */
that.get_containing_entity = function() {
return that.containing_entity;
};
+ /**
+ * Builder overrides for dialogs belonging to this entity
+ *
+ * It's purpose is to set valid context and add the dialogs.
+ */
that.dialog_build_overrides = {
$pre_ops: [
function (spec, context) {
@@ -112,6 +219,14 @@ exp.entity = IPA.entity = function(spec) {
$factory: IPA.dialog
};
+ /**
+ * Get dialog with given name
+ *
+ * Uses lazy creation - creates dialogs from spec if not done yet.
+ *
+ * @param {string} name
+ * @return Dialog
+ */
that.get_dialog = function(name) {
//build all dialogs on the first time
@@ -123,6 +238,12 @@ exp.entity = IPA.entity = function(spec) {
return that.dialogs.get(name);
};
+ /**
+ * Add one or multiple dialog(s) to entity
+ *
+ * New dialogs are built if specs are supplied.
+ * @param {IPA.dialog|Array.<IPA.dialog>} dialog - dialog(s) or spec(s) to add
+ */
that.add_dialog = function(dialog) {
var add = function (dialog) {
@@ -143,24 +264,55 @@ exp.entity = IPA.entity = function(spec) {
return that;
};
+ /**
+ * Add facet group
+ * @deprecated
+ */
that.add_facet_group = function(facet_group) {
that.facet_groups.put(facet_group.name, facet_group);
};
+ /**
+ * Get facet group
+ * @deprecated
+ */
that.get_facet_group = function(name) {
return that.facet_groups.get(name);
};
+ /**
+ * Remove facet group
+ * @deprecated
+ */
that.remove_facet_groups = function() {
that.facet_groups.empty();
};
+ /**
+ * This method is used only in get_facet method and there is no sense to
+ * use it alone. Will be removed.
+ * @deprecated
+ */
that.add_redirect_info = function(facet_name) {
if (!that.redirect_facet && facet_name){
that.redirect_facet = facet_name;
}
};
+ /**
+ * Get facet with given name.
+ *
+ * Uses lazy creation. All facets are created from facet specs upon first
+ * get_facet call.
+ *
+ * - returns current or first facet if name is *undefined*.
+ * - returns default facet if name == 'default' - first facet of non-empty
+ * facet group
+ *
+ * @param {string|undefined|"default"} name - facet name
+ * @return {IPA.facet}
+ *
+ */
that.get_facet = function(name) {
var i, facets;
@@ -202,6 +354,12 @@ exp.entity = IPA.entity = function(spec) {
return that.facets.get(name);
};
+ /**
+ * Add facet to entity
+ *
+ * @param {IPA.facet} facet - facet to add
+ * @param {string} facet.facet_group - facet group to add the facet
+ */
that.add_facet = function(facet) {
facet.entity = that;
@@ -217,6 +375,11 @@ exp.entity = IPA.entity = function(spec) {
return that;
};
+ /**
+ * Helper function - evaluates if entity as any attribute members.
+ * Useful for knowing when to add 'no_members' option to RPC call.
+ * @return {boolean}
+ */
that.has_members = function() {
var members = that.metadata.attribute_members;
var has = false;
@@ -231,6 +394,9 @@ exp.entity = IPA.entity = function(spec) {
return has;
};
+ /**
+ * Builder used for building this entity.
+ */
that.builder = spec.builder || IPA.entity_builder(that);
that.entity_init = that.init;
@@ -238,7 +404,19 @@ exp.entity = IPA.entity = function(spec) {
return that;
};
-exp.entity_builder =IPA.entity_builder = function(entity) {
+/**
+ * Entity post builder
+ *
+ * - contains methods for entity post creation operations.
+ * - has chained API.
+ * - direct usage is not recommended. It's usable only when overriding standard
+ * behavior. By default, calls of most methods are registered as post operations
+ * for {@link _base.builder}.
+ *
+ * @class entity.entity_builder
+ * @alternateClassName IPA.entity_builder
+ */
+exp.entity_builder = IPA.entity_builder = function(entity) {
var that = IPA.object();
@@ -246,6 +424,7 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
var facet = null;
var section = null;
+ /** Default facet groups **/
that.default_facet_groups = [
'member',
'settings',
@@ -253,6 +432,10 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
'managedby'
];
+ /**
+ * Build and add facet group
+ * @param {Object} spec - facet group specification
+ */
that.facet_group = function(spec) {
if (typeof spec === 'string') {
@@ -276,6 +459,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Replace facet groups
+ *
+ * @param {Array.<Object>} specs - specifications of new facet groups
+ */
that.facet_groups = function(specs) {
entity.remove_facet_groups();
@@ -288,6 +476,10 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add facet spec
+ * @param {Object} spec
+ */
that.facet = function(spec) {
entity.facet_specs.push(spec);
@@ -295,6 +487,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add search facet
+ * @deprecated
+ * @param {Object} spec
+ */
that.search_facet = function(spec) {
spec.$type = spec.$type || 'search';
@@ -306,6 +503,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add nested search facet
+ * @deprecated
+ * @param {Object} spec
+ */
that.nested_search_facet = function(spec) {
spec.$type = spec.$type || 'nested_search';
@@ -315,6 +517,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add details facet
+ * @deprecated
+ * @param {Object} spec
+ */
that.details_facet = function(spec) {
spec.$type = spec.$type || 'details';
@@ -324,6 +531,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add association facet
+ * @deprecated
+ * @param {Object} spec
+ */
that.association_facet = function(spec) {
spec.$type = spec.$type || 'association';
@@ -333,6 +545,11 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add attribute_facet facet
+ * @deprecated
+ * @param {Object} spec
+ */
that.attribute_facet = function(spec) {
spec.$type = spec.$type || 'attribute';
@@ -342,6 +559,18 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add missing association facets
+ *
+ * Facets are based on entity attribute_members. Doesn't add duplicates so
+ * facet defined in entity spec are ignored and only the missing are added.
+ *
+ * Direct usage is deprecated. Use `standard_association_facets: true`
+ * in entity spec instead.
+ *
+ * @deprecated
+ * @param {Object} spec - object to be mixed-in in each new facet spec
+ */
that.standard_association_facets = function(spec) {
spec = spec || {};
@@ -403,7 +632,7 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return null;
}
- /*
+ /**
* If it's an indirect attribute member, return its direct facets spec
* if it exists.
*/
@@ -426,6 +655,13 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
}
}
+ /**
+ * Set containing(parent) entity
+ *
+ * Direct usage is deprecated. Set `containing_entity: 'entity_name'` in
+ * entity spec instead.
+ * @deprecated
+ */
that.containing_entity = function(entity_name) {
add_redirect_info();
entity.containing_entity = IPA.get_entity(entity_name);
@@ -450,6 +686,12 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that;
};
+ /**
+ * Add adder dialog spec
+ *
+ * Set `adder_dialog: { ... }` in entity instead.
+ * @deprecated
+ */
that.adder_dialog = function(spec) {
spec.$factory = spec.$factory || IPA.entity_adder_dialog;
spec.name = spec.name || 'add';
@@ -463,6 +705,12 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
return that.dialog(spec);
};
+ /**
+ * Add deleter_dialog spec
+ *
+ * Set `deleter_dialog: { ... }` in entity instead.
+ * @deprecated
+ */
that.deleter_dialog = function(spec) {
spec.$factory = spec.$factory || IPA.search_deleter_dialog;
spec.name = spec.name || 'remove';
@@ -472,11 +720,28 @@ exp.entity_builder =IPA.entity_builder = function(entity) {
that.facet_groups(entity.facet_group_specs || that.default_facet_groups);
-
-
return that;
};
+/**
+ * Entity post build operations
+ *
+ * they:
+ *
+ * - invokes `enable_test()`, `init()`
+ * - sets containing entity
+ * - creates standard association facets
+ * - add adder dialog
+ * - adds deleter dialog
+ *
+ * @member entity
+ * @property {Object} entity_post_ops
+ * @property {Function} entity_post_ops.init
+ * @property {Function} entity_post_ops.containing_entity
+ * @property {Function} entity_post_ops.standard_association_facets
+ * @property {Function} entity_post_ops.adder_dialog
+ * @property {Function} entity_post_ops.deleter_dialog
+ */
exp.entity_post_ops = {
init: function(entity, spec, context) {
@@ -526,33 +791,75 @@ exp.entity_post_ops = {
}
};
+/**
+ * Entity policy base class
+ *
+ * Policy is a mediator object. Usually it handles inter-facet communication.
+ *
+ * Specific policy should override `facet_created` method.
+ *
+ * @class entity.entity_policy
+ * @alternateClassName IPA.entity_policy
+ * @abstract
+ */
exp.entity_policy = IPA.entity_policy = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Entity this policy is associated with
+ * @property {entity.entity}
+ */
that.entity = spec.entity;
+ /**
+ * Facet created
+ *
+ * Functional entry point. This method is called after facets are created.
+ * It allows the policy to registered various event handlers to facets or
+ * do other work.
+ */
that.facets_created = function() {
};
return that;
};
+/**
+ * Collection of entity policies.
+ * @class entity.entity_policies
+ * @alternateClassName IPA.entity_policies
+ */
exp.entity_policies = IPA.entity_policies = function(spec) {
var that = IPA.object();
+ /**
+ * Entity to be set to all policies
+ */
that.entity = spec.entity;
+
+ /**
+ * Policies
+ */
that.policies = [];
+ /**
+ * Add policy
+ * @param {entity.entity_policy} policy
+ */
that.add_policy = function(policy) {
policy.entity = that.entity;
that.policies.push(policy);
};
+ /**
+ * Add policies
+ * @param {Array.<entity.entity_policy>} policies
+ */
that.add_policies = function(policies) {
if (!policies) return;
@@ -562,6 +869,9 @@ exp.entity_policies = IPA.entity_policies = function(spec) {
}
};
+ /**
+ * Call each policy's `facet_policy` method
+ */
that.facets_created = function() {
for (var i=0; i<that.policies.length; i++) {
@@ -576,17 +886,53 @@ exp.entity_policies = IPA.entity_policies = function(spec) {
return that;
};
+/**
+ * Facet update policy
+ *
+ * This policy sets destination facet of destination entity as expired
+ * when specific event of source facet of this entity is raised.
+ *
+ * @class entity.facet_update_policy
+ * @extends entity.entity_policy
+ * @alternateClassName IPA.facet_update_policy
+ *
+ * @param {Object} spec
+ * @param {string} spec.event - event name
+ * @param {string} spec.source_facet - source facet name
+ * @param {string} spec.dest_facet - destination facet name
+ * @param {string} spec.dest_entity_name - destination entity name
+ *
+ */
exp.facet_update_policy = IPA.facet_update_policy = function(spec) {
spec = spec || {};
var that = IPA.entity_policy();
+ /**
+ * Source event name
+ * @property {string} event=on_update
+ */
that.event = spec.event || 'on_update';
+
+ /**
+ * Source facet name
+ */
that.source_facet_name = spec.source_facet;
+
+ /**
+ * Destination facet name
+ */
that.dest_facet_name = spec.dest_facet;
+
+ /**
+ * Destination entity name
+ */
that.dest_entity_name = spec.dest_entity;
+ /**
+ * @inheritDoc
+ */
that.facets_created = function() {
that.source_facet = that.entity.get_facet(that.source_facet_name);
@@ -605,6 +951,9 @@ exp.facet_update_policy = IPA.facet_update_policy = function(spec) {
event.attach(that.set_expired_flag);
};
+ /**
+ * Set facet as expired
+ */
that.set_expired_flag = function() {
that.dest_facet.set_expired_flag();
@@ -613,17 +962,36 @@ exp.facet_update_policy = IPA.facet_update_policy = function(spec) {
return that;
};
+/**
+ * Adder facet update policy
+ *
+ * Update destination details facet when new object is added (adder dialog
+ * 'added' event).
+ *
+ * @class entity.adder_facet_update_policy
+ * @extends entity.entity_policy
+ * @alternateClassName IPA.adder_facet_update_policy
+ *
+ */
exp.adder_facet_update_policy = IPA.adder_facet_update_policy = function(spec) {
spec = spec || {};
var that = IPA.entity_policy();
+ /**
+ * Source event name
+ * @property {string} event='added'
+ */
that.event = spec.event || 'added';
+ /** Adder dialog name */
that.dialog_name = spec.dialog_name || 'add';
+ /** Destination facet name */
that.dest_facet_name = spec.dest_facet || 'details';
+ /** Destination entity name */
that.dest_entity_name = spec.dest_entity;
+ /** @inheritDoc */
that.facets_created = function() {
that.dialog = that.entity.get_dialog(that.dialog_name);
@@ -642,6 +1010,7 @@ exp.adder_facet_update_policy = IPA.adder_facet_update_policy = function(spec) {
event.attach(that.set_expired_flag);
};
+ /** Set facet as expired */
that.set_expired_flag = function() {
that.dest_facet.set_expired_flag();
@@ -650,6 +1019,16 @@ exp.adder_facet_update_policy = IPA.adder_facet_update_policy = function(spec) {
return that;
};
+
+/**
+ * Search facet update policy
+ *
+ * Expires details facet when search facet is updated.
+ *
+ * @class entity.search_facet_update_policy
+ * @extends entity.facet_update_policy
+ * @alternateClassName IPA.search_facet_update_policy
+ */
exp.search_facet_update_policy = IPA.search_facet_update_policy = function(spec) {
spec = spec || {};
@@ -659,6 +1038,15 @@ exp.search_facet_update_policy = IPA.search_facet_update_policy = function(spec)
return IPA.facet_update_policy(spec);
};
+/**
+ * Details facet update policy
+ *
+ * Expires search facet when details facet is updated.
+ *
+ * @class entity.details_facet_update_policy
+ * @extends entity.facet_update_policy
+ * @alternateClassName IPA.details_facet_update_policy
+ */
exp.details_facet_update_policy =IPA.details_facet_update_policy = function(spec) {
spec = spec || {};
diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js
index b01452dd7..44ebfe5af 100644
--- a/install/ui/src/freeipa/facet.js
+++ b/install/ui/src/freeipa/facet.js
@@ -44,51 +44,65 @@ define([
Singleton_registry, builder, IPA, $, navigation, phases, reg, su, text) {
/**
+ * Facet module
+ *
+ * @class facet
+ * @singleton
+ */
+var exp = {};
+exp.facet_spec = {};
+
+/**
* Facet represents the content of currently displayed page.
*
- * = Show, Clear, Refresh mechanism =
+ * ## Show, Clear, Refresh mechanism
*
* Use cases:
- * a) Display facet with defined arguments.
- * b) Switch to facet
- * c) Update facet state
*
- * == Display facet by route ==
- * 1) somebody sets route
- * 2) Route is evaluated, arguments extracted.
- * 3) Facet state is updated `set_state(args, pkeys)`.(saves previous state)
- * 4) Facet show() is called
+ * - Display facet with defined arguments.
+ * - Switch to facet
+ * - Update facet state
+ *
+ * ## Display facet by route
+ *
+ * 1. somebody sets route
+ * 2. Route is evaluated, arguments extracted.
+ * 3. Facet state is updated `set_state(args, pkeys)`.(saves previous state)
+ * 4. Facet show() is called
+ *
+ * ## Display facet with defined arguments
+ *
+ * 1. Somebody calls navigation.show(xxx);
+ * 2. Facet state is updated `set_state(args, pkeys)`.(saves previous state)
+ * 3. Route is updated, but the hash change is ignored
+ * 4. Facet show() is called.
+ * - First time show
+ * a. creates DOM
+ * b. display DOM
+ * c. refresh();
+ * - Next time
+ * a. display DOM
+ * b. `needs_update()` (compares previous state with current)
+ * - true:
+ * 1. clear() - each facet can override to supress clear or
+ * control the behaviour
+ * 2. refresh()
*
- * == Display facet with defined arguments ==
- * 1) Somebody calls navigation.show(xxx);
- * 2) Facet state is updated `set_state(args, pkeys)`.(saves previous state)
- * 3) Route is updated, but the hash change is ignored
- * 4) Facet show() is called.
- * 5.1) First time show
- * a) creates DOM
- * b) display DOM
- * c) refresh();
- * 5.2) Next time
- * a) display DOM
- * b) needs_update()? (compares previous state with current)
- * true:
- * 1) clear() - each facet can override to supress clear or
- * control the behaviour
- * 2) refresh()
+ * ## Swith to facet
*
- * == Swith to facet ==
* Same as display facet but only without arguments. Arguments are extracted at
* step 2.
*
- * == Update facet state ==
- * 1) set_state(args, pkeys?)
- * 2) needs_update()?
- * true:
- * a) clear()
- * b) refresh()
- * 2) Update route, ignore hash change event
+ * ## Update facet state
*
- * == Updating hash ==
+ * 1. set_state(args, pkeys?)
+ * 2. needs_update()?
+ * - true:
+ * 1. clear()
+ * 2. refresh()
+ * 3. Update route, ignore hash change event
+ *
+ * ## Updating hash
* Hash updates are responsibility of navigation component and application
* controller. Application controller should listen to facet's `state_change`
* event. And call something like navigation.update_hash(facet).
@@ -96,77 +110,185 @@ define([
* navigation.update_hash should find all the necessary state properties (args,
* pkeys).
*
- * == needs_update method ==
- *
+ * ## needs_update method
+ * todo
*
+ * @class facet.facet
+ * @alternateClassName IPA.facet
*/
-
-var exp = {};
-exp.facet_spec = {};
-
exp.facet = IPA.facet = function(spec, no_init) {
spec = spec || {};
var that = new Evented();
+ /**
+ * Entity this facet belongs to
+ * @property {entity.entity}
+ */
that.entity = IPA.get_entity(spec.entity);
+ /**
+ * Facet name
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Facet label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+
+ /**
+ * Facet title
+ * @property {string}
+ */
that.title = text.get(spec.title || that.label);
+
+ /**
+ * Facet tab label
+ * @property {string}
+ */
that.tab_label = text.get(spec.tab_label || that.label);
+
+ /**
+ * Facet element's CSS class
+ * @property {string}
+ */
that.display_class = spec.display_class;
+
+ /**
+ * Flag. Marks the facet as read-only - doesn't support modify&update
+ * operation.
+ * @property {boolean}
+ */
that.no_update = spec.no_update;
+ /**
+ * Breadcrumb navigation is not displayed when set.
+ * @property {boolean}
+ */
that.disable_breadcrumb = spec.disable_breadcrumb;
+
+ /**
+ * Facet tabs are not displayed when set.
+ * @property {boolean}
+ */
that.disable_facet_tabs = spec.disable_facet_tabs;
+ /**
+ * State object for actions
+ * @property {facet.state}
+ */
that.action_state = builder.build('', spec.state || {}, {}, { $factory: exp.state });
+
+ /**
+ * Collection of facet actions
+ * @property {facet.action_holder}
+ */
that.actions = builder.build('', { actions: spec.actions }, {}, { $factory: exp.action_holder } );
+ /**
+ * Array of actions which are displayed in facet header
+ * @property {Array.<string>}
+ */
that.header_actions = spec.header_actions;
+
+ /**
+ * Facet header
+ * @property {facet.facet_header}
+ */
that.header = spec.header || IPA.facet_header({ facet: that });
+ /**
+ * Hard override for `needs_update()` logic. When set, `needs_update`
+ * should always return this value.
+ * @property {boolean}
+ */
that._needs_update = spec.needs_update;
+
+ /**
+ * Marks facet as expired - needs update
+ *
+ * Difference between `_needs_update` is that `expired_flag` should be
+ * cleared after update.
+ *
+ * @property {boolean}
+ */
that.expired_flag = true;
+
+ /**
+ * Last time when facet was updated.
+ * @property {Date}
+ */
that.last_updated = null;
+
+ /**
+ * Timeout[s] from `last_modified` after which facet should be expired
+ * @property {number} expire_timeout=600
+ */
that.expire_timeout = spec.expire_timeout || 600; //[seconds]
+
+ /**
+ * Raised when facet gets updated
+ * @event
+ */
that.on_update = IPA.observer();
+
+ /**
+ * Raised after `load()`
+ * @event
+ */
that.post_load = IPA.observer();
+ /**
+ * Dialogs
+ * @property {ordered_map}
+ */
that.dialogs = $.ordered_map();
/**
* domNode of container
* Suppose to contain domNode of this and other facets.
+ * @property {jQuery}
*/
that.container_node = spec.container_node;
/**
- * FIXME: that.container should be eliminated
- * now it's the same as domNode
- */
- //that.container
-
- /**
* domNode which contains all content of a facet.
* Should contain error content and content. When error is moved to
* standalone facet it will replace functionality of content.
+ * @property {jQuery}
*/
that.domNode = null;
- // facet group name
+ /**
+ * Facet group name
+ * @property {string}
+ */
that.facet_group = spec.facet_group;
+ /**
+ * Redirection target information.
+ *
+ * Can be facet and/or entity name.
+ * @property {Object}
+ * @param {string} entity entity name
+ * @param {string} facet facet name
+ */
that.redirect_info = spec.redirect_info;
/**
* Public state
- *
+ * @property {facet.FacetState}
*/
that.state = new FacetState();
+ /**
+ * Set and normalize pkeys. Merges with existing if present. If keys length
+ * differs, the alignment is from the last one to the first one.
+ */
that.set_pkeys = function(pkeys) {
pkeys = that.get_pkeys(pkeys);
@@ -176,7 +298,7 @@ exp.facet = IPA.facet = function(spec, no_init) {
/**
* Return THE pkey of this facet. Basically the last one of pkeys list.
*
- * @type String
+ * @return {string} pkey
*/
that.get_pkey = function() {
var pkeys = that.get_pkeys();
@@ -194,7 +316,8 @@ exp.facet = IPA.facet = function(spec, no_init) {
* One can get merge current pkeys with supplied if `pkeys` param is
* specified.
*
- * @param String[] new pkeys to merge
+ * @param {string[]} pkeys new pkeys to merge
+ * @return {string[]} pkeys
*/
that.get_pkeys = function(pkeys) {
var new_keys = [];
@@ -228,6 +351,12 @@ exp.facet = IPA.facet = function(spec, no_init) {
return new_keys;
};
+ /**
+ * Get pkey prefix.
+ *
+ * Opposite method to `get_pkey` - get's all pkeys except the last one.
+ * @return {Array.<string>}
+ */
that.get_pkey_prefix = function() {
var pkeys = that.get_pkeys();
if (pkeys.length > 0) pkeys.pop();
@@ -235,6 +364,14 @@ exp.facet = IPA.facet = function(spec, no_init) {
return pkeys;
};
+ /**
+ * Checks if two objects has the same properties with equal values.
+ *
+ * @param {Object} a
+ * @param {Object} b
+ * @return {boolean} `a` and `b` are value-equal
+ * @protected
+ */
that.state_diff = function(a, b) {
var diff = false;
var checked = {};
@@ -271,6 +408,11 @@ exp.facet = IPA.facet = function(spec, no_init) {
return diff;
};
+ /**
+ * Reset facet state to supplied
+ *
+ * @param {Object} state state to set
+ */
that.reset_state = function(state) {
if (state.pkeys) {
@@ -279,12 +421,19 @@ exp.facet = IPA.facet = function(spec, no_init) {
that.state.reset(state);
};
+ /**
+ * Get copy of current state
+ *
+ * @return {Object} state
+ */
that.get_state = function() {
return that.state.clone();
};
/**
* Merges state into current and notifies it.
+ *
+ * @param {Object} state object to merge into current state
*/
that.set_state = function(state) {
@@ -294,11 +443,20 @@ exp.facet = IPA.facet = function(spec, no_init) {
that.state.set(state);
};
+ /**
+ * Handle state set
+ * @param {Object} old_state
+ * @param {Object} state
+ */
that.on_state_set = function(old_state, state) {
that._on_state_change(state);
};
+ /**
+ * Handle state change
+ * @protected
+ */
that._on_state_change = function(state) {
// basically a show method without displaying the facet
@@ -327,6 +485,13 @@ exp.facet = IPA.facet = function(spec, no_init) {
}
};
+ /**
+ * Fires `facet-state-change` event with given state as event parameter.
+ *
+ * @fires facet-state-change
+ * @protected
+ * @param {Object} state
+ */
that._notify_state_change = function(state) {
that.emit('facet-state-change', {
facet: that,
@@ -334,15 +499,29 @@ exp.facet = IPA.facet = function(spec, no_init) {
});
};
+ /**
+ * Get dialog with given name from facet dialog collection
+ *
+ * @param {string} name
+ * @return {IPA.dialog} dialog
+ */
that.get_dialog = function(name) {
return that.dialogs.get(name);
};
+ /**
+ * Add dialog to facet dialog collection
+ *
+ * @param {IPA.dialog} dialog
+ */
that.dialog = function(dialog) {
that.dialogs.put(dialog.name, dialog);
return that;
};
+ /**
+ * Create facet's HTML representation
+ */
that.create = function() {
var entity_name = !!that.entity ? that.entity.name : '';
@@ -389,6 +568,12 @@ exp.facet = IPA.facet = function(spec, no_init) {
domNode.removeClass('active-facet');
};
+ /**
+ * Create facet header
+ *
+ * @param {jQuery} container
+ * @protected
+ */
that.create_header = function(container) {
that.header.create(container);
@@ -398,9 +583,22 @@ exp.facet = IPA.facet = function(spec, no_init) {
}).appendTo(container);
};
+ /**
+ * Create content
+ *
+ * @param {jQuery} container
+ * @protected
+ * @abstract
+ */
that.create_content = function(container) {
};
+ /**
+ * Create control buttons
+ *
+ * @param {jQuery} container
+ * @protected
+ */
that.create_control_buttons = function(container) {
if (that.control_buttons) {
@@ -408,11 +606,22 @@ exp.facet = IPA.facet = function(spec, no_init) {
}
};
+ /**
+ * Update h1 element in title container
+ *
+ * @deprecated Please update title in facet header or it's widget instead.
+ */
that.set_title = function(container, title) {
var element = $('h1', that.title_container);
element.html(title);
};
+ /**
+ * Show facet
+ *
+ * - clear & refresh if needs update
+ * - mark itself as active facet
+ */
that.show = function() {
that.entity.facet = that; // FIXME: remove
@@ -442,36 +651,87 @@ exp.facet = IPA.facet = function(spec, no_init) {
}
};
+ /**
+ * Show content container and hide error container.
+ *
+ * Opposite to `show_error`.
+ * @protected
+ */
that.show_content = function() {
that.content.css('display', 'block');
that.error_container.css('display', 'none');
};
+ /**
+ * Show error container and hide content container.
+ *
+ * Opposite to `show_content`
+ * @protected
+ */
that.show_error = function() {
that.content.css('display', 'none');
that.error_container.css('display', 'block');
};
+ /**
+ * Check if error is displayed (instead of content)
+ *
+ * @return {boolean} error visible
+ */
that.error_displayed = function() {
return that.error_container &&
that.error_container.css('display') === 'block';
};
+ /**
+ * Un-mark itself as active facet
+ */
that.hide = function() {
that.domNode.removeClass('active-facet');
};
+ /**
+ * Update widget content with supplied data
+ * @param {Object} data
+ */
that.load = function(data) {
that.data = data;
that.header.load(data);
};
+ /**
+ * Start refresh
+ *
+ * - get up-to-date data
+ * - load the data
+ * @abstract
+ */
that.refresh = function() {
};
+ /**
+ * Clear all widgets
+ * @abstract
+ */
that.clear = function() {
};
+ /**
+ * Check if facet needs update
+ *
+ * That means if:
+ *
+ * - new state (`state` or supplied state) is different that old_state
+ * (`old_state`)
+ * - facet is expired
+ * - `expired_flag` is set or
+ * - expire_timeout takes effect
+ * - error is displayed
+ *
+ *
+ * @param {Object} [new_state] supplied state
+ * @return {boolean} needs update
+ */
that.needs_update = function(new_state) {
if (that._needs_update !== undefined) return that._needs_update;
@@ -497,32 +757,48 @@ exp.facet = IPA.facet = function(spec, no_init) {
return needs_update;
};
+ /**
+ * Sets expire flag
+ */
that.set_expired_flag = function() {
that.expired_flag = true;
};
+ /**
+ * Clears `expired_flag` and resets `last_updated`
+ */
that.clear_expired_flag = function() {
that.expired_flag = false;
that.last_updated = Date.now();
};
+ /**
+ * Check whether the facet is dirty
+ *
+ * Dirty can mean that value of displayed object was modified but the change
+ * was not reflected to data source
+ *
+ * @returns {boolean}
+ */
that.is_dirty = function() {
return false;
};
/**
- * Wheater we can switch to different facet.
- * @returns Boolean
+ * Whether we can switch to different facet.
+ * @returns {boolean}
*/
that.can_leave = function() {
return !that.is_dirty();
};
/**
- * Show dialog displaying a message explaining why we can't switch facet.
+ * Get dialog displaying a message explaining why we can't switch facet.
* User can supply callback which is called when a leave is permitted.
*
- * Listeneres should set 'callback' property to listen state evaluation.
+ * TODO: rename to get_leave_dialog
+ *
+ * @param {Function} permit_callback
*/
that.show_leave_dialog = function(permit_callback) {
@@ -535,6 +811,15 @@ exp.facet = IPA.facet = function(spec, no_init) {
return dialog;
};
+ /**
+ * Display error page instead of facet content
+ *
+ * Use this call when unrecoverable error occurs.
+ *
+ * @param {Object} error_thrown - error to be displayed
+ * @param {string} error_thrown.name
+ * @param {string} error_thrown.message
+ */
that.report_error = function(error_thrown) {
var add_option = function(ul, text, handler) {
@@ -596,6 +881,11 @@ exp.facet = IPA.facet = function(spec, no_init) {
that.show_error();
};
+ /**
+ * Get facet based on `redirect_info` and {@link
+ * entity.entity.redirect_facet}
+ * @return {facet.facet} facet to be redirected to
+ */
that.get_redirect_facet = function() {
var entity = that.entity;
@@ -619,6 +909,9 @@ exp.facet = IPA.facet = function(spec, no_init) {
return facet;
};
+ /**
+ * Redirect to redirection target
+ */
that.redirect = function() {
var facet = that.get_redirect_facet();
@@ -628,6 +921,10 @@ exp.facet = IPA.facet = function(spec, no_init) {
var redirect_error_codes = [4001];
+ /**
+ * Redirect if error thrown is
+ * @protected
+ */
that.redirect_error = function(error_thrown) {
/*If the error is in talking to the server, don't attempt to redirect,
@@ -640,6 +937,10 @@ exp.facet = IPA.facet = function(spec, no_init) {
}
};
+ /**
+ * Initialize facet
+ * @protected
+ */
that.init_facet = function() {
that.action_state.init(that);
@@ -672,14 +973,47 @@ exp.facet = IPA.facet = function(spec, no_init) {
return that;
};
+/**
+ * Facet header
+ *
+ * Widget-like object which purpose is to render facet's header.
+ *
+ * By default, facet header consists of:
+ *
+ * - breadcrumb navigation
+ * - title
+ * - action list
+ * - facet tabs
+ *
+ * @class facet.facet_header
+ * @alternateClassName IPA.facet_header
+ */
exp.facet_header = IPA.facet_header = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Facet this header belongs to
+ * @property {facet.facet}
+ */
that.facet = spec.facet;
+ /**
+ * Action list with facet's header actions
+ * @property {facet.action_list_widget} action_list
+ */
+
+ /**
+ * Facet title widget
+ * @property {facet.facet_title} title_widget
+ */
+
+ /**
+ * Initialize facet header
+ * @protected
+ */
that.init = function() {
if (that.facet.header_actions) {
@@ -705,6 +1039,9 @@ exp.facet_header = IPA.facet_header = function(spec) {
that.title_widget = IPA.facet_title();
};
+ /**
+ * Select tab with the same name as related facet or default
+ */
that.select_tab = function() {
if (that.facet.disable_facet_tabs) return;
@@ -718,6 +1055,13 @@ exp.facet_header = IPA.facet_header = function(spec) {
}
};
+ /**
+ * Set new pkey in title and breadcrumb navigation
+ *
+ * Limits the pkey if it's too long.
+ *
+ * @param {string} value pkey
+ */
that.set_pkey = function(value) {
if (!value) return;
@@ -804,6 +1148,12 @@ exp.facet_header = IPA.facet_header = function(spec) {
that.adjust_elements();
};
+ /**
+ * Create link for facet tab
+ * @protected
+ * @param {jQuery} container
+ * @param {facet.facet} other_facet
+ */
that.create_facet_link = function(container, other_facet) {
var li = $('<li/>', {
@@ -827,6 +1177,12 @@ exp.facet_header = IPA.facet_header = function(spec) {
}).appendTo(li);
};
+ /**
+ * Create facet tab group
+ * @protected
+ * @param {jQuery} container
+ * @param {Object} facet_group
+ */
that.create_facet_group = function(container, facet_group) {
var section = $('<div/>', {
@@ -849,6 +1205,10 @@ exp.facet_header = IPA.facet_header = function(spec) {
}
};
+ /**
+ * Create header's HTML
+ * @param {jQuery} container
+ */
that.create = function(container) {
that.container = container;
@@ -904,6 +1264,18 @@ exp.facet_header = IPA.facet_header = function(spec) {
}
};
+ /**
+ * Update displayed information with new data
+ *
+ * Data is result of FreeIPA RPC command.
+ *
+ * Updates (if present in data):
+ *
+ * - facet group links with number of records
+ * - facet group labels with facet's pkey
+ *
+ * @param {Object} data
+ */
that.load = function(data) {
if (!data) return;
var result = data.result.result;
@@ -945,6 +1317,10 @@ exp.facet_header = IPA.facet_header = function(spec) {
}
};
+ /**
+ * Reflect facet's action state summary into title widget class and icon
+ * tooltip.
+ */
that.update_summary = function() {
var summary = that.facet.action_state.summary();
@@ -957,6 +1333,10 @@ exp.facet_header = IPA.facet_header = function(spec) {
that.adjust_elements();
};
+ /**
+ * Compute maximum pkey length to be displayed in header
+ * @return {number} length
+ */
that.get_max_pkey_length = function() {
var label_w, max_pkey_w, max_pkey_l, al, al_w, icon_w, char_w, container_w;
@@ -980,6 +1360,10 @@ exp.facet_header = IPA.facet_header = function(spec) {
return max_pkey_l;
};
+ /**
+ * Adjust position of header widgets, mainly action list, according to
+ * title length.
+ */
that.adjust_elements = function() {
if (that.action_list) {
@@ -995,6 +1379,9 @@ exp.facet_header = IPA.facet_header = function(spec) {
}
};
+ /**
+ * Clear displayed information
+ */
that.clear = function() {
that.load();
if (that.action_list) that.action_list.clear();
@@ -1003,12 +1390,30 @@ exp.facet_header = IPA.facet_header = function(spec) {
return that;
};
+/**
+ * Facet title widget
+ *
+ * A widget-like object for title representation in a facet header.
+ *
+ * @class facet.facet_title
+ * @alternateClassName IPA.facet_title
+ */
exp.facet_title = IPA.facet_title = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Update displayed information with supplied data
+ *
+ * @param {Object} data
+ * @param {string} data.pkey
+ * @param {string} data.title
+ * @param {string} data.tooltip
+ * @param {string} data.icon_tooltip
+ * @param {string} data.css_class css class for title container
+ */
that.update = function(data) {
var tooltip = data.tooltip || data.title;
@@ -1029,6 +1434,9 @@ exp.facet_title = IPA.facet_title = function(spec) {
that.set_icon_tooltip(icon_tooltip);
};
+ /**
+ * Create HTML elements
+ */
that.create = function(container) {
that.title_container = $('<div/>', {
@@ -1048,10 +1456,22 @@ exp.facet_title = IPA.facet_title = function(spec) {
}).appendTo(h3);
};
+ /**
+ * Set maximum width of the widget
+ *
+ * @param {number|string} width
+ */
that.set_max_width = function(width) {
that.title_container.css('max-width', width+'px');
};
+ /**
+ * Set CSS class
+ *
+ * Can be used for various purposes like icon change.
+ *
+ * @param {string} css_class
+ */
that.set_class = function(css_class) {
if (that.css_class) {
@@ -1065,6 +1485,11 @@ exp.facet_title = IPA.facet_title = function(spec) {
that.css_class = css_class;
};
+ /**
+ * Set icon tooltip
+ *
+ * @param {string} tooltip
+ */
that.set_icon_tooltip = function(tooltip) {
that.icon.attr('title', tooltip);
};
@@ -1072,42 +1497,114 @@ exp.facet_title = IPA.facet_title = function(spec) {
return that;
};
+/**
+ * Facet which displays information in a table
+ *
+ * @class facet.table_facet
+ * @extends facet.facet
+ * @alternateClassName IPA.table_facet
+ */
exp.table_facet = IPA.table_facet = function(spec, no_init) {
spec = spec || {};
var that = IPA.facet(spec, no_init);
+ /**
+ * Entity of data displayed in the table
+ * @property {entity.entity}
+ */
that.managed_entity = spec.managed_entity ? IPA.get_entity(spec.managed_entity) : that.entity;
+ /**
+ * Show pagination control
+ * @property {boolean}
+ */
that.pagination = spec.pagination === undefined ? true : spec.pagination;
+
+ /**
+ * Get complete records on search, otherwise pkeys only.
+ */
that.search_all_entries = spec.search_all_entries;
+
+ /**
+ * Sort records
+ */
that.sort_enabled = spec.sort_enabled === undefined ? true : spec.sort_enabled;
+
+ /**
+ * Records are selectable
+ *
+ * Ie. by checkboxes
+ */
that.selectable = spec.selectable === undefined ? true : spec.selectable;
+
+ /**
+ * Raised when selection changes
+ * @event
+ */
that.select_changed = IPA.observer();
+ /**
+ * Record's attribute name which controls whether row will be displayed
+ * as enabled or disabled.
+ *
+ * Mutually exclusive with `row_disabled_attribute`
+ * @property {string}
+ */
that.row_enabled_attribute = spec.row_enabled_attribute;
+
+ /**
+ * Same as `row_enabled_attribute`
+ * @property {string}
+ */
that.row_disabled_attribute = spec.row_disabled_attribute;
+
+ /**
+ * Name of record's details facet
+ * @property {string}
+ */
that.details_facet_name = spec.details_facet || 'default';
+ /**
+ * Name of facet's table
+ */
that.table_name = spec.table_name;
+ /**
+ * Facet's table columns
+ */
that.columns = $.ordered_map();
+ /**
+ * Get all columns
+ */
that.get_columns = function() {
return that.columns.values;
};
+ /**
+ * Get column with given name
+ * @param {string} name column name
+ */
that.get_column = function(name) {
return that.columns.get(name);
};
+ /**
+ * Add column
+ * @param {IPA.column} column
+ */
that.add_column = function(column) {
column.entity = that.managed_entity;
column.facet = that;
that.columns.put(column.name, column);
};
+ /**
+ * Create column according to spec and add it to column collection
+ * @param {Object} spec column spec
+ */
that.create_column = function(spec) {
var column;
if (spec instanceof Object) {
@@ -1124,15 +1621,31 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
return column;
};
+ /**
+ * Same as `create_column`
+ * @deprecated
+ */
that.column = function(spec){
that.create_column(spec);
return that;
};
+ /**
+ * @inheritDoc
+ */
that.create_content = function(container) {
that.table.create(container);
};
+ /**
+ * Transforms data into records and displays them in the end.
+ *
+ * 1. table is loaded with supplied data
+ * 2. expire flag is cleared
+ *
+ * @fires post_load
+ * @param {Object} data
+ */
that.load = function(data) {
that.facet_load(data);
@@ -1162,6 +1675,14 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
};
+ /**
+ * Transforms data into records and displays them in the end.
+ *
+ * It's expected that `data` contain complete records.
+ *
+ * @protected
+ * @param {Object} data
+ */
that.load_all = function(data) {
var result = data.result.result;
@@ -1181,6 +1702,15 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
}
};
+ /**
+ * Create a map with records as values and pkeys as keys
+ *
+ * Extracts records from data, where data originates from RPC command.
+ *
+ * @protected
+ * @param {Object} data RPC command data
+ * @return {ordered_map} record map
+ */
that.get_records_map = function(data) {
var records_map = $.ordered_map();
@@ -1198,6 +1728,17 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
return records_map;
};
+ /**
+ * Transforms data into records and displays them in the end.
+ *
+ * - subset is selected if data contains more than page-size results
+ * - page is selected based on `state.page`
+ * - get complete records by `get_records()` method when data contains only
+ * pkeys (skipped if table has only one column - pkey)
+ *
+ * @protected
+ * @param {Object} data
+ */
that.load_page = function(data) {
// get primary keys (and the complete records if search_all_entries is true)
@@ -1277,6 +1818,13 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
);
};
+ /**
+ * Clear table and add new rows with supplied records.
+ *
+ * Select previously selected rows.
+ *
+ * @param {Array.<Object>} records
+ */
that.load_records = function(records) {
that.table.empty();
for (var i=0; i<records.length; i++) {
@@ -1285,6 +1833,15 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
that.table.set_values(that.selected_values);
};
+ /**
+ * Add new row to table
+ *
+ * Enables/disables row according to `row_enabled_attribute` or
+ * `row_disabled_attribute` and optional column formatter for that attr.
+ *
+ * @protected
+ * @param {Object} record
+ */
that.add_record = function(record) {
var tr = that.table.add_record(record);
@@ -1305,10 +1862,24 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
that.table.set_row_enabled(tr, value);
};
+ /**
+ * Get command name used in get_records
+ * @protected
+ * @return {string} command name
+ */
that.get_records_command_name = function() {
return that.managed_entity.name+'_get_records';
};
+ /**
+ * Create batch RPC command for obtaining complete records for each supplied
+ * primary key.
+ *
+ * @protected
+ * @param {Array.<string>} pkeys primary keys
+ * @param {Function} on_success command success handler
+ * @param {Function} on_failure command error handler
+ */
that.create_get_records_command = function(pkeys, on_success, on_error) {
var batch = IPA.batch_command({
@@ -1336,6 +1907,14 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
return batch;
};
+ /**
+ * Execute command for obtaining complete records
+ *
+ * @protected
+ * @param {Array.<string>} pkeys primary keys
+ * @param {Function} on_success command success handler
+ * @param {Function} on_failure command error handler
+ */
that.get_records = function(pkeys, on_success, on_error) {
var batch = that.create_get_records_command(pkeys, on_success, on_error);
@@ -1343,10 +1922,24 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
batch.execute();
};
+ /**
+ * Get values selected in a table (checked rows)
+ * @return {Array.<string>} values
+ */
that.get_selected_values = function() {
return that.table.get_selected_values();
};
+ /**
+ * Create table
+ *
+ * - reflect facet settings (pagination, scrollable, ...)
+ * - create columns
+ * - override handler for pagination
+ *
+ * @protected
+ * @param {entity.entity} entity table entity
+ */
that.init_table = function(entity) {
that.table = IPA.table_widget({
@@ -1418,6 +2011,9 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
};
};
+ /**
+ * Create and add columns based on spec
+ */
that.init_table_columns = function() {
var columns = spec.columns || [];
for (var i=0; i<columns.length; i++) {
@@ -1432,69 +2028,208 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) {
return that;
};
+/**
+ * Facet group
+ *
+ * Collection of facets with similar purpose.
+ *
+ * @class facet.facet_group
+ * @alternateClassName IPA.facet_group
+ */
exp.facet_group = IPA.facet_group = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Name
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+ /**
+ * Facet collection
+ * @property {ordered_map}
+ */
that.facets = $.ordered_map();
+ /**
+ * Add facet to the map
+ * @param {facet.facet} facet
+ */
that.add_facet = function(facet) {
that.facets.put(facet.name, facet);
};
+ /**
+ * Get facet with given name
+ * @param {string} name
+ * @return {facet.facet/null}
+ */
that.get_facet = function(name) {
return that.facets.get(name);
};
+ /**
+ * Get index of facet with given name
+ * @param {string} name
+ * @return {facet.facet/null}
+ */
that.get_facet_index = function(name) {
return that.facets.get_key_index(name);
};
+ /**
+ * Get facet by position in collection
+ * @param {number} index
+ * @return {facet.facet/null}
+ */
that.get_facet_by_index = function(index) {
return that.facets.get_value_by_index(index);
};
- that.get_facet_count = function(index) {
+ /**
+ * Get number of facet in collection
+ * @return {number} count
+ */
+ that.get_facet_count = function() {
return that.facets.length;
};
return that;
};
+/**
+ * Action
+ *
+ * @class facet.action
+ * @alternateClassName IPA.action
+ */
exp.action = IPA.action = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Name
+ *
+ * Action identifier within facet
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+ /**
+ * Enabled
+ *
+ * Action can't be executed when not enabled.
+ * @property {boolean}
+ * @readonly
+ */
that.enabled = spec.enabled !== undefined ? spec.enabled : true;
+
+ /**
+ * List of states required by action to be enabled
+ * @property {Array.<string>}
+ */
that.enable_cond = spec.enable_cond || [];
+
+ /**
+ * List of states which makes action disabled
+ * @property {Array.<string>}
+ */
that.disable_cond = spec.disable_cond || [];
+
+ /**
+ * Value of `enabled` property changed
+ * @event
+ */
that.enabled_changed = IPA.observer();
+ /**
+ * Controls whether action or representing widget should be visible.
+ *
+ * Action can't be executed when not visible.
+ * @property {boolean}
+ * @readonly
+ */
that.visible = spec.visible !== undefined ? spec.visible : true;
+
+ /**
+ * List of states required by action to be visible
+ * @property {Array.<string>}
+ */
that.show_cond = spec.show_cond || [];
+
+ /**
+ * List of states which makes action not visible
+ * @property {Array.<string>}
+ */
that.hide_cond = spec.hide_cond || [];
+
+ /**
+ * Value of `visible` property changed
+ * @event
+ */
that.visible_changed = IPA.observer();
+ /**
+ * Action execution logic
+ *
+ * One has to set `handler` or override `execute_action` method.
+ *
+ * @property {Function} handler
+ * @property {facet.facet} handler.facet
+ * @property {Function} handler.on_success
+ * @property {Function} handler.on_error
+ */
that.handler = spec.handler;
+ /**
+ * Controls whether action must be confirmed.
+ *
+ * If so, confirm dialog is displayed before actual execution.
+ * @property {boolean}
+ */
that.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : false;
+
+ /**
+ * Message to be displayed in confirm dialog
+ * @property {string}
+ */
that.confirm_msg = text.get(spec.confirm_msg || '@i18n:actions.confirm');
+ /**
+ * Spec of confirm dialog
+ *
+ * Defaults to: {@link IPA.confirm_dialog}
+ */
that.confirm_dialog = spec.confirm_dialog !== undefined ? spec.confirm_dialog :
IPA.confirm_dialog;
-
-
+ /**
+ * Performs actual action execution
+ *
+ * - override point
+ *
+ * @protected
+ * @param {facet.facet} facet
+ * @param {Function} on_success
+ * @param {Function} on_error
+ */
that.execute_action = function(facet, on_success, on_error) {
if (that.handler) {
@@ -1502,6 +2237,16 @@ exp.action = IPA.action = function(spec) {
}
};
+ /**
+ * Execute action
+ *
+ * - only if enabled and visible
+ * - confirm dialog is display if configured
+ *
+ * @param {facet.facet} facet
+ * @param {Function} on_success
+ * @param {Function} on_error
+ */
that.execute = function(facet, on_success, on_error) {
if (!that.enabled || !that.visible) return;
@@ -1529,14 +2274,33 @@ exp.action = IPA.action = function(spec) {
that.execute_action(facet, on_success, on_error);
};
+ /**
+ * Set confirm message to confirm dialog
+ * @protected
+ * @param {facet.facet} facet
+ */
that.update_confirm_dialog = function(facet) {
that.dialog.message = that.get_confirm_message(facet);
};
+ /**
+ * Get confirm message
+ *
+ * - override point for message modifications
+ *
+ * @protected
+ * @param {facet.facet} facet
+ */
that.get_confirm_message = function(facet) {
return that.confirm_msg;
};
+ /**
+ * Setter for `enabled`
+ *
+ * @fires enabled_changed
+ * @param {boolean} enabled
+ */
that.set_enabled = function(enabled) {
var old = that.enabled;
@@ -1548,6 +2312,12 @@ exp.action = IPA.action = function(spec) {
}
};
+ /**
+ * Setter for `visible`
+ *
+ * @fires enabled_changed
+ * @param {boolean} visible
+ */
that.set_visible = function(visible) {
var old = that.visible;
@@ -1562,14 +2332,33 @@ exp.action = IPA.action = function(spec) {
return that;
};
+/**
+ * Action collection and state reflector
+ *
+ * - sets `enabled` and `visible` action properties at action state change
+ * and facet load
+ *
+ * @class facet.action_holder
+ * @alternateClassName IPA.action_holder
+ */
exp.action_holder = IPA.action_holder = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Collection of actions
+ * @property {ordered_map}
+ * @protected
+ */
that.actions = $.ordered_map();
+ /**
+ * Build actions defined in spec.
+ * Register handlers for facet events(`action_state.changed`, `post_load`)
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
var i, action, actions;
@@ -1586,6 +2375,12 @@ exp.action_holder = IPA.action_holder = function(spec) {
that.facet.post_load.attach(that.on_load);
};
+ /**
+ * Evaluate actions `visibility` and `enable` according to action conditions
+ * and supplied state
+ *
+ * @param {Array.<string>} state
+ */
that.state_changed = function(state) {
var actions, action, i, enabled, visible;
@@ -1603,14 +2398,29 @@ exp.action_holder = IPA.action_holder = function(spec) {
}
};
+ /**
+ * Get action with given named
+ * @param {string} name
+ * @return {facet.action}
+ */
that.get = function(name) {
return that.actions.get(name);
};
+ /**
+ * Add action to collection
+ * @param {facet.action} action
+ */
that.add = function(action) {
that.actions.put(action.name, action);
};
+ /**
+ * Facet load event handler
+ *
+ * - gets action state and evaluates action conditions
+ * @protected
+ */
that.on_load = function() {
var state = that.facet.action_state.get();
that.state_changed(state);
@@ -1619,22 +2429,60 @@ exp.action_holder = IPA.action_holder = function(spec) {
return that;
};
+/**
+ * Facet action state
+ *
+ * @class facet.state
+ * @alternateClassName IPA.state
+ */
exp.state = IPA.state = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * State map
+ *
+ * - key: evaluator's name
+ * - value: evaluator's value
+ * @property {ordered_map}
+ * @protected
+ */
that.state = $.ordered_map();
- //when state changes. Params: state, Context: this
+ /**
+ * Raised when state changes.
+ *
+ * - params: state
+ * - context: this
+ * @event
+ */
that.changed = IPA.observer();
+ /**
+ * State evaluators
+ * @property {Array.<facet.state_evaluator>}
+ */
that.evaluators = builder.build('state_evaluator', spec.evaluators) || [];
+
+ /**
+ * Summary evaluators
+ * @property {facet.summary_evaluator}
+ */
that.summary_evaluator = builder.build('', spec.summary_evaluator || IPA.summary_evaluator);
+ /**
+ * Summary conditions
+ * @property {Array.<Object>}
+ */
that.summary_conditions = builder.build('', spec.summary_conditions) || [];
+ /**
+ * Initializes evaluators
+ *
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
var i, evaluator;
@@ -1648,6 +2496,10 @@ exp.state = IPA.state = function(spec) {
}
};
+ /**
+ * Event handler for evaluator's 'changed' event
+ * @protected
+ */
that.on_eval_changed = function() {
var evaluator = this;
@@ -1657,6 +2509,11 @@ exp.state = IPA.state = function(spec) {
that.notify();
};
+ /**
+ * Get unified state
+ *
+ * @return {Array.<string>}
+ */
that.get = function() {
var state, i;
@@ -1672,12 +2529,21 @@ exp.state = IPA.state = function(spec) {
return state;
};
+ /**
+ * Evaluate and get summary
+ * @return {Object} summary
+ */
that.summary = function() {
var summary = that.summary_evaluator.evaluate(that);
return summary;
};
+ /**
+ * Raise change event with state as parameter
+ * @protected
+ * @fires changed
+ */
that.notify = function(state) {
state = state || that.get();
@@ -1688,6 +2554,11 @@ exp.state = IPA.state = function(spec) {
return that;
};
+/**
+ * Summary evaluator for {@link facet.state}
+ * @class facet.summary_evaluator
+ * @alternateClassName IPA.summary_evaluator
+ */
exp.summary_evaluator = IPA.summary_evaluator = function(spec) {
spec = spec || {};
@@ -1723,20 +2594,66 @@ exp.summary_evaluator = IPA.summary_evaluator = function(spec) {
return that;
};
+/**
+ * State evaluator for {@link facet.state}.
+ *
+ * - Base class for specific evaluators.
+ * - Evaluator observes facet and reflect its state by a list of string tags
+ * (evaluated state).
+ * - Default behavior is that evaluator listens to event, specified by
+ * `event_name` property. The event is handled by `on_event` method.
+ * Descendant classes should override this method. Methods like `on_event`
+ * should notify state change using `notify_on_change` method.
+ *
+ * @class facet.state_evaluator
+ * @alternateClassName IPA.state_evaluator
+ */
exp.state_evaluator = IPA.state_evaluator = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Name
+ * @property {string}
+ */
that.name = spec.name || 'state_evaluator';
+
+ /**
+ * Event name
+ * @property {string}
+ */
that.event_name = spec.event;
- //when state changes. Params: state, Context: this
+ /**
+ * State changes
+ *
+ * - Params: state
+ * - Context: this
+ * @event
+ * @property {IPA.observer}
+ */
that.changed = IPA.observer();
+
+ /**
+ * Evaluated state
+ * @property {Array.<string>}
+ */
that.state = [];
+
+ /**
+ * State is changed for the first time
+ * @property {boolean}
+ */
that.first_pass = true;
+ /**
+ * Init the evaluator
+ *
+ * - register event listener
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
if (that.event_name && facet[that.event_name]) {
@@ -1744,9 +2661,20 @@ exp.state_evaluator = IPA.state_evaluator = function(spec) {
}
};
+ /**
+ * Event handler
+ *
+ * @localdoc - intended to be overridden
+ */
that.on_event = function() {
};
+ /**
+ * Notify state change
+ * @fires changed
+ * @protected
+ * @param {Array.<string>} old_state
+ */
that.notify_on_change = function(old_state) {
if (that.first_pass || IPA.array_diff(that.state, old_state)) {
@@ -1758,6 +2686,12 @@ exp.state_evaluator = IPA.state_evaluator = function(spec) {
return that;
};
+/**
+ * Sets 'dirty' state when facet is dirty
+ * @class facet.dirty_state_evaluator
+ * @extends facet.state_evaluator
+ * @alternateClassName IPA.dirty_state_evaluator
+ */
exp.dirty_state_evaluator = IPA.dirty_state_evaluator = function(spec) {
spec = spec || {};
@@ -1767,6 +2701,10 @@ exp.dirty_state_evaluator = IPA.dirty_state_evaluator = function(spec) {
var that = IPA.state_evaluator(spec);
that.name = spec.name || 'dirty_state_evaluator';
+ /**
+ * Handles 'dirty_changed' event
+ * @param {boolean} dirty
+ */
that.on_event = function(dirty) {
var old_state = that.state;
@@ -1782,6 +2720,13 @@ exp.dirty_state_evaluator = IPA.dirty_state_evaluator = function(spec) {
return that;
};
+/**
+ * Sets 'item-selected' state when table facets selection changes and some
+ * record is selected.
+ * @class facet.selected_state_evaluator
+ * @extends facet.state_evaluator
+ * @alternateClassName IPA.selected_state_evaluator
+ */
exp.selected_state_evaluator = IPA.selected_state_evaluator = function(spec) {
spec = spec || {};
@@ -1791,6 +2736,10 @@ exp.selected_state_evaluator = IPA.selected_state_evaluator = function(spec) {
var that = IPA.state_evaluator(spec);
that.name = spec.name || 'selected_state_evaluator';
+ /**
+ * Handles 'select_changed' event
+ * @param {Array} selected
+ */
that.on_event = function(selected) {
var old_state = that.state;
@@ -1806,6 +2755,12 @@ exp.selected_state_evaluator = IPA.selected_state_evaluator = function(spec) {
return that;
};
+/**
+ * Sets 'self-service' state when in self-service mode
+ * @class facet.self_service_state_evaluator
+ * @extends facet.state_evaluator
+ * @alternateClassName IPA.self_service_state_evaluator
+ */
exp.self_service_state_evaluator = IPA.self_service_state_evaluator = function(spec) {
spec = spec || {};
@@ -1815,6 +2770,9 @@ exp.self_service_state_evaluator = IPA.self_service_state_evaluator = function(s
var that = IPA.state_evaluator(spec);
that.name = spec.name || 'self_service_state_evaluator';
+ /**
+ * Evaluates self-service
+ */
that.on_event = function() {
var old_state = that.state;
@@ -1830,6 +2788,14 @@ exp.self_service_state_evaluator = IPA.self_service_state_evaluator = function(s
return that;
};
+/**
+ * Set desired state when facet parameter is equal to desired value after
+ * facet event(`post_load` by default).
+ *
+ * @class facet.facet_attr_state_evaluator
+ * @extends facet.state_evaluator
+ * @alternateClassName IPA.facet_attr_state_evaluator
+ */
exp.facet_attr_state_evaluator = IPA.facet_attr_state_evaluator = function(spec) {
spec = spec || {};
@@ -1838,10 +2804,27 @@ exp.facet_attr_state_evaluator = IPA.facet_attr_state_evaluator = function(spec)
var that = IPA.state_evaluator(spec);
that.name = spec.name || 'facet_attr_se';
+
+ /**
+ * Facet attribute name
+ * @property {string}
+ */
that.attribute = spec.attribute;
+
+ /**
+ * Value to compare
+ */
that.value = spec.value;
+
+ /**
+ * State to add when value is equal
+ * @property {string}
+ */
that.state_value = spec.state_value;
+ /**
+ * Compare facet's value with desired and set state if equal.
+ */
that.on_event = function() {
var old_state = that.state;
@@ -1859,6 +2842,13 @@ exp.facet_attr_state_evaluator = IPA.facet_attr_state_evaluator = function(spec)
return that;
};
+/**
+ * Set `read_only` state when facet is `read_only`
+ *
+ * @class facet.read_only_state_evaluator
+ * @extends facet.facet_attr_state_evaluator
+ * @alternateClassName IPA.read_only_state_evaluator
+ */
exp.read_only_state_evaluator = IPA.read_only_state_evaluator = function(spec) {
spec = spec || {};
@@ -1872,6 +2862,13 @@ exp.read_only_state_evaluator = IPA.read_only_state_evaluator = function(spec) {
return that;
};
+/**
+ * Set `direct` state when facet's association_type property is `direct`
+ *
+ * @class facet.association_type_state_evaluator
+ * @extends facet.facet_attr_state_evaluator
+ * @alternateClassName IPA.association_type_state_evaluator
+ */
exp.association_type_state_evaluator = IPA.association_type_state_evaluator = function(spec) {
spec = spec || {};
@@ -1885,26 +2882,92 @@ exp.association_type_state_evaluator = IPA.association_type_state_evaluator = fu
return that;
};
+/**
+ * Button for executing facet action
+ *
+ * Usable as facet control button in {@link facet.control_buttons_widget}.
+ *
+ * @class facet.action_button_widget
+ * @extends IPA.widget
+ * @alternateClassName IPA.action_button_widget
+ */
exp.action_button_widget = IPA.action_button_widget = function(spec) {
spec = spec || {};
var that = IPA.widget(spec);
+ /**
+ * Name
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+
+ /**
+ * Tooltip
+ * @property {string}
+ */
that.tooltip = text.get(spec.tooltip);
+
+ /**
+ * Button href
+ *
+ * - purely visual thing, the click itself is handled internally.
+ * @property {string}
+ */
that.href = spec.href || that.name;
+
+ /**
+ * Icon name
+ * @property {string}
+ */
that.icon = spec.icon;
+ /**
+ * Name of action this button should execute
+ * @property {string}
+ */
that.action_name = spec.action || that.name;
+ /**
+ * Enabled
+ * @property {boolean}
+ * @readonly
+ */
that.enabled = spec.enabled !== undefined ? spec.enabled : true;
+
+ /**
+ * Visible
+ * @property {boolean}
+ * @readonly
+ */
that.visible = spec.visible !== undefined ? spec.visible : true;
+ /**
+ * Subject to removal
+ * @deprecated
+ */
that.show_cond = spec.show_cond || [];
+
+ /**
+ * Subject to removal
+ * @deprecated
+ */
that.hide_cond = spec.hide_cond || [];
+ /**
+ * Init button
+ *
+ * - set facet, action
+ * - register event listeners
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
that.facet = facet;
@@ -1913,6 +2976,9 @@ exp.action_button_widget = IPA.action_button_widget = function(spec) {
that.action.visible_changed.attach(that.set_visible);
};
+ /**
+ * @inheritDoc
+ */
that.create = function(container) {
that.widget_create(container);
@@ -1932,6 +2998,11 @@ exp.action_button_widget = IPA.action_button_widget = function(spec) {
that.set_visible(that.action.visible);
};
+ /**
+ * Button click handler
+ *
+ * Executes action by default.
+ */
that.on_click = function() {
if (!that.enabled) return;
@@ -1939,6 +3010,10 @@ exp.action_button_widget = IPA.action_button_widget = function(spec) {
that.action.execute(that.facet);
};
+ /**
+ * Enabled setter
+ * @param {boolean} enabled
+ */
that.set_enabled = function(enabled) {
that.widget_set_enabled(enabled);
@@ -1951,6 +3026,10 @@ exp.action_button_widget = IPA.action_button_widget = function(spec) {
}
};
+ /**
+ * Visible setter
+ * @param {boolean} visible
+ */
that.set_visible = function(visible) {
that.visible = visible;
@@ -1967,15 +3046,30 @@ exp.action_button_widget = IPA.action_button_widget = function(spec) {
return that;
};
+/**
+ * Facet button bar
+ *
+ * @class facet.control_buttons_widget
+ * @extends IPA.widget
+ * @alternateClassName IPA.control_buttons_widget
+ */
exp.control_buttons_widget = IPA.control_buttons_widget = function(spec) {
spec = spec || {};
var that = IPA.widget(spec);
+ /**
+ * Buttons
+ * @property {Array.<facet.action_button_widget>}
+ */
that.buttons = builder.build('widget', spec.buttons, {},
{ $factory: exp.action_button_widget} ) || [];
+ /**
+ * Initializes buttons
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
var i;
@@ -1987,6 +3081,9 @@ exp.control_buttons_widget = IPA.control_buttons_widget = function(spec) {
}
};
+ /**
+ * @inheritDoc
+ */
that.create = function(container) {
that.container = $('<div/>', {
@@ -2003,6 +3100,13 @@ exp.control_buttons_widget = IPA.control_buttons_widget = function(spec) {
return that;
};
+/**
+ * Evaluate state by enable and disable condition
+ *
+ * @member facet
+ * @return {boolean} true - all enable condition are met and none disable condition
+ * is met
+ */
exp.eval_cond = IPA.eval_cond = function(enable_cond, disable_cond, state) {
var i, cond;
@@ -2028,6 +3132,13 @@ exp.eval_cond = IPA.eval_cond = function(enable_cond, disable_cond, state) {
return true;
};
+/**
+ * Action list widget to be displayed in facet header
+ *
+ * @class facet.action_list_widget
+ * @extends IPA.composite_widget
+ * @alternateClassName IPA.action_list_widget
+ */
exp.action_list_widget = IPA.action_list_widget = function(spec) {
spec = spec || {};
@@ -2051,9 +3162,27 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
var that = IPA.composite_widget(spec);
+ /**
+ * Names of actions, which should be later obtained from facet
+ * @property {Array.<string>}
+ */
that.action_names = spec.actions || [];
+
+ /**
+ * Actions
+ * @property {ordered_map}
+ */
that.actions = $.ordered_map();
+ /**
+ * Initializes action list
+ *
+ * - set facet
+ * - get actions from facet
+ * - init child widgets
+ *
+ * @param {facet.facet} facet
+ */
that.init = function(facet) {
var options, actions, action, name, i;
@@ -2075,6 +3204,14 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
that.init_options();
};
+ /**
+ * Add action
+ * @param {facet.action} action
+ * @param {boolean} [batch] Set to `true` when adding multiple actions to
+ * prevent unnecessary option initialization and
+ * recreation. Set it back to `false` when adding
+ * last option.
+ */
that.add_action = function(action, batch) {
that.actions.put(action.name, action);
action.enabled_changed.attach(that.action_enabled_changed);
@@ -2087,6 +3224,9 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
}
};
+ /**
+ * Create and set select options from actions
+ */
that.init_options = function() {
var options, actions, action, i;
@@ -2105,17 +3245,30 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
that.action_select.options = options;
};
+ /**
+ * Force select to recreate options
+ */
that.recreate_options = function() {
that.action_select.create_options();
};
+ /**
+ * Handler for action selection in select
+ * @protected
+ */
that.on_action_change = function() {
var action = that.get_selected();
that.apply_button.set_enabled(action.enabled);
};
+ /**
+ * Handler for click on apply button.
+ *
+ * - executes selected action if enabled
+ * @protected
+ */
that.on_apply = function() {
var action = that.get_selected();
@@ -2127,12 +3280,31 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
}
};
+ /**
+ * Global action success handler
+ *
+ * @localdoc - override point
+ * @protected
+ * @abstract
+ */
that.on_action_success = function() {
};
+ /**
+ * Global action error handler
+ *
+ * @localdoc - override point
+ * @protected
+ * @abstract
+ */
that.on_action_error = function() {
};
+ /**
+ * Handle action's `enabled_changed` event.
+ * @protected
+ * @param {boolean} enabled
+ */
that.action_enabled_changed = function(enabled) {
var action = this;
var selected_action = that.get_selected();
@@ -2143,12 +3315,23 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
}
};
+ /**
+ * Get selected action
+ * @return {facet.action}
+ */
that.get_selected = function() {
var selected = that.action_select.save()[0];
var action = that.actions.get(selected);
return action;
};
+ /**
+ * Subject to removal
+ *
+ * This method is full of bugs.
+ *
+ * @deprecated
+ */
that.get_disabled = function() {
var disabled = [];
@@ -2164,6 +3347,9 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
return disabled;
};
+ /**
+ * Select first enabled action
+ */
that.select_first_enabled = function() {
var actions = that.actions.values;
@@ -2181,6 +3367,9 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
that.action_select.update([first]);
};
+ /**
+ * @inheritDoc
+ */
that.clear = function() {
that.select_first_enabled();
@@ -2189,6 +3378,12 @@ exp.action_list_widget = IPA.action_list_widget = function(spec) {
return that;
};
+/**
+ * Facet state
+ * @extends Stateful
+ * @mixins Evented
+ * @class facet.FacetState
+ */
var FacetState = exp.FacetState = declare([Stateful, Evented], {
/**
@@ -2230,7 +3425,7 @@ var FacetState = exp.FacetState = declare([Stateful, Evented], {
*
* Can be called with hash of name/value pairs.
*
- * Raises 'set' event.
+ * @fires set
*/
set: function(name, value) {
@@ -2251,7 +3446,7 @@ var FacetState = exp.FacetState = declare([Stateful, Evented], {
/**
* Set completely new state. Old state is cleared.
*
- * Raises 'reset' event.
+ * @fires reset
*/
reset: function(object) {
var old_state = this.clone();
@@ -2270,16 +3465,26 @@ var registry = new Singleton_registry();
reg.set('facet', registry);
builder.set('facet', registry.builder);
-// Action builder and registry
+/**
+ * Action builder with registry
+ * @member facet
+ */
exp.action_builder = builder.get('action');
exp.action_builder.factory = exp.action;
reg.set('action', exp.action_builder.registry);
-// State Evaluator builder and registry
+/**
+ * State Evaluator builder and registry
+ * @member facet
+ */
exp.state_evaluator_builder = builder.get('state_evaluator');
exp.state_evaluator.factory = exp.action;
reg.set('state_evaluator', exp.state_evaluator.registry);
+/**
+ * Register widgets to global registry
+ * @member facet
+ */
exp.register = function() {
var w = reg.widget;
diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js
index 087f6e289..f054ecc0e 100644
--- a/install/ui/src/freeipa/field.js
+++ b/install/ui/src/freeipa/field.js
@@ -35,55 +35,187 @@ define([
'./text'],
function(array, lang, metadata_provider, builder, IPA, $, navigation, phases, reg, text) {
+/**
+ * Field module
+ * @class field
+ * @singleton
+ */
var exp = {};
+/**
+ * Field
+ * @class IPA.field
+ */
IPA.field = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Entity
+ * @property {entity.entity}
+ */
that.entity = IPA.get_entity(spec.entity);
+
+ /**
+ * Facet
+ * @property {facet.facet}
+ */
that.facet = spec.facet;
+
+ /**
+ * Container
+ * @property {facet.facet|IPA.dialog}
+ */
that.container = null;
+
+ /**
+ * Name
+ * @property {string}
+ */
that.name = spec.name;
+
+ /**
+ * Entity param name
+ *
+ * - defaults to `name`
+ * - can be change if multiple fields touches the same param
+ * @property {string}
+ */
that.param = spec.param || spec.name;
/**
- * For most options param == acl_param. But some params might be virtual and
- * actual rights might be defined by other param.
+ * Entity param which provides access control rights
+ *
+ * - defaults to `param`
+ * - some params might be virtual and thus actual rights might be
+ * defined by other param.
+ * @property {string}
*/
that.acl_param = spec.acl_param || that.param;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+
+ /**
+ * Tooltip
+ * @property {string}
+ */
that.tooltip = text.get(spec.tooltip);
+
+ /**
+ * Measurement unit
+ * @property {string}
+ */
that.measurement_unit = spec.measurement_unit;
+
+ /**
+ * Formatter
+ *
+ * - transforms field value to widget value
+ * - only for read-only fields
+ * @property {IPA.formatter}
+ */
that.formatter = builder.build('formatter', spec.formatter);
+ /**
+ * Widget
+ * @property {IPA.input_widget}
+ */
that.widget = null;
+
+ /**
+ * Widget name within `container`
+ * @property {string}
+ */
that.widget_name = spec.widget;
- // override the required flag in metadata
+ /**
+ * Override the required flag in metadata
+ * @property {boolean}
+ */
that.required = spec.required;
- // read_only is set when widget is created
+ /**
+ * read_only is set when widget is created
+ * @readonly
+ * @property {boolean}
+ */
that.read_only = spec.read_only;
- // writable is set during load
+ /**
+ * Writable is set during load
+ * @readonly
+ * @property {boolean}
+ */
that.writable = true;
+ /**
+ * Enabled
+ * @readonly
+ * @property {boolean}
+ */
that.enabled = spec.enabled === undefined ? true : spec.enabled;
+
+ /**
+ * Flags
+ * @property {Array.<string>}
+ */
that.flags = spec.flags || [];
+ /**
+ * Undo is displayable
+ *
+ * - when false, undo button is not displayed even when the field is dirty
+ * @property {boolean}
+ */
that.undo = spec.undo === undefined ? true : spec.undo;
+ /**
+ * Metadata
+ * @property {Object}
+ */
that.metadata = spec.metadata;
+
+ /**
+ * Validators
+ * @property {Array.<IPA.validator>}
+ */
that.validators = builder.build('validator', spec.validators) || [];
+ /**
+ * Field priority
+ * @property {number}
+ */
that.priority = spec.priority;
+ /**
+ * Loaded values
+ * @property {Array.<Object>}
+ */
that.values = [];
+
+ /**
+ * Field is dirty (value is modified)
+ * @readonly
+ * @property {boolean}
+ */
that.dirty = false;
+
+ /**
+ * Current value is valid - passes validators
+ * @property {boolean}
+ */
that.valid = true;
+ /**
+ * Dirty has changed
+ * @event
+ * @property {IPA.observer}
+ */
that.dirty_changed = IPA.observer();
var init = function() {
@@ -105,6 +237,10 @@ IPA.field = function(spec) {
that.validators.push(IPA.metadata_validator());
};
+ /**
+ * Evaluate if field has to have some value
+ * @return {boolean}
+ */
that.is_required = function() {
if (that.read_only) return false;
if (!that.writable) return false;
@@ -113,18 +249,30 @@ IPA.field = function(spec) {
return that.metadata && that.metadata.required;
};
+ /**
+ * Required setter
+ * @param {boolean} required
+ */
that.set_required = function(required) {
that.required = required;
that.update_required();
};
+ /**
+ * Update required state in widget to match field's
+ * @protected
+ */
that.update_required = function() {
if(that.widget && that.widget.set_required) {
that.widget.set_required(that.is_required());
}
};
+ /**
+ * Check if value is set when it has to be. Show error if not.
+ * @return {boolean}
+ */
that.validate_required = function() {
var values = that.save();
if (IPA.is_empty(values) && that.is_required() && that.enabled) {
@@ -138,9 +286,10 @@ IPA.field = function(spec) {
};
/**
- * Returns true and clears the error message if the field value passes
- * the validation pattern. If the field value does not pass validation,
- * displays the error message and returns false.
+ * Returns true and clears the error message if the field value passes
+ * the validation pattern. If the field value does not pass validation,
+ * displays the error message and returns false.
+ * @return {boolean}
*/
that.validate = function() {
that.hide_error();
@@ -170,7 +319,7 @@ IPA.field = function(spec) {
/**
* This function stores the entire record and the values
- * of the field, then invoke reset() to update the UI.
+ * of the field, then invoke `reset()` to update the UI.
*/
that.load = function(record) {
that.record = record;
@@ -182,6 +331,14 @@ IPA.field = function(spec) {
that.reset();
};
+ /**
+ * Get value of attribute with given name from record (during `load`)
+ *
+ * @protected
+ * @param {Object} record
+ * @param {string} name
+ * @return {Array} array of values
+ */
that.get_value = function(record, name) {
var value = record[name];
@@ -197,6 +354,24 @@ IPA.field = function(spec) {
return value;
};
+ /**
+ * Evaluate if field is writable according to ACL in record and field
+ * configuration. Updates `writable` property.
+ *
+ * Not writable:
+ *
+ * - primary keys
+ * - with 'no_update' metadata flag
+ *
+ * Writable:
+ *
+ * - attribute level rights for acl param contains 'w'
+ * - with 'w_if_no_aci' flag and no attribute level rights and user has
+ * rights to modify objectclass
+ *
+ * @protected
+ * @param {Object} record
+ */
that.load_writable = function(record) {
that.writable = true;
@@ -229,6 +404,9 @@ IPA.field = function(spec) {
}
};
+ /**
+ * Reset field and widget to loaded values
+ */
that.reset = function() {
that.set_widget_flags();
that.update_required();
@@ -237,6 +415,9 @@ IPA.field = function(spec) {
that.set_dirty(false);
};
+ /**
+ * Update widget with loaded values.
+ */
that.update = function() {
if (!that.widget || !that.widget.update) return;
@@ -259,6 +440,13 @@ IPA.field = function(spec) {
that.widget.update(formatted_values);
};
+ /**
+ * Create and return update info.
+ *
+ * Update info is a record which contains information about modifications
+ * since load.
+ * @return {Object} update info
+ */
that.get_update_info = function() {
var update_info = IPA.update_info_builder.new_update_info();
@@ -274,6 +462,7 @@ IPA.field = function(spec) {
* This function saves the values entered in the UI.
* It returns the values in an array, or null if
* the field should not be saved.
+ * @return {Array} values
*/
that.save = function(record) {
@@ -296,6 +485,8 @@ IPA.field = function(spec) {
* This function compares the original values and the
* values entered in the UI. If the values have changed
* it will return true.
+ * @protected
+ * @return {boolean} dirty
*/
that.test_dirty = function() {
@@ -318,6 +509,13 @@ IPA.field = function(spec) {
return !that.dirty_are_equal(that.values, values);
};
+ /**
+ * Compares values in two arrays
+ * @protected
+ * @param {Array} orig_vals
+ * @param {Array} new_vals
+ * @return {boolean} values are equal
+ */
that.dirty_are_equal = function(orig_vals, new_vals) {
orig_vals.sort();
@@ -333,14 +531,17 @@ IPA.field = function(spec) {
};
/**
- * This function compares the original values and the
- * values entered in the UI. If the values have changed
- * it will return true.
+ * Getter for `dirty`
+ * @return {boolean}
*/
that.is_dirty = function() {
return that.dirty;
};
+ /**
+ * Setter for `dirty`
+ * @param {boolean} dirty
+ */
that.set_dirty = function(dirty) {
var old = that.dirty;
that.dirty = dirty;
@@ -354,14 +555,28 @@ IPA.field = function(spec) {
};
+ /**
+ * Display validation error
+ * @protected
+ * @param {string} message
+ */
that.show_error = function(message) {
if (that.widget && that.widget.show_error) that.widget.show_error(message);
};
+ /**
+ * Hide validation error
+ * @protected
+ */
that.hide_error = function() {
if (that.widget && that.widget.hide_error) that.widget.hide_error();
};
+ /**
+ * Show/hide undo button
+ * @protected
+ * @param {boolean} value true:show, false:hide
+ */
that.show_undo = function(value) {
if (that.widget && that.widget.show_undo) {
if(value) { that.widget.show_undo(); }
@@ -369,6 +584,10 @@ IPA.field = function(spec) {
}
};
+ /**
+ * `enabled` setter
+ * @param {boolean} value
+ */
that.set_enabled = function(value) {
that.enabled = value;
if (that.widget && that.widget.set_enabled) {
@@ -376,9 +595,17 @@ IPA.field = function(spec) {
}
};
+ /**
+ * Subject to removal
+ * @deprecated
+ */
that.refresh = function() {
};
+ /**
+ * Reflect `label`, `tooltip`, `measurement_unit`, `undo`, `writable`,
+ * `read_only` into widget.
+ */
that.set_widget_flags = function() {
if (that.widget) {
@@ -391,6 +618,9 @@ IPA.field = function(spec) {
}
};
+ /**
+ * Bind field to a widget defined by `widget_name`
+ */
that.widgets_created = function() {
that.widget = that.container.widgets.get_widget(that.widget_name);
@@ -403,11 +633,17 @@ IPA.field = function(spec) {
}
};
+ /**
+ * Handler for widget's `value_changed` event
+ */
that.widget_value_changed = function() {
that.set_dirty(that.test_dirty());
that.validate();
};
+ /**
+ * Handler for widget's `undo_clicked` event
+ */
that.widget_undo_clicked = function() {
that.reset();
};
@@ -427,14 +663,29 @@ IPA.field = function(spec) {
return that;
};
+/**
+ * Validator
+ *
+ * - base class, always returns positive result
+ *
+ * @class IPA.validator
+ */
IPA.validator = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Error message
+ * @property {string}
+ */
that.message = text.get(spec.message || '@i18n:widget.validation.error');
+ /**
+ * Create negative validation result
+ * @return {Object} result
+ */
that.false_result = function(message) {
return {
valid: false,
@@ -442,12 +693,22 @@ IPA.validator = function(spec) {
};
};
+ /**
+ * Create positive validation result
+ * @return {Object} result
+ */
that.true_result = function() {
return {
valid: true
};
};
+ /**
+ * Perform validation logic
+ * @param {Mixed} value
+ * @param {Object} context expected context is field which value is validated
+ * @return {Object} validation result
+ */
that.validate = function() {
return that.true_result();
};
@@ -455,10 +716,21 @@ IPA.validator = function(spec) {
return that;
};
+/**
+ * Metadata validator
+ *
+ * Validates value according to supplied metadata
+ *
+ * @class IPA.metadata_validator
+ * @extends IPA.validator
+ */
IPA.metadata_validator = function(spec) {
var that = IPA.validator(spec);
+ /**
+ * @inheritDoc
+ */
that.validate = function(value, context) {
var message;
@@ -507,14 +779,27 @@ IPA.metadata_validator = function(spec) {
return that;
};
+/**
+ * Checks if value is supported
+ *
+ * @class IPA.unsupported_validator
+ * @extends IPA.validator
+ */
IPA.unsupported_validator = function(spec) {
spec.message = spec.message ||'@i18n:widgets.validation.unsupported';
var that = IPA.validator(spec);
+ /**
+ * Unsupported values
+ * @property {Array.<string>}
+ */
that.unsupported = spec.unsupported || [];
+ /**
+ * @inheritDoc
+ */
that.validate = function(value, context) {
if (IPA.is_empty(value)) return that.true_result();
@@ -527,15 +812,32 @@ IPA.unsupported_validator = function(spec) {
return that;
};
+/**
+ * Check if value is the same as in other field.
+ *
+ * - designed for password confirmation
+ *
+ * @class IPA.same_password_validator
+ * @extends IPA.validator
+ */
IPA.same_password_validator = function(spec) {
spec = spec || {};
var that = IPA.validator(spec);
+
+ /**
+ * Other field name
+ * @property {string}
+ */
that.other_field = spec.other_field;
that.message = text.get(spec.message || '@i18n:password.password_must_match',
"Passwords must match");
+
+ /**
+ * @inheritDoc
+ */
that.validate = function(value, context) {
var other_field = context.container.fields.get_field(that.other_field);
@@ -550,15 +852,33 @@ IPA.same_password_validator = function(spec) {
return that;
};
+/**
+ * Used along with checkbox widget
+ *
+ * @class IPA.checkbox_field
+ * @extends IPA.field
+ */
IPA.checkbox_field = function(spec) {
spec = spec || {};
var that = IPA.field(spec);
+ /**
+ * Check value by default
+ * @property {boolean}
+ */
that.checked = spec.checked || false;
+
+ /**
+ * Boolean formatter for parsing loaded values.
+ * @property {IPA.boolean_formatter}
+ */
that.boolean_formatter = IPA.boolean_formatter();
+ /**
+ * @inheritDoc
+ */
that.load = function(record) {
that.record = record;
@@ -575,13 +895,20 @@ IPA.checkbox_field = function(spec) {
that.reset();
};
+ /**
+ * @inheritDoc
+ */
that.widgets_created = function() {
that.field_widgets_created();
that.widget.checked = that.checked;
};
- // a checkbox will always have a value, so it's never required
+ /**
+ * A checkbox will always have a value, so it's never required.
+ *
+ * @return {boolean} false
+ */
that.is_required = function() {
return false;
};
@@ -591,6 +918,12 @@ IPA.checkbox_field = function(spec) {
return that;
};
+/**
+ * Used along with checkboxes widget
+ *
+ * @class IPA.checkboxes_field
+ * @extends IPA.field
+ */
IPA.checkboxes_field = function(spec) {
spec = spec || {};
@@ -600,17 +933,29 @@ IPA.checkboxes_field = function(spec) {
return that;
};
+/**
+ * Used along with radio widget
+ *
+ * @class IPA.radio_field
+ * @extends IPA.field
+ */
IPA.radio_field = function(spec) {
spec = spec || {};
var that = IPA.field(spec);
- // a radio will always have a value, so it's never required
+ /**
+ * A radio will always have a value, so it's never required
+ * @return {boolean} false
+ */
that.is_required = function() {
return false;
};
+ /**
+ * @inheritDoc
+ */
that.widgets_created = function() {
that.field_widgets_created();
@@ -619,23 +964,38 @@ IPA.radio_field = function(spec) {
return that;
};
+/**
+ * Used along with multivalued widget
+ *
+ * @class IPA.multivalued_field
+ * @extends IPA.field
+ */
IPA.multivalued_field = function(spec) {
spec = spec || {};
var that = IPA.field(spec);
+ /**
+ * @inheritDoc
+ */
that.load = function(record) {
that.field_load(record);
};
+ /**
+ * @inheritDoc
+ */
that.test_dirty = function() {
var dirty = that.field_test_dirty();
dirty = dirty || that.widget.test_dirty(); //also checks order
return dirty;
};
+ /**
+ * @inheritDoc
+ */
that.validate = function() {
var values = that.save();
@@ -643,6 +1003,12 @@ IPA.multivalued_field = function(spec) {
return that.validate_core(values);
};
+ /**
+ * Validate each value separately.
+ * @protected
+ * @param {Array} values
+ * @return {boolean} valid
+ */
that.validate_core = function(values) {
that.hide_error();
@@ -672,17 +1038,35 @@ IPA.multivalued_field = function(spec) {
return that;
};
+/**
+ * Used along with ssh key widget
+ *
+ * @class IPA.sshkeys_field
+ * @extends IPA.multivalued_field
+ */
IPA.sshkeys_field = function(spec) {
spec = spec || {};
var that = IPA.multivalued_field(spec);
- // Fixes upgrade issue. When attr rights are missing due to lack of object class.
+ /**
+ * By default has 'w_if_no_aci' flag.
+ *
+ * - fixes upgrade issue. When attr rights are missing due to lack of
+ * object class.
+ */
that.flags = spec.flags || ['w_if_no_aci'];
+ /**
+ * Name of fingerprint param
+ * @property {string}
+ */
that.sshfp_attr = spec.sshfp_attr || 'sshpubkeyfp';
+ /**
+ * @inheritDoc
+ */
that.load = function(record) {
var keys = that.get_value(record, that.param);
@@ -710,6 +1094,9 @@ IPA.sshkeys_field = function(spec) {
that.reset();
};
+ /**
+ * @inheritDoc
+ */
that.dirty_are_equal = function(orig_vals, new_vals) {
var i;
@@ -725,12 +1112,21 @@ IPA.sshkeys_field = function(spec) {
return that;
};
+/**
+ * Used along with select widget
+ *
+ * @class IPA.select_field
+ * @extends IPA.field
+ */
IPA.select_field = function(spec) {
spec = spec || {};
var that = IPA.field(spec);
+ /**
+ * @inheritDoc
+ */
that.widgets_created = function() {
that.field_widgets_created();
@@ -739,19 +1135,38 @@ IPA.select_field = function(spec) {
return that;
};
+/**
+ * Used along with link widget
+ *
+ * @class IPA.link_field
+ * @extends IPA.field
+ */
IPA.link_field = function(spec) {
spec = spec || {};
var that = IPA.field(spec);
+ /**
+ * Entity a link points to
+ * @property {entity.entity}
+ */
that.other_entity = IPA.get_entity(spec.other_entity);
function other_pkeys () {
return that.facet.get_pkeys();
}
+
+ /**
+ * Function which should return primary keys of link target in case of
+ * link points to an entity.
+ * @property {Function}
+ */
that.other_pkeys = spec.other_pkeys || other_pkeys;
+ /**
+ * Handler for widget `link_click` event
+ */
that.on_link_clicked = function() {
navigation.show_entity(
@@ -760,12 +1175,21 @@ IPA.link_field = function(spec) {
that.other_pkeys());
};
+ /**
+ * @inheritDoc
+ */
that.load = function(record) {
that.field_load(record);
that.check_entity_link();
};
+ /**
+ * Check if entity exists
+ *
+ * - only if link points to an entity
+ * - update widget's `is_link` accordingly
+ */
that.check_entity_link = function() {
//In some cases other entity may not be present.
@@ -793,6 +1217,9 @@ IPA.link_field = function(spec) {
}).execute();
};
+ /**
+ * @inheritDoc
+ */
that.widgets_created = function() {
that.field_widgets_created();
that.widget.link_clicked.attach(that.on_link_clicked);
@@ -802,16 +1229,42 @@ IPA.link_field = function(spec) {
return that;
};
+/**
+ * Field for enabling/disabling entity
+ *
+ * - expects radio widget
+ * - requires facet to use 'update_info' update method
+ *
+ * @class IPA.enable_field
+ * @extends IPA.field
+ */
IPA.enable_field = function(spec) {
spec = spec || {};
var that = IPA.radio_field(spec);
+ /**
+ * Name of entity's enable method
+ * @property {string}
+ */
that.enable_method = spec.enable_method || 'enable';
+
+ /**
+ * Name of entity's disable method
+ * @property {string}
+ */
that.disable_method = spec.enable_method || 'disable';
+
+ /**
+ * Value of radio's enable option
+ * @property {string}
+ */
that.enable_option = spec.enable_option || 'TRUE';
+ /**
+ * @inheritDoc
+ */
that.get_update_info = function() {
var info = IPA.update_info_builder.new_update_info();
@@ -840,30 +1293,59 @@ IPA.enable_field = function(spec) {
return that;
};
-// TODO: Add support for nested fields
+/**
+ * Collection of fields
+ * @class IPA.field_container
+ */
IPA.field_container = function(spec) {
spec = spec || {};
var that = IPA.object();
- that.container = spec.container; //usually facet or dialog
+ /**
+ * Parent container
+ *
+ * - usually facet or dialog
+ */
+ that.container = spec.container;
+ /**
+ * Collection of fields
+ * @property {ordered_map}
+ * @protected
+ */
that.fields = $.ordered_map();
+ /**
+ * Get field with given name
+ * @param {string} name
+ * @return {IPA.field}
+ */
that.get_field = function(name) {
return that.fields.get(name);
};
- that.get_fields = function(name) {
+ /**
+ * Get all fields
+ * @return {Array.<IPA.field>}
+ */
+ that.get_fields = function() {
return that.fields.values;
};
+ /**
+ * Add field
+ * @param {IPA.field} field
+ */
that.add_field = function(field) {
field.container = that.container;
that.fields.put(field.name, field);
};
+ /**
+ * Call each field's `widgets_created` method.
+ */
that.widgets_created = function() {
var fields = that.fields.values;
@@ -877,16 +1359,33 @@ IPA.field_container = function(spec) {
return that;
};
+/**
+ * Old field builder
+ * @class IPA.field_builder
+ */
IPA.field_builder = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Field context property: container
+ * @property {facet.facet|IPA.dialog}
+ */
that.container = spec.container;
- that.field_options = spec.field_options || {};
+ /**
+ * Map of additional field context properties
+ * @property {Object}
+ */
+ that.field_options = spec.field_options || {};
+ /**
+ * Build one field
+ * @param {Object} spec
+ * @param {facet.facet|IPA.dialog} container
+ */
that.build_field = function(spec, container) {
var context = lang.mixin({}, that.field_options);
@@ -895,6 +1394,11 @@ IPA.field_builder = function(spec) {
return field;
};
+ /**
+ * Build multiple fields
+ * @param {Array.<Object>} spec
+ * @param {facet.facet|IPA.dialog} container
+ */
that.build_fields = function(specs, container) {
return that.build_field(specs, container);
@@ -903,7 +1407,11 @@ IPA.field_builder = function(spec) {
return that;
};
-
+/**
+ * Field pre_op build operation
+ * @member field
+ * @return spec
+ */
exp.pre_op = function(spec, context) {
if (context.facet) spec.facet = context.facet;
@@ -912,13 +1420,21 @@ exp.pre_op = function(spec, context) {
return spec;
};
+/**
+ * Field post_op build operation
+ * @member field
+ * @return obj
+ */
exp.post_op = function(obj, spec, context) {
if (context.container) context.container.add_field(obj);
return obj;
};
-// Field builder and registry
+/**
+ * Field builder with registry
+ * @member field
+ */
exp.builder = builder.get('field');
exp.builder.factory = IPA.field;
exp.builder.string_mode = 'property';
@@ -927,11 +1443,17 @@ reg.set('field', exp.builder.registry);
exp.builder.pre_ops.push(exp.pre_op);
exp.builder.post_ops.push(exp.post_op);
-// Validator builder and registry
+/**
+ * Validator builder with registry
+ * @member field
+ */
exp.validator_builder = builder.get('validator');
-//exp.validator_builder.factory = IPA.formatter;
reg.set('validator', exp.validator_builder.registry);
+/**
+ * Register fields and validators to global registry
+ * @member field
+ */
exp.register = function() {
var f = reg.field;
var v = reg.validator;
diff --git a/install/ui/src/freeipa/hbac.js b/install/ui/src/freeipa/hbac.js
index e977b4d26..0fb40373e 100644
--- a/install/ui/src/freeipa/hbac.js
+++ b/install/ui/src/freeipa/hbac.js
@@ -224,6 +224,7 @@ return {
};};
/**
+ * @ignore
* @param {Object} facet spec
*/
var add_hbacrule_details_facet_widgets = function (spec) {
diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js
index 0e9fdefb9..b3017650d 100644
--- a/install/ui/src/freeipa/ipa.js
+++ b/install/ui/src/freeipa/ipa.js
@@ -31,6 +31,16 @@ define(['./jquery',
'./text'],
function($, JSON, i18n, metadata_provider, builder, reg, text) {
+/**
+ * @class
+ * @singleton
+ *
+ * Defined in ipa module. Other modules extend it.
+ *
+ * There is a long-term goal to reduce the number of items in this namespace
+ * and move them to separate modules.
+ *
+ */
var IPA = function() {
var that = {
@@ -40,6 +50,10 @@ var IPA = function() {
// live server path
that.url = '/ipa/ui/';
+ /**
+ * jQuery AJAX options used by RPC commands
+ * @property
+ */
that.ajax_options = {
type: 'POST',
contentType: 'application/json',
@@ -48,17 +62,57 @@ var IPA = function() {
processData: false
};
+ /**
+ * i18n messages
+ * @deprecated
+ * @property {Object}
+ */
that.messages = {};
+
+ /**
+ * User information
+ *
+ * - output of ipa user-find --whoami
+ */
that.whoami = {};
+ /**
+ * Map of entities
+ * @deprecated
+ * @property {ordered_map}
+ */
that.entities = $.ordered_map();
+
+ /**
+ * Map of entity factories
+ * @deprecated
+ */
that.entity_factories = {};
+ /**
+ * Number of currently active command calls - controls visibility of network indicator
+ */
that.network_call_count = 0;
+ /**
+ * UI state
+ * @property {boolean} initialized - Intialization completed:
+ * - metadata
+ * - user information
+ * - server configuration
+ * @property {boolean} logged_kerberos - User authenticated by
+ * Kerberos negotiation
+ * @property {boolean} logged_password - User authenticated by password
+ */
that.ui = {};
- /* initialize the IPA JSON-RPC helper */
+ /**
+ * Load initialization data and initialize UI
+ * @param {Object} params
+ * @param {string} params.url - URL of JSON RPC interface
+ * @param {Function} params.on_success - success callback
+ * @param {Function} params.on_error - error callback
+ */
that.init = function(params) {
// if current path matches live server path, use live data
@@ -160,6 +214,12 @@ var IPA = function() {
batch.execute();
};
+ /**
+ * Prepares `user-find --whoami` command
+ * @protected
+ * @param {boolean} batch - Specifies if it will be used as single command or
+ * in a batch.
+ */
that.get_whoami_command = function(batch) {
return IPA.command({
entity: 'user',
@@ -175,6 +235,13 @@ var IPA = function() {
});
};
+ /**
+ * Executes RPC commands to load metadata
+ * @protected
+ * @param {Object} params
+ * @param {Function} params.on_success
+ * @param {Function} params.on_error
+ */
that.init_metadata = function(params) {
var objects = IPA.command({
@@ -216,6 +283,12 @@ var IPA = function() {
metadata_command.execute();
};
+ /**
+ * Register entity factory in global registry
+ * @deprecated
+ * @param {string} name - Entity name
+ * @param {Function} factory - Entity factory
+ */
that.register = function(name, factory) {
reg.entity.remove(name);
reg.entity.register({
@@ -225,15 +298,28 @@ var IPA = function() {
});
};
+ /**
+ * Return entity instance with given name from global entity registry
+ * @deprecated
+ * @param {string} name - entity name
+ */
that.get_entity = function(name) {
return reg.entity.get(name);
};
+ /**
+ * Display network activity indicator
+ */
that.display_activity_icon = function() {
that.network_call_count++;
$('.network-activity-indicator').css('visibility', 'visible');
};
+ /**
+ * Hide network activity indicator
+ *
+ * - based on network_call_count
+ */
that.hide_activity_icon = function() {
that.network_call_count--;
@@ -249,19 +335,26 @@ var IPA = function() {
}();
/**
- * Basic object
- *
- * Framework objects created by factories should use this instead of {} when
- * creating base objects. As an alternative they can just set __fw_obj
- * property.
+ * Framework objects created by factories should use this
+ * instead of empty object when creating base objects. As an alternative
+ * they can just set __fw_obj property.
*
* __fw_obj property serves for telling the framework that it's instantiated
* object and not an object specification (spec).
+ *
+ * @class
*/
-IPA.object = function() {
+IPA.object = function(s) {
return new IPA.obj_cls();
};
+/**
+ * Make request on Kerberos authentication url to initialize Kerberos negotiation.
+ *
+ * Set result to IPA.ui.logged_kerberos.
+ *
+ * @member IPA
+ */
IPA.get_credentials = function() {
var status;
@@ -289,6 +382,14 @@ IPA.get_credentials = function() {
return status;
};
+/**
+ * Logout
+ *
+ * - terminate the session.
+ * - redirect to logout landing page on success
+ *
+ * @member IPA
+ */
IPA.logout = function() {
function show_error(message) {
@@ -335,6 +436,14 @@ IPA.logout = function() {
$.ajax(request);
};
+/**
+ * Login by username and password
+ *
+ * @member IPA
+ * @param {string} username
+ * @param {string} password
+ * @return {string} Logout status - {password-expired, denied, invalid, success}
+ */
IPA.login_password = function(username, password) {
var result = 'invalid';
@@ -383,6 +492,17 @@ IPA.login_password = function(username, password) {
return result;
};
+/**
+ * Reset user's password
+ *
+ * @member IPA
+ * @param {string} username
+ * @param {string} old_password
+ * @param {string} new_password
+ * @return {Object} result
+ * @return {string} result.status
+ * @return {string} result.message
+ */
IPA.reset_password = function(username, old_password, new_password) {
//possible results: 'ok', 'invalid-password', 'policy-error'
@@ -439,6 +559,13 @@ IPA.reset_password = function(username, old_password, new_password) {
return result;
};
+/**
+ * Check if password is about to expired (based on
+ * IPA.server_config.ipapwdexpadvnotify). If so, display a notification
+ * message with a link to reset password dialog.
+ *
+ * @member IPA
+ */
IPA.update_password_expiration = function() {
var now, expires, notify_days, diff, message, container;
@@ -476,6 +603,11 @@ IPA.update_password_expiration = function() {
}
};
+/**
+ * Show password dialog for self-service change of password.
+ *
+ * @member IPA
+ */
IPA.password_selfservice = function() {
var reset_dialog = IPA.user_password_dialog({
self_service: true,
@@ -495,6 +627,11 @@ IPA.password_selfservice = function() {
reset_dialog.open();
};
+/**
+ * Parse value as UTC date
+ * @member IPA
+ * @return Data
+ */
IPA.parse_utc_date = function(value) {
if (!value) return null;
@@ -527,14 +664,17 @@ IPA.parse_utc_date = function(value) {
/**
* Call an IPA command over JSON-RPC.
*
- * Arguments:
- * name - command name (optional)
- * entity - command entity (optional)
- * method - command method
- * args - list of arguments, e.g. [username]
- * options - dict of options, e.g. {givenname: 'Pavel'}
- * on_success - callback function if command succeeds
- * on_error - callback function if command fails
+ * @class IPA.command
+ *
+ * @param {Object} spec - construct specification
+ * @param {string} spec.name - command name (optional)
+ * @param {string} spec.entity - command entity(name) (optional)
+ * @param {string} spec.method - command method
+ * @param {string[]} spec.args - list of arguments, e.g. ['username']
+ * @param {Object} spec.options - dict of options, e.g. {givenname: 'Petr'}
+ * @param {Function} spec.on_success - callback function if command succeeds
+ * @param {Function} spec.on_error - callback function if command fails
+ *
*/
IPA.command = function(spec) {
@@ -542,44 +682,109 @@ IPA.command = function(spec) {
var that = IPA.object();
+ /** @property {string} name Name */
that.name = spec.name;
+ /** @property {entity.entity} entity Entity */
that.entity = spec.entity;
+
+ /** @property {string} method Method */
that.method = spec.method;
+ /** @property {string[]} args Command Arguments */
that.args = $.merge([], spec.args || []);
+
+ /** @property {Object} options Option map */
that.options = $.extend({}, spec.options || {});
+ /**
+ * Success handler
+ * @property {Function}
+ * @param {Object} data
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ */
that.on_success = spec.on_success;
+
+ /**
+ * Error handler
+ * @property {Function}
+ * @param {XMLHttpRequest} xhr
+ * @param {string} text_status
+ * @param {{name:string,message:string}} error_thrown
+ */
that.on_error = spec.on_error;
+ /**
+ * Allow retrying of execution if previous ended as error
+ *
+ * Manifested by error dialog. Set it to `false` for custom error dialogs or
+ * error handling without any dialog.
+ * @property {Boolean} retry=true
+ */
that.retry = typeof spec.retry == 'undefined' ? true : spec.retry;
+ /** @property {string} error_message Default error message */
that.error_message = text.get(spec.error_message || '@i18n:dialogs.batch_error_message', 'Some operations failed.');
+
+ /** @property {ordered_map.<number,string>} error_messages Error messages map */
that.error_messages = $.ordered_map({
911: 'Missing HTTP referer. <br/> You have to configure your browser to send HTTP referer header.'
});
+ /**
+ * Get command name
+ *
+ * - it's `entity.name + '_' + method`
+ * - or `method`
+ * @return {string}
+ */
that.get_command = function() {
return (that.entity ? that.entity+'_' : '') + that.method;
};
+ /**
+ * Add argument
+ * @param {string} arg
+ */
that.add_arg = function(arg) {
that.args.push(arg);
};
+ /**
+ * Add arguments
+ * @param {string[]} args
+ */
that.add_args = function(args) {
$.merge(that.args, args);
};
+ /**
+ * Set option
+ * @param {string} name
+ * @param {Mixed} value
+ */
that.set_option = function(name, value) {
that.options[name] = value;
};
+ /**
+ * Extends options map with another options map
+ *
+ * @param {{opt1:Mixed, opt2:Mixed}} options
+ */
that.set_options = function(options) {
$.extend(that.options, options);
};
+ /**
+ * Add value to an option
+ *
+ * - creates a new option if it does not exist yet
+ * - for option overriding use `set_option` method
+ * @param {string} name
+ * @param {Mixed} value
+ */
that.add_option = function(name, value) {
var values = that.options[name];
if (!values) {
@@ -589,14 +794,26 @@ IPA.command = function(spec) {
values.push(value);
};
+ /**
+ * Get option value
+ * @return {Mixed}
+ */
that.get_option = function(name) {
return that.options[name];
};
+ /**
+ * Remove option from option map
+ */
that.remove_option = function(name) {
delete that.options[name];
};
+ /**
+ * Execute the command.
+ *
+ * Set `on_success` and/or `on_error` handlers to be informed about result.
+ */
that.execute = function() {
function dialog_open(xhr, text_status, error_thrown) {
@@ -788,6 +1005,15 @@ IPA.command = function(spec) {
$.ajax(that.request);
};
+ /**
+ * Parse successful command result and get all errors.
+ * @protected
+ * @param {IPA.command} command
+ * @param {Object} result
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ * @return {IPA.error_list}
+ */
that.get_failed = function(command, result, text_status, xhr) {
var errors = IPA.error_list();
if(result && result.failed) {
@@ -809,12 +1035,21 @@ IPA.command = function(spec) {
return errors;
};
+ /**
+ * Check if command accepts option
+ * @param {string} option_name
+ * @return {Boolean}
+ */
that.check_option = function(option_name) {
var metadata = IPA.get_command_option(that.get_command(), option_name);
return metadata !== null;
};
+ /**
+ * Encodes command into JSON-RPC command object
+ * @return {Object}
+ */
that.to_json = function() {
var json = {};
@@ -827,6 +1062,10 @@ IPA.command = function(spec) {
return json;
};
+ /**
+ * Encodes command into CLI command string
+ * @return {string}
+ */
that.to_string = function() {
var string = that.get_command().replace(/_/g, '-');
@@ -844,7 +1083,18 @@ IPA.command = function(spec) {
return that;
};
-IPA.batch_command = function (spec) {
+/**
+ * Call multiple IPA commands in a batch over JSON-RPC.
+ *
+ * @class IPA.batch_command
+ * @extends IPA.command
+ *
+ * @param {Object} spec
+ * @param {Array.<IPA.command>} spec.commands - IPA commands to be executed
+ * @param {Function} spec.on_success - callback function if command succeeds
+ * @param {Function} spec.on_error - callback function if command fails
+ */
+IPA.batch_command = function(spec) {
spec = spec || {};
@@ -852,22 +1102,40 @@ IPA.batch_command = function (spec) {
var that = IPA.command(spec);
+ /** @property {IPA.command[]} commands Commands */
that.commands = [];
+ /** @property {IPA.error_list} errors Errors */
that.errors = IPA.error_list();
+
+ /**
+ * Show error if some command fail
+ * @property {Boolean} show_error=true
+ */
that.show_error = typeof spec.show_error == 'undefined' ?
true : spec.show_error;
+ /**
+ * Add command
+ * @param {IPA.command} command
+ */
that.add_command = function(command) {
that.commands.push(command);
that.add_arg(command.to_json());
};
+ /**
+ * Add commands
+ * @param {IPA.command[]} commands
+ */
that.add_commands = function(commands) {
for (var i=0; i<commands.length; i++) {
that.add_command(commands[i]);
}
};
+ /**
+ * @inheritDoc
+ */
that.execute = function() {
that.errors.clear();
@@ -886,6 +1154,16 @@ IPA.batch_command = function (spec) {
command.execute();
};
+ /**
+ * Internal XHR success handler
+ *
+ * Parses data and looks for errors. `on_success` or `on_error` is then
+ * called.
+ * @protected
+ * @param {Object} data
+ * @param {string} text_status
+ * @param {XMLHttpRequest} xhr
+ */
that.batch_command_on_success = function(data, text_status, xhr) {
for (var i=0; i<that.commands.length; i++) {
@@ -965,6 +1243,13 @@ IPA.batch_command = function (spec) {
}
};
+ /**
+ * Internal XHR error handler
+ * @protected
+ * @param {XMLHttpRequest} xhr
+ * @param {string} text_status
+ * @param {{name:string,message:string}} error_thrown
+ */
that.batch_command_on_error = function(xhr, text_status, error_thrown) {
// TODO: undefined behavior
if (that.on_error) {
@@ -975,16 +1260,45 @@ IPA.batch_command = function (spec) {
return that;
};
-
+/**
+ * Call multiple IPA commands over JSON-RPC separately and wait for every
+ * command's response.
+ *
+ * - concurrent command fails if any command fails
+ * - result is reported when each command finishes
+ *
+ * @class IPA.concurrent_command
+ *
+ * @param {Object} spec - construct specification
+ * @param {Array.<IPA.command>} spec.commands - IPA commands to execute
+ * @param {Function} spec.on_success - callback function if each command succeed
+ * @param {Function} spec.on_error - callback function one command fails
+ *
+ */
IPA.concurrent_command = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /** @property {IPA.command[]} commands Commands */
that.commands = [];
+
+ /**
+ * Success handler
+ * @property {Function}
+ */
that.on_success = spec.on_success;
+
+ /**
+ * Error handler
+ * @property {Function}
+ */
that.on_error = spec.on_error;
+ /**
+ * Add commands
+ * @param {IPA.command[]} commands
+ */
that.add_commands = function(commands) {
if(commands && commands.length) {
@@ -996,6 +1310,9 @@ IPA.concurrent_command = function(spec) {
}
};
+ /**
+ * Execute the commands one by one.
+ */
that.execute = function() {
var command_info, command, i;
@@ -1035,6 +1352,10 @@ IPA.concurrent_command = function(spec) {
}
};
+ /**
+ * Internal error handler
+ * @protected
+ */
that.error_handler = function(command_info, xhr, text_status, error_thrown) {
command_info.completed = true;
@@ -1046,6 +1367,10 @@ IPA.concurrent_command = function(spec) {
that.command_completed();
};
+ /**
+ * Internal success handler
+ * @protected
+ */
that.success_handler = function(command_info, data, text_status, xhr) {
command_info.completed = true;
@@ -1057,6 +1382,11 @@ IPA.concurrent_command = function(spec) {
that.command_completed();
};
+ /**
+ * Check if all commands finished.
+ * If so, report it.
+ * @protected
+ */
that.command_completed = function() {
var all_completed = true;
@@ -1077,6 +1407,10 @@ IPA.concurrent_command = function(spec) {
}
};
+ /**
+ * Call each command's success handler and `on_success`.
+ * @protected
+ */
that.on_success_all = function() {
for(var i=0; i < that.commands.length; i++) {
@@ -1095,6 +1429,10 @@ IPA.concurrent_command = function(spec) {
}
};
+ /**
+ * Call each command's error handler and `on_success`.
+ * @protected
+ */
that.on_error_all = function() {
if(that.on_error) {
@@ -1116,11 +1454,24 @@ IPA.concurrent_command = function(spec) {
return that;
};
+/**
+ * Build object with {@link builder}.
+ * @member IPA
+ * @param {Object} spec - contruction spec
+ * @param {Object} context
+ * @param {Object} overrides
+ */
IPA.build = function(spec, context, overrides) {
return builder.build(null, spec, context, overrides);
};
+/**
+ * Create a object defined by spec with IPA.object as parent.
+ * @member IPA
+ * @param {Object} spec
+ * @return {Object} new object with all properties as spec
+ */
IPA.default_factory = function(spec) {
spec = spec || {};
@@ -1132,23 +1483,46 @@ IPA.default_factory = function(spec) {
return that;
};
-/* helper function used to retrieve information about an attribute */
+/**
+ * Helper function used to retrieve information about an object attribute from metadata
+ * @member IPA
+ * @param {string} entity_name
+ * @param {string} name - attribute name
+ */
IPA.get_entity_param = function(entity_name, name) {
return metadata_provider.get(['@mo-param', entity_name, name].join(':'));
};
+/**
+ * Helper function used to retrieve information about an command argument from metadata
+ * @member IPA
+ * @param {string} command_name
+ * @param {string} arg_name - argument name
+ */
IPA.get_command_arg = function(command_name, arg_name) {
return metadata_provider.get(['@mc-arg', command_name, arg_name].join(':'));
};
+
+/**
+ * Helper function used to retrieve information about an command option from metadata
+ * @member IPA
+ * @param {string} command_name
+ * @param {string} option_name - argument name
+ */
IPA.get_command_option = function(command_name, option_name) {
return metadata_provider.get(['@mc-opt', command_name, option_name].join(':'));
};
-/* helper function used to retrieve attr name with members of type `member` */
+/**
+ * Helper function used to retrieve information about an attribute member
+ * @member IPA
+ * @param {string} obj_name - object(entity) name
+ * @param {string} member - attribute member
+ */
IPA.get_member_attribute = function(obj_name, member) {
var obj = metadata_provider.get('@mo:'+obj_name);
@@ -1169,6 +1543,11 @@ IPA.get_member_attribute = function(obj_name, member) {
return null;
};
+/**
+ * Create HTML representation of network spinner.
+ * @member IPA
+ * @return {HTMLElement} Network spinner node
+ */
IPA.create_network_spinner = function(){
var span = $('<span/>', {
'class': 'network-activity-indicator'
@@ -1179,6 +1558,18 @@ IPA.create_network_spinner = function(){
return span;
};
+/**
+ * Dirty dialog
+ *
+ * Should be used as an indication of unsaved changes on page when leaving the
+ * page. Offers user to safe/reset the changes or cancel the action.
+ *
+ * @class
+ * @extends IPA.dialog
+ * @param {Object} spec
+ * @param {IPA.facet} spec.facet - Dirty facet
+ * @param {string} [spec.message] - Displayed message
+ */
IPA.dirty_dialog = function(spec) {
spec = spec || {};
@@ -1186,9 +1577,14 @@ IPA.dirty_dialog = function(spec) {
spec.width = spec.width || '25em';
var that = IPA.dialog(spec);
+
+ /** @property {facet.facet} facet Facet*/
that.facet = spec.facet;
+
+ /** @property {string} message Dirty message*/
that.message = text.get(spec.message || '@i18n:dialogs.dirty_message');
+ /** @inheritDoc */
that.create = function() {
that.container.append(that.message);
};
@@ -1222,12 +1618,25 @@ IPA.dirty_dialog = function(spec) {
}
});
+ /**
+ * Function which is called when user click on 'update' or 'delete' button
+ */
that.callback = function() {
};
return that;
};
+/**
+ * Error dialog
+ *
+ * Serves for notifying an error in RPC command.
+ *
+ * @class
+ * @extends IPA.dialog
+ * @mixins IPA.confirm_mixin
+ * @param {Object} spec
+ */
IPA.error_dialog = function(spec) {
spec = spec || {};
@@ -1240,20 +1649,32 @@ IPA.error_dialog = function(spec) {
IPA.confirm_mixin().apply(that);
+ /** @property {XMLHttpRequest} xhr Command's xhr */
that.xhr = spec.xhr || {};
+ /** @property {string} text_status Command's text status */
that.text_status = spec.text_status || '';
+ /** @property {{name:string,message:string}} error_thrown Command's error */
that.error_thrown = spec.error_thrown || {};
+ /** @property {IPA.command} command Command */
that.command = spec.command;
+ /** @property {IPA.error_list} errors Errors */
that.errors = spec.errors;
+ /** @property {string[]} visible_buttons=['retry', 'cancel'] Visible button names */
that.visible_buttons = spec.visible_buttons || ['retry', 'cancel'];
-
+ /**
+ * Beautify error message
+ *
+ * Multi-lined text may contain TAB character as first char of the line
+ * to hint at marking the whole line differently.
+ * @param {jQuery} container Container to add the beautified message.
+ * @param {string} message
+ */
that.beautify_message = function(container, message) {
var lines = message.split(/\n/g);
var line_span;
for(var i=0; i<lines.length; i++) {
- // multi-lined text may contain TAB character as first char of the line
- // to hint at marking the whole line differently
+
if (lines[i].charAt(0) == '\t') {
line_span = $('<p />', {
'class': 'error-message-hinted',
@@ -1267,6 +1688,7 @@ IPA.error_dialog = function(spec) {
}
};
+ /** @inheritDoc */
that.create = function() {
if (that.error_thrown.url) {
$('<p/>', {
@@ -1327,12 +1749,15 @@ IPA.error_dialog = function(spec) {
}
};
+ /**
+ * Create dialog buttons
+ * @protected
+ */
that.create_buttons = function() {
- /**
- * When a user initially opens the Web UI without a Kerberos
- * ticket, the messages including the button labels have not
- * been loaded yet, so the button labels need default values.
- */
+
+ // When a user initially opens the Web UI without a Kerberos
+ // ticket, the messages including the button labels have not
+ // been loaded yet, so the button labels need default values.
var visible = that.visible_buttons.indexOf('retry') > -1;
var label = text.get('@i18n:buttons.retry', 'Retry');
@@ -1368,19 +1793,35 @@ IPA.error_dialog = function(spec) {
});
};
+ /**
+ * Retry handler
+ * @protected
+ */
that.on_retry = function() {
that.close();
that.command.execute();
};
+ /**
+ * OK button handler
+ * @protected
+ */
that.on_ok = function() {
that.close();
};
+ /**
+ * Cancel button and negative confirmation handler
+ * @protected
+ */
that.on_cancel = function() {
that.close();
};
+ /**
+ * Positive confirmation handler
+ * @protected
+ */
that.on_confirm = function() {
if (that.visible_buttons.indexOf('retry') > -1) that.on_retry();
else that.on_ok();
@@ -1391,13 +1832,23 @@ IPA.error_dialog = function(spec) {
return that;
};
+/**
+ * Error list
+ *
+ * Collection for RPC command errors.
+ *
+ * @class IPA.error_list
+ * @private
+ */
IPA.error_list = function() {
var that = IPA.object();
+ /** Clear errors */
that.clear = function() {
that.errors = [];
};
+ /** Add error */
that.add = function(command, name, message, status) {
that.errors.push({
command: command,
@@ -1407,10 +1858,15 @@ IPA.error_list = function() {
});
};
+ /** Add errors */
that.add_range = function(error_list) {
that.errors = that.errors.concat(error_list.errors);
};
+ /**
+ * Check if there are no errors
+ * @return {Boolean}
+ */
that.is_empty = function () {
return that.errors.length === 0;
};
@@ -1419,6 +1875,14 @@ IPA.error_list = function() {
return that;
};
+/**
+ * Error handler for IPA.command which handles error #4304 as success.
+ *
+ * 4304 is raised when part of an operation succeeds and the part that failed
+ * isn't critical.
+ * @member IPA
+ * @param {IPA.entity_adder_dialog} adder_dialog
+ */
IPA.create_4304_error_handler = function(adder_dialog) {
var set_pkey = function(result) {
@@ -1460,6 +1924,16 @@ IPA.create_4304_error_handler = function(adder_dialog) {
};
};
+/**
+ * Unauthorized dialog
+ *
+ * Notifies that user's session is expired. It supports forms-based authentication
+ * and password reset when password is expired.
+ *
+ * @class IPA.unauthorized_dialog
+ * @extends IPA.error_dialog
+ * @param {Object} spec
+ */
IPA.unauthorized_dialog = function(spec) {
spec = spec || {};
@@ -1515,14 +1989,18 @@ IPA.unauthorized_dialog = function(spec) {
var that = IPA.error_dialog(spec);
+ /** @inheritDoc */
that.title = spec.title || text.get('@i18n:login.login', "Login");
+ /** @property {string} message Session expired message */
that.message = text.get(spec.message || '@i18n:ajax.401.message',
"Your session has expired. Please re-login.");
+ /** @property {string} form_auth_msg Forms authentication message */
that.form_auth_msg = text.get(spec.form_auth_msg || '@i18n:login.form_auth',
"To login with username and password, enter them in the fields below then click Login.");
+ /** @property {string} krb_auth_msg Kerberos authentication message */
that.krb_auth_msg = text.get(spec.krb_auth_msg || '@i18n:login.krb_auth_msg',
" To login with Kerberos, please make sure you" +
" have valid tickets (obtainable via kinit) and " +
@@ -1531,21 +2009,29 @@ IPA.unauthorized_dialog = function(spec) {
that.krb_auth_msg = that.krb_auth_msg.replace('${host}', window.location.hostname);
+ /** @property {string} form_auth_failed Forms authentication failure message */
that.form_auth_failed = "<p><strong>Please re-enter your username or password</strong></p>" +
"<p>The password or username you entered is incorrect. " +
"Please try again (make sure your caps lock is off).</p>" +
"<p>If the problem persists, contact your administrator.</p>";
+ /** @property {string} password_expired Password expired message */
that.password_expired = "Your password has expired. Please enter a new password.";
+ /** @property {string} denied Login denied message */
that.denied = "Sorry you are not allowed to access this service.";
+ /** @inheritDoc */
that.create = function() {
that.session_expired_form();
that.create_reset_form();
};
+ /**
+ * Create session expired form
+ * @protected
+ */
that.session_expired_form = function() {
that.session_form = $('<div\>').appendTo(that.container);
@@ -1585,6 +2071,10 @@ IPA.unauthorized_dialog = function(spec) {
that.username_widget.value_changed.attach(that.on_username_change);
};
+ /**
+ * Create password reset form
+ * @protected
+ */
that.create_reset_form = function() {
that.reset_form = $('<div\>', {
@@ -1611,6 +2101,10 @@ IPA.unauthorized_dialog = function(spec) {
that.verify_password_widget = that.widgets.get_widget('reset.verify_password');
};
+ /**
+ * Create dialog buttons
+ * @protected
+ */
that.create_buttons = function() {
that.buttons.empty();
@@ -1649,12 +2143,17 @@ IPA.unauthorized_dialog = function(spec) {
});
};
+ /** @inheritDoc */
that.open = function() {
that.dialog_open();
that.show_session_form();
that.check_error_reason();
};
+ /**
+ * Check if response contains IPA specific rejection reason.
+ * @protected
+ */
that.check_error_reason = function() {
if (this.xhr) {
var reason = this.xhr.getResponseHeader("X-IPA-Rejection-Reason");
@@ -1664,6 +2163,10 @@ IPA.unauthorized_dialog = function(spec) {
}
};
+ /**
+ * User name field value change handler
+ * @protected
+ */
that.on_username_change = function() {
var password_field = that.fields.get_field('password');
@@ -1672,6 +2175,11 @@ IPA.unauthorized_dialog = function(spec) {
if (!user_specified) that.password_widget.clear();
};
+ /**
+ * Enable fields with given name
+ * @protected
+ * @param {string[]} field_names
+ */
that.enable_fields = function(field_names) {
var field, fields, i, enable;
@@ -1683,6 +2191,10 @@ IPA.unauthorized_dialog = function(spec) {
}
};
+ /**
+ * Shows session expired form. Hides other.
+ * @protected
+ */
that.show_session_form = function() {
that.current_view = 'session';
@@ -1693,6 +2205,10 @@ IPA.unauthorized_dialog = function(spec) {
that.username_widget.focus_input();
};
+ /**
+ * Shows password reset form. Hides other.
+ * @protected
+ */
that.show_reset_form = function() {
that.current_view = 'reset';
@@ -1706,6 +2222,11 @@ IPA.unauthorized_dialog = function(spec) {
that.new_password_widget.focus_input();
};
+ /**
+ * Show login error message - based on reason
+ * @protected
+ * @param {"invalid"|"denied"|string} reason
+ */
that.show_login_error_message = function(reason) {
var errors = {
'invalid': that.form_auth_failed,
@@ -1720,6 +2241,10 @@ IPA.unauthorized_dialog = function(spec) {
}
};
+ /**
+ * Cancel handler
+ * @protected
+ */
that.on_cancel = function() {
that.username_widget.clear();
@@ -1731,6 +2256,10 @@ IPA.unauthorized_dialog = function(spec) {
that.show_session_form();
};
+ /**
+ * Initiates login procedure
+ * @protected
+ */
that.on_login = function() {
var username = that.username_widget.save();
@@ -1760,6 +2289,10 @@ IPA.unauthorized_dialog = function(spec) {
}
};
+ /**
+ * Login success handler
+ * @protected
+ */
that.on_login_success = function() {
that.login_error_box.css('display', 'none');
@@ -1769,6 +2302,10 @@ IPA.unauthorized_dialog = function(spec) {
that.on_retry();
};
+ /**
+ * Initiates password reset procedure
+ * @protected
+ */
that.on_reset = function() {
if (!that.validate()) return;
@@ -1791,6 +2328,10 @@ IPA.unauthorized_dialog = function(spec) {
}
};
+ /**
+ * Password reset success handler
+ * @protected
+ */
that.on_reset_success = function() {
that.login_error_box.css('display', 'none');
@@ -1807,7 +2348,10 @@ IPA.unauthorized_dialog = function(spec) {
that.on_login();
};
- //replaces confirm_mixin method
+ /**
+ * Key up handler for proper keyboard usage.
+ * @protected
+ */
that.on_key_up = function(event) {
if (that.switching) {
@@ -1836,6 +2380,15 @@ IPA.unauthorized_dialog = function(spec) {
return that;
};
+/**
+ * Shorten text to desired number of characters.
+ *
+ * If shortened, '...' is appended to the shortened text.
+ * @member IPA
+ * @param {string} value - text to shorten
+ * @param {number} max_length - maximum number of characters
+ * @return {string} shortened text
+ */
IPA.limit_text = function(value, max_length) {
if (!value) return '';
@@ -1849,6 +2402,13 @@ IPA.limit_text = function(value, max_length) {
return limited_text;
};
+
+/**
+ * Convert strings to options.
+ * @member IPA
+ * @param {string[]} values - options as strings
+ * @return {Array.<{value,label}>} options
+ */
IPA.create_options = function(values) {
var options = [];
@@ -1870,6 +2430,19 @@ IPA.create_options = function(values) {
return options;
};
+/**
+ * Check if value is not defined.
+ *
+ * True when:
+ *
+ * - value is undefined or null or ''
+ * - value is empty Array
+ * - value is Array with an empty string ('')
+ * - value is empty Object- {}
+ * @member IPA
+ * @param value - value to check
+ * @return {boolean}
+ */
IPA.is_empty = function(value) {
var empty = false;
@@ -1893,11 +2466,29 @@ IPA.is_empty = function(value) {
return empty;
};
+/**
+ * Check if value is not null or undefined.
+ * @member IPA
+ * @param value
+ * @param {boolean} check_empty_str - additional check for empty string
+ */
IPA.defined = function(value, check_empty_str) {
return value !== null && value !== undefined &&
((check_empty_str && value !== '') || !check_empty_str);
};
+
+/**
+ * Check if arrays differ.
+ *
+ * False when:
+ *
+ * - length and items or arrays equals (===)
+ * - undefined state of both is the same
+ * @member IPA
+ * @param a
+ * @param b
+ */
IPA.array_diff = function(a, b) {
if (a === b || (!a && !b)) return false;
@@ -1913,10 +2504,23 @@ IPA.array_diff = function(a, b) {
return false;
};
+/**
+ * Shows confirm dialog with message
+ * @member IPA
+ * @param {string} msg - message
+ * @return {boolean} confirmed state
+ */
IPA.confirm = function(msg) {
return window.confirm(msg);
};
+/**
+ * Display positive notification message
+ * @member IPA
+ * @param {string} message
+ * @param {number} [timeout=IPA.config.message_timeout] - duration for the
+ * message to be displayed [ms]
+ */
IPA.notify_success = function(message, timeout) {
if (!message) return; // don't show undefined, null and such
@@ -1951,6 +2555,12 @@ IPA.notify_success = function(message, timeout) {
}, timeout || IPA.config.message_timeout);
};
+/**
+ * Get number of succeeded commands in RPC command
+ * @member IPA
+ * @param {Object} data - RPC command data
+ * @return {number}
+ */
IPA.get_succeeded = function(data) {
var succeeded = data.result.completed;
@@ -1966,6 +2576,15 @@ IPA.get_succeeded = function(data) {
return succeeded;
};
+/**
+ * Global configuration
+ * @member IPA
+ * @property {number} default_priority - command default priority. Used in
+ * 'update info' concept
+ * @property {number} message_timeout - timeout for notification messages
+ * @property {number} message_fadeout_time
+ * @property {number} message_fadein_time
+ */
IPA.config = {
default_priority: 500,
message_timeout: 3000, // [ms]
diff --git a/install/ui/src/freeipa/menu.js b/install/ui/src/freeipa/menu.js
index c903e16df..3da643890 100644
--- a/install/ui/src/freeipa/menu.js
+++ b/install/ui/src/freeipa/menu.js
@@ -18,11 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Menu proxy.
- *
- * Exports public interface for dealing with menu items.
- */
+
define([
'dojo/_base/lang',
'./app', // creates circular dependency
@@ -37,12 +33,20 @@ define([
},
/**
+ * Menu proxy.
+ *
+ * Exports public interface for dealing with menu items.
+ * @class menu
+ */
+
+ /**
* Adds menu item.
* Takes a spec of menu item.
* Normalizes item's name, parent, adds children if specified
*
- * @param {menu_item} items
- * @param {String|menu_item} parent
+ * @method add_item
+ * @param {navigation.MenuItem} item
+ * @param {string|navigation.MenuItem} parent
* @param {Object} options
*/
add_item = function(item, parent, options) {
@@ -53,8 +57,8 @@ define([
/**
* Removes menu item
*
- * @param {String|menu_item} name or menu item to remove
- *
+ * @method remove_item
+ * @param {string|navigation.MenuItem} name or menu item to remove
*/
remove_item = function(item) {
@@ -66,9 +70,10 @@ define([
* Query internal data store by using default search options or supplied
* search options.
*
- * @param Object Query filter
- * @param ?Object Search options, overrides default
- * @return QueryResult
+ * @method query
+ * @param {Object} query
+ * @param {Object} [search_options] Search options, overrides default
+ * @return {QueryResult}
*/
query = function(query, search_options) {
@@ -83,6 +88,8 @@ define([
/**
* Get current instance of menu
+ * @method get
+ * @return {navigation.Menu}
*/
get = function() {
return get_menu();
diff --git a/install/ui/src/freeipa/metadata.js b/install/ui/src/freeipa/metadata.js
index d33d3ae8f..cfdc91b11 100644
--- a/install/ui/src/freeipa/metadata.js
+++ b/install/ui/src/freeipa/metadata.js
@@ -24,6 +24,22 @@ define([
'./_base/Search_provider'
], function(lang, Provider, Search_provider) {
+ /**
+ * Metadata provider
+ *
+ * Contains multiple providers for specific metadata searches:
+ *
+ * - `@m:`: provider for whole metadata
+ * - `@mo:`: provider for objects (entities)
+ * - `@mc:`: provider for commands
+ * - `@mo-param:`: search provider for object params
+ * - `@mc-arg:`: search provider for command arguments
+ * - `@mc-opt:`: search provider for command options
+ *
+ * @class metadata
+ * @singleton
+ * @extends _base.Provider
+ */
var metadata = new Provider({
code: '@m:'
});
diff --git a/install/ui/src/freeipa/navigation.js b/install/ui/src/freeipa/navigation.js
index 038732cee..8b96d6f97 100644
--- a/install/ui/src/freeipa/navigation.js
+++ b/install/ui/src/freeipa/navigation.js
@@ -18,15 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Navigation tells application to show certain facet.
- *
- * It's proxy for navigation/Router instance in current running
- * application.
- *
- * Modules just use the interface, they don't have to care about the logic in
- * the background.
- */
+
define([
'dojo/_base/lang',
'./app', // creates circular dependency
@@ -41,14 +33,25 @@ define([
},
/**
+ * Navigation tells application to show certain facet.
+ *
+ * It's proxy for navigation/Router instance in current running
+ * application.
+ *
+ * Modules just use the interface, they don't have to care about the logic in
+ * the background.
+ * @class navigation
+ */
+
+ /**
* Sets property of params depending on arg type following way:
* for String sets params.facet
* for Facet sets params.facet (based on show function)
* for Object sets params.args
* for Array sets params.pkeys
- *
+ * @ignore
* @param Object params
- * @param {Object|Facet|String|Function} arg
+ * @param {Object|facet.facet|string|Function} arg
*/
set_params = function(params, arg) {
if (lang.isArray(arg)) {
@@ -78,7 +81,10 @@ define([
*
* When it's an object (Facet) and has an entity set it will be
* dealt as entity facet.
- *
+ * @method show
+ * @param {Object|facet.facet|string|Function} arg1
+ * @param {Object|facet.facet|string|Function} arg2
+ * @param {Object|facet.facet|string|Function} arg3
*/
show = function(arg1, arg2, arg3) {
@@ -111,17 +117,17 @@ define([
},
/**
- * Show entity facet.
- *
- * @param String Enity name
- * @param {Object|Facet|String|Function} arg1
- * @param {Object|Facet|String|Function} arg2
- * @param {Object|Facet|String|Function} arg3
+ * Show entity facet
*
* arg1,arg2,arg3 are:
* facet name as String
* pkeys as Array
* args as Object
+ * @method show_entity
+ * @param String Enity name
+ * @param {Object|facet.facet|string|Function} arg1
+ * @param {Object|facet.facet|string|Function} arg2
+ * @param {Object|facet.facet|string|Function} arg3
*/
show_entity = function(entity_name, arg1, arg2, arg3) {
var nav = get_router();
@@ -134,6 +140,10 @@ define([
params.pkeys, params.args);
},
+ /**
+ * Show default facet
+ * @method show_default
+ */
show_default = function() {
// TODO: make configurable
return show_entity('user', 'search');
diff --git a/install/ui/src/freeipa/navigation/Menu.js b/install/ui/src/freeipa/navigation/Menu.js
index 677171d4d..a5e96d3c9 100644
--- a/install/ui/src/freeipa/navigation/Menu.js
+++ b/install/ui/src/freeipa/navigation/Menu.js
@@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
define(['dojo/_base/declare',
'dojo/store/Memory',
'dojo/_base/array',
@@ -29,67 +28,45 @@ define(['dojo/_base/declare',
'../text'
], function(declare, Memory_store, array, lang, Observable, Evented, reg, text) {
-/**
- * Menu store
- *
- * Maintains menu hierarchy and selection state.
- */
-return declare([Evented], {
+return declare([Evented],
/**
- * Following properties can be specified in menu item spec:
- * @property {String} name
- * @property {String} label
- * @property {String} title
- * @property {Number} position: position among siblings
- * @property {menu_item_spec_array} children
- * @property {String} entity: entity name
- * @property {String} facet: facet name
- * @property {Boolean} hidden: menu item is no visible, but can serve for
- * other evaluations (nested entities)
- *
- * Following properties are not in created menu item:
- * - children
+ * Menu store
*
+ * Maintains menu hierarchy and selection state.
*
- * Following properties can be stored in menu item at runtime:
- *
- * @property {Boolean} selected
- * @property {String} parent: name of parent menu item
- * @property {String} selected_child: last selected child. Can be set even
- * if the child is not selected
+ * @class navigation.Menu
*
*/
-
+ {
/**
* Menu name
- * @type String
+ * @property {String}
*/
name: null,
/**
* Dojo Store of menu items
- * @type: Store
+ * @property {Store}
*/
items: null,
/**
* Delimiter used in name creation
* To avoid having multiple menu items with the same name.
- * @type String
+ * @property {String}
*/
path_delimiter: '/',
/**
* Selected menu items
- * @type Array of menu items
+ * @property {Array}
*/
selected: [],
/**
* Default search options: sort by position
- *
- * @type Object
+ * @property {Object}
*/
search_options: { sort: [{attribute:'position'}]},
@@ -97,8 +74,8 @@ return declare([Evented], {
* Takes a spec of menu item.
* Normalizes item's name, parent, adds children if specified
*
- * @param {menu_item} items
- * @param {String|menu_item} parent
+ * @param {Object} item - spec
+ * @param {string/Object} parent - name or menu item
* @param {Object} options
*/
add_item: function(item, parent, options) {
@@ -168,6 +145,10 @@ return declare([Evented], {
return true;
},
+ /**
+ * Add multiple items
+ * @param {Array} items - spec of items
+ */
add_items: function(/* Array */ items) {
array.forEach(items, function(item) {
this.add_item(item);
@@ -177,8 +158,8 @@ return declare([Evented], {
/**
* Query internal data store by using default search options.
*
- * @param Object Query filter
- * @return QueryResult
+ * @param {Object} Query filter
+ * @return {QueryResult}
*/
query: function(query) {
return this.items.query(query, this.search_options);
@@ -186,6 +167,7 @@ return declare([Evented], {
/**
* Marks item and all its parents as selected.
+ * @private
*/
_select: function(item) {
@@ -202,7 +184,7 @@ return declare([Evented], {
/**
* Selects a menu item and all it's ancestors.
- * @param {string|menu_item} Menu item to select
+ * @param {string/navigation.MenuItem} item menu item to select
*/
select: function(item) {
@@ -234,6 +216,11 @@ return declare([Evented], {
return select_state;
},
+ /**
+ * @param {Object} spec - Specification object
+ * @param {Array} spec.items - Menu items
+ * @param {string} spec.name - Name
+ */
constructor: function(spec) {
spec = spec || {};
this.items = new Observable( new Memory_store({
@@ -246,4 +233,4 @@ return declare([Evented], {
declare.safeMixin(this, spec);
}
}); //declare freeipa.menu
-}); //define \ No newline at end of file
+}); //define
diff --git a/install/ui/src/freeipa/navigation/MenuItem.js b/install/ui/src/freeipa/navigation/MenuItem.js
new file mode 100644
index 000000000..1b2358cf6
--- /dev/null
+++ b/install/ui/src/freeipa/navigation/MenuItem.js
@@ -0,0 +1,98 @@
+/* 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/>.
+*/
+
+/**
+ * This is a virtual object which serves only for documentation purposes. It
+ * describes what properties has the created menu item and what can be part
+ * of menu item object specification.
+ *
+ * Following properties are not in created in menu item:
+ *
+ * - children
+ *
+ * Following properties may be part of menu item at runtime:
+ *
+ * - selected
+ * - parent
+ * - selected_child
+ *
+ * @class navigation.MenuItem
+ * @abstract
+ */
+var MenuItem = {
+ /**
+ * Name - menu item identifier
+ */
+ name: '',
+
+ /**
+ * Visible text
+ */
+ label: '',
+
+ /**
+ * Title/Tooltip
+ */
+ title: '',
+
+ /**
+ * Position for ordering
+ */
+ position: 0,
+
+ /**
+ * Children
+ *
+ * - next navigation level
+ * @property {Array.<navigation.MenuItem>}
+ */
+ children: null,
+
+ /**
+ * Entity name
+ */
+ entity: '',
+
+ /**
+ * Facet name
+ */
+ facet: '',
+
+ /**
+ * Control item visibility but can serve for other evaluations (nested entities)
+ */
+ hidden: '',
+
+ /**
+ * Runtime property
+ * Should not be set by hand. Indicates whether item is selected.
+ */
+ selected: false,
+
+ /**
+ * Parent menu item's name
+ */
+ parent: null,
+
+ /**
+ * Some child is selectd. Runtime property.
+ */
+ selected_child: null
+};
diff --git a/install/ui/src/freeipa/navigation/Router.js b/install/ui/src/freeipa/navigation/Router.js
index 3ac8357ed..a3b2a6791 100644
--- a/install/ui/src/freeipa/navigation/Router.js
+++ b/install/ui/src/freeipa/navigation/Router.js
@@ -30,31 +30,34 @@ define(['dojo/_base/declare',
function(declare, lang, array, Evented, ioquery, router, IPA, reg) {
/**
- * Class navigation
+ * Router
+ *
* This component keeps menu and routes in sync. It signalizes
* other components to display facet by sending 'show-facet' event.
* Other components can use navigate_to_* methods to change currently
* displayed facet. This change can be canceled in 'facet-change'
* event handler.
+ * @class navigation.Router
*/
var navigation = declare([Evented], {
/**
* Holds references to register route handlers.
* Can be used for unregistering routes.
- * @type Array
+ * @property {Array.<Function>}
*/
route_handlers: [],
/**
* Prefix of all routes for this navigation. Useful for multiple
* navigation objects in one application.
- * @type String
+ * @property {string}
*/
route_prefix: '',
/**
* Variations of entity routes
+ * @property {Array.<string>}
*/
entity_routes: [
'/e/:entity/:facet/:pkeys/*args',
@@ -66,6 +69,7 @@ define(['dojo/_base/declare',
/**
* Variations of simple page routes
+ * @property {Array.<string>}
*/
page_routes: [
'/p/:page/*args',
@@ -75,7 +79,7 @@ define(['dojo/_base/declare',
/**
* Used during facet changing. Set it to true in 'facet-change'
* event handler to stop the change.
- * @type Boolean
+ * @property {boolean}
*/
canceled: false,
@@ -83,7 +87,7 @@ define(['dojo/_base/declare',
* Flag to indicate that next hash change should not invoke showing a
* facet.
* Main purpose: updating hash.
- * @type Boolen
+ * @property {boolean}
*/
ignore_next: false,
@@ -92,8 +96,8 @@ define(['dojo/_base/declare',
* Register a route-handler pair to a dojo.router
* Handler will be run in context of this object
*
- * @param {string|array} route or routes to register
- * @param {function} handler to be associated with the route(s)
+ * @param {string|Array.<string>} route or routes to register
+ * @param {Function} handler to be associated with the route(s)
*/
register_route: function(route, handler) {
// TODO: add multiple routes for one handler
@@ -121,6 +125,7 @@ define(['dojo/_base/declare',
/**
* Handler for entity routes
* Shouldn't be invoked directly.
+ * @param {Object} event route event args
*/
entity_route_handler: function(event) {
@@ -157,6 +162,7 @@ define(['dojo/_base/declare',
/**
* General facet route handler
* Shouldn't be invoked directly.
+ * @param {Object} event route event args
*/
page_route_handler: function(event) {
@@ -249,8 +255,8 @@ define(['dojo/_base/declare',
/**
* Changes hash to supplied
*
- * @param {String} Hash to set
- * @param {Boolean} Whether to suppress following hash change handler
+ * @param {string} Hash to set
+ * @param {boolean} Whether to suppress following hash change handler
*/
update_hash: function(hash, ignore_change) {
this.ignore_next = !!ignore_change;
@@ -299,7 +305,7 @@ define(['dojo/_base/declare',
/**
* Creates hash from supplied facet and state.
*
- * @param {facet} facet
+ * @param {facet.facet} facet
* @param {Object} state
*/
create_hash: function(facet, state) {
@@ -346,6 +352,11 @@ define(['dojo/_base/declare',
return keys;
},
+ /**
+ * Raise 'error'
+ * @protected
+ * @fires error
+ */
_error: function(msg, type, context) {
this.emit('error', {
diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js
index 66116b583..9d4c5eff9 100644
--- a/install/ui/src/freeipa/navigation/menu_spec.js
+++ b/install/ui/src/freeipa/navigation/menu_spec.js
@@ -20,7 +20,15 @@
define([], function() {
+/**
+ * Specification of menu
+ * @singleton
+ * @class navigation.menu_spec
+ */
var nav = {};
+ /**
+ * Admin menu
+ */
nav.admin = {
name: 'admin',
items: [
@@ -131,6 +139,9 @@ var nav = {};
]
};
+/**
+ * Self-service menu
+ */
nav.self_service = {
name: 'self-service',
items: [
diff --git a/install/ui/src/freeipa/netgroup.js b/install/ui/src/freeipa/netgroup.js
index 4b2de497a..2922d5b94 100644
--- a/install/ui/src/freeipa/netgroup.js
+++ b/install/ui/src/freeipa/netgroup.js
@@ -77,6 +77,7 @@ var spec = {
/**
+ * @ignore
* @param {Object} facet spec
*/
var add_netgroup_details_facet_widgets = function (spec) {
diff --git a/install/ui/src/freeipa/ordered-map.js b/install/ui/src/freeipa/ordered-map.js
index c8c735a39..70e23b1cf 100644
--- a/install/ui/src/freeipa/ordered-map.js
+++ b/install/ui/src/freeipa/ordered-map.js
@@ -24,6 +24,7 @@ define([
], function($) {
/**
* Wrapper for jquery.ordered_map
+ * @class ordered_map
*/
return $.ordered_map;
}); \ No newline at end of file
diff --git a/install/ui/src/freeipa/phases.js b/install/ui/src/freeipa/phases.js
index 18acecc8a..86605e3d6 100644
--- a/install/ui/src/freeipa/phases.js
+++ b/install/ui/src/freeipa/phases.js
@@ -18,18 +18,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Phases module provides access mainly serves as an registration point for
- * phase tasks. It also provides access to Phase controller.
- */
define([
'./_base/Phase_controller'
], function(Phase_controller) {
/**
* Phases specification object.
- *
- * @type String[]
+ * @ignore
+ * @property {string[]}
*/
var spec = {
phases: [
@@ -47,6 +43,12 @@ define([
/**
* Phases module
+ *
+ * Provides access mainly serves as an registration point for
+ * phase tasks. It also provides access to Phase controller.
+ *
+ * @class phases
+ * @singleton
*/
var phases = {
/**
@@ -57,9 +59,9 @@ define([
/**
* Registers a phase task
*
- * @param {String} Phase name
- * @param {Function} Task handler. Should return promise if async.
- * @param {Number} Priority of task. Default 10.
+ * @param {string} phase_name
+ * @param {Function} handler Task handler. Should return promise if async.
+ * @param {number} [priority=10]
*/
on: function(phase_name, handler, priority) {
this.controller.add_task(phase_name, handler, priority);
@@ -73,8 +75,8 @@ define([
* after: 'name-of-phase'
* position: 'position for new phase'
*
- * @param {String} Phase name
- * @param {Object} Options
+ * @param {string} phase_name
+ * @param {Object} options
*/
add: function(phase_name, options) {
this.controller.add_phase(phase_name, null, options);
@@ -83,8 +85,8 @@ define([
/**
* Checks if phases with given name exists
*
- * @param {String} Name
- * @return {Boolean}
+ * @param {string} name
+ * @return {boolean}
*/
exists: function(name) {
return this.controller.exists(name);
diff --git a/install/ui/src/freeipa/plugin_loader.js b/install/ui/src/freeipa/plugin_loader.js
index ce545301b..de3bc4357 100644
--- a/install/ui/src/freeipa/plugin_loader.js
+++ b/install/ui/src/freeipa/plugin_loader.js
@@ -18,9 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * Plugin loader
- */
define([
'dojo/_base/array',
'dojo/_base/lang',
@@ -28,8 +25,17 @@ define([
'dojo/promise/all'
],function(array, lang, Deferred, all) {
+ /**
+ * Plugin loader
+ * @class
+ * @singleton
+ */
var plugin_loader = {
+ /**
+ * Register plugins
+ * @param {Array.<string>} plugins
+ */
register_plugins: function(plugins) {
var packages = [];
@@ -44,6 +50,11 @@ define([
require({ packages: packages});
},
+ /**
+ * Load plugin
+ * @param {string} name
+ * @return {Promise}
+ */
load_plugin: function(name) {
var plugin_loaded = new Deferred();
@@ -56,6 +67,12 @@ define([
return plugin_loaded.promise;
},
+ /**
+ * Load plugins
+ *
+ * - loads plugin list from `freeipa/plugins` module.
+ * @return {Promise}
+ */
load_plugins: function() {
var plugins_loaded = new Deferred();
diff --git a/install/ui/src/freeipa/reg.js b/install/ui/src/freeipa/reg.js
index 62319d9bc..e045d4617 100644
--- a/install/ui/src/freeipa/reg.js
+++ b/install/ui/src/freeipa/reg.js
@@ -25,19 +25,22 @@
* Construct registry do. It's expected that there will be different types of
* registries for various object types.
*
- * Existing registries can be access directly by properties.
+ * Existing registries can be accessed directly by properties.
*
* Use set method for setting new registry.
- * Use get/registry method for getting/registering of object in a registry.
+ * Use get/registry method for getting/registering object in a registry.
+ *
+ * Registries should be named by their object type in singular form:
*
- * Registries should be named by their object type in singular form.
- * I.e.:
* * entity
* * widget
* * action
* * formatter
* * facet
* * dialog
+ *
+ * @class reg
+ * @singleton
*/
define(['dojo/_base/declare',
'dojo/_base/array',
@@ -49,17 +52,36 @@ define(['dojo/_base/declare',
reg.builder.ctor = Singleton_registry;
var exp = reg._map;
+
+ /**
+ * Get registry
+ * @param {string} object_type
+ * @param {string} type
+ * @return {_base.Construct_registry/_base.Singleton_registry}
+ */
exp.get = function(object_type, type) {
var registry = reg.get(object_type);
return registry.get(type);
};
+ /**
+ * Create and register new registry
+ * @param {string} object_type
+ * @param {string} type
+ * @param {Function} func
+ * @param {Object} default_spec
+ */
exp.register = function(object_type, type, func, default_spec) {
var registry = reg.get(object_type);
registry.register(type, func, default_spec);
};
+ /**
+ * Set new registry
+ * @param {string} object_type
+ * @param {_base.Construct_registry|_base.Singleton_registry} registry
+ */
exp.set = function(object_type, registry) {
reg.set(object_type, registry);
};
diff --git a/install/ui/src/freeipa/selinux.js b/install/ui/src/freeipa/selinux.js
index 8a308b434..e71487667 100644
--- a/install/ui/src/freeipa/selinux.js
+++ b/install/ui/src/freeipa/selinux.js
@@ -108,6 +108,7 @@ var spec = {
/**
+ * @ignore
* @param {Object} facet spec
*/
var add_selinux_details_facet_widgets = function (spec) {
diff --git a/install/ui/src/freeipa/spec_util.js b/install/ui/src/freeipa/spec_util.js
index 7d60dc101..1053ebd1d 100644
--- a/install/ui/src/freeipa/spec_util.js
+++ b/install/ui/src/freeipa/spec_util.js
@@ -25,13 +25,18 @@ define(['dojo/_base/declare',
var undefined;
+ /**
+ * Utility for working with specification objects
+ * @class spec_util
+ * @singleton
+ */
var exp = {
/**
* Set default value of spec's attribute when not already
*
* @param {Object} spec
- * @param {String} attribute name
+ * @param {string} attribute name
* @param {*} default value
* @param {Object} object
*/
diff --git a/install/ui/src/freeipa/sudo.js b/install/ui/src/freeipa/sudo.js
index cb620e41b..b01621ddd 100644
--- a/install/ui/src/freeipa/sudo.js
+++ b/install/ui/src/freeipa/sudo.js
@@ -226,6 +226,7 @@ return {
};};
/**
+ * @ignore
* @param {Object} facet spec
*/
var add_sudorule_details_facet_widgets = function (spec) {
diff --git a/install/ui/src/freeipa/text.js b/install/ui/src/freeipa/text.js
index a439237ae..776b9ee0d 100644
--- a/install/ui/src/freeipa/text.js
+++ b/install/ui/src/freeipa/text.js
@@ -18,15 +18,23 @@
* 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', './metadata'],
function(Provider, i18n, metadata) {
+ /**
+ * Text provider
+ *
+ * Serves for returning labels, titles, messages from:
+ *
+ * - {@link _base.i18n} provider
+ * - and {@link metadata} provider
+ *
+ * Other providers can extends its functionality.
+ *
+ * @class text
+ * @singleton
+ * @extends _base.Provider
+ */
var text = new Provider({
providers: [
i18n,
diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js
index 1fdcf25a5..34c3a7adf 100644
--- a/install/ui/src/freeipa/user.js
+++ b/install/ui/src/freeipa/user.js
@@ -34,6 +34,12 @@ define([
'./certificate'],
function(IPA, $, phases, reg, text) {
+/**
+ * User module
+ * @class user
+ * @alternateClassName IPA.user
+ * @singleton
+ */
var exp = IPA.user = {};
var make_spec = function() {
@@ -409,6 +415,7 @@ IPA.user.details_facet = function(spec) {
};
/**
+ * @member user
* Makes user association facets read-only in self service
*/
IPA.user.association_facet_ss_pre_op = function(spec, context) {
diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js
index d42b2008d..3891bf9b1 100644
--- a/install/ui/src/freeipa/widget.js
+++ b/install/ui/src/freeipa/widget.js
@@ -33,38 +33,122 @@ define(['dojo/_base/array',
],
function(array, lang, builder, IPA, $, phases, reg, text) {
+/**
+ * Widget module
+ * =============
+ *
+ * External usage:
+ *
+ * var widget = require('freeipa/widget')
+ * @class widget
+ * @singleton
+ */
var exp = {};
+/**
+ * Width of column which contains only checkbox
+ * @member IPA
+ * @property {number}
+ */
IPA.checkbox_column_width = 22;
+
+/**
+ * String to show next to required fields to indicate that the field is required.
+ * @member IPA
+ * @property {string}
+ */
IPA.required_indicator = '*';
+/**
+ * Base widget
+ * @class
+ * @param {Object} spec
+ * @abstract
+ */
IPA.widget = function(spec) {
spec = spec || {};
var that = IPA.object();
+ /**
+ * Widget name. Should be container unique.
+ */
that.name = spec.name;
+
+ /**
+ * Widget element ID.
+ * @deprecated
+ */
that.id = spec.id;
+
+ /**
+ * Label
+ * @property {string}
+ */
that.label = text.get(spec.label);
+
+ /**
+ * Helper text
+ * @property {string}
+ */
that.tooltip = text.get(spec.tooltip);
+
+ /**
+ * Measurement unit
+ * @property {string}
+ */
that.measurement_unit = spec.measurement_unit;
+
+ /**
+ * Parent entity
+ * @deprecated
+ * @property {IPA.entity}
+ */
that.entity = IPA.get_entity(spec.entity); //some old widgets still need it
+
+ /**
+ * Parent facet
+ * @property {IPA.facet}
+ */
that.facet = spec.facet;
+
+ /**
+ * Widget is enabled - can be focus and edited (depends also on writable
+ * and read_only)
+ * @property {boolean}
+ */
that.enabled = spec.enabled === undefined ? true : spec.enabled;
+ /**
+ * Create HTML representation of a widget.
+ * @method
+ * @param {HTMLElement} container - Container node
+ */
that.create = function(container) {
container.addClass('widget');
that.container = container;
};
+ /**
+ * Reset widget content. All user-modifiable information have to be
+ * changed back to widgets defaults.
+ */
that.clear = function() {
};
+ /**
+ * Set enabled state.
+ * @param {boolean} value - True - enabled; False - disabled
+ */
that.set_enabled = function(value) {
that.enabled = value;
};
+ /**
+ * Whether widget should be displayed.
+ * @param {boolean} value - True - visible; False - hidden
+ */
that.set_visible = function(visible) {
if (visible) {
@@ -74,6 +158,12 @@ IPA.widget = function(spec) {
}
};
+ /**
+ * Utility method. Build widget based on spec with this widget's context.
+ * @param {boolean} spec - Widget specification object
+ * @param {Object} context - Context object. Gets mixed with this widget context.
+ * @param {Object} overrides - Build overrides
+ */
that.build_child = function(spec, context, overrides) {
var def_c = {
@@ -91,27 +181,90 @@ IPA.widget = function(spec) {
return that;
};
+/**
+ * Base class for input gathering widgets.
+ * @class
+ * @extends IPA.widget
+ * @abstract
+ */
IPA.input_widget = function(spec) {
spec = spec || {};
var that = IPA.widget(spec);
+ /**
+ * Widget's width.
+ * @deprecated
+ * @property {number}
+ */
that.width = spec.width;
+
+ /**
+ * Widget's height.
+ * @deprecated
+ * @property {number}
+ */
that.height = spec.height;
+ /**
+ * Enable undo button showing. Undo button is displayed when user
+ * modifies data.
+ * @property {boolean} undo=true
+ */
that.undo = spec.undo === undefined ? true : spec.undo;
+
+ /**
+ * User has rights to modify widgets content. Ie. based on LDAP ACL.
+ * @property {boolean} writable=true
+ */
that.writable = spec.writable === undefined ? true : spec.writable;
+
+ /**
+ * This widget content is read-only.
+ * @property {boolean}
+ */
that.read_only = spec.read_only;
+
+ /**
+ * Mark the widget to be hidden (form or dialog may not display it).
+ * @property {boolean}
+ */
that.hidden = spec.hidden;
//events
//each widget can contain several events
+ /**
+ * Value changed event.
+ *
+ * Raised when user modifies data by hand.
+ *
+ * @event
+ */
that.value_changed = IPA.observer();
+
+ /**
+ * Undo clicked event.
+ *
+ * @event
+ */
that.undo_clicked = IPA.observer();
+
+ /**
+ * Updated event.
+ *
+ * Raised when widget content gets updated - raised by
+ * {@link IPA.input_widget#update} method.
+ *
+ * @event
+ */
that.updated = IPA.observer();
+ /**
+ * Creates HTML representation of error link
+ * @param {HTMLElement} container - node to place the error link
+ */
that.create_error_link = function(container) {
container.append(' ');
@@ -122,6 +275,10 @@ IPA.input_widget = function(spec) {
}).appendTo(container);
};
+ /**
+ * Creates HTML representation of required indicator.
+ * @param {HTMLElement} container - node to place the indicator
+ */
that.create_required = function(container) {
that.required_indicator = $('<span/>', {
'class': 'required-indicator',
@@ -130,6 +287,11 @@ IPA.input_widget = function(spec) {
}).appendTo(container);
};
+ /**
+ * Update displayed information by supplied values.
+ * @param {Object|Array|null} values - values to be edited/displayed by
+ * widget.
+ */
that.update = function() {
};
@@ -137,6 +299,7 @@ IPA.input_widget = function(spec) {
* This function saves the values entered in the UI.
* It returns the values in an array, or null if
* the field should not be saved.
+ * @returns {Array|null} entered values
*/
that.save = function() {
return [];
@@ -147,6 +310,8 @@ IPA.input_widget = function(spec) {
* On_undo is a link click callback. It can be specified to custom
* callback. If a callback isn't set, default callback is used. If
* spefified to value other than a function, no callback is registered.
+ * @param {HTMLElement} container
+ * @param {Function} link clicked callback
*/
that.create_undo = function(container, on_undo) {
container.append(' ');
@@ -170,33 +335,60 @@ IPA.input_widget = function(spec) {
}
};
+ /**
+ * Get reference to undo element
+ * @return {jQuery} undo button jQuery reference
+ */
that.get_undo = function() {
return $(that.undo_span);
};
+ /**
+ * Display undo button
+ */
that.show_undo = function() {
that.get_undo().css('display', 'inline');
};
+ /**
+ * Hide undo button
+ */
that.hide_undo = function() {
$(that.undo_span).css('display', 'none');
};
+ /**
+ * Get error link reference
+ * @return {jQuery} error link jQuery reference
+ */
that.get_error_link = function() {
return $('span[name="error_link"]', that.container);
};
+ /**
+ * Show error message
+ * @protected
+ * @param {string} message
+ */
that.show_error = function(message) {
var error_link = that.get_error_link();
error_link.html(message);
error_link.css('display', 'block');
};
+ /**
+ * Hide error message
+ * @protected
+ */
that.hide_error = function() {
var error_link = that.get_error_link();
error_link.css('display', 'none');
};
+ /**
+ * Set required
+ * @param {boolean} required
+ */
that.set_required = function(required) {
that.required = required;
@@ -206,6 +398,10 @@ IPA.input_widget = function(spec) {
}
};
+ /**
+ * Set enabled
+ * @param {boolean} value - enabled
+ */
that.set_enabled = function(value) {
that.widget_set_enabled(value);
@@ -214,16 +410,35 @@ IPA.input_widget = function(spec) {
}
};
+ /**
+ * Raise value change event
+ * @protected
+ */
that.on_value_changed = function() {
var value = that.save();
that.value_changed.notify([value], that);
};
+ /**
+ * Widget is writable
+ * @return {boolean}
+ */
that.is_writable = function() {
return !that.read_only && !!that.writable;
};
+ /**
+ * Focus input element
+ * @abstract
+ */
that.focus_input = function() {};
+
+ /**
+ * Mark element as deleted.
+ *
+ * Ie. textbox with strike-through
+ * @abstract
+ */
that.set_deleted = function() {};
// methods that should be invoked by subclasses
@@ -233,7 +448,14 @@ IPA.input_widget = function(spec) {
return that;
};
-/*uses a browser specific technique to select a range.*/
+/**
+ * Select text in input.
+ * Uses a browser specific technique to select a range.
+ * @member IPA
+ * @param {jQuery} input jQuery reference
+ * @param {number} start
+ * @param {number} end
+ */
IPA.select_range = function(input,start, end) {
input.focus();
if (input[0].setSelectionRange) {
@@ -247,20 +469,40 @@ IPA.select_range = function(input,start, end) {
}
};
-
+/**
+ * A textbox widget. Displayed as label when not modifiable.
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.text_widget = function(spec) {
spec = spec || {};
var that = IPA.input_widget(spec);
+ /**
+ * Size of the input.
+ * @property {number}
+ */
that.size = spec.size || 30;
+
+ /**
+ * Input type
+ * @property {string} input_type='text'
+ */
that.input_type = spec.input_type || 'text';
+
+ /**
+ * Select range of text
+ */
that.select_range = function(start, end){
IPA.select_range(that.input, start, end);
};
+ /**
+ * @inheritDoc
+ */
that.create = function(container) {
that.widget_create(container);
@@ -294,6 +536,9 @@ IPA.text_widget = function(spec) {
that.set_enabled(that.enabled);
};
+ /**
+ * @inheritDoc
+ */
that.update = function(values) {
var value = values && values.length ? values[0] : '';
@@ -310,6 +555,9 @@ IPA.text_widget = function(spec) {
that.updated.notify([], that);
};
+ /**
+ * @inheritDoc
+ */
that.save = function() {
if (!that.is_writable()) {
return null;
@@ -319,15 +567,24 @@ IPA.text_widget = function(spec) {
}
};
+ /**
+ * @inheritDoc
+ */
that.clear = function() {
that.input.val('');
that.display_control.text('');
};
+ /**
+ * @inheritDoc
+ */
that.focus_input = function() {
that.input.focus();
};
+ /**
+ * @inheritDoc
+ */
that.set_deleted = function(deleted) {
if(deleted) {
that.input.addClass('strikethrough');
@@ -342,6 +599,11 @@ IPA.text_widget = function(spec) {
return that;
};
+/**
+ * @class
+ * @extends IPA.text_widget
+ * A textbox widget where input type is 'password'.
+ */
IPA.password_widget = function(spec) {
spec = spec || {};
@@ -351,6 +613,12 @@ IPA.password_widget = function(spec) {
return that;
};
+/**
+ * Widget which allows to edit multiple values. It display one
+ * editor (text widget by default) for each value.
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.multivalued_widget = function(spec) {
spec = spec || {};
@@ -644,26 +912,35 @@ IPA.multivalued_widget = function(spec) {
};
/**
- * Widget base for checkboxes and radios. Doesn't handle dirty state's but
- * its supposed to be nestable.
+ * Option widget base
+ *
+ * @class IPA.option_widget_base
+ * @mixin
+ *
+ * Widget base for checkboxes and radios. Doesn't handle dirty states but
+ * it's nestable.
*
* Nesting rules:
- * 1. parent should be checked when one of its child is checked
+ *
+ * 1. parent should be checked when one of its child is checked
+ *
* Consequences:
- * * childs get unchecked when parent gets unchecked
- * * parent will be checked when child is checked even when input
+ * - childs get unchecked when parent gets unchecked
+ * - parent will be checked when child is checked even when input
* values don't contain parent's value.
- * 2. parent can be configured not to include it's value when children are
+ * 2. parent can be configured not to include it's value when children are
* checked
- * 3. each subtree containing a checked input has to return at least one value
+ * 3. each subtree containing a checked input has to return at least one value
* on save()
- * 4. each option has to have unique value
+ * 4. each option has to have unique value
*
* Has subset of widget interface - overrides the values in widget
- * * save(): get values
- * * update(values): set values
- * * value_changed: event when change happens
- * * create: creates HTML
+ *
+ * - save(): get values
+ * - update(values): set values
+ * - value_changed: event when change happens
+ * - create: creates HTML
+ *
*/
IPA.option_widget_base = function(spec, that) {
@@ -717,6 +994,7 @@ IPA.option_widget_base = function(spec, that) {
/**
* Normalizes options spec
+ * @protected
*/
that.prepare_options = function(options) {
@@ -732,14 +1010,17 @@ IPA.option_widget_base = function(spec, that) {
};
/**
- * Option has following interface: {
- * label: String
- * value: String
- * nested: Boolean
- * widget: Widget
- * combine_values: Boolean, default true. Whether to include this value
- * if some of its children is specified
- * }
+ * Prepare option
+ *
+ * Transform option spec to option.
+ * @protected
+ * @param {Object} spec
+ * @param {string} spec.label
+ * @param {string} spec.value
+ * @param {boolean} spec.nested
+ * @param {IPA.widget} spec.widget
+ * @param {boolean} spec.combine_values - default true. Whether to
+ * include this value if some of its children is specified
*/
that.prepare_option = function(spec) {
@@ -1071,15 +1352,27 @@ IPA.option_widget_base = function(spec, that) {
return that;
};
+
+/**
+ * Radio widget
+ *
+ * - default layout: inline
+ *
+ * @class IPA.radio_widget
+ * @extends IPA.input_widget
+ * @mixins IPA.option_widget_base
+ */
IPA.radio_widget = function(spec) {
spec = spec || {};
+
spec.input_type = spec.input_type || 'radio';
spec.layout = spec.layout || 'inline';
var that = IPA.input_widget(spec);
IPA.option_widget_base(spec, that);
+ /** @inheritDoc */
that.create = function(container) {
that.widget_create(container);
that.owb_create(container);
@@ -1094,6 +1387,13 @@ IPA.radio_widget = function(spec) {
return that;
};
+/**
+ * Single checkbox widget
+ *
+ * @class
+ * @extends IPA.input_widget
+ * @mixins IPA.option_widget_base
+ */
IPA.checkbox_widget = function (spec) {
var checked = 'checked';
@@ -1128,6 +1428,15 @@ IPA.checkbox_widget = function (spec) {
return that;
};
+/**
+ * Multiple checkbox widget
+ *
+ * - default layout: vertical
+ *
+ * @class
+ * @extends IPA.input_widget
+ * @mixins IPA.option_widget_base
+ */
IPA.checkboxes_widget = function (spec) {
spec = spec || {};
spec.input_type = spec.input_type || 'checkbox';
@@ -1136,6 +1445,12 @@ IPA.checkboxes_widget = function (spec) {
return that;
};
+/**
+ * Select widget
+ *
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.select_widget = function(spec) {
spec = spec || {};
@@ -1248,6 +1563,12 @@ IPA.select_widget = function(spec) {
return that;
};
+/**
+ * Textarea widget
+ *
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.textarea_widget = function (spec) {
spec = spec || {};
@@ -1313,20 +1634,40 @@ IPA.textarea_widget = function (spec) {
return that;
};
+/**
+ * Base class for formatters
+ *
+ * Formatter can be used in various widgets such as column to perform value
+ * parsing, normalization and output formatting.
+ *
+ * @class
+ */
IPA.formatter = function(spec) {
spec = spec || {};
var that = IPA.object();
- that.type = spec.type; // default is text
+ /**
+ * Type of output format
+ *
+ * - default: plain text
+ * @property {string}
+ */
+ that.type = spec.type;
- // parse attribute value into a normalized value
+ /**
+ * Parse attribute value into a normalized value
+ * @return parsed value
+ */
that.parse = function(value) {
return value;
};
- // format normalized value
+ /**
+ * Format normalized value
+ * @return formatted value
+ */
that.format = function(value) {
return value;
};
@@ -1334,18 +1675,30 @@ IPA.formatter = function(spec) {
return that;
};
+/**
+ * Formatter for boolean values
+ * @class
+ * @extends IPA.formatter
+ */
IPA.boolean_formatter = function(spec) {
spec = spec || {};
var that = IPA.formatter(spec);
+ /** Formatted value for true */
that.true_value = text.get(spec.true_value || '@i18n:true');
+ /** Formatted value for false */
that.false_value = text.get(spec.false_value || '@i18n:false');
+ /** Show formatted value if parsed value is false */
that.show_false = spec.show_false;
+ /** Parse return inverted value */
that.invert_value = spec.invert_value;
- // convert string boolean value into real boolean value, or keep the original value
+ /**
+ * Convert string boolean value into real boolean value, or keep
+ * the original value
+ */
that.parse = function(value) {
if (value === undefined || value === null) return '';
@@ -1371,7 +1724,9 @@ IPA.boolean_formatter = function(spec) {
return value;
};
- // convert boolean value into formatted string, or keep the original value
+ /**
+ * Convert boolean value into formatted string, or keep the original value
+ */
that.format = function(value) {
if (typeof value === 'boolean') {
@@ -1396,6 +1751,11 @@ IPA.boolean_formatter = function(spec) {
return that;
};
+/**
+ * Format as HTML disabled/enabled status icon
+ * @class
+ * @extends IPA.boolean_formatter
+ */
IPA.boolean_status_formatter = function(spec) {
spec = spec || {};
@@ -1418,7 +1778,11 @@ IPA.boolean_status_formatter = function(spec) {
return that;
};
-/* Take an LDAP format date in UTC and format it */
+/**
+ * Take an LDAP format date in UTC and format it
+ * @class
+ * @extends IPA.formatter
+ */
IPA.utc_date_formatter = function(spec) {
spec = spec || {};
@@ -1436,9 +1800,23 @@ IPA.utc_date_formatter = function(spec) {
return that;
};
-/*
- The entity name must be set in the spec either directly or via entity.name
-*/
+/**
+ * Column for {@link IPA.table_widget}
+ *
+ * Handles value rendering.
+ *
+ * @class
+ * @param {Object} spec
+ * @param {string|IPA.entity} spec.entity Entity or its name
+ * @param {string} spec.name
+ * @param {string} [spec.label]
+ * @param {number} [spec.width]
+ * @param {string} [spec.primary_key]
+ * @param {boolean} spec.link
+ * render as link
+ * @param {IPA.formatter|Object} spec.formatter
+ * formatter or its spec
+ */
IPA.column = function (spec) {
spec = spec || {};
@@ -1461,6 +1839,24 @@ IPA.column = function (spec) {
};
}
+ /**
+ * Extract value from record and set formatted value to a container
+ *
+ * - parses and formats value if formatter is set
+ * - also works with promises. Value can be a promise or promise can be
+ * encapsulated in a object along with temporal value.
+ *
+ * {
+ * promise: deffered.promise,
+ * temp: 'temporal value to be shown until promise is resolve'
+ * }
+ *
+ *
+ *
+ * @param {jQuery} container
+ * @param {Object} record - value is located using 'name' property
+ * @param {boolean} suppress_link
+ */
that.setup = function(container, record, suppress_link) {
var value = record[that.name];
var type;
@@ -1493,6 +1889,10 @@ IPA.column = function (spec) {
that.set_value(container, value, type, suppress_link);
};
+ /**
+ * Set value to the container
+ * @protected
+ */
that.set_value = function(container, value, type, suppress_link) {
value = value ? value.toString() : '';
@@ -1518,6 +1918,11 @@ IPA.column = function (spec) {
}
};
+ /**
+ * Handle clicks on link.
+ *
+ * Intended to be overridden.
+ */
that.link_handler = function(value) {
return false;
};
@@ -1535,6 +1940,25 @@ IPA.column = function (spec) {
return that;
};
+/**
+ * Table
+ *
+ * TODO: document properties and methods
+ *
+ * @class
+ * @extends IPA.input_widget
+ *
+ * @param {Object} spec
+ * @param {boolean} [spec.scrollable]
+ * @param {boolean} [spec.selectable=true]
+ * @param {boolean} [spec.save_values=true]
+ * @param {string} [spec.class] css class
+ * @param {boolean} [spec.pagination] render pagination
+ * @param {number} [spec.page_length=20]
+ * @param {boolean} [spec.multivalued=true]
+ * @param {Array} columns columns or columns specs
+ * @param {string} [value_attr_name=name]
+ */
IPA.table_widget = function (spec) {
spec = spec || {};
@@ -1937,6 +2361,13 @@ IPA.table_widget = function (spec) {
return $('input[name="'+that.name+'"]:checked', that.tbody).closest('tr');
};
+ /**
+ * Create record from supplied result.
+ *
+ * @param {Object} result
+ * @param {number} index Used when record information for each individual
+ * column is located in an array at given index
+ */
that.get_record = function(result, index) {
var record = {};
@@ -2066,7 +2497,29 @@ IPA.table_widget = function (spec) {
return that;
};
-
+/**
+ * Attribute table
+ *
+ * A table which acks as `IPA.association_table` but serves only for one
+ * multivalued attribute.
+ *
+ * TODO: document properties and methods
+ *
+ * @class
+ * @extends IPA.table_widget
+ *
+ * @param {Object} spec
+ * @param {string} [spec.attribute_nam] name of attribute if different
+ * than widget name
+ * @param {boolean} [spec.adder_dialog] adder dialog spec
+ * @param {boolean} [spec.css_class]
+ * @param {string} [spec.add_command] add command/method name
+ * @param {string} [spec.remove_command] remove command/method name
+ * @param {Function} [spec.on_add]
+ * @param {Function} [spec.on_add_error]
+ * @param {Function} [spec.on_remove]
+ * @param {Function} [spec.on_remove_error]
+ */
IPA.attribute_table_widget = function(spec) {
@@ -2408,6 +2861,27 @@ IPA.attribute_table_widget = function(spec) {
return that;
};
+/**
+ * Combobox widget
+ *
+ * Widget which allows to select a value from a predefined set or write custom
+ * value.
+ *
+ * TODO: document properties and methods
+ *
+ * @class
+ * @extends IPA.input_widget
+ *
+ * @param {Object} spec
+ * @param {string} [spec.attribute_nam] name of attribute if different
+ * than widget name
+ * @param {boolean} [spec.editable] user can write his own values
+ * @param {boolean} [spec.searchable]
+ * @param {number} [spec.size] number of rows in dropdown select
+ * @param {boolean} [spec.empty_option] has empty option
+ * @param {Array} [spec.options] - options to pick from
+ * @param {number} [spec.z_index]
+ */
IPA.combobox_widget = function(spec) {
spec = spec || {};
@@ -2830,6 +3304,23 @@ IPA.combobox_widget = function(spec) {
return that;
};
+/**
+ * Entity select widget
+ *
+ * Specialized combobox which allows to select an entity. Widget performs
+ * search - an RPC call - to get a list of entities.
+ *
+ * TODO: document properties and methods
+ *
+ * @class
+ * @extends IPA.combobox_widget
+ *
+ * @param {Object} spec
+ * @param {string} [spec.other_entity]
+ * @param {string} [spec.other_field]
+ * @param {Array} [spec.options]
+ * @param {Object} [spec.filter_options] RPC command options
+ */
IPA.entity_select_widget = function(spec) {
spec = spec || {};
@@ -2887,13 +3378,27 @@ IPA.entity_select_widget = function(spec) {
return that;
};
-
+/**
+ * Display value as a link or text
+ *
+ * @class
+ * @extends IPA.input_widget
+ *
+ * @param {Object} spec
+ * @param {boolean} [spec.is_link=false]
+ */
IPA.link_widget = function(spec) {
var that = IPA.input_widget(spec);
that.is_link = spec.is_link || false;
+
+ /**
+ * Raised when link is clicked
+ * @event
+ */
that.link_clicked = IPA.observer();
+ /** @inheritDoc */
that.create = function(container) {
that.widget_create(container);
that.link =
@@ -2911,6 +3416,7 @@ IPA.link_widget = function(spec) {
appendTo(container);
};
+ /** @inheritDoc */
that.update = function (values){
if (values || values.length > 0) {
@@ -2932,6 +3438,7 @@ IPA.link_widget = function(spec) {
that.updated.notify([], that);
};
+ /** @inheritDoc */
that.clear = function() {
that.nonlink.text('');
that.link.text('');
@@ -2941,6 +3448,25 @@ IPA.link_widget = function(spec) {
return that;
};
+/**
+ * Create link which behaves as button
+ *
+ * @method
+ * @member IPA
+ *
+ * @param {Object} spec
+ * @param {string} [spec.name]
+ * @param {string} [spec.label] button text
+ * @param {string} [spec.title=label] button title
+ * @param {string} [spec.icon] icon name (class)
+ * @param {string} [spec.id]
+ * @param {string} [spec.href]
+ * @param {string} [spec.style] css style
+ * @param {string} [spec.class]
+ * @param {Function} [spec.click] click handler
+ * @param {boolean} [spec.focusable] button is focusable
+ *
+ */
IPA.action_button = function(spec) {
spec = spec || {};
@@ -2978,6 +3504,25 @@ IPA.action_button = function(spec) {
return button;
};
+/**
+ * Create button
+ *
+ * Has different styling than action button.
+ *
+ * @method
+ * @member IPA
+ *
+ * @param {Object} spec
+ * @param {string} [spec.name]
+ * @param {string} [spec.label] button text
+ * @param {string} [spec.title=label] button title
+ * @param {string} [spec.icon] icon name (class)
+ * @param {string} [spec.id]
+ * @param {string} [spec.href]
+ * @param {string} [spec.style] css style
+ * @param {string} [spec.class]
+ * @param {Function} [spec.click] click handler
+ */
IPA.button = function(spec) {
spec = spec || {};
@@ -3001,18 +3546,34 @@ IPA.button = function(spec) {
return button;
};
+/**
+ * Widget encapsulating an `IPA.button`
+ *
+ * @class
+ * @extends IPA.widget
+ */
IPA.button_widget = function(spec) {
spec = spec || {};
var that = IPA.widget(spec);
+ /** Displayed link */
that.href = spec.href;
+ /** CSS style */
that.style = spec.style;
+ /** Click handler */
that.click = spec.click;
+ /** CSS class */
that['class'] = spec['class'];
+ /** CSS class for disabled button */
that.disabled_class = 'button-disabled';
+ /**
+ * Widget click handler.
+ *
+ * Calls provided click handler.
+ */
that.on_click = function() {
if (that.click) {
@@ -3021,6 +3582,7 @@ IPA.button_widget = function(spec) {
return false;
};
+ /** @inheritDoc */
that.create = function(container) {
that.button = IPA.button({
id: that.id,
@@ -3036,6 +3598,7 @@ IPA.button_widget = function(spec) {
that.set_enabled(that.enabled);
};
+ /** @inheritDoc */
that.set_enabled = function(enabled) {
that.widget_set_enabled(enabled);
@@ -3051,13 +3614,21 @@ IPA.button_widget = function(spec) {
return that;
};
+/**
+ * Widget just for rendering provided HTML code
+ *
+ * @class
+ * @extends IPA.widget
+ */
IPA.html_widget = function(spec) {
spec = spec || {};
var that = IPA.widget(spec);
+ /** Code to render */
that.html = spec.html;
+ /** Container CSS class */
that.css_class = spec.css_class;
that.create = function(container) {
@@ -3076,6 +3647,12 @@ IPA.html_widget = function(spec) {
return that;
};
+/**
+ * Widget just for rendering provided HTML code
+ *
+ * @class
+ * @extends IPA.widget
+ */
IPA.composite_widget = function(spec) {
spec = spec || {};
@@ -3105,6 +3682,11 @@ IPA.composite_widget = function(spec) {
return that;
};
+/**
+ * Section which can be collapsed
+ * @class
+ * @extends IPA.composite_widget
+ */
IPA.collapsible_section = function(spec) {
spec = spec || {};
@@ -3155,13 +3737,27 @@ IPA.collapsible_section = function(spec) {
return that;
};
+/**
+ * Section which can be collapsed
+ * @class
+ * @extends IPA.collapsible_section
+ */
IPA.details_section = IPA.collapsible_section;
+/**
+ * Base layout
+ * @class
+ */
IPA.layout = function(spec) {
return {};
};
-// Creates list of widgets into table with two columns: label and widget
+/**
+ * Table layout
+ * Creates list of widgets into table with two columns: label and widget
+ * @class
+ * @extends IPA.layout
+ */
IPA.table_layout = function(spec) {
spec = spec || {};
@@ -3237,6 +3833,11 @@ IPA.table_layout = function(spec) {
return that;
};
+/**
+ * Collapsible section with table layout
+ * @class
+ * @extends IPA.details_section
+ */
IPA.details_table_section = function(spec) {
spec = spec || {};
@@ -3280,6 +3881,11 @@ IPA.details_table_section = function(spec) {
return that;
};
+/**
+ * Policy which hides specific widget if it doesn't have any value
+ * @class
+ * @extends IPA.facet_policy
+ */
IPA.hide_empty_row_policy = function (spec) {
spec = spec || {};
@@ -3301,7 +3907,12 @@ IPA.hide_empty_row_policy = function (spec) {
return that;
};
-//non-collabsible section
+/**
+ * Not collabsible details section with table layout
+ *
+ * @class
+ * @extends IPA.details_table_section
+ */
IPA.details_table_section_nc = function(spec) {
spec = spec || {};
@@ -3313,6 +3924,19 @@ IPA.details_table_section_nc = function(spec) {
return that;
};
+/**
+ * Section which can contain multiple subsections
+ *
+ * Only one subsection can be active. Widgets in non-active subsections are
+ * disabled.
+ *
+ * Selection of active section is based on radio button selection.
+ *
+ * Presence of `multiple_choice_section_policy` is required.
+ *
+ * @class
+ * @extends IPA.composite_widget
+ */
IPA.multiple_choice_section = function(spec) {
spec = spec || {};
@@ -3457,6 +4081,9 @@ IPA.multiple_choice_section = function(spec) {
return that;
};
+/**
+ * Policy which makes `multiple_choice_section` work properly.
+ */
IPA.multiple_choice_section_policy = function(spec) {
spec = spec || {};
@@ -3475,6 +4102,13 @@ IPA.multiple_choice_section_policy = function(spec) {
return that;
};
+/**
+ * Enable widget
+ * Basically a radio button
+ *
+ * @class
+ * @extends IPA.radio_widget
+ */
IPA.enable_widget = function(spec) {
spec = spec || {};
@@ -3484,7 +4118,13 @@ IPA.enable_widget = function(spec) {
return that;
};
-
+/**
+ * Header widget
+ *
+ * Can be used as subsection header.
+ * @class
+ * @extends IPA.widget
+ */
IPA.header_widget = function(spec) {
spec = spec || {};
@@ -3505,16 +4145,32 @@ IPA.header_widget = function(spec) {
return that;
};
+/**
+ * Event
+ *
+ * @class IPA.observer
+ */
IPA.observer = function(spec) {
var that = IPA.object();
+ /**
+ * Listeners
+ */
that.listeners = [];
+ /**
+ * Register new listener
+ * @param {Function} callback
+ */
that.attach = function(callback) {
that.listeners.push(callback);
};
+ /**
+ * Remove registered listener
+ * @param {Function} callback
+ */
that.detach = function(callback) {
for(var i=0; i < that.listeners.length; i++) {
if(callback === that.listeners[i]) {
@@ -3524,6 +4180,13 @@ IPA.observer = function(spec) {
}
};
+ /**
+ * Call all listeners in order of registration with given context and
+ * arguments.
+ *
+ * @param {Array} arguments
+ * @param {Object} context
+ */
that.notify = function(args, context) {
args = args || [];
context = context || this;
@@ -3536,11 +4199,26 @@ IPA.observer = function(spec) {
return that;
};
+/**
+ * Utility class for HMTL generation
+ * @class
+ */
IPA.html_util = function() {
var that = IPA.object();
+
+ /**
+ * Last used ID
+ * @property {number}
+ */
that.id_count = 0;
+ /**
+ * Creates unique ID
+ * Usable for controls where same id/name would cause unintended
+ * interactions. IE. radios with same name influence each other.
+ * @param {string} prefix is concatenated with current `id_count`
+ */
that.get_next_id = function(prefix) {
that.id_count++;
return prefix ? prefix + that.id_count : that.id_count;
@@ -3549,6 +4227,14 @@ IPA.html_util = function() {
return that;
}();
+/**
+ * Widget container
+ *
+ * - provides means for nesting widgets
+ * - used ie in facets, dialogs or composite widgets
+ *
+ * @class
+ */
IPA.widget_container = function(spec) {
spec = spec || {};
@@ -3626,6 +4312,10 @@ IPA.widget_container = function(spec) {
return that;
};
+/**
+ * Widget builder
+ * @class
+ */
IPA.widget_builder = function(spec) {
spec = spec || {};
@@ -3651,6 +4341,14 @@ IPA.widget_builder = function(spec) {
return that;
};
+/**
+ * SSH keys widget
+ *
+ * Multivalued widget with SSH key widget instead of text widget.
+ *
+ * @class
+ * @extends IPA.multivalued_widget
+ */
IPA.sshkeys_widget = function(spec) {
spec = spec || {};
@@ -3677,6 +4375,12 @@ IPA.sshkeys_widget = function(spec) {
return that;
};
+/**
+ * SSH key widget
+ *
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.sshkey_widget = function(spec) {
spec = spec || {};
@@ -3859,6 +4563,14 @@ IPA.sshkey_widget = function(spec) {
return that;
};
+/**
+ * Action panel
+ *
+ * - usable in sections
+ *
+ * @class
+ * @extends IPA.widget
+ */
IPA.action_panel = function(spec) {
spec = spec || {};
@@ -3983,6 +4695,16 @@ IPA.action_panel = function(spec) {
return that;
};
+/**
+ * Value map widget
+ *
+ * Read-only widget which shows different string based on current value.
+ *
+ * Basically there is a map between values(keys) and strings (displayed values).
+ *
+ * @class
+ * @extends IPA.input_widget
+ */
IPA.value_map_widget = function(spec) {
spec = spec || {};
@@ -4034,6 +4756,11 @@ IPA.value_map_widget = function(spec) {
return that;
};
+/**
+ * pre_op operations for widgets
+ * - sets facet and entity if present in context
+ * @member widget
+ */
exp.pre_op = function(spec, context) {
if (context.facet) spec.facet = context.facet;
@@ -4043,6 +4770,7 @@ exp.pre_op = function(spec, context) {
/**
* Enables widget nesting
+ * @member widget
*/
exp.post_op = function(obj, spec, context) {
@@ -4056,7 +4784,11 @@ exp.post_op = function(obj, spec, context) {
return obj;
};
-// Widget builder and registry
+/**
+ * Widget builder
+ * - instantiated in global builder registry for type: 'widget'
+ * @member widget
+ */
exp.builder = builder.get('widget');
exp.builder.factory = IPA.text_widget;
exp.builder.string_mode = 'property';
@@ -4066,12 +4798,19 @@ exp.builder.post_ops.push(exp.post_op);
reg.set('widget', exp.builder.registry);
-// Formatter builder and registry
+/**
+ * Formatter builder
+ * - added as builder for 'formatter' registry
+ * @member widget
+ */
exp.formatter_builder = builder.get('formatter');
exp.formatter_builder.factory = IPA.formatter;
reg.set('formatter', exp.formatter_builder.registry);
-
+/**
+ * Register widgets and formatters to registries
+ * @member widget
+ */
exp.register = function() {
var w = reg.widget;
var f = reg.formatter;
diff --git a/install/ui/src/freeipa/widgets/App.js b/install/ui/src/freeipa/widgets/App.js
index abec9754e..569cecef9 100644
--- a/install/ui/src/freeipa/widgets/App.js
+++ b/install/ui/src/freeipa/widgets/App.js
@@ -42,8 +42,7 @@ define(['dojo/_base/declare',
* This class serves as top level widget. It creates basic UI: controls
* rendering of header, footer and placeholder for facets.
*
- * @name freeipa.widgets.app
- * @class
+ * @class widgets.App
*/
var app = declare([Stateful, Evented], {
diff --git a/install/ui/src/freeipa/widgets/Menu.js b/install/ui/src/freeipa/widgets/Menu.js
index 61178b046..1e4c08211 100644
--- a/install/ui/src/freeipa/widgets/Menu.js
+++ b/install/ui/src/freeipa/widgets/Menu.js
@@ -35,38 +35,39 @@ define(['dojo/_base/declare',
return declare([Evented], {
/**
- * @name freeipa.widget.menu
- * @class
- *
* Creates UI for freeipa.navigation.menu. Provides an event when
* a menu items is selected.
*
- * event: item-select(menu_item)
+ * @class widgets.Menu
+ */
+
+ /**
+ * @event item-select(menu_item)
*/
/**
* Object store of menu items
* @protected
- * @type freeipa.navigation.menu
+ * @property {navigation.Menu}
*/
menu: null,
/**
* domNode of this widget. FIXME: move to superclass (none yet)
- * @type Node
+ * @property {HTMLElement}
*/
domNode: null,
/**
* Turns off update on data change
- * @type Boolen
+ * @property {boolean}
*/
ignore_changes: false,
/**
* Css class for nodes containing a submenu of certain level_class
- * @type String
+ * @property {string}
*/
level_class: 'menu-level',
@@ -92,9 +93,9 @@ define(['dojo/_base/declare',
* Top level items are rendered if menu_items is null
*
* @protected
- * @param {menu_item|null} menu_item
- * @param {Node} node
- * @param {Number} level
+ * @param {navigation.MenuItem|null} menu_item
+ * @param {HTMLElement} node
+ * @param {number} level
*/
_render_children: function (menu_item, node, level) {
@@ -150,8 +151,8 @@ define(['dojo/_base/declare',
* menu_item's state.
*
* @protected
- * @param {menu_item|string} menu_item
- * @param {Node} [li_node]
+ * @param {navigation.MenuItem|string} menu_item
+ * @param {HTMLElement} [li_node]
*/
_update_item: function(menu_item, li_node) {
@@ -182,7 +183,7 @@ define(['dojo/_base/declare',
/**
* Displays only supplied menu items.
- * @param {menu_item[]} menu_items Items to show
+ * @param {navigation.MenuItem[]} menu_items Items to show
*/
select: function(menu_items) {
@@ -215,9 +216,9 @@ define(['dojo/_base/declare',
* Handles changes in this.menu object.
*
* @protected
- * @param {menu_item} object
- * @param {Number} removedFrom
- * @param {Number} insertedInto
+ * @param {navigation.MenuItem} object
+ * @param {number} removedFrom
+ * @param {number} insertedInto
*/
_items_changed: function(object, removedFrom, insertedInto) {
@@ -234,7 +235,7 @@ define(['dojo/_base/declare',
/**
* Sets this.menu and starts to watch its changes
- * @param {freeipa.navigation.menu} menu
+ * @param {navigation.Menu} menu
*/
set_menu: function(menu) {
this.menu = menu;
@@ -249,6 +250,8 @@ define(['dojo/_base/declare',
/**
* Internal handler for clicking on menu item.
* Raises item-select event.
+ * @protected
+ * @param {navigation.MenuItem} menu_items
*/
_item_clicked: function(menu_item) {
this.emit('item-select', menu_item);
@@ -259,7 +262,7 @@ define(['dojo/_base/declare',
*
* Intended for overriding.
*
- * @param {menu_item} menu_item
+ * @param {navigation.MenuItem} menu_item
* @param {Event} event
*/
item_clicked: function(menu_item/*, event*/) {