webgme
Version:
Web-based Generic Modeling Environment
368 lines (294 loc) • 11.4 kB
JavaScript
/*globals define, $*/
/*jshint browser: true*/
/**
* @author rkereskenyi / https://github.com/rkereskenyi
* @author nabana / https://github.com/nabana
*/
define([
'js/Controls/PropertyGrid/PropertyGridWidgetManager',
'css!./styles/PropertyGridPart.css'
], function (PropertyGridWidgetManager) {
'use strict';
/** Outer-most className for GUI's */
var PropertyGridPart,
CSS_NAMESPACE = 'pgp',
CLASS_CLOSED = 'closed',
CLASS_CONTROLLER_ROW = 'cr',
RESET_BUTTON_BASE = $('<i class="glyphicon glyphicon-remove-circle reset-badge btn-reset" title="Reset value"/>'),
INVALID_BASE_VALUE_BASE = $('<i class="fa fa-exclamation-triangle reset-badge" ' +
'title="Inherits META-invalid property"/>'),
INVALID_BUTTON_BASE = $('<i class="glyphicon glyphicon-exclamation-sign reset-badge btn-reset" ' +
'title="Remove META-invalid property"/>'),
PASSWORD_BUTTON_BASE = $('<i class="glyphicon glyphicon-eye-open reset-badge btn-reset" ' +
'title="Show Password"/>');
PropertyGridPart = function (params) {
if (params.el) {
this._containerElement = params.el;
}
this._el = $('<div/>', {
class: CSS_NAMESPACE
});
this.__ul = $('<ul/>', {});
this._el.append(this.__ul);
this.__folders = {};
this.__widgets = {};
this._closed = false;
this.__onChange = undefined;
this.__onFinishChange = undefined;
this.__onReset = undefined;
this._name = params.name || undefined;
//if (this._name === CONSTANTS.PROPERTY_GROUP_META) {
// this._toggleClosed();
//}
this._parent = params.parent;
// Are we a root level GUI?
if (params.parent === undefined) {
this._widgetManager = new PropertyGridWidgetManager();
this._containerElement.append(this._el);
// Oh, you're a nested GUI!
} else {
this._addNestedGUI(params);
this._widgetManager = params.parent._widgetManager;
}
};
PropertyGridPart.prototype._addNestedGUI = function (params) {
var titleRow = this._addRow(this, $(document.createTextNode(params.text || params.name))),
onClickTitle,
self = this;
onClickTitle = function (e) {
e.preventDefault();
e.stopPropagation();
self._toggleClosed();
return false;
};
titleRow.addClass('title');
titleRow.on('click', onClickTitle);
};
/*************** PRIVATE API *************************/
PropertyGridPart.prototype._toggleClosed = function () {
if (this._closed === true) {
this.open();
} else {
this.close();
}
};
/**
* Add a row to the end of the GUI or before another row.
*
* @param gui
* @param [dom] If specified, inserts the dom content in the new row
* @param [liBefore] If specified, places the new row before another row
*/
PropertyGridPart.prototype._addRow = function (gui, dom, liBefore) {
var li = $('<li/>');
if (dom) {
li.append(dom);
}
if (liBefore) {
li.insertBefore(liBefore);
} else {
this.__ul.append(li);
}
return li;
};
PropertyGridPart.prototype._change = function (args) {
if (this.__onChange) {
this.__onChange.call(this, args);
}
};
PropertyGridPart.prototype._finishChange = function (args) {
if (this.__onFinishChange) {
this.__onFinishChange.call(this, args);
}
};
PropertyGridPart.prototype._reset = function (propertyName) {
if (this.__onReset) {
this.__onReset.call(this, propertyName);
}
};
PropertyGridPart.prototype._getAccumulatedName = function () {
var parentName = this._parent ? this._parent._getAccumulatedName() : undefined;
return parentName ? parentName + '.' + this._name : this._name;
};
/*************** END OF - PRIVATE API *************************/
/*************** PUBLIC API **************************/
PropertyGridPart.prototype.open = function () {
this._closed = false;
this.__ul.removeClass(CLASS_CLOSED);
};
PropertyGridPart.prototype.close = function () {
this._closed = true;
this.__ul.addClass(CLASS_CLOSED);
};
PropertyGridPart.prototype.add = function (propertyDesc) {
var self = this,
container = $('<div/>'),
spnName = $('<span/>', {class: 'property-name'}),
divAction = $('<div/>', {class: 'p-reset'}),
extraCss = {},
widget,
actionBtn,
passwordBtn,
li;
if (this.__widgets[propertyDesc.name] !== undefined) {
throw new Error('You already have a widget with the name "' + propertyDesc.name + '"');
}
if (!propertyDesc.id) {
propertyDesc.id = this._getAccumulatedName() + '.' + propertyDesc.name;
}
widget = this._widgetManager.getWidgetForProperty(propertyDesc);
this.__widgets[propertyDesc.name] = widget;
widget.el.addClass('c');
widget.onChange(function (args) {
self._change(args);
});
widget.onFinishChange(function (args) {
self._finishChange(args);
});
spnName.text(widget.propertyName || widget.propertyText);
spnName.attr('title', widget.propertyText || widget.propertyName);
if (propertyDesc.options) {
if (propertyDesc.options.textColor) {
extraCss.color = propertyDesc.options.textColor;
}
if (propertyDesc.options.textItalic) {
extraCss['font-style'] = 'italic';
}
if (propertyDesc.options.textBold) {
extraCss['font-weight'] = 'bold';
}
spnName.css(extraCss);
// invalid value
if (propertyDesc.options.invalidValue === true) {
widget.el.addClass('has-invalid-value');
}
// resettable and invalid in terms of not having a definition.
if (propertyDesc.options.invalid === true && propertyDesc.options.resetable === true) {
actionBtn = INVALID_BUTTON_BASE.clone();
} else if (propertyDesc.options.resetable === true) {
actionBtn = RESET_BUTTON_BASE.clone();
} else if (propertyDesc.options.invalid === true) {
divAction.append(INVALID_BASE_VALUE_BASE.clone());
spnName.addClass('p-reset');
}
if (actionBtn) {
divAction.append(actionBtn);
spnName.addClass('p-reset');
actionBtn.on('click', function (event) {
if (self.__widgets[propertyDesc.name]._isReadOnly === false) {
self._reset(propertyDesc.id);
}
event.stopPropagation();
event.preventDefault();
});
}
if(propertyDesc.options.isPassword) {
passwordBtn = PASSWORD_BUTTON_BASE.clone();
passwordBtn.on('click', function () {
if ($(this).hasClass('glyphicon-eye-open')) {
//was in password mode
$(this).removeClass('glyphicon-eye-open');
$(this).addClass('glyphicon-eye-close');
$(this).prop('title', 'hide password');
self.__widgets[propertyDesc.name].showPassword(true);
} else {
// should hide now
$(this).removeClass('glyphicon-eye-close');
$(this).addClass('glyphicon-eye-open');
$(this).prop('title', 'show password');
self.__widgets[propertyDesc.name].showPassword(false);
}
});
divAction.append(passwordBtn);
spnName.addClass('p-reset');
}
}
container.append(spnName).append(divAction).append(widget.el);
li = this._addRow(undefined, container);
li.addClass(CLASS_CONTROLLER_ROW);
if (propertyDesc.valueType) {
li.addClass(propertyDesc.valueType);
} else {
li.addClass(typeof propertyDesc.value);
}
if (propertyDesc.focusWidget) {
widget.focus();
}
return widget;
};
PropertyGridPart.prototype.addFolder = function (name, text) {
var newGuiParams = {name: name, text: text, parent: this},
gui,
li,
self = this;
if (this.__folders[name] !== undefined) {
throw new Error('You already have a folder with the name "' + name + '"');
}
gui = new PropertyGridPart(newGuiParams);
this.__folders[name] = gui;
gui.onChange(function (args) {
self._change(args);
});
gui.onFinishChange(function (args) {
self._finishChange(args);
});
gui.onReset(function (propertyName) {
self._reset(propertyName);
});
li = this._addRow(this, gui._el);
li.addClass('folder');
return gui;
};
PropertyGridPart.prototype.onChange = function (fnc) {
this.__onChange = fnc;
return this;
};
PropertyGridPart.prototype.onFinishChange = function (fnc) {
this.__onFinishChange = fnc;
return this;
};
PropertyGridPart.prototype.onReset = function (fnc) {
this.__onReset = fnc;
return this;
};
PropertyGridPart.prototype.clear = function () {
var i;
if (this._parent) {
this.__onChange = undefined;
this.__onFinishChange = undefined;
}
for (i in this.__widgets) {
if (this.__widgets.hasOwnProperty(i)) {
this.__widgets[i].remove();
delete this.__widgets[i];
}
}
for (i in this.__folders) {
if (this.__folders.hasOwnProperty(i)) {
this.__folders[i].clear();
delete this.__folders[i];
}
}
this.__ul.empty();
};
PropertyGridPart.prototype.setReadOnly = function (isReadOnly) {
var i;
//set all its widget to isReadOnly
for (i in this.__widgets) {
if (this.__widgets.hasOwnProperty(i)) {
this.__widgets[i].setReadOnly(isReadOnly);
}
}
//set all its sub-folders to isReadOnly
for (i in this.__folders) {
if (this.__folders.hasOwnProperty(i)) {
this.__folders[i].setReadOnly(isReadOnly);
}
}
};
PropertyGridPart.prototype.registerWidgetForType = function (type, widget) {
this._widgetManager.registerWidgetForType(type, widget);
};
/*************** END OF - PUBLIC API **************************/
return PropertyGridPart;
});