UNPKG

kekule

Version:

Open source JavaScript toolkit for chemoinformatics

1,098 lines (1,040 loc) 31.8 kB
/** * @fileoverview * Implementation of button widgets. * @author Partridge Jiang */ /* * requires /lan/classes.js * requires /utils/kekule.utils.js * requires /utils/kekule.domUtils.js * requires /xbrowsers/kekule.x.js * requires /widgets/kekule.widget.base.js * requires /widgets/kekule.widget.containers.js * requires /widgets/commonCtrls/kekule.widget.images.js */ (function(){ "use strict"; var EU = Kekule.HtmlElementUtils; var CNS = Kekule.Widget.HtmlClassNames; /** @ignore */ Kekule.Widget.HtmlClassNames = Object.extend(Kekule.Widget.HtmlClassNames, { BUTTON: 'K-Button', BUTTON_KINDED: 'K-Button-Kinded', BUTTON_GROUP: 'K-Button-Group', COMPACT_BUTTON: 'K-Compact-Button', BTN_COMPACT_MARK: 'K-Compact-Mark' }); /** * An general button widget. * @class * @augments Kekule.Widget.BaseWidget * * @property {String} actionType Value of 'button', 'submit' or 'reset'. * This property is actually mapped to 'type' attribute of button element. * @property {String} text Text on button. * @property {Kekule.Widge.Glyph} leadingGlyph * @property {Kekule.Widge.Glyph} tailingGlyph * @property {Bool} showLeadingGlyph * @property {Bool} showTailingGlyph * @property {Bool} showDropDownMark Whether show a dropdown mark (&#x25BC,▼). * @property {String} buttonKind Predefined kind that defines outlook of button. Value from {@link Kekule.Widget.Button.Kinds}. */ Kekule.Widget.Button = Class.create(Kekule.Widget.BaseWidget, /** @lends Kekule.Widget.Button# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.Button', /** @private */ BINDABLE_TAG_NAMES: ['input', 'button', 'a', 'label'], /** @private */ CSS_DROPDOWN_CLASS_NAME: 'K-DropDownMark', /** @private */ DEF_GLYPH_WIDTH: '16px', /** @private */ DEF_GLYPH_HEIGHT: '16px', /** @constructs */ initialize: function(/*$super, */parentOrElementOrDocument, text) { // must init internal part vars before $super, as they may be setted in super constructor this._elemTextPart = null; // used internally this._elemLeadingGlyphPart = null; this._elemTailingGlyphPart = null; this.tryApplySuper('initialize', [parentOrElementOrDocument]) /* $super(parentOrElementOrDocument) */; if (text) this.setText(text); }, /** @private */ initProperties: function() { this.defineElemAttribMappingProp('actionType', 'type'); this.defineProp('text', {'dataType': DataType.STRING, 'serializable': false, 'getter': function() { //return Kekule.HtmlElementUtils.getInnerText(this.getElement()); var elem = (this._elemTextPart || this.getElement()); return elem? elem.innerHTML: null; }, 'setter': function(value) { this.changeContentText(value); } }); /* this.defineProp('allowTextWrap', {'dataType': DataType.BOOL, 'serialzable': false, 'setter': function(value) { if (value) this.removeClassName(CNS.TEXT_NO_WRAP); else this.addClassName(CNS.TEXT_NO_WRAP); } }); */ /* this.defineProp('showText', {'dataType': DataType.BOOL, 'setter': function(value) { this.setPropStoreFieldValue('showText', value); //this._elemTextPart.style.display = value? '': 'none'; if (value) this.removeClassName(CNS.HIDE_TEXT); else this.addClassName(CNS.HIDE_TEXT); } }); */ this.defineProp('leadingGlyph', {'dataType': 'Kekule.Widget.Glyph', 'serializable': false, 'scope': Class.PropertyScope.PUBLIC, 'setter': null, 'getter': function(canCreate) { var result = this.getPropStoreFieldValue('leadingGlyph'); if (!result && canCreate) { result = this._createDefaultGlyphWidget(this._elemLeadingGlyphPart); this.setPropStoreFieldValue('leadingGlyph', result); } return result; } }); this.defineProp('tailingGlyph', {'dataType': 'Kekule.Widget.Glyph', 'serializable': false, 'scope': Class.PropertyScope.PUBLIC, 'setter': null, 'getter': function(canCreate) { var result = this.getPropStoreFieldValue('tailingGlyph'); if (!result && canCreate) { result = this._createDefaultGlyphWidget(this._elemTailingGlyphPart); this.setPropStoreFieldValue('tailingGlyph', result); } return result; } }); /* this.defineProp('showGlyph', {'dataType': DataType.BOOL, 'setter': function(value) { this.setPropStoreFieldValue('showGlyph', value); if (value) this.removeClassName(CNS.HIDE_GLYPH); else this.addClassName(CNS.HIDE_GLYPH); } }); */ this.defineProp('showLeadingGlyph', {'dataType': DataType.BOOL, 'scope': Class.PropertyScope.PUBLIC, 'setter': function(value) { this.setPropStoreFieldValue('showLeadingGlyph', value); this._elemLeadingGlyphPart.style.display = (value && this.getShowGlyph())? '': 'none'; } }); this.defineProp('showTailingGlyph', {'dataType': DataType.BOOL, 'scope': Class.PropertyScope.PUBLIC, 'setter': function(value) { this.setPropStoreFieldValue('showTailingGlyph', value); this._elemTailingGlyphPart.style.display = (value && this.getShowGlyph())? '': 'none'; } }); /* this.defineProp('showDropDownMark', {'dataType': DataType.BOOL, 'setter': function(value) { this.setPropStoreFieldValue('showDropDownMark', value); if (value && (!this._elemDropDownMarkPart)) this._createDropDownPart(this.getElement()); if ((!value) && this._elemDropDownMarkPart) this._releaseDropDownPart(); } }); */ this.defineProp('buttonKind', {'dataType': DataType.STRING, 'setter': function(value) { var old = this.getButtonKind(); if (value !== old) { this.cancelButtonKind(old); this.applyButtonKind(value); this.setPropStoreFieldValue('buttonKind', value); } } }); }, initPropValues: function(/*$super*/) { this.tryApplySuper('initPropValues') /* $super() */; // set style property before create element and appending to parent, important // as parent may set property of self this.setPropStoreFieldValue('showText', true); this.setPropStoreFieldValue('showGlyph', true); this.setPropStoreFieldValue('showLeadingGlyph', true); this.setPropStoreFieldValue('showTailingGlyph', true); this.setPropStoreFieldValue('useCornerDecoration', true); //this.setPropStoreFieldValue('showDropDownMark', false); this.setAllowTextWrap(false); }, /** @private */ _createDefaultGlyphWidget: function(parentElem) { var g = new Kekule.Widget.Glyph(this); g.setWidth(this.DEF_GLYPH_WIDTH).setHeight(this.DEF_GLYPH_HEIGHT); g.setStatic(true).setInheritState(true).setInheritStatic(true).setInheritEnabled(true); g.appendToElem(parentElem); return g; }, /* @private */ /* _createDropDownPart: function(parentElem) { // TODO: now use an unicode triangle to mark drop down. Need to change it to image in the future. var result = this.createDecorationContent(parentElem); result.innerHTML = '&#x25BC;'; Kekule.HtmlElementUtils.addClass(result, this.CSS_DROPDOWN_CLASS_NAME); this._elemDropDownMarkPart = result; return result; }, */ /* @private */ /* _releaseDropDownPart: function() { if (this._elemDropDownMarkPart && this._elemDropDownMarkPart.parentNode) { this._elemDropDownMarkPart.parentNode.removeChild(this._elemDropDownMarkPart); this._elemDropDownMarkPart = null; } }, */ /** @ignore */ doGetWidgetClassName: function(/*$super*/) { return this.tryApplySuper('doGetWidgetClassName') /* $super() */ + ' ' + CNS.BUTTON; //this.CSS_CLASS_NAME; }, /** @ignore */ doCreateRootElement: function(doc) { var result = doc.createElement('button'); result.setAttribute('type', 'button'); // avoid default submit type /* var result = doc.createElement('a'); result.setAttribute('href', 'javascript:void(0)'); */ return result; }, /** @ignore */ doBindElement: function(/*$super, */element) { this.tryApplySuper('doBindElement', [element]) /* $super(element) */; //var text = EU.getInnerText(element); var text = element.innerHTML || ''; element.innerHTML = ''; // clear old content first this._elemTextPart = this.createTextContent(text, element); this._elemLeadingGlyphPart = this.createGlyphContent(element, this._elemTextPart, CNS.PART_PRI_GLYPH_CONTENT); this._elemTailingGlyphPart = this.createGlyphContent(element, null, CNS.PART_ASSOC_GLYPH_CONTENT); /* if (this.getShowDropDownMark()) this._createDropDownPart(element); */ if (this.getUseCornerDecoration()) EU.addClass(element, CNS.CORNER_ALL); }, /* @ignore */ /* getStateClassName: function($super, state) { var result = $super(state) + ' '; var WS = Kekule.Widget.State; result += (state === WS.ACTIVE)? CNS.STATE_BTN_ACTIVE: (state === WS.HOVER)? CNS.STATE_BTN_HOVER: (state === WS.FOCUSED)? CNS.STATE_BTN_FOCUSED: (state === WS.DISABLED)? CNS.STATE_BTN_DISABLED: CNS.STATE_BTN_NORMAL; return result; }, */ /** @private */ changeContentText: function(newText) { /* if (this._elemTextPart) { this.getElement().removeChild(this._elemTextPart); this._elemTextPart = this.createTextContent(text, element); } */ this._elemTextPart.innerHTML = newText || ''; }, /** @private */ isPeriodicalExecuting: function(/*$super*/) { return this.tryApplySuper('isPeriodicalExecuting') /* $super() */ && this.getIsActive(); }, /** @private */ doReactActiviting: function(/*$super, */e) { this.tryApplySuper('doReactActiviting', [e]) /* $super(e) */; if (this.getEnablePeriodicalExec()) this.startPeriodicalExec(e); }, /** @private */ doReactDeactiviting: function(/*$super, */e) { //if (this.getEnablePeriodicalExec()) this.stopPeriodicalExec(); // stop it anyway if (this.getIsActive()) // meet a active-deactive event, clicked or key pressed on button { this.execute(e); //console.log('execute', e); } }, /** @private */ cancelButtonKind: function(kind) { if (kind) { this.removeClassName(kind); this.removeClassName(CNS.BUTTON_KINDED); } }, /** @private */ applyButtonKind: function(kind) { if (kind) { this.addClassName(CNS.BUTTON_KINDED); this.addClassName(kind); } } // event handlers /** @private */ /* react_click: function(e) { this.execute(); } */ }); /** * Predefined button kinds. * @class */ Kekule.Widget.Button.Kinds = { DROPDOWN: 'K-Kind-DropDown', POPUP: 'K-Kind-Popup', SEARCH: 'K-Kind-Search', EDIT: 'K-Kind-Edit', ENTER: 'K-Kind-Enter' /* ELLIPSIS: 'K-Kind-Ellipsis' */ }; /** * An check button widget. Press on it will toggle the check state of button. * @class * @augments Kekule.Widget.Button * * @property {Bool} checked Whether the button has been pressed down. * @property {Bool} autoCheck If true, the button will be automatically checked/unchecked when clicking on it. */ /** * Invoked button is checked. * event param of it has field: {widget} * @name Kekule.Widget.CheckButton#check * @event */ /** * Invoked button is unchecked. * event param of it has field: {widget} * @name Kekule.Widget.CheckButton#uncheck * @event */ /** * Invoked button checked state changed. * event param of it has field: {widget, checked} * @name Kekule.Widget.CheckButton#checkChange * @event */ Kekule.Widget.CheckButton = Class.create(Kekule.Widget.Button, /** @lends Kekule.Widget.CheckButton# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.CheckButton', /** @constructs */ initialize: function(/*$super, */parentOrElementOrDocument, text) { this.tryApplySuper('initialize', [parentOrElementOrDocument, text]) /* $super(parentOrElementOrDocument, text) */; }, /** @private */ initProperties: function() { this.defineProp('checked', {'dataType': DataType.BOOL, 'setter': function(value) { if (this.getPropStoreFieldValue('checked') !== value) { this.setPropStoreFieldValue('checked', value); this.checkChanged(); this.stateChanged(); } } }); this.defineProp('autoCheck', {'dataType': DataType.BOOL}); }, /** @ignore */ initPropValues: function(/*$super*/) { this.tryApplySuper('initPropValues') /* $super() */; this.setAutoCheck(true); }, /** * Called when checked property is changed. * Desendants may override this method. */ checkChanged: function() { // do nothing here if (this.getChecked()) this.invokeEvent('check'); else this.invokeEvent('uncheck'); this.invokeEvent('checkChange', {'checked': this.getChecked()}); }, /** @ignore */ getStateClassName: function(/*$super, */state) { var st = this.getChecked()? Kekule.Widget.State.ACTIVE: state; return this.tryApplySuper('getStateClassName', [st]) /* $super(st) */; }, /** @ignore */ doReactDeactiviting: function(/*$super, */e) //doExecute: function($super, invokerHtmlEvent) { //$super(invokerHtmlEvent); var oldChecked = this.getChecked(); this.tryApplySuper('doReactDeactiviting', [e]) /* $super(e) */; // execute runs here, may also change checked status if (this.getAutoCheck()) this._doToggleCheckOnSelf(oldChecked); }, /** @private */ _doToggleCheckOnSelf: function(oldChecked) { if (this.getEnabled()) this.setChecked(/*!this.getChecked()*/!oldChecked); } }); /** * An check button widget. Press on it will toggle the check state of button. * @class * @augments Kekule.Widget.CheckButton * * @property {Bool} checked Whether the button has been pressed down. */ Kekule.Widget.RadioButton = Class.create(Kekule.Widget.CheckButton, /** @lends Kekule.Widget.RadioButton# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.RadioButton', /** @constructs */ initialize: function(/*$super, */parentOrElementOrDocument, text) { this.tryApplySuper('initialize', [parentOrElementOrDocument, text]) /* $super(parentOrElementOrDocument, text) */; //this.setGroup(''); // default value, avoid undefined }, /** @private */ initProperties: function() { this.defineProp('group', {'dataType': DataType.STRING}); }, /** @ignore */ checkChanged: function(/*$super*/) { this.tryApplySuper('checkChanged') /* $super() */; if (this.getChecked()) { //check parent widget, and set all radio button with same group name to unchecked this.uncheckSiblings(); } }, /** @private */ uncheckSiblings: function() { //console.log('uncheck siblings'); var parent = this.getParent(); var groupName = this.getGroup(); if (parent) { var ws = parent.getChildWidgets(); for (var i = 0, l = ws.length; i < l; ++i) { var w = ws[i]; if ((w !== this) && w.getGroup && w.setChecked && (w.getGroup() === groupName)) w.setChecked(false); } } }, /** @ignore */ doReactDeactiviting: function(/*$super, */e) { this.tryApplySuper('doReactDeactiviting', [e]) /* $super(e) */; }, /** @ignore */ _doToggleCheckOnSelf: function(/*$super, */oldChecked) { if (oldChecked) return; // radio button cannot uncheck self else this.tryApplySuper('_doToggleCheckOnSelf', [oldChecked]) /* $super(oldChecked) */; }, /** @private */ _doCheckOnSelf: function() { if (this.getEnabled()) this.setChecked(true); } }); /** * An drop-down button widget. Press on it will show another widget to its right or bottom. * @class * @augments Kekule.Widget.Button * * @property {Kekule.Widget.BaseWidget} dropDownWidget Widget that will be shown when button is pressed. * //@property {Bool} dropDownOnHover Whether shows drop down widget on mouse hover and hide it on mouse leave. * @property {Int} dropPosition Value from {@link Kekule.Widget.Position}, position of top-left corner of drop widget (based on current button). * Set it to null means automatically. * @property {Func} dropDownWidgetGetter An external function to return drop down widget. Useful to create drop down widget on demand. */ /** * Invoked when the drop down widget is invoked by button. * event param of it has field: {dropDown: Widget} * @name Kekule.Widget.DropDownButton#dropDown * @event */ Kekule.Widget.DropDownButton = Class.create(Kekule.Widget.Button, /** @lends Kekule.Widget.DropDownButton# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.DropDownButton', /** @private */ doFinalize: function(/*$super*/) { this.tryApplySuper('doFinalize') /* $super() */; /* var w = this.getDropDownWidget(); if (w) w.finalize(); */ }, /** @private */ initProperties: function() { this.defineProp('dropDownWidget', {'dataType': 'Kekule.Widget.BaseWidget', 'serializable': false, 'getter': function() { var result = this.getPropStoreFieldValue('dropDownWidget'); if (!result) { var getter = this.getDropDownWidgetGetter(); if (getter) { result = getter(this); this.setPropStoreFieldValue('dropDownWidget', result); } } return result; }, 'setter': function(value) { this.setPropStoreFieldValue('dropDownWidget', value); if (value) // hide it first { value.setDisplayed(false); } } }); this.defineProp('dropDownWidgetGetter', {'dataType': DataType.FUNCTION, 'serializable': false}); //this.defineProp('dropDownOnHover', {'dataType': DataType.BOOL}); this.defineProp('dropPosition', {'dataType': DataType.INT}); }, /** @ignore */ doCreateRootElement: function(/*$super, */doc) { /* var result = doc.createElement('a'); result.setAttribute('href', 'javascript:void(0)'); return result; // NOTE: use <button> will cause problem in Firefox */ return this.tryApplySuper('doCreateRootElement', [doc]) /* $super(doc) */; }, /** @private */ calcActualDropPosition: function() { var D = Kekule.Widget.Position; var pos = this.getDropPosition(); if (!pos) // automatically { var p = this.getParent(); var layout = p? p.getLayout(): Kekule.Widget.Layout.HORIZONTAL; // check which direction can display all part of widget and drop dropdown widget to that direction //var selfClientRect = Kekule.HtmlElementUtils.getElemBoundingClientRect(this.getElement()); var selfClientRect = Kekule.HtmlElementUtils.getElemPageRect(this.getElement(), true); var viewPortDim = Kekule.HtmlElementUtils.getViewportDimension(this.getElement()); var dropElem = this.getDropDownWidget().getElement(); // add the dropdown element to DOM tree first, else the offsetDimension will always return 0 dropElem.style.visible = 'hidden'; dropElem.style.display = ''; this.getElement().appendChild(dropElem); // IMPORTANT: must append to self, otherwise style may be different var dropDim = Kekule.HtmlElementUtils.getElemOffsetDimension(dropElem); // then remove from DOM tree this.getElement().removeChild(dropElem); if (layout) { if (layout === Kekule.Widget.Layout.VERTICAL) // check left or right { var left = selfClientRect.x; var right = viewPortDim.width - left - selfClientRect.width; // we prefer right, check if right can display drop down widget if (right >= dropDim.width) pos = D.RIGHT; else pos = (left > right)? D.LEFT: D.RIGHT; } else // check top or bottom { var top = selfClientRect.y; var bottom = viewPortDim.height - top - selfClientRect.height; // we prefer bottom if (bottom >= dropDim.height) pos = D.BOTTOM; else pos = (top > bottom)? D.TOP: D.BOTTOM; } } } return pos; }, /** @private */ showDropDownWidget: function() { var dropWidget = this.getDropDownWidget(); // move drop widget's element inside self's var dropElem = dropWidget.getElement(); dropElem.style.position = 'absolute'; var elem = this.getElement(); // set position /* var D = Kekule.Widget.Position; var SU = Kekule.StyleUtils; var pos = this.calcActualDropPosition(); var xprop = (pos & D.LEFT)? 'right': 'left'; var yprop = (pos & D.TOP)? 'bottom': 'top'; var x = (pos & D.LEFT) || (pos & D.RIGHT)? this.getOffsetWidth(): 0; var y = (pos & D.BOTTOM) || (pos & D.TOP)? this.getOffsetHeight(): 0; x += 'px'; y += 'px'; dropElem.style.left = ''; dropElem.style.right = ''; dropElem.style[xprop] = x; dropElem.style.top = ''; dropElem.style.bottom = ''; dropElem.style[yprop] = y; dropElem.style.zIndex = 10; //elem.appendChild(dropElem); dropWidget.setParent(this); dropWidget.appendToElem(elem); // must append after set position, else the computedStyle of elem may change */ // show //dropWidget.setIsPopup(true); dropWidget.show(this, null, Kekule.Widget.ShowHideType.DROPDOWN); this.invokeEvent('dropDown', {'dropDown': dropWidget}); }, /** @private */ hideDropDownWidget: function() { this.getDropDownWidget().hide(this); }, /** @private */ isDropDownWidgetShown: function() { var w = this.getDropDownWidget(); var result = w && w.isShown(); /* if (result) // check if widget add as child of self element result = (w.getParent() === this) && (w.getElement().parentNode === this.getElement()); */ return result; }, /** @private */ doExecute: function(/*$super, */invokerHtmlEvent) { if (this.getDropDownWidget()) { //console.log('drop', this.isDropDownWidgetShown()); if (this.isDropDownWidgetShown()) { this.hideDropDownWidget(); } else { this.showDropDownWidget(); } } this.tryApplySuper('doExecute', [invokerHtmlEvent]) /* $super(invokerHtmlEvent) */; } }); /** * An container to hold a set of buttons. * @class * @augments Kekule.Widget.Toolbar * * //@property {Bool} showText Whether show text in all buttons in group. * //@property {Bool} showGlyph Whether show glyph in all buttons in group. */ Kekule.Widget.ButtonGroup = Class.create(Kekule.Widget.Toolbar, /** @lends Kekule.Widget.ButtonGroup# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.ButtonGroup', /** @construct */ initialize: function(/*$super, */parentOrElementOrDocument) { this.tryApplySuper('initialize', [parentOrElementOrDocument]) /* $super(parentOrElementOrDocument) */; }, /** @ignore */ initPropValues: function(/*$super*/) { this.tryApplySuper('initPropValues') /* $super() */; this.setPropStoreFieldValue('showText', true); this.setPropStoreFieldValue('showGlyph', true); this.setAllowChildWrap(false); }, /** @ignore */ doGetWidgetClassName: function(/*$super*/) { return this.tryApplySuper('doGetWidgetClassName') /* $super() */ + ' ' + CNS.BUTTON_GROUP; }, /** @ignore */ doCreateRootElement: function(doc) { var result = doc.createElement('span'); return result; }, /** @ignore */ getDefaultChildWidgetClassName: function() { return 'Kekule.Widget.Button'; } }); /** * An a set of buttons display only one at a time. * @class * @augments Kekule.Widget.DropDownButton * * @property {Int} buttonSetLayout Layout of button set. Set to null to auto calculate it. * @property {selected} Currently selected button in set. * @property {Bool} cloneSelectedOutlook */ /** * Invoked when a button in set is selected. * event param of it has field: {selected: button} * @name Kekule.Widget.CompactButtonSet#select * @event */ Kekule.Widget.CompactButtonSet = Class.create(Kekule.Widget.DropDownButton, /** @lends Kekule.Widget.CompactButtonSet# */ { /** @private */ CLASS_NAME: 'Kekule.Widget.CompactButtonSet', /** @constructs */ initialize: function(/*$super, */parentOrElementOrDocument, text) { this.reactSetButtonExecuteBind = this.reactSetButtonExecute.bind(this); //this.reactSetButtonCheckBind = this.reactSetButtonCheck.bind(this); this.setPropStoreFieldValue('showCompactMark', true); this.setPropStoreFieldValue('cloneSelectedOutlook', true); this.tryApplySuper('initialize', [parentOrElementOrDocument, text]) /* $super(parentOrElementOrDocument, text) */; //this._compactMark = this.createCompactMark(); if (!this.getButtonSet()) this.initButtonGroup(); }, /** @private */ initProperties: function() { this.defineProp('buttonSet', {'dataType': 'Kekule.Widget.ButtonGroup', 'serializable': false, 'setter': function(value) { var old = this.getButtonSet(); if (old !== value) { if (old) old.finalize(); this.initButtonGroup(value); } } }); this.defineProp('buttonSetLayout', {'dataType': DataType.INT}); this.defineProp('selected', {'dataType': 'Kekule.Widget.Button', 'serializable': false, 'setter': function(value) { if (value) { if (this.getButtonSet().hasChild(value)) { if (this.getCloneSelectedOutlook()) this.cloneSetButton(value); if (value.setChecked) value.setChecked(true); } } else // setSelected(null), uncheck all { var w = this.getSelected(); if (w) w.setChecked(false); } this.setPropStoreFieldValue('selected', value); } }); this.defineProp('cloneSelectedOutlook', {'dataType': DataType.BOOL}); this.defineProp('showCompactMark', {'dataType': DataType.BOOL, 'setter': function(value) { var old = this.getShowCompactMark(); if (old !== value) { this.setPropStoreFieldValue('showCompactMark', value); if (value) this.createCompactMark(); else this.removeCompactMark(); } } }); }, /** @ignore */ doGetWidgetClassName: function(/*$super*/) { return this.tryApplySuper('doGetWidgetClassName') /* $super() */ + ' ' + CNS.COMPACT_BUTTON; //this.CSS_CLASS_NAME; }, /** @private */ doSetShowText: function(/*$super, */value) { if (this.getButtonSet()) this.getButtonSet().setShowText(value); return this.tryApplySuper('doSetShowText', [value]) /* $super(value) */; }, /** @private */ doSetShowGlyph: function(/*$super, */value) { if (this.getButtonSet()) this.getButtonSet().setShowGlyph(value); return this.tryApplySuper('doSetShowGlyph', [value]) /* $super(value) */; }, /** @private */ createCompactMark: function() { var btnElem = this.getElement(); if (this._compactMark) btnElem.removeChild(this._compactMark); var mark = this.getDocument().createElement('span'); mark.className = CNS.BTN_COMPACT_MARK; btnElem.appendChild(mark); this._compactMark = mark; return mark; }, /** @private */ removeCompactMark: function() { var btnElem = this.getElement(); if (this._compactMark) btnElem.removeChild(this._compactMark); }, /** @private */ initButtonGroup: function(btnSet) { if (!btnSet) { btnSet = new Kekule.Widget.ButtonGroup(this); } else { // if some button already checked, clone styles later var checkedBtn = this._getCheckedButtonInGroup(btnSet) } btnSet.setDisplayed(false); btnSet.setShowText(this.getShowText()); btnSet.setShowGlyph(this.getShowGlyph()); this.setPropStoreFieldValue('buttonSet', btnSet); this.setDropDownWidget(btnSet); btnSet.addEventListener('execute', this.reactSetButtonExecuteBind); btnSet.addEventListener('check', this.reactSetButtonExecuteBind); if (checkedBtn) { this.cloneSetButton(checkedBtn); } }, /** @private */ _getCheckedButtonInGroup: function(btnGroup) { var ws = btnGroup.getChildWidgets(); for (var i = 0, l = ws.length; i < l; ++i) { var w = ws[i]; if (w.getChecked && w.getChecked()) return w; } return null; }, /** @private */ cloneSetButton: function(btn) { if (!this.getCloneSelectedOutlook()) return; var thisElem = this.getElement(); var setElem = this.getButtonSet().getElement(); /* var innerHTML = btn.getElement().innerHTML; if (thisElem.contains(setElem)) thisElem.removeChild(setElem); // remove first, avoid element lost in IE thisElem.innerHTML = innerHTML; */ var DU = Kekule.DomUtils; var thisChildren = DU.getDirectChildElems(thisElem); var btnChildren = DU.getDirectChildElems(btn.getElement()); var setElemInside = false; for (var i = 0, l = thisChildren.length; i < l; ++i) { var child = thisChildren[i]; if (child !== setElem) thisElem.removeChild(child); else setElemInside = true; } for (var i = 0, l = btnChildren.length; i < l; ++i) { var child = btnChildren[i].cloneNode(true); //console.log(child, setElem); if (setElemInside) thisElem.insertBefore(child, setElem); else thisElem.appendChild(child); } if (this._clonedCustomHtmlClassName) this.removeClassName(this._clonedCustomHtmlClassName); this._clonedCustomHtmlClassName = btn.getCustomHtmlClassName(); //console.log(this._clonedCustomHtmlClassName); if (this._clonedCustomHtmlClassName) this.addClassName(this._clonedCustomHtmlClassName); this._compactMark = null; this.createCompactMark(); //this.getButtonSet().setParent(this); }, /** @private */ calcActualButtonSetLayout: function() { var L = Kekule.Widget.Layout; var result = this.getButtonSetLayout(); if (!result) // auto calc { var p = this.getParent(); var layout = p? p.getLayout(): L.HORIZONTAL; result = (layout === L.VERTICAL)? L.HORIZONTAL: L.VERTICAL; } return result; }, /** @private */ showDropDownWidget: function(/*$super*/) { var layout = this.calcActualButtonSetLayout(); this.getButtonSet().setLayout(layout); this.tryApplySuper('showDropDownWidget') /* $super() */; }, /** @private */ reactSetButtonExecute: function(e) { if (e.target instanceof Kekule.Widget.Button) // click on set button { if (e.target !== this.getSelected()) { if (!this._currExecButton || this._currExecButton !== e.target) { try { this._currExecButton = e.target; e.target.setIsFocused(false); e.target.setIsHover(false); e.target.setIsActive(false); this.setSelected(e.target); if (this.getButtonSet().isShown()) this.getButtonSet().hide(); /* var self = this; this.getButtonSet().hide(function() { self.setSelected(e.target); }); */ this.invokeEvent('select', {'selected': e.target}); } finally { this._currExecButton = null; } } } } }, /** * Append a button to set. * @param {Kekule.Widget.Button} btn * @param {Bool} asSelected */ append: function(btn, asSelected) { this.getButtonSet().appendWidget(btn); if (asSelected) this.setSelected(btn); return this; }, /** * Insert a button before ref button. * @param {Kekule.Widget.Button} btn * @param {Kekule.Widget.Button} ref */ insertBefore: function(btn, ref, asSelected) { this.getButtonSet().insertWidgetBefore(btn); if (asSelected) this.setSelected(btn); return this; }, /** * Remove btn from set. * @param {Kekule.Widget.Button} btn * @param {Bool} doNotFinalize If set to true, the btn will not be finalized. */ remove: function(btn, doNotFinalize) { this.getButtonSet().removeWidget(btn, doNotFinalize); return this; } }); })();