UNPKG

aolists-webtop

Version:

Web interface for aoLists

938 lines (872 loc) 29.4 kB
/** * @class aoVisualPanel * @class aoVisualTabs * @class aoVisualHolder * @extends Ext.Panel * * @author Jose Gonzalez * @copyright (c) 2014, by Candid.Concepts LC * @version 1.0 * * @license aoVisualPanel is licensed under the terms of * the Open Source LGPL 3.0 license. Commercial use is permitted to the extent * that the code/component(s) do NOT become part of another Open Source or Commercially * licensed development library or toolkit without explicit permission. * * <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html" * target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p> * */ Ext.ns('Ext.ux.form'); /** * Creates new aoVisualPanel * @constructor * @param {Object} config A config object */ Ext.ux.form.aoVisualPanel = Ext.extend(Ext.Panel, { layout: 'absolute', /** * @private * creates both fields and installs the necessary event handlers */ initComponent: function () { // call parent initComponent Ext.ux.form.aoVisualPanel.superclass.initComponent.call(this); // Get the definition var wkgdef = my.Definitions.get(this); // Any? if (wkgdef) { // Loop through fields for (var i = 0; i < wkgdef.fields.length; i++) { this.add(my.Definitions.Fields.generate(wkgdef, wkgdef.fields[i])); } } // Click event this.addEvents('panelclick'); }, /** * @private * Renders underlying primary and secondary and provides a workaround for side error icon bug */ onRender: function (ct, position) { if (!this.isRendered) { // render underlying hidden field Ext.ux.form.aoVisualPanel.superclass.onRender.call(this, ct, position); // Do any indefine thing my.Definitions.Fields.handleInDefine(this); // we're rendered flag this.isRendered = true; // Do any indefine thing my.Definitions.Fields.handleInDefine(this); this.fireEvent("render", this); } }, /** * @private * Sets up the menu to add objects to the panel */ initInDefine: function (panel) { // Setup drop target var stg = my.Helper.get(this); if (!stg.dropTarget) { stg.dropTarget = new Ext.dd.DropTarget(this.body, { ddGroup: this.getId() }); // And link in the fields for (var i = 0; i < this.items.items.length; i++) { var fld = this.items.items[i]; if (fld.initInDefine) { fld.initInDefine(fld); } } } // Setup add menu panel.getEl().on('mouseup', function (e) { var loc = my.Functions.getAllXY(this.getEl(), e); var menuitems = []; menuitems.push({ text: 'Add Field', panel: panel, loc: loc, handler: function () { this.panel.addDefinition('string', this.loc.relative); } }); menuitems.push({ text: 'Add Tabs', panel: panel, loc: loc, handler: function () { this.panel.addDefinition('tabs', this.loc.relative); } }); menuitems.push({ text: 'Add Group', panel: panel, loc: loc, handler: function () { this.panel.addDefinition('group', this.loc.relative); } }); menuitems.push({ text: 'Add Tabbed Group', panel: panel, loc: loc, handler: function () { this.panel.addDefinition('tabgroup', this.loc.relative); } }); var menu = new Ext.menu.Menu({ renderTo: document.body, floating: true, items: menuitems }); menu.showAt(loc.absolute); }, panel); }, addDefinition: function (type, loc) { var def = my.Definitions.Fields.addField(this.local, { type: type, location: { x: loc[0], y: loc[1] } }); var extdef = my.Definitions.Fields.generate(this.local, def); return this.add(extdef); } }); Ext.reg('aovpanel', Ext.ux.form.aoVisualPanel); /** * Creates new aoVisualTabs * @constructor * @param {Object} config A config object */ Ext.ux.form.aoVisualTabs = Ext.extend(Ext.Panel, { /** * @private * creates both fields and installs the necessary event handlers */ initComponent: function () { // call parent initComponent Ext.ux.form.aoVisualTabs.superclass.initComponent.call(this); }, /** * @private * Renders underlying primary and secondary and provides a workaround for side error icon bug */ onRender: function (ct, position) { if (!this.isRendered) { // render underlying hidden field Ext.ux.form.aoVisualTabs.superclass.onRender.call(this, ct, position); // Do any indefine thing my.Definitions.Fields.handleInDefine(this); // we're rendered flag this.isRendered = true; // Do any indefine thing my.Definitions.Fields.handleInDefine(this); this.fireEvent("render", this); } } }); Ext.reg('aovtabs', Ext.ux.form.aoVisualTabs); /** * Creates new aoVisualHolder * @constructor * @param {Object} config A config object */ Ext.ux.form.aoVisualHolder = Ext.extend(Ext.form.Field, { /** * @cfg {String/Object} defaultAutoCreate DomHelper element spec * Let superclass to create hidden field instead of textbox. Hidden will be submittend to server */ defaultAutoCreate: { tag: 'input', type: 'hidden' }, /** * @cfg {Number} separatorWidth Width of separator in pixels (defaults to 0) */ separatorWidth: 0, /** * @cfg {Number} primaryyWidth Width of primary field in pixels (defaults to 40) */ primaryWidth: 40, /** * @cfg {function} primaryBase Base for primary field (defaults to label). */ primaryBase: function (src) { return new Ext.form.Label(src); }, /** * @cfg {Object} primaryConfig Config for primary constructor. */ primaryConfig: {}, /** * @cfg {string} primaryClickEvent Event for click event (default null for no event). */ primaryClickEvent: null, /** * @cfg {Number} primaryyWidth Width of primary field in pixels (defaults to 40) */ secondaryMinWidth: 25, /** * @cfg {function} secondaryBase Base for secondary field (defaults to textfield). */ secondaryBase: function (src) { return new Ext.form.TextField(src); }, /** * @cfg {Object} secondaryConfig Config for secondary constructor. */ secondaryConfig: {}, /** * @cfg {string} secondaryClickEvent Event for click event (default null for no event). */ secondaryClickEvent: null, /** * @cfg {Number} tertiaryyWidth Width of tertiary field in pixels (defaults to 8) */ tertiaryWidth: 8, /** * @cfg {function} tertiaryBase Base for tertiary field (defaults to button). */ tertiaryBase: function (src) { return new Ext.Button(src); }, /** * @cfg {Object} tertiaryConfig Config for tertiary constructor. */ tertiaryConfig: {}, /** * @cfg {string} tertiaryClickEvent Event for click event (default null for no event). */ tertiaryClickEvent: null, /** * @private * creates both fields and installs the necessary event handlers */ initComponent: function () { // Adjust fields this.fieldLabel = this.label; // call parent initComponent Ext.ux.form.aoVisualHolder.superclass.initComponent.call(this); // Compute width this.setComponentWidth(this.width); // create primary var primaryXConfig = Ext.apply({ id: this.id + '-p', width: this.primaryWidth, selectOnFocus: this.selectOnFocus, readOnly: this.readOnly, listeners: { blur: { scope: this, fn: this.onBlur }, focus: { scope: this, fn: this.onFocus }, click: { scope: this, fn: this.onPClick } } }, this.primaryConfig); this.df = this.primaryBase(primaryXConfig); this.df.ownerCt = this; // create secondary var secondaryXConfig = Ext.apply({ id: this.id + '-s', width: this.secondaryWidth, selectOnFocus: this.selectOnFocus, readOnly: this.readOnly, listeners: { blur: { scope: this, fn: this.onBlur }, focus: { scope: this, fn: this.onFocus }, click: { scope: this, fn: this.onSClick } } }, this.secondaryConfig); this.tf = this.secondaryBase(secondaryXConfig); this.tf.ownerCt = this; // create tertiary var tertiaryXConfig = Ext.apply({ id: this.id + '-t', width: this.tertiaryWidth, selectOnFocus: this.selectOnFocus, readOnly: this.readOnly, listeners: { blur: { scope: this, fn: this.onBlur }, focus: { scope: this, fn: this.onFocus }, click: { scope: this, fn: this.onTClick } } }, this.tertiaryConfig); this.bf = this.tertiaryBase(tertiaryXConfig); this.bf.ownerCt = this; // relay events this.relayEvents(this.df, ['focus', 'specialkey', 'invalid', 'valid']); this.relayEvents(this.tf, ['focus', 'specialkey', 'invalid', 'valid']); this.relayEvents(this.bf, ['focus', 'specialkey', 'invalid', 'valid']); }, /** * @private * Renders underlying primary and secondary and provides a workaround for side error icon bug */ onRender: function (ct, position) { if (!this.isRendered) { // render underlying hidden field Ext.ux.form.aoVisualHolder.superclass.onRender.call(this, ct, position); this.df.tabIndex = this.tabIndex; this.tf.tabIndex = this.tabIndex; this.bf.tabIndex = this.tabIndex; // render primary and secondary // create bounding table var t = Ext.DomHelper.append(ct, { tag: 'table', style: 'border-collapse:collapse', width: this.width, children: [{ tag: 'tr', children: [{ tag: 'td', //style: 'padding-right:' + this.separatorWidth.toString() + 'px', cls: 'ux-primary' }, { tag: 'td', cls: 'ux-secondary' }, { tag: 'td', cls: 'ux-tertiary' }] }] }, true); this.tableEl = t; this.wrap = t.wrap({ cls: 'x-form-field-wrap' }); this.wrap.setStyle('position', 'absolute'); this.wrap.on("mousedown", this.onMouseDown, this, { delay: 10 }); // render primary & secondary this.df.render(t.child('td.ux-primary')); this.tf.render(t.child('td.ux-secondary')); if (this.menu) { this.bf.render(t.child('td.ux-tertiary')); } else { this.bf.destroy(); this.bf = null; } this.setComponentWidth(this.width); // workaround for IE trigger misalignment bug if (Ext.isIE && Ext.isStrict) { t.select('input').applyStyles({ top: 0 }); } this.on('specialkey', this.onSpecialKey, this); this.df.el.swallowEvent(['keydown', 'keypress']); this.tf.el.swallowEvent(['keydown', 'keypress']); if (this.bf) { this.bf.el.swallowEvent(['keydown', 'keypress']); } // setup name for submit this.el.dom.name = this.hiddenName || this.name || this.id; // prevent helper fields from being submitted this.df.el.dom.removeAttribute("name"); this.tf.el.dom.removeAttribute("name"); if (this.bf) { this.bf.el.dom.removeAttribute("name"); } // we're rendered flag this.isRendered = true; // update hidden field this.updateValue(); // Do any indefine thing my.Definitions.Fields.handleInDefine(this); this.fireEvent("render", this); } }, /** * @private * Sets up the rezie/reposition logic */ initInDefine: function (ctl) { // Can we wrap? if (this.isRendered) { // Get the storage var stg = my.Helper.get(ctl); // Resize done? if (!stg.resizer) { stg.resizer = new Ext.Resizable(ctl.wrap.id, { handles: 'e', pinned: false, draggable: true, transparent: true, listeners: { resize: { fn: this.handleResize, scope: this } } }); stg.resizer.dd.vHolder = ctl; stg.resizer.dd.addToGroup(ctl.ownerCt.getId()); stg.resizer.dd.onMouseDown = function (e, ctl) { this.flagClick = true; }; stg.resizer.dd.onMouseUp = function (e, ctl) { if (this.flagClick) { var stg = my.Helper.getLocal(this.vHolder); var typeitems = []; my.Menu.SetChecked(typeitems, { text: 'String', itype: 'string' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Integer', itype: 'int' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Positive Integer', itype: 'positiveint' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Float', itype: 'float' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Date', itype: 'date' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Time', itype: 'time' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Phone', itype: 'phone' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'ZIP Code', itype: 'zip' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'Currency', itype: 'currency' }, stg.wkgdef.type); my.Menu.SetChecked(typeitems, { text: 'E-Mail', itype: 'email' }, stg.wkgdef.type); var menuitems = []; menuitems.push({ text: 'Edit Label', source: this, loc: e.xy, handler: function () { var a = 1; } }); menuitems.push({ text: 'Set Type', source: this, loc: e.xy, handler: function () { var a = 1; }, menu: new Ext.menu.Menu({ items: typeitems }) }); var menu = new Ext.menu.Menu({ renderTo: document.body, floating: true, items: menuitems }); menu.showAt(e.xy); //e.preventDefault(); //e.stopPropagation(); //e.stopEvent(); } }; stg.resizer.dd.onDragDrop = function (e, id) { this.flagClick = false; var deltaX = this.lastPageX - this.startPageX; var deltaY = this.lastPageY - this.startPageY; var stg = my.Helper.getLocal(this.vHolder); stg.wkgdef.location.x += deltaX; stg.wkgdef.location.y += deltaY; this.vHolder.wrap.setLeft(e.xy[0]); this.vHolder.wrap.setTop(e.xy[1]); }; } } }, /** * @private */ adjustSize: Ext.BoxComponent.prototype.adjustSize, handleResize: function (ctl, w) { this.setWidth(w + 8); }, /** * @private */ alignErrorIcon: function () { this.errorIcon.alignTo(this.tableEl, 'tl-tr', [2, 0]); }, /** * Calls clearInvalid on the primary and secondary */ clearInvalid: function () { if (this.df.clearInvalid) { this.df.clearInvalid(); } if (this.tf.clearInvalid) { this.tf.clearInvalid(); } if (this.bf && this.bf.clearInvalid) { this.bf.clearInvalid(); } }, /** * Calls markInvalid on both primary and secondary * @param {String} msg Invalid message to display */ markInvalid: function (msg) { if (this.df.markInvalid) { this.df.markInvalid(msg); } if (this.tf.markInvalid) { this.tf.markInvalid(msg); } if (this.bf && this.bf.markInvalid) { this.bf.markInvalid(msg); } }, /** * @private * called from Component::destroy. * Destroys all elements and removes all listeners we've created. */ beforeDestroy: function () { if (this.isRendered) { // this.removeAllListeners(); this.wrap.removeAllListeners(); this.wrap.remove(); this.tableEl.remove(); this.df.destroy(); this.tf.destroy(); if (this.bf) { this.bf.destroy(); } } }, /** * Disable this component. * @return {Ext.Component} this */ disable: function () { if (this.isRendered) { this.df.disabled = this.disabled; this.df.onDisable(); this.tf.onDisable(); if (this.bf) { this.bf.onDisable(); } } this.disabled = true; this.df.disabled = true; this.tf.disabled = true; if (this.bf) { this.bf.disabled = true; } this.fireEvent("disable", this); return this; }, /** * Enable this component. * @return {Ext.Component} this */ enable: function () { if (this.rendered) { this.df.onEnable(); this.tf.onEnable(); if (this.bf) { this.bf.onEnable(); } } this.disabled = false; this.df.disabled = false; this.tf.disabled = false; if (this.bf) { this.bf.disabled = false; } this.fireEvent("enable", this); return this; }, /** * @private Focus date filed */ focus: function () { this.tf.focus(); }, /** * @private */ getPositionEl: function () { return this.wrap; }, // }}} // {{{ /** * @private */ getResizeEl: function () { return this.wrap; }, /** * @return {Boolean} true = valid, false = invalid * @private Calls isValid methods of underlying primary and secondary and returns the result */ isValid: function () { return this.tf.isValid(); }, /** * Returns true if this component is visible * @return {boolean} */ isVisible: function () { return this.tf.rendered && this.tf.getActionEl().isVisible(); }, /** * @private Handles blur event */ onBlur: function (f) { // called by both primary and secondary blur events // revert focus to previous field if clicked in between if (this.wrapClick) { f.focus(); this.wrapClick = false; } this.updateValue(); // fire events later (function () { if (!this.tf.hasFocus) { var v = this.getValue(); if (String(v) !== String(this.startValue)) { if (this.rmtID) { this.rmtID = null; } if (!this.handleChange || !this.handleChange()) { this.fireEvent("change", this, v, this.startValue); } } this.hasFocus = false; this.fireEvent('blur', this); } }).defer(200, this); }, /** * @private Handles focus event */ onFocus: function () { if (!this.hasFocus) { this.hasFocus = true; this.startValue = this.getValue(); this.fireEvent("focus", this); } }, /** * @private Handles generic click event */ onClick: function (evt) {}, /** * @private Handles primary click event */ onPClick: function (ctl, e) { this.onClick(this.primaryClickEvent); }, /** * @private Handles secondary click event */ onSClick: function (ctl, e) { this.onClick(this.secondaryClickEvent); }, /** * @private Handles tertiary click event */ onTClick: function (ctl, e) { this.onClick(this.tertiaryClickEvent); }, /** * @private Just to prevent blur event when clicked in the middle of fields */ onMouseDown: function (e) { if (!this.disabled) { this.wrapClick = 'td' === e.target.nodeName.toLowerCase(); } }, /** * @private * Handles Tab and Shift-Tab events */ onSpecialKey: function (t, e) { var key = e.getKey(); if (key === e.TAB) { if (t === this.df && !e.shiftKey) { e.stopEvent(); this.tf.focus(); } if (t === this.tf && e.shiftKey) { e.stopEvent(); this.df.focus(); } } // otherwise it misbehaves in editor grid if (key === e.ENTER) { this.updateValue(); } }, setComponentWidth: function (w) { if (w) { // Compute width this.tertiaryWidth = (this.menu ? 8 : 0); this.secondaryWidth = w - (this.primaryWidth + this.tertiaryWidth); if (this.secondaryWidth < this.secondaryMinWidth) this.secondaryWidth = this.secondaryMinWidth; // Computed width this.width = this.primaryWidth + this.secondaryWidth + this.tertiaryWidth; if (this.isRendered) { // Adjust primary if (this.df && this.df.setWidth) { this.df.setWidth(this.primaryWidth); if (Ext.isIE) { this.df.el.up('td').setWidth(this.primaryWidth); } } // Adjust secondary if (this.tf && this.tf.setWidth) { this.tf.setWidth(this.secondaryWidth); if (Ext.isIE) { this.tf.el.up('td').setWidth(this.secondaryWidth); } } // Adjust tertiary if (this.menu) { if (this.bf && this.bf.setWidth) { this.bf.setWidth(this.tertiaryWidth); if (Ext.isIE) { this.bf.el.up('td').setWidth(this.tertiaryWidth); } } } // Set the wrap if (this.wrap) { this.wrap.setWidth(this.width); } } // Definition var stg = my.Helper.getLocal(this); stg.wkgdef.size.width = this.width; } }, setComponentHeight: function (h) { if (h) { if (this.tf && this.tf.setHeight) { this.tf.setHeight(h); } // Save this.height = h; // Set the wrap if (this.wrap) { this.wrap.setHeight(this.height); } // Definition var stg = my.Helper.getLocal(this); stg.wkgdef.size.height = this.height; } }, /** * @private * Sets correct sizes of underlying primary and secondary * With workarounds for IE bugs */ setSize: function (w, h) { this.setComponentHeight(h); this.setComponentWidth(w); }, /** * Hide or show this component by boolean * @return {Ext.Component} this */ setVisible: function (visible) { if (visible) { this.df.show(); this.tf.show(); if (this.bf) { this.bf.show(); } } else { this.df.hide(); this.tf.hide(); if (this.bf) { this.bf.hide(); } } return this; }, show: function () { return this.setVisible(true); }, hide: function () { return this.setVisible(false); }, /** * @private Updates all of Date, Time and Hidden */ updateValue: function () { if (this.isRendered) { this.el.dom.value = this.getValue(); } this.value = this.getValue(); }, /** * @return {Boolean} true = valid, false = invalid * calls validate methods of secondary */ validate: function () { return this.tf.validate(); }, /** * Returns renderer suitable to render this field * @param {Object} Column model config */ renderer: function (field) { var renderer = function (val) { return val; }; return renderer; }, /** * @private Sets the value of primary */ setPrimary: function (value) { this.df.setText(value); }, /** * @private Gets the value of primary */ getPrimary: function () { return null; }, /** * @private Sets the value of secondary */ setSecondary: function (value) { this.tf.setValue(name); }, /** * @private Gets the value of secondary */ getSecondary: function () { return this.tf.getValue(); }, /** * @param {String} val Value to set * Sets the value of this field */ setValue: function (val) { if (!val) { this.setSecondary(''); } else { this.setSecondary(val); } this.updateValue(); }, /** * @return {String} Returns value of this field */ getValue: function () { return this.getSecondary(); } }); Ext.reg('aoxholder', Ext.ux.form.aoVisualHolder);