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 <amisnyov@redhat.com>
This commit is contained in:
Petr Vobornik
2013-11-25 13:56:27 +01:00
parent dec7f98aa9
commit 642345fd53
6 changed files with 355 additions and 2 deletions

View File

@@ -36,6 +36,7 @@
"name": "Facets",
"classes": [
"facet.facet",
"facets.Facet",
"*_facet"
]
},

View File

@@ -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 {

View File

@@ -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

View File

@@ -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',

View File

@@ -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

View File

@@ -0,0 +1,329 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define(['dojo/_base/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<widgets.length; i++) {
var widget = widgets[i];
var modern = typeof widget.render === 'function';
if (modern) {
widget.container_node = this.children_node;
widget.render();
} else {
var container = $('<div/>').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;
});