diff options
Diffstat (limited to 'install/ui/src/freeipa/widget.js')
-rw-r--r-- | install/ui/src/freeipa/widget.js | 386 |
1 files changed, 293 insertions, 93 deletions
diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js index a9b77694e..9b04acc91 100644 --- a/install/ui/src/freeipa/widget.js +++ b/install/ui/src/freeipa/widget.js @@ -32,13 +32,15 @@ define(['dojo/_base/array', './datetime', './ipa', './jquery', + './navigation', './phases', './reg', './rpc', - './text' + './text', + './util' ], - function(array, lang, Evented, has, keys, on, builder, datetime, IPA, $, - phases, reg, rpc, text) { + function(array, lang, Evented, has, keys, on, builder, datetime, + IPA, $, navigation, phases, reg, rpc, text, util) { /** * Widget module @@ -128,6 +130,12 @@ IPA.widget = function(spec) { that.enabled = spec.enabled === undefined ? true : spec.enabled; /** + * Enables showing of validation errors + * @property {boolean} + */ + that.show_errors = spec.show_errors === undefined ? true : spec.show_errors; + + /** * Create HTML representation of a widget. * @method * @param {HTMLElement} container - Container node @@ -190,6 +198,24 @@ IPA.widget = function(spec) { return child; }; + that.add_class = function(cls) { + if (that.container) { + that.container.addClass(cls); + } + }; + + that.remove_class = function(cls) { + if (that.container) { + that.container.removeClass(cls); + } + }; + + that.toggle_class = function(cls, flag) { + if (that.container) { + that.container.toggleClass(cls, flag); + } + }; + that.widget_create = that.create; that.widget_set_enabled = that.set_enabled; @@ -259,6 +285,7 @@ IPA.input_widget = function(spec) { * Value changed event. * * Raised when user modifies data by hand. + * @deprecated * * @event */ @@ -266,6 +293,7 @@ IPA.input_widget = function(spec) { /** * Undo clicked event. + * @deprecated * * @event */ @@ -273,6 +301,7 @@ IPA.input_widget = function(spec) { /** * Updated event. + * @deprecated * * Raised when widget content gets updated - raised by * {@link IPA.input_widget#update} method. @@ -327,6 +356,13 @@ IPA.input_widget = function(spec) { }; /** + * Alias of save + */ + that.get_value = function() { + return that.save(); + }; + + /** * This function creates an undo link in the container. * 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 @@ -383,27 +419,60 @@ IPA.input_widget = function(spec) { * @return {jQuery} error link jQuery reference */ that.get_error_link = function() { - return $('span[name="error_link"]', that.container); + return $('span[name="error_link"]', that.container).eq(0); + }; + + /** + * Set's validity of widget's value. Usually checked by outside logic. + * @param {Object} result Validation result as defined in IPA.validator + */ + that.set_valid = function(result) { + + var old = that.valid; + that.valid = result.valid; + + that.toggle_class('valid', that.valid); + if (!that.valid) { + that.show_error(result.message); + } else { + that.hide_error(); + } + if (old !== that.valid) { + that.emit("valid-change", { + source: that, + valid: that.valid, + result: result + }); + } }; /** * Show error message * @protected - * @param {string} message + * @fires error-show + * @param {Object} error */ that.show_error = function(message) { - var error_link = that.get_error_link(); - error_link.html(message); - error_link.css('display', ''); - that.emit('error-show', { source: that, error: message }); + if (that.show_errors) { + var error_link = that.get_error_link(); + error_link.html(message); + error_link.css('display', ''); + } + that.emit('error-show', { + source: that, + error: message, + displayed: that.show_errors + }); }; /** * Hide error message * @protected + * @fires error-hide */ that.hide_error = function() { var error_link = that.get_error_link(); + error_link.html(''); error_link.css('display', 'none'); that.emit('error-hide', { source: that }); }; @@ -458,6 +527,38 @@ IPA.input_widget = function(spec) { }; /** + * Set writable + * @fires writable-change + * @param {boolean} writable + */ + that.set_writable = function(writable) { + + var changed = writable !== that.writable; + + that.writable = writable; + + if (changed) { + that.emit('writable-change', { source: that, writable: writable }); + } + }; + + /** + * Set read only + * @fires readonly-change + * @param {boolean} writable + */ + that.set_read_only = function(read_only) { + + var changed = read_only !== that.read_only; + + that.read_only = read_only; + + if (changed) { + that.emit('readonly-change', { source: that, read_only: read_only }); + } + }; + + /** * Focus input element * @abstract */ @@ -499,6 +600,7 @@ IPA.input_widget = function(spec) { // methods that should be invoked by subclasses that.widget_hide_error = that.hide_error; that.widget_show_error = that.show_error; + that.widget_set_valid = that.set_valid; return that; }; @@ -680,7 +782,7 @@ IPA.multivalued_widget = function(spec) { that.child_spec = spec.child_spec; that.size = spec.size || 30; that.undo_control; - that.initialized = false; + that.initialized = true; that.rows = []; @@ -693,24 +795,16 @@ IPA.multivalued_widget = function(spec) { row.remove_link.show(); } - that.value_changed.notify([], that); - that.emit('child-value-change', { source: that, row: row }); that.emit('value-change', { source: that }); + that.emit('child-value-change', { source: that, row: row }); }; that.on_child_undo_clicked = function(row) { if (row.is_new) { that.remove_row(row); } else { - //reset - row.widget.update(row.original_values); - row.widget.set_deleted(false); - row.deleted = false; - row.remove_link.show(); + that.reset_row(row); } - - row.widget.hide_undo(); - that.value_changed.notify([], that); that.emit('child-undo-click', { source: that, row: row }); }; @@ -745,20 +839,45 @@ IPA.multivalued_widget = function(spec) { } }; - that.show_child_error = function(index, error) { + that.set_valid = function (result) { - that.rows[index].widget.show_error(error); - }; + var old = that.valid; + that.valid = result.valid; - that.get_saved_value_row_index = function(index) { + if (!result.valid && result.errors) { + var offset = 0; + for (var i=0; i<that.rows.length; i++) { - for (var i=0; i<that.rows.length;i++) { + var val_result = null; + if (that.rows[i].deleted) { + offset++; + val_result = { valid: true }; + } else { + val_result = result.results[i-offset]; + } + var widget = that.rows[i].widget; + if (val_result) widget.set_valid(val_result); + } + + if (that.rows.length > 0) { + var error_link = that.get_error_link(); + error_link.css('display', 'none'); + error_link.html(''); + } else { + that.show_error(result.message); + } - if(that.rows[i].deleted) index++; - if(i === index) return i; + } else { + that.hide_error(); } - return -1; //error state + if (old !== that.valid) { + that.emit("valid-change", { + source: that, + valid: that.valid, + result: result + }); + } }; that.save = function() { @@ -829,10 +948,10 @@ IPA.multivalued_widget = function(spec) { row.original_values = values; row.widget.update(values); - row.widget.value_changed.attach(function() { + on(row.widget, 'value-change', function() { that.on_child_value_changed(row); }); - row.widget.undo_clicked.attach(function() { + on(row.widget, 'undo-click', function() { that.on_child_undo_clicked(row); }); on(row.widget, 'error-show', function() { @@ -847,8 +966,6 @@ IPA.multivalued_widget = function(spec) { html: text.get('@i18n:buttons.remove'), click: function () { that.remove_row(row); - that.value_changed.notify([], that); - that.emit('value-change', { source: that }); return false; } }).appendTo(row.container); @@ -902,6 +1019,17 @@ IPA.multivalued_widget = function(spec) { }).appendTo(container); }; + that.reset_row = function(row) { + row.widget.update(row.original_values); + row.widget.set_deleted(false); + row.deleted = false; + row.remove_link.show(); + row.widget.hide_undo(); + + that.value_changed.notify([], that); + that.emit('value-change', { source: that }); + }; + that.remove_row = function(row) { if (row.is_new) { row.container.remove(); @@ -912,6 +1040,8 @@ IPA.multivalued_widget = function(spec) { row.remove_link.hide(); row.widget.show_undo(); } + that.value_changed.notify([], that); + that.emit('value-change', { source: that }); }; that.remove_rows = function() { @@ -929,30 +1059,14 @@ IPA.multivalued_widget = function(spec) { if (row.deleted || row.is_new) return true; - var values = row.widget.save(); - if (!values) return false; - - if (row.original_values.length !== values.length) return true; + var value = row.widget.save(); - for (var i=0; i<values.length; i++) { - if (values[i] !== row.original_values[i]) { - return true; - } + if (util.dirty(value, row.original_values, { unordered: true })) { + return true; } - return false; }; - that.test_dirty = function() { - var dirty = false; - - for(var i=0; i < that.rows.length; i++) { - dirty = dirty || that.test_dirty_row(that.rows[i]); - } - - return dirty; - }; - that.update = function(values, index) { var value; @@ -1693,10 +1807,15 @@ IPA.select_widget = function(spec) { }; that.update = function(values) { + var old = that.save()[0]; var value = values[0]; var option = $('option[value="'+value+'"]', that.select); - if (!option.length) return; - option.prop('selected', true); + if (option.length) { + option.prop('selected', true); + } else { + // default was selected instead of supplied value, hence notify + util.emit_delayed(that,'value-change', { source: that }); + } that.updated.notify([], that); that.emit('update', { source: that }); }; @@ -1869,7 +1988,8 @@ IPA.boolean_formatter = function(spec) { spec = spec || {}; var that = IPA.formatter(spec); - + /** Parse error */ + that.parse_error = text.get(spec.parse_error || 'Boolean value expected'); /** Formatted value for true */ that.true_value = text.get(spec.true_value || '@i18n:true'); /** Formatted value for false */ @@ -1881,9 +2001,9 @@ IPA.boolean_formatter = function(spec) { /** * Result of parse of `undefined` or `null` value will be `empty_value` * if set. - * @property {boolean|undefined} + * @property {boolean} */ - that.empty_value = spec.empty_value; + that.empty_value = spec.empty_value !== undefined ? spec.empty_value : false; /** * Convert string boolean value into real boolean value, or keep @@ -1894,9 +2014,8 @@ IPA.boolean_formatter = function(spec) { */ that.parse = function(value) { - if (value === undefined || value === null) { - if (that.empty_value !== undefined) value = that.empty_value; - else return ''; + if (util.is_empty(value)) { + value = that.empty_value; } if (value instanceof Array) { @@ -1910,11 +2029,17 @@ IPA.boolean_formatter = function(spec) { value = true; } else if (value === 'false') { value = false; - } // leave other values unchanged + } } if (typeof value === 'boolean') { if (that.invert_value) value = !value; + } else { + throw { + reason: 'parse', + value: that.empty_value, + message: that.parse_error + }; } return value; @@ -1987,13 +2112,32 @@ IPA.datetime_formatter = function(spec) { var that = IPA.formatter(spec); that.template = spec.template; + that.parse_error = text.get(spec.parse_error || '@i18n:widget.validation.datetime'); + + that.parse = function(value) { + if (value === '') return null; + var date = datetime.parse(value); + if (!date) { + throw { + reason: 'parse', + value: null, + message: that.parse_error + }; + } + return date; + }; that.format = function(value) { if (!value) return ''; - var date = datetime.parse(value); - if (!date) return value; - var str = datetime.format(date, that.template); + if (!(value instanceof Date)) { + throw { + reason: 'format', + value: '', + message: 'Input value is not of Date type' + }; + } + var str = datetime.format(value, that.template); return str; }; return that; @@ -2659,12 +2803,6 @@ IPA.table_widget = function (spec) { return rows; }; - that.show_error = function(message) { - var error_link = that.get_error_link(); - error_link.html(message); - error_link.css('display', ''); - }; - that.set_enabled = function(enabled) { that.widget_set_enabled(enabled); @@ -3599,13 +3737,26 @@ IPA.entity_select_widget = function(spec) { IPA.link_widget = function(spec) { var that = IPA.input_widget(spec); - that.is_link = spec.is_link || false; + /** + * Entity a link points to + * @property {entity.entity} + */ + that.other_entity = IPA.get_entity(spec.other_entity); /** - * Raised when link is clicked - * @event + * Function which should return primary keys of link target in case of + * link points to an entity. + * @property {Function} */ - that.link_clicked = IPA.observer(); + that.other_pkeys = spec.other_pkeys || other_pkeys; + + that.is_link = spec.is_link || false; + + that.value = []; + + function other_pkeys () { + return that.facet.get_pkeys(); + } /** @inheritDoc */ that.create = function(container) { @@ -3617,8 +3768,7 @@ IPA.link_widget = function(spec) { html: '', 'class': 'link-btn', click: function() { - that.link_clicked.notify([], that); - that.emit('link-click', { source: that }); + that.on_link_clicked(); return false; } }).appendTo(container); @@ -3628,11 +3778,19 @@ IPA.link_widget = function(spec) { }; /** @inheritDoc */ - that.update = function (values){ + that.update = function(values) { + + that.value = util.normalize_value(values)[0] || ''; + that.link.html(that.value); + that.nonlink.html(that.value); - if (values || values.length > 0) { - that.nonlink.text(values[0]); - that.link.text(values[0]); + that.check_entity_link(); + that.updated.notify([], that); + that.emit('update', { source: that }); + }; + + that.update_link = function() { + if (that.value) { if(that.is_link) { that.link.css('display',''); that.nonlink.css('display','none'); @@ -3641,13 +3799,54 @@ IPA.link_widget = function(spec) { that.nonlink.css('display',''); } } else { - that.link.html(''); - that.nonlink.html(''); that.link.css('display','none'); that.nonlink.css('display','none'); } - that.updated.notify([], that); - that.emit('update', { source: that }); + }; + + /** + * Handler for widget `link_click` event + */ + that.on_link_clicked = function() { + + navigation.show_entity( + that.other_entity.name, + 'default', + that.other_pkeys()); + }; + + /** + * Check if entity exists + * + * - only if link points to an entity + * - updates link visibility accordingly + */ + that.check_entity_link = function() { + + //In some cases other entity may not be present. + //For example when DNS is not configured. + if (!that.other_entity) { + that.is_link = false; + return; + } + + rpc.command({ + entity: that.other_entity.name, + method: 'show', + args: that.other_pkeys(), + options: {}, + retry: false, + on_success: function(data) { + that.is_link = data.result && data.result.result; + that.update_link(); + }, + on_error: function() { + that.is_link = false; + that.update_link(); + } + }).execute(); + + that.update_link(); }; /** @inheritDoc */ @@ -4119,7 +4318,7 @@ exp.fluid_layout = IPA.fluid_layout = function(spec) { text: label_text }).appendTo(label_cont); - var input = widget.get_input(); + var input = widget.get_input && widget.get_input(); if (input && input.length) input = input[0]; @@ -4150,6 +4349,8 @@ exp.fluid_layout = IPA.fluid_layout = function(spec) { that.register_state_handlers = function(widget) { on(widget, 'require-change', that.on_require_change); on(widget, 'enabled-change', that.on_enabled_change); + on(widget, 'readonly-change', that.on_require_change); + on(widget, 'writable-change', that.on_require_change); on(widget, 'error-show', that.on_error_show); on(widget, 'error-hide', that.on_error_hide); }; @@ -4165,7 +4366,7 @@ exp.fluid_layout = IPA.fluid_layout = function(spec) { var row = that._get_row(event); if (!row) return; - row.toggleClass('required', !!event.required); + row.toggleClass('required', !!event.required && event.source.is_writable()); }; that.on_error_show = function(event) { @@ -4184,7 +4385,7 @@ exp.fluid_layout = IPA.fluid_layout = function(spec) { that.update_state = function(row, widget) { row.toggleClass('disabled', !widget.enabled); - row.toggleClass('required', !!widget.required); + row.toggleClass('required', !!widget.required && widget.is_writable()); }; that._get_row = function(event) { @@ -4685,9 +4886,10 @@ IPA.widget_container = function(spec) { /** * Widget builder - * @class + * @class widget.widget_builder + * @alternateClassName IPA.widget_builder */ -IPA.widget_builder = function(spec) { +exp.widget_builder = IPA.widget_builder = function(spec) { spec = spec || {}; @@ -4792,9 +4994,9 @@ IPA.sshkey_widget = function(spec) { that.create_error_link(container); }; - that.update = function(values) { + that.update = function(value) { - var key = values && values.length ? values[0] : null; + var key = value[0]; if (!key || key === '') { key = {}; @@ -4821,9 +5023,7 @@ IPA.sshkey_widget = function(spec) { }; that.save = function() { - var value = that.key.key; - value = value ? [value] : ['']; - return value; + return that.key; }; that.update_link = function() { |