From 642345fd53faabd9183bef1a7667bdb7956d27f7 Mon Sep 17 00:00:00 2001 From: Petr Vobornik Date: Mon, 25 Nov 2013 13:56:27 +0100 Subject: webui: standalone facet `facet.Facet` is a new base class for facets. It doesn't have any dependencies on entities so it's usable for general purpose facets, e.g., future API browser, load facet or login facet. https://fedorahosted.org/freeipa/ticket/3903 Reviewed-By: Adam Misnyovszki --- install/ui/doc/categories.json | 1 + install/ui/ipa.css | 10 +- install/ui/jsl.conf | 1 + install/ui/src/freeipa/_base/construct.js | 12 ++ install/ui/src/freeipa/facet.js | 4 +- install/ui/src/freeipa/facets/Facet.js | 329 ++++++++++++++++++++++++++++++ 6 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 install/ui/src/freeipa/facets/Facet.js (limited to 'install/ui') diff --git a/install/ui/doc/categories.json b/install/ui/doc/categories.json index e8ae56b79..d1e2d61e4 100644 --- a/install/ui/doc/categories.json +++ b/install/ui/doc/categories.json @@ -36,6 +36,7 @@ "name": "Facets", "classes": [ "facet.facet", + "facets.Facet", "*_facet" ] }, diff --git a/install/ui/ipa.css b/install/ui/ipa.css index a65505695..ca8ccaffc 100644 --- a/install/ui/ipa.css +++ b/install/ui/ipa.css @@ -198,12 +198,20 @@ textarea[readonly] { /* ---- Facet ---- */ .facet { + position: relative; + display: none; +} + +#simple-container .content { + height: 100%; +} + +#container .facet { position: absolute; top: 110px; left: 10px; right: 10px; bottom: 0; - display: none; } .active-facet { diff --git a/install/ui/jsl.conf b/install/ui/jsl.conf index 62343cb1c..4bc1fdecb 100644 --- a/install/ui/jsl.conf +++ b/install/ui/jsl.conf @@ -136,6 +136,7 @@ +process src/freeipa/_base/*.js +process src/freeipa/dialogs/*.js +process src/freeipa/navigation/*.js ++process src/freeipa/facets/*.js +process src/freeipa/widgets/*.js +process src/*.js +process ./*.js \ No newline at end of file diff --git a/install/ui/src/freeipa/_base/construct.js b/install/ui/src/freeipa/_base/construct.js index ce675e588..6db2134b8 100644 --- a/install/ui/src/freeipa/_base/construct.js +++ b/install/ui/src/freeipa/_base/construct.js @@ -107,6 +107,18 @@ define(['dojo/_base/declare', return lang._mixin(r, src, construct.clone); }, + /** + * Run object's init function after instantiation if it has one + * @param {Object} obj + * @param {Object} spec + */ + init_post_op: function(obj, spec) { + if (obj && typeof obj.init === 'function') { + obj.init(spec); + } + return obj; + }, + no_cs_for_type_error: function(type) { return { error: 'No construction specification for given type', diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js index f235ddc8f..5fc59ea3b 100644 --- a/install/ui/src/freeipa/facet.js +++ b/install/ui/src/freeipa/facet.js @@ -29,6 +29,7 @@ define([ 'dojo/Stateful', 'dojo/Evented', './_base/Singleton_registry', + './_base/construct', './builder', './ipa', './jquery', @@ -42,7 +43,7 @@ define([ './field', './widget' ], function(declare, lang, construct, on, Stateful, Evented, - Singleton_registry, builder, IPA, $, + Singleton_registry, construct_utils, builder, IPA, $, navigation, phases, reg, rpc, su, text) { /** @@ -3493,6 +3494,7 @@ var FacetState = exp.FacetState = declare([Stateful, Evented], { var registry = new Singleton_registry(); reg.set('facet', registry); builder.set('facet', registry.builder); +registry.builder.post_ops.push(construct_utils.init_post_op); /** * Action builder with registry diff --git a/install/ui/src/freeipa/facets/Facet.js b/install/ui/src/freeipa/facets/Facet.js new file mode 100644 index 000000000..8b55cec12 --- /dev/null +++ b/install/ui/src/freeipa/facets/Facet.js @@ -0,0 +1,329 @@ +/* Authors: + * Petr Vobornik + * + * 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 . +*/ + +define(['dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/Evented', + 'dojo/dom-construct', + 'dojo/dom-class', + 'dojo/on', + '../builder', + '../facet', + '../ipa', // for util functions + '../jquery', + '../text', + '../widgets/ContainerMixin' + ], + function(declare, lang, Evented, construct, dom_class, + on, builder, mod_facet, IPA, $, text, ContainerMixin) { + + /** + * Base class of Facet + * + * A future replacement/base class for `facet.facet` + * + * @class facets.Facet + * @mixins widgets.ContainerMixin + */ + var Facet = declare([Evented, ContainerMixin], { + + /** + * Name of preferred facet container + * + * Leave unset to use default container. + * @property {string} + */ + preferred_container: null, + + /** + * Facet name + * @property {string} + */ + name: null, + + /** + * Facet label + * @property {string} + */ + label: null, + + /** + * Facet title + * @property {string} + */ + title: null, + + /** + * Facet element's CSS class + * @property {string} + */ + 'class': null, + + /** + * Class which tells that the facet should be visible + * @property {string} + */ + active_class: 'active', + + /** + * dom_node of container + * Suppose to contain dom_node of this and other facets. + * @property {jQuery} + */ + container_node: null, + + /** + * dom_node which contains all content of this Facet. + * @property {HTMLElement} + * @readonly + */ + dom_node: null, + + /** + * DOM node which serves as container for child widgets + * @property {HTMLElement} + */ + children_node: null, + + /** + * Redirection target information. + * + * Can be facet and/or entity name. + * @property {Object} + * @param {string} entity entity name + * @param {string} facet facet name + */ + redirect_info: null, + + /** + * Public state + * @property {facet.FacetState} + * @protected + */ + state: null, + + /** + * 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 + */ + state_diff: function(a, b) { + var diff = false; + var checked = {}; + + var check_diff = function(a, b, skip) { + + var same = true; + skip = skip || {}; + + for (var key in a) { + if (a.hasOwnProperty(key) && !(key in skip)) { + var va = a[key]; + var vb = b[key]; + if (lang.isArray(va)) { + if (IPA.array_diff(va,vb)) { + same = false; + skip[a] = true; + break; + } + } else { + if (va != vb) { + same = false; + skip[a] = true; + break; + } + } + } + } + return !same; + }; + + diff = check_diff(a,b, checked); + diff = diff || check_diff(b,a, checked); + return diff; + }, + + /** + * Reset facet state to supplied + * + * @param {Object} state state to set + */ + reset_state: function(state) { + this.state.reset(state); + }, + + /** + * Get copy of current state + * + * @return {Object} state + */ + get_state: function() { + return this.state.clone(); + }, + + /** + * Merges state into current and notifies it. + * + * @param {Object} state object to merge into current state + */ + set_state: function(state) { + this.state.set(state); + }, + + /** + * Handle state set + * @param {Object} old_state + * @param {Object} state + * @protected + */ + on_state_set: function(old_state, state) { + this.on_state_change(state); + }, + + /** + * Handle state change + * @param {Object} state + * @protected + */ + on_state_change: function(state) { + + this._notify_state_change(state); + }, + + /** + * Fires `facet-state-change` event with given state as event parameter. + * + * @fires facet-state-change + * @protected + * @param {Object} state + */ + _notify_state_change: function(state) { + this.emit('facet-state-change', { + facet: this, + state: state + }); + }, + + /** + * Create facet's HTML representation + * NOTE: may be renamed to render + */ + create: function() { + + if (this.dom_node) { + construct.empty(this.dom_node); + } else { + this.dom_node = construct.create('div', { + 'class': 'facet', + name: this.name, + 'data-name': this.name + }); + } + if (this.container_node) { + construct.place(this.dom_node, this.container_node); + } + this.children_node = this.dom_node; + return this.dom_node; + }, + + /** + * Render child widgets + */ + render_children: function() { + var widgets = this.get_widgets(); + + for (var i=0;i').appendTo(this.children_node); + widget.create(container); + } + } + }, + + /** + * Show facet + * + * - mark itself as active facet + */ + show: function() { + + if (!this.dom_node) { + this.create(); + this.render_children(); + } + + dom_class.add(this.dom_node, 'active-facet'); + this.emit('show', { source: this }); + }, + + /** + * Un-mark itself as active facet + */ + hide: function() { + dom_class.remove(this.dom_node, 'active-facet'); + this.emit('hide', { source: this }); + }, + + /** + * Initializes facet + * + * Facet builder should run this method after instantiation. + * @param {Object} spec + */ + init: function(spec) { + + this.add_widgets(spec.widgets || []); + }, + + can_leave: function() { + return true; + }, + + show_leave_dialog: function(callback) { + window.console.warning('Unimplemented'); + }, + + /** Constructor */ + constructor: function(spec) { + + this.preferred_container = spec.preferred_container; + this.name = spec.name; + this.label = text.get(spec.label); + this.title = text.get(spec.title || spec.label); + this['class'] = spec['class']; + this.container_node = spec.container_node; + this.dom_node = spec.dom_node; + this.redirect_info = spec.redirect_info; + this.state = new mod_facet.FacetState(); + on(this.state, 'set', lang.hitch(this, this.on_state_set)); + } + }); + + return Facet; +}); \ No newline at end of file -- cgit