UNPKG

kekule

Version:

Open source JavaScript toolkit for chemoinformatics

1,323 lines (1,273 loc) 118 kB
/** * @fileoverview * Implements an editor with essential UI. * @author Partridge Jiang */ /* * requires /lan/classes.js * requires /utils/kekule.utils.js * requires /render/kekule.render.utils.js * requires /widgets/kekule.widget.base.js * requires /widgets/kekule.widget.helpers.js * requires /widgets/chem/kekule.chemWidget.base.js * requires /widgets/operation/kekule.actions.js * requires /widgets/commonCtrls/kekule.widget.buttons.js * requires /widgets/commonCtrls/kekule.widget.containers.js * requires /widgets/advCtrls/objInspector/kekule.widget.objInspectors.js * requires /widgets/chem/structureTreeView/kekule.chemWidget.structureTreeViews.js * requires /widgets/chem/editor/kekule.chemEditor.baseEditors.js * requires /widgets/chem/editor/kekule.chemEditor.nexus.js * requires /widgets/chem/editor/kekule.chemEditor.objModifiers.js * requires /localization */ (function(){ var PS = Class.PropertyScope; var AU = Kekule.ArrayUtils; var CW = Kekule.ChemWidget; var CE = Kekule.Editor; var CNS = Kekule.Widget.HtmlClassNames; var CCNS = Kekule.ChemWidget.HtmlClassNames; var BNS = Kekule.ChemWidget.ComponentWidgetNames; //var CWT = Kekule.ChemWidgetTexts; /** @ignore */ Kekule.ChemWidget.HtmlClassNames = Object.extend(Kekule.ChemWidget.HtmlClassNames, { COMPOSER: 'K-Chem-Composer', COMPOSER_GRID_LAYOUT: 'K-Chem-Composer-Grid-Layout', // a special class indicating that the composer is using CSS grid layout COMPOSER_LANDSCAPE: 'K-Chem-Composer-Landscape', // a special class indicating that the composer is in landscape mode (client width > height) COMPOSER_PORTRAIT: 'K-Chem-Composer-Portrait', // a special class indicating that the composer is in portrait mode (client width <>> height) COMPOSER_EDITOR_STAGE: 'K-Chem-Composer-Editor-Stage', COMPOSER_ADV_PANEL: 'K-Chem-Composer-Adv-Panel', COMPOSER_ISSUE_PANEL: 'K-Chem-Composer-Issue-Panel', COMPOSER_ISSUE_PANEL_WRAPPER: 'K-Chem-Composer-Issue-Panel-Wrapper', COMPOSER_ISSUE_PANEL_TOOL_PANEL: 'K-Chem-Composer-Issue-Panel-ToolPanel', COMPOSER_ISSUE_PANEL_INSPECTOR_REGION: 'K-Chem-Composer-Issue-Panel-InspectorRegion', COMPOSER_TOP_REGION: 'K-Chem-Composer-Top-Region', COMPOSER_LEFT_REGION: 'K-Chem-Composer-Left-Region', COMPOSER_BOTTOM_REGION: 'K-Chem-Composer-Bottom-Region', COMPOSER_TOOLBAR: 'K-Chem-Composer-Toolbar', COMPOSER_COMMON_TOOLBAR: 'K-Chem-Composer-Common-Toolbar', COMPOSER_ZOOM_TOOLBAR: 'K-Chem-Composer-Zoom-Toolbar', COMPOSER_CHEM_TOOLBAR: 'K-Chem-Composer-Chem-Toolbar', COMPOSER_ASSOC_TOOLBAR: 'K-Chem-Composer-Assoc-Toolbar', COMPOSER_STYLE_TOOLBAR: 'K-Chem-Composer-Style-Toolbar', COMPOSER_OBJMODIFIER_TOOLBAR: 'K-Chem-Composer-ObjModifier-Toolbar', COMPOSER_FONTNAME_BOX: 'K-Chem-Composer-FontName-Box', COMPOSER_FONTSIZE_BOX: 'K-Chem-Composer-FontSize-Box', COMPOSER_NODEDISPLAYMODE_BOX: 'K-Chem-Composer-NodeDisplayMode-Box', COMPOSER_COLOR_BOX: 'K-Chem-Composer-Color-Box', COMPOSER_TEXTDIRECTION_BUTTON: 'K-Chem-Composer-TextDirection-Button', COMPOSER_TEXTDIRECTION_BUTTON_DEFAULT: 'K-Chem-Composer-TextDirection-Button-Default', COMPOSER_TEXTDIRECTION_BUTTON_LTR: 'K-Chem-Composer-TextDirection-Button-LTR', COMPOSER_TEXTDIRECTION_BUTTON_RTL: 'K-Chem-Composer-TextDirection-Button-RTL', COMPOSER_TEXTDIRECTION_BUTTON_TTB: 'K-Chem-Composer-TextDirection-Button-TTB', COMPOSER_TEXTDIRECTION_BUTTON_BTT: 'K-Chem-Composer-TextDirection-Button-BTT', COMPOSER_TEXTALIGN_BUTTON: 'K-Chem-Composer-TextAlign-Button', COMPOSER_TEXTALIGN_BUTTON_HORIZONTAL: 'K-Chem-Composer-TextAlign-Button-Horizontal', COMPOSER_TEXTALIGN_BUTTON_VERTICAL: 'K-Chem-Composer-TextAlign-Button-Vertical', COMPOSER_TEXTALIGN_BUTTON_DEFAULT: 'K-Chem-Composer-TextAlign-Button', COMPOSER_TEXTALIGN_BUTTON_LEADING: 'K-Chem-Composer-TextAlign-Button-Leading', COMPOSER_TEXTALIGN_BUTTON_TRAILING: 'K-Chem-Composer-TextAlign-Button-Trailing', COMPOSER_TEXTALIGN_BUTTON_CENTER: 'K-Chem-Composer-TextAlign-Button-Center', COMPOSER_TEXTALIGN_BUTTON_LEFT: 'K-Chem-Composer-TextAlign-Button-Left', COMPOSER_TEXTALIGN_BUTTON_RIGHT: 'K-Chem-Composer-TextAlign-Right', COMPOSER_TEXTALIGN_BUTTON_TOP: 'K-Chem-Composer-TextAlign-Top', COMPOSER_TEXTALIGN_BUTTON_BOTTOM: 'K-Chem-Composer-TextAlign-Bottom', COMPOSER_DIALOG: 'K-Chem-ComposerDialog', //'K-Chem-Viewer-Assoc-Editor' COMPOSER_FRAME: 'K-Chem-ComposerFrame', COMPOSER_FRAME_CONTENT_DOC: 'K-Chem-ComposerFrame-ContentDoc', COMPOSER_FRAME_CONTENT_BODY: 'K-Chem-ComposerFrame-ContentBody' }); Kekule.globalOptions.add('chemWidget.composer', { commonToolButtons: [ BNS.newDoc, //BNS.loadFile, BNS.loadData, BNS.saveData, BNS.undo, BNS.redo, BNS.copy, BNS.cut, BNS.paste, //BNS.cloneSelection, BNS.zoomIn, //BNS.reset, //BNS.resetZoom, BNS.zoomOut, BNS.config, BNS.objInspector ], chemToolButtons: [ BNS.manipulate, BNS.erase, BNS.molBond, //BNS.molAtom, //BNS.molFormula, BNS.molAtomAndFormula, BNS.molRing, BNS.molCharge, BNS.glyph, BNS.textImage ], styleToolComponentNames: [ BNS.fontName, BNS.fontSize, BNS.color, BNS.textDirection, BNS.textAlign ] }); /** * The style toolbar for composer. * @class * @augments Kekule.Widget.Toolbar * @param {Kekule.Editor.Composer} composer Parent composer. * * @property {Kekule.Editor.Composer} composer Parent composer. * @property {String} fontName Font name setted in toolbar. * @property {Number} fontSize Font size setted in toolbar, in px. * @property {Int} textAlign Text align setted in toolbar. * * @property {Array} components Array of component names that shows in tool bar. */ Kekule.Editor.ComposerStyleToolbar = Class.create(Kekule.Widget.Toolbar, /** @lends Kekule.Editor.ComposerStyleToolbar# */ { /** @private */ CLASS_NAME: 'Kekule.Editor.ComposerStyleToolbar', /** * @private * @ignore */ ATOM_COLOR_SPECIAL_VALUE_INFO: { text: Kekule.$L('ChemWidgetTexts.HINT_USE_ATOM_CUSTOM_COLOR'), value: 'Atom', className: CNS.COLORPICKER_SPEC_COLOR_MIXED }, /** @private */ LINKED_VALUE_FIELD: '__$value__', /** @constructs */ initialize: function(/*$super, */composer) { this.tryApplySuper('initialize', [composer]) /* $super(composer) */; this.setPropStoreFieldValue('composer', composer); this.createChildWidgets(); this.appendToWidget(composer); this._relatedPropNames = (composer.getCoordMode() === Kekule.CoordMode.COORD3D)? ['renderOptions', 'render3DOptions']: ['renderOptions']; this.getEditor().addEventListener('selectionChange', function(e){ if (!this._isApplying) this.updateStyleValues(); }, this); this.getEditor().addEventListener('editObjChanged', function(e){ var propNames = e.propNames; if (!propNames || !propNames.length || !Kekule.ArrayUtils.intersect(this._relatedPropNames, propNames).length) // not changing render options { return; } if (!this._isApplying) this.updateStyleValues(); }, this); this._isApplying = false; // private }, /** @private */ doFinalize: function(/*$super*/) { this.clearWidgets(); // already clear in $super() this.tryApplySuper('doFinalize') /* $super() */; }, /** @private */ initProperties: function() { this.defineProp('composer', {'dataType': 'Kekule.Editor.Composer', 'serializable': false, 'setter': null}); this.defineProp('fontNameBox', {'dataType': 'Kekule.Widget.ComboBox', 'serializable': false, 'setter': null}); this.defineProp('fontSizeBox', {'dataType': 'Kekule.Widget.ComboBox', 'serializable': false, 'setter': null}); this.defineProp('colorBox', {'dataType': 'Kekule.Widget.ColorDropButton', 'serializable': false, 'setter': null}); this.defineProp('textDirectionButtonSet', {'dataType': 'Kekule.Widget.CompactButtonSet', 'serializable': false, 'setter': null}); this.defineProp('textHorizontalAlignButtonSet', {'dataType': 'Kekule.Widget.CompactButtonSet', 'serializable': false, 'setter': null}); this.defineProp('textVerticalAlignButtonSet', {'dataType': 'Kekule.Widget.CompactButtonSet', 'serializable': false, 'setter': null}); this.defineProp('fontName', {'dataType': DataType.STRING, 'serializable': false, 'getter': function() { return this.getFontNameBox()? this.getFontNameBox().getValue(): null; }, 'setter': function(value) { if (this.getFontNameBox()) { this.getFontNameBox().setValue(value); } } }); this.defineProp('fontSize', {'dataType': DataType.NUMBER, 'serializable': false, 'getter': function() { return this.getFontSizeBox()? parseFloat(this.getFontSizeBox().getValue()): null; }, 'setter': function(value) { if (this.getFontSizeBox()) { this.getFontSizeBox().setValue(value); } } }); this.defineProp('color', {'dataType': DataType.STRING, 'serializable': false, 'getter': function() { return this.getColorBox()? this.getColorBox().getValue(): undefined; }, 'setter': function(value) { if (this.getColorBox()) { this.getColorBox().setValue(value); } } }); this.defineProp('textDirection', {'dataType': DataType.INT, 'serializable': false, 'getter': function() { return this._getButtonSetLinkedValue(this.getTextDirectionButtonSet()); }, 'setter': function(value) { this._setButtonSetLinkedValue(this.getTextDirectionButtonSet(), value); } }); this.defineProp('textHorizontalAlign', {'dataType': DataType.INT, 'serializable': false, 'getter': function() { return this._getButtonSetLinkedValue(this.getTextHorizontalAlignButtonSet()); }, 'setter': function(value) { this._setButtonSetLinkedValue(this.getTextHorizontalAlignButtonSet(), value); } }); this.defineProp('textVerticalAlign', {'dataType': DataType.INT, 'serializable': false, 'getter': function() { return this._getButtonSetLinkedValue(this.getTextVerticalAlignButtonSet()); }, 'setter': function(value) { this._setButtonSetLinkedValue(this.getTextVerticalAlignButtonSet(), value); } }); this.defineProp('componentNames', {'dataType': DataType.ARRAY, 'serializable': false, 'getter': function() { var result = this.getPropStoreFieldValue('componentNames'); if (!result) // create default one { result = this.getDefaultComponentNames(); this.setPropStoreFieldValue('componentNames', result); } return result; }, 'setter': function(value) { this.setPropStoreFieldValue('componentNames', value); this.recreateComponents(); } }); }, /** @ignore */ initPropValues: function(/*$super*/) { this.tryApplySuper('initPropValues') /* $super() */; this.setShowGlyph(true); }, /** @ignore */ removeWidget: function(/*$super, */widget, doNotFinalize) { if (widget === this.getFontNameBox()) this.setPropStoreFieldValue('fontNameBox', null); if (widget === this.getFontSizeBox()) this.setPropStoreFieldValue('fontSizeBox', null); if (widget === this.getColorBox()) this.setPropStoreFieldValue('colorBox', null); if (widget === this.getTextDirectionButtonSet()) this.setPropStoreFieldValue('textDirectionButtonSet', null); if (widget === this.getTextHorizontalAlignButtonSet()) this.setPropStoreFieldValue('textHorizontalAlignButtonSet', null); if (widget === this.getTextVerticalAlignButtonSet()) this.setPropStoreFieldValue('textVerticalAlignButtonSet', null); this.tryApplySuper('removeWidget', [widget, doNotFinalize]) /* $super(widget, doNotFinalize) */; }, /** @ignore */ doGetWidgetClassName: function(/*$super*/) { var result = this.tryApplySuper('doGetWidgetClassName') /* $super() */ + ' ' + CCNS.COMPOSER_TOOLBAR + ' ' + CCNS.COMPOSER_STYLE_TOOLBAR; return result; }, /** @private */ getEditor: function() { return this.getComposer().getEditor(); }, /** @private */ getEditorConfigs: function() { return this.getEditor().getEditorConfigs(); }, /** @private */ createChildWidgets: function(componentNames) { if (!componentNames) componentNames = this.getComponentNames(); for (var i = 0, l = componentNames.length; i < l; ++i) { var name = componentNames[i]; if (name === BNS.fontName) { // font name var comboBox = new Kekule.Widget.ComboBox(this); this.fillFontNameBox(comboBox); comboBox.addClassName(CCNS.COMPOSER_FONTNAME_BOX); comboBox.setHint(/*CWT.HINT_FONTNAME*/Kekule.$L('ChemWidgetTexts.HINT_FONTNAME')); comboBox.addEventListener('valueChange', function(e) { this.applyFontName(); }, this); this.setPropStoreFieldValue('fontNameBox', comboBox); } else if (name === BNS.fontSize) { // font size comboBox = new Kekule.Widget.ComboBox(this); this.fillFontSizeBox(comboBox); comboBox.addClassName(CCNS.COMPOSER_FONTSIZE_BOX); comboBox.setHint(/*CWT.HINT_FONTSIZE*/Kekule.$L('ChemWidgetTexts.HINT_FONTSIZE')); comboBox.addEventListener('valueChange', function(e) { this.applyFontSize(); }, this); this.setPropStoreFieldValue('fontSizeBox', comboBox); } else if (name === BNS.color) { // color box var colorBox = new Kekule.Widget.ColorDropButton(this); colorBox.setHint(/*CWT.HINT_PICK_COLOR*/Kekule.$L('ChemWidgetTexts.HINT_PICK_COLOR')); colorBox.setShowText(false); colorBox.setSpecialColors([Kekule.Widget.ColorPicker.SpecialColors.UNSET, this.ATOM_COLOR_SPECIAL_VALUE_INFO]); colorBox.addClassName(CCNS.COMPOSER_COLOR_BOX); colorBox.addEventListener('valueChange', function(e) { this.applyColor(); }, this); this.setPropStoreFieldValue('colorBox', colorBox); } else if (name === BNS.textDirection) { // text direction button // its drop downs var TD = Kekule.Render.TextDirection; var childInfos = [ {'value': TD.DEFAULT, 'text': /*CWT.CAPTION_TEXT_DIRECTION_DEFAULT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION_DEFAULT'), className: CCNS.COMPOSER_TEXTDIRECTION_BUTTON_DEFAULT}, {'value': TD.LTR, 'text': /*CWT.CAPTION_TEXT_DIRECTION_LTR*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION_LTR'), className: CCNS.COMPOSER_TEXTDIRECTION_BUTTON_LTR}, {'value': TD.RTL, 'text': /*CWT.CAPTION_TEXT_DIRECTION_RTL*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION_RTL'), className: CCNS.COMPOSER_TEXTDIRECTION_BUTTON_RTL}, {'value': TD.TTB, 'text': /*CWT.CAPTION_TEXT_DIRECTION_TTB*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION_TTB'), className: CCNS.COMPOSER_TEXTDIRECTION_BUTTON_TTB}, {'value': TD.BTT, 'text': /*CWT.CAPTION_TEXT_DIRECTION_BTT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION_BTT'), className: CCNS.COMPOSER_TEXTDIRECTION_BUTTON_BTT} ]; var btnSet = this._createStyleButtonSet( /*CWT.CAPTION_TEXT_DIRECTION, CWT.HINT_TEXT_DIRECTION,*/ Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_DIRECTION'), Kekule.$L('ChemWidgetTexts.HINT_TEXT_DIRECTION'), CCNS.COMPOSER_TEXTDIRECTION_BUTTON, childInfos); btnSet.addEventListener('select', function(e) { this.applyTextDirection(); }, this); this.setPropStoreFieldValue('textDirectionButtonSet', btnSet); } else if (name === BNS.textAlign) { // horizontal text align button var TA = Kekule.Render.TextAlign; var childInfos = [ {'value': TA.DEFAULT, 'text': /*CWT.CAPTION_TEXT_ALIGN_DEFAULT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_DEFAULT'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_DEFAULT}, {'value': TA.LEADING, 'text': /*CWT.CAPTION_TEXT_ALIGN_LEADING*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_LEADING'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_LEADING}, {'value': TA.TRAILING, 'text': /*CWT.CAPTION_TEXT_ALIGN_TRAILING*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_TRAILING'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_TRAILING}, {'value': TA.CENTER, 'text': /*CWT.CAPTION_TEXT_ALIGN_CENTER*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_CENTER'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_CENTER}, {'value': TA.LEFT, 'text': /*CWT.CAPTION_TEXT_ALIGN_LEFT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_LEFT'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_LEFT}, {'value': TA.RIGHT, 'text': /*CWT.CAPTION_TEXT_ALIGN_RIGHT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_RIGHT'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_RIGHT} ]; var btnSet = this._createStyleButtonSet( /*CWT.CAPTION_TEXT_HORIZONTAL_ALIGN, CWT.HINT_TEXT_HORIZONTAL_ALIGN,*/ Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_HORIZONTAL_ALIGN'), Kekule.$L('ChemWidgetTexts.HINT_TEXT_HORIZONTAL_ALIGN'), CCNS.COMPOSER_TEXTALIGN_BUTTON_HORIZONTAL, childInfos); btnSet.addEventListener('select', function(e) { this.applyTextHorizontalAlign(); }, this); this.setPropStoreFieldValue('textHorizontalAlignButtonSet', btnSet); // vertical text align button var TA = Kekule.Render.TextAlign; var childInfos = [ {'value': TA.DEFAULT, 'text': /*CWT.CAPTION_TEXT_ALIGN_DEFAULT*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_DEFAULT'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_DEFAULT}, {'value': TA.LEADING, 'text': /*CWT.CAPTION_TEXT_ALIGN_LEADING*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_LEADING'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_LEADING}, {'value': TA.TRAILING, 'text': /*CWT.CAPTION_TEXT_ALIGN_TRAILING*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_TRAILING'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_TRAILING}, {'value': TA.CENTER, 'text': /*CWT.CAPTION_TEXT_ALIGN_CENTER*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_CENTER'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_CENTER}, {'value': TA.TOP, 'text': /*CWT.CAPTION_TEXT_ALIGN_TOP*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_TOP'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_TOP}, {'value': TA.BOTTOM, 'text': /*CWT.CAPTION_TEXT_ALIGN_BOTTOM*/Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_ALIGN_BOTTOM'), className: CCNS.COMPOSER_TEXTALIGN_BUTTON_BOTTOM} ]; var btnSet = this._createStyleButtonSet( /*CWT.CAPTION_TEXT_VERTICAL_ALIGN, CWT.HINT_TEXT_VERTICAL_ALIGN,*/ Kekule.$L('ChemWidgetTexts.CAPTION_TEXT_VERTICAL_ALIGN'), Kekule.$L('ChemWidgetTexts.HINT_TEXT_VERTICAL_ALIGN'), CCNS.COMPOSER_TEXTALIGN_BUTTON_VERTICAL, childInfos); btnSet.addEventListener('select', function(e) { this.applyTextVerticalAlign(); }, this); this.setPropStoreFieldValue('textVerticalAlignButtonSet', btnSet); } } this.updateStyleValues(); }, /** @private */ _createStyleButtonSet: function(text, hint, className, childItemInfos) { var btnSet = new Kekule.Widget.CompactButtonSet(this); btnSet.setText(text); btnSet.setHint(hint); btnSet.addClassName(className); btnSet.setShowText(false); // show drop down mark rather than compact mark, keep a similar outlook to other widgets btnSet.setShowCompactMark(false); btnSet.setButtonKind(Kekule.Widget.Button.Kinds.DROPDOWN); btnSet.getButtonSet().addClassName(CCNS.COMPOSER_STYLE_TOOLBAR); btnSet.getButtonSet().setShowText(true); // drop down children if (childItemInfos) { for (var i = 0, l = childItemInfos.length; i < l; ++i) { var info = childItemInfos[i]; var btn = new Kekule.Widget.RadioButton(btnSet, info.text || ''); btn.setHint(info.hint || ''); btn.addClassName(info.className); btn[this.LINKED_VALUE_FIELD] = info.value; btnSet.append(btn, info.selected); } } return btnSet; }, /** @private */ _getButtonSetLinkedValue: function(btnSet) { var selected = btnSet? btnSet.getSelected(): null; return selected? selected[this.LINKED_VALUE_FIELD]: undefined; }, /** @private */ _setButtonSetLinkedValue: function(btnSet, value) { if (btnSet) { var group = btnSet.getButtonSet(); var children = group.getChildWidgets(); btnSet.setSelected(null); // uncheck all first for (var i = 0 , l = children.length; i < l; ++i) { var child = children[i]; if (child.hasOwnProperty(this.LINKED_VALUE_FIELD)) { if (child[this.LINKED_VALUE_FIELD] == value) { btnSet.setSelected(child); break; } } } } }, /** @private */ getDefaultComponentNames: function() { return Kekule.globalOptions.chemWidget.composer.styleToolComponentNames; /* return [ BNS.fontName, BNS.fontSize, BNS.color, BNS.textDirection, BNS.textAlign ]; */ }, /** @private */ recreateComponents: function() { var cnames = this.getComponentNames(); this.clearWidgets(); this.createChildWidgets(cnames); }, /** @private */ fillFontSizeBox: function(sizeComboBox) { var listedSizes = this.getEditorConfigs().getStyleSetterConfigs().getListedFontSizes(); var boxItems = [{'text': /*Kekule.ChemWidgetTexts.S_VALUE_DEFAULT*/Kekule.$L('ChemWidgetTexts.S_VALUE_DEFAULT'), 'value': undefined}]; for (var i = 0, l = listedSizes.length; i < l; ++i) { boxItems.push({'text': listedSizes[i] + ' px', 'value': listedSizes[i]}); } sizeComboBox.setItems(boxItems); }, /** @private */ fillFontNameBox: function(fontComboBox) { var listedNames = this.getEditorConfigs().getStyleSetterConfigs().getListedFontNames(); var boxItems = [{'text': /*Kekule.ChemWidgetTexts.S_VALUE_DEFAULT*/Kekule.$L('ChemWidgetTexts.S_VALUE_DEFAULT'), 'value': ''}]; for (var i = 0, l = listedNames.length; i < l; ++i) { boxItems.push({'text': listedNames[i], 'value': listedNames[i]}); } fontComboBox.setItems(boxItems); }, /** * Apply style settings to objects in editor. * @param {Array} chemObjs * @param {Hash} styles Hash of style. {renderOptionName: value}. * @param {Bool} is3DOption If true, styles will be put to Render3DOptions, otherwise RenderOptions will be set. * @private */ applyStyle: function(chemObjs, styles, is3DOption) { this._isApplying = true; try { //Kekule.Render.RenderOptionUtils.setRenderOptionValueOfObjs(chemObjs, styles, is3DOption); var editor = this.getEditor(); editor.modifyObjectsRenderOptions(chemObjs, styles, is3DOption, true); } finally { this._isApplying = false; } }, /** * Returns common render option or render 3D option value of chemObjs. * If values in objects are not same, null will be returned. * @param {Array} chemObjs * @param {String} stylePropName * @param {Bool} is3DOption * @returns {Variant} * @private */ getStyleValue: function(chemObjs, stylePropName, is3DOption) { return Kekule.Render.RenderOptionUtils.getCascadeRenderOptionValueOfObjs(chemObjs, stylePropName, is3DOption); }, /** * Apply styles to selected objects in editor. * @private */ applyStyleToEditorSelection: function(styles, is3DOption) { var objs = this.getEditor().getSelection(); if (objs && objs.length) return this.applyStyle(objs, styles, is3DOption); }, /** @private */ applyFontName: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var fontName = this.getFontName(); this.applyStyle(objs, {'fontFamily': fontName/*, 'atomFontFamily': fontName*/}); } }, /** @private */ applyFontSize: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var fontSize = this.getFontSize(); this.applyStyle(objs, {'fontSize': fontSize/*, 'atomFontSize': fontSize*/}); } }, /** @private */ applyColor: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var color = this.getColor(); if (color === this.ATOM_COLOR_SPECIAL_VALUE_INFO.value) { this.applyStyle(objs, {'useAtomSpecifiedColor': true, 'color': undefined}); } else { if (color == Kekule.Widget.ColorPicker.SpecialColors.UNSET) color = undefined; this.applyStyle(objs, {'useAtomSpecifiedColor': false, 'color': color}); } } }, /** @private */ applyTextDirection: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var direction = this.getTextDirection(); this.applyStyle(objs, {'charDirection': direction}); } }, /** @private */ applyTextHorizontalAlign: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var value = this.getTextHorizontalAlign(); this.applyStyle(objs, {'horizontalAlign': value}); } }, /** @private */ applyTextVerticalAlign: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { var value = this.getTextVerticalAlign(); this.applyStyle(objs, {'verticalAlign': value}); } }, /** @private */ updateStyleValues: function(objs) { if (!objs) objs = this.getEditor().getSelection(); if (objs && objs.length) { this.updateFontName(objs); this.updateFontSize(objs); this.updateColor(objs); this.updateTextDirection(objs); this.updateTextHorizontalAlign(objs); this.updateTextVerticalAlign(objs); } }, /** @private */ updateFontName: function(objs) { if (objs && objs.length && this.getFontNameBox()) { var fontName = this.getStyleValue(objs, 'fontFamily'); // TODO: atom font family? this.setFontName(fontName || ''); } }, /** @private */ updateFontSize: function(objs) { if (objs && objs.length && this.getFontSizeBox()) { var fontSize = this.getStyleValue(objs, 'fontSize'); // TODO: atom font size? this.setFontSize(fontSize || undefined); } }, /** @private */ updateColor: function(objs) { if (objs && objs.length && this.getColorBox()) { var color; var useAtomSpecified = this.getStyleValue(objs, 'useAtomSpecifiedColor'); var color = this.getStyleValue(objs, 'color'); this.getColorBox().setColorClassName(null); if (color) { this.getColorBox().setColorClassName(null); } else if (useAtomSpecified) { color = this.ATOM_COLOR_SPECIAL_VALUE_INFO.value; this.getColorBox().setColorClassName(this.ATOM_COLOR_SPECIAL_VALUE_INFO.className); } this.setColor(color || undefined); } }, /** @private */ updateTextDirection: function(objs) { if (objs && objs.length && this.getTextDirectionButtonSet()) { var value = this.getStyleValue(objs, 'charDirection'); this.setTextDirection(value); /* if (Kekule.ObjUtils.notUnset(value)) { } */ } }, /** @private */ updateTextHorizontalAlign: function(objs) { if (objs && objs.length && this.getTextHorizontalAlignButtonSet()) { var value = this.getStyleValue(objs, 'horizontalAlign'); this.setTextHorizontalAlign(value); } }, /** @private */ updateTextVerticalAlign: function(objs) { if (objs && objs.length && this.getTextVerticalAlignButtonSet()) { var value = this.getStyleValue(objs, 'verticalAlign'); this.setTextVerticalAlign(value); } }, /** * Update toolbar and child widget outlook and other settings according to editor's state. */ updateState: function() { var editor = this.getEditor(); var hasSelection = (editor && editor.hasSelection()); //this.setEnabled(hasSelection); /* var children = [ this.getFontNameBox(), this.getFontSizeBox(), this.getColorBox(), this.getTextDirectionButtonSet(), this.getTextAlignButtonSet() ]; */ if (this.getFontNameBox()) this.getFontNameBox().setEnabled(hasSelection); if (this.getFontSizeBox()) this.getFontSizeBox().setEnabled(hasSelection); if (this.getColorBox()) this.getColorBox().setEnabled(hasSelection); if (this.getTextDirectionButtonSet()) this.getTextDirectionButtonSet().setEnabled(hasSelection); if (this.getTextHorizontalAlignButtonSet()) this.getTextHorizontalAlignButtonSet().setEnabled(hasSelection); if (this.getTextVerticalAlignButtonSet()) this.getTextVerticalAlignButtonSet().setEnabled(hasSelection); } }); /** * The style toolbar for composer. * @class * @augments Kekule.Widget.Toolbar * @param {Kekule.Editor.Composer} composer Parent composer. * * @property {Kekule.Editor.Composer} composer Parent composer. * @property {Array} components Array of component names that shows in tool bar. */ Kekule.Editor.ComposerObjModifierToolbar = Class.create(Kekule.Widget.Toolbar, /** @lends Kekule.Editor.ComposerObjModifierToolbar# */ { /** @private */ CLASS_NAME: 'Kekule.Editor.ComposerObjModifierToolbar', /** @constructs */ initialize: function(/*$super, */composer) { this.tryApplySuper('initialize', [composer]) /* $super(composer) */; this.setPropStoreFieldValue('modifiers', []); this.setPropStoreFieldValue('modifierMap', new Kekule.MapEx()); this.setPropStoreFieldValue('composer', composer); this.appendToWidget(composer); composer.addEventListener('selectionChange', function(e){ if (!this._isApplying) this.updateModifierValues(); }, this); composer.addEventListener('selectedObjsUpdated', function(e){ /* var propNames = e.propNames; if (!propNames || !propNames.length || !Kekule.ArrayUtils.intersect(this._relatedPropNames, propNames).length) // not changing render options { return; } */ if (!this._isApplying) { if (composer.getEditor().isManipulatingObject()) this._suppressUpdateModifierValuesInManipulation = true; else { //console.log('selectedObjsUpdated', composer.getEditor()._objectManipulateFlag, e); this.updateModifierValues(); } } }, this); composer.addEventListener('endManipulateObject', function(e){ if (this._suppressUpdateModifierValuesInManipulation) { this.updateModifierValues(); this._suppressUpdateModifierValuesInManipulation = false; } }, this); this._isApplying = false; // private }, /** @private */ initProperties: function() { this.defineProp('composer', {'dataType': 'Kekule.Editor.Composer', 'serializable': false, 'setter': null}); this.defineProp('modifierMap', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('modifiers', {'dataType': DataType.ARRAY, 'serializable': false, 'setter': null}); }, /** @ignore */ initPropValues: function(/*$super*/) { this.tryApplySuper('initPropValues') /* $super() */; this.setShowGlyph(true); }, /** @private */ doFinalize: function(/*$super*/) { this.clearWidgets(); this.getModifierMap().finalize(); var modifiers = this.getModifiers(); for (var i = 0, l = modifiers.length; i < l; ++i) modifiers[i].finalize(); this.tryApplySuper('doFinalize') /* $super() */; }, /** @ignore */ doGetWidgetClassName: function(/*$super*/) { var result = this.tryApplySuper('doGetWidgetClassName') /* $super() */ + ' ' + CCNS.COMPOSER_TOOLBAR + ' ' + CCNS.COMPOSER_OBJMODIFIER_TOOLBAR; return result; }, /** @private */ getEditor: function() { return this.getComposer().getEditor(); }, /** @private */ getEditorConfigs: function() { return this.getEditor().getEditorConfigs(); }, /** @private */ getAllowedModifierCategories: function() { var c = this.getComposer(); return c && c.getAllowedObjModifierCategories(); }, /** * Returns selection of editor. * @returns {Array} * @private */ getTargetObjs: function() { return this.getEditor().getSelection(); }, /** * Returns modifier classes that can be displayed on toolbar. * @returns {Array} * @private */ getAvailableModifierClasses: function() { var targetClasses = []; var targets = this.getTargetObjs(); for (var i = 0, l = targets.length; i < l; ++i) { if (targets[i].getClass) AU.pushUnique(targetClasses, targets[i].getClass()); } var result = []; var allowedCategories = this.getAllowedModifierCategories(); for (var i = 0, l = targetClasses.length; i < l; ++i) { var modifierClasses = Kekule.Editor.ObjModifierManager.getModifierClasses(targetClasses[i], allowedCategories); if (modifierClasses) AU.pushUnique(result, modifierClasses); } if (result.length) result.sort(function(a, b){ var protoA = a && ClassEx.getPrototype(a); var protoB = b && ClassEx.getPrototype(b); var nameA = protoA && protoA.getModifierName && protoA.getModifierName(); var nameB = protoB && protoB.getModifierName && protoB.getModifierName(); return (nameA === nameB)? 0: (nameA < nameB)? -1: 1; }); return result; }, /** * Return a cached or newly created modifier instance of class. * @param {Class} modifierClass * @param {Bool} autoCreate * @return {Kekule.Editor.ObjModifier.Base} */ getModifierInstanceOfClass: function(modifierClass, autoCreate) { var map = this.getModifierMap(); var result = map.get(modifierClass); if (!result && autoCreate) { result = new modifierClass(this.getEditor()); map.set(modifierClass, result); } return result; }, /** * Refresh displayed modifier widgets on toolbar. */ updateModifierWidgets: function() { var modifiers = []; this.clearWidgets(true); // clear old widgets but do not finalize var modifierClasses = this.getAvailableModifierClasses(); for (var i = 0, l = modifierClasses.length; i < l; ++i) { var mClass = modifierClasses[i]; var modifier = this.getModifierInstanceOfClass(mClass, true); // auto create var widget = modifier.getWidget(); if (widget) { this.appendWidget(widget); modifiers.push(modifier); } } this.setPropStoreFieldValue('modifiers', modifiers); this.updateModifierValues(); if (this._isAllModifierWidgetButtons(modifiers)) // if all modifiers are buttons, use btnGroup style rather than toolbar { this.removeClassName(CNS.TOOLBAR).addClassName(CNS.BUTTON_GROUP); } else { this.removeClassName(CNS.BUTTON_GROUP).addClassName(CNS.TOOLBAR); } }, /** * Update toolbar and child widget outlook and other settings according to editor's state. */ updateState: function() { this.updateModifierWidgets(); }, /** * Refresh modifier widget according to current state of selection in editor. */ updateModifierValues: function() { var modifiers = this.getModifiers(); for (var i = 0, l = modifiers.length; i < l; ++i) { modifiers[i].loadFromTargets(); } }, /** @private */ _isAllModifierWidgetButtons: function(modifiers) { for (var i = 0, l = modifiers.length; i < l; ++i) { var m = modifiers[i]; var w = m && m.getWidget(); if (!w || !w.getDisplayed() || w instanceof Kekule.Widget.Button) continue; else return false } return true; } }); /** * A editor with essential UI for end users. * @class * @augments Kekule.ChemWidget.AbstractWidget * @param {Variant} parentOrElementOrDocument * @param {Kekule.Editor.BaseEditor} editor An editor instance embedded in UI. * * @property {Kekule.Editor.BaseEditor} editor The editor instance embedded in UI. * @property {Array} commonToolButtons buttons in common tool bar. This is a array of predefined strings, e.g.: ['zoomIn', 'zoomOut', 'resetZoom', 'molDisplayType', ...]. * If not set, default buttons will be used. * In the array, complex hash can also be used to add custom buttons, e.g.: <br /> * [ <br /> * 'zoomIn', 'zoomOut',<br /> * {'name': 'myCustomButton1', 'widgetClass': 'Kekule.Widget.Button', 'action': actionClass},<br /> * {'name': 'myCustomButton2', 'htmlClass': 'MyClass' 'caption': 'My Button', 'hint': 'My Hint', '#execute': function(){ ... }},<br /> * ]<br /> * @property {Array} chemToolButtons buttons in chem tool bar. This is a array of predefined strings, e.g.: ['zoomIn', 'zoomOut', 'resetZoom', 'molDisplayType', ...]. * If not set, default buttons will be used. * Chem tool often has a series of child tool buttons, you can also control to display which child buttons, e.g.: * [ * {'name': 'bond', 'attached': ['bondSingle', 'bondDouble']}, <br /> * 'atom', 'formula',<br /> * ] <br /> * Note: currently same child button can not be existed in different chem tool buttons. * In the array, complex hash can also be used to add custom buttons, e.g.: <br /> * [ <br /> * 'atom', 'formula',<br /> * {'name': 'myCustomButton1', 'widgetClass': 'Kekule.Widget.Button', 'action': actionClass},<br /> * {'name': 'myCustomButton2', 'htmlClass': 'MyClass' 'caption': 'My Button', 'hint': 'My Hint', '#execute': function(){ ... }},<br /> * ]<br /> * @property {Array} styleToolComponentNames Array of component names that shows in style tool bar. * @property {Bool} enableStyleToolbar * @property {Bool} enableObjModifierToolbar * @property {Array} allowedObjModifierCategories * @property {Bool} showObjInspector Whether show advanced object inspector and structure view. * @property {Bool} showIssueInspector Whether show error inspector panel. * @property {Bool} enableIssueInspectorSolutions Whether the solution section in issue inspector should be displayed. * Note: The solution section will be actually displayed when both this property and enableAutoIssueCheck are true. * If enableAutoIssueCheck is false, the issues in inspector may not reflect to the current state of chem objects, * so running the solutions may not mess up the editor content. * @property {Bool} autoSetMinDimension * * @property {Kekule.Editor.BaseEditorConfigs} editorConfigs Configuration of this editor. * @property {Bool} enableOperHistory Whether undo/redo is enabled. * @property {Kekule.OperationHistory} operHistory History of operations. Used to enable undo/redo function. * @property {Int} renderType Display in 2D or 3D. Value from {@link Kekule.Render.RendererType}. * @property {Kekule.ChemObject} chemObj The root object in editor. * @property {Bool} enableOperContext If this property is set to true, object being modified will be drawn in a * separate context to accelerate the interface refreshing. * @property {Object} objContext Context to draw basic chem objects. Can be 2D or 3D context. Alias of property drawContext * @property {Object} operContext Context to draw objects being operated. Can be 2D or 3D context. * @property {Object} uiContext Context to draw UI marks. Usually this is a 2D context. * @property {Object} objDrawBridge Bridge to draw chem objects. Alias of property drawBridge. * @property {Object} uiDrawBridge Bridge to draw UI markers. * @property {Array} selection An array of selected basic object. * * @property {Bool} enableLoadNewFile Whether open a external file to displayer is allowed. * @property {Bool} enableCreateNewDoc Whether create new object in editor is allowed. * @property {Bool} allowCreateNewChild Whether new direct child of space can be created. * Note: if the space is empty, one new child will always be allowed to create. * @property {Bool} allowAppendDataToCurr Whether display "append data" check box in the data load dialog. */ Kekule.Editor.Composer = Class.create(Kekule.ChemWidget.AbstractWidget, /** @lends Kekule.Editor.Composer# */ { /** @private */ CLASS_NAME: 'Kekule.Editor.Composer', /** @private */ BINDABLE_TAG_NAMES: ['div'], /** @private */ CHEM_TOOL_CHILD_FIELDS: '__$children__', /** @constructs */ initialize: function(/*$super, */parentOrElementOrDocument, editor) { /* this.updateStyleToolbarStateBind = this.updateStyleToolbarState.bind(this); this.updateObjModifierToolbarStateBind = this.updateObjModifierToolbarState.bind(this); */ this.updateSelectionAssocToolbarStateBind = this.updateSelectionAssocToolbarState.bind(this); this.setPropStoreFieldValue('enableIssueInspectorSolutions', true); this.setPropStoreFieldValue('enableStyleToolbar', true); this.setPropStoreFieldValue('enableObjModifierToolbar', true); this.setPropStoreFieldValue('editor', editor); this.setPropStoreFieldValue('editorNexus', new Kekule.Editor.EditorNexus()); this.tryApplySuper('initialize', [parentOrElementOrDocument]) /* $super(parentOrElementOrDocument) */; /* if (!editor) editor = this.createDefaultEditor(); */ this.bindEditor(editor); var ed = this.getEditor(); if (ed) // editor is newly created ed.setChemObj(ed.getChemObj()); // a force readjust size, otherwise there will be size problem in IE8 // tool bars may already be created by setting buttons property if (!this.getCommonBtnGroup()) this.createCommonToolbar(); if (!this.getChemBtnGroup()) this.createChemToolbar(); if (!this.getZoomBtnGroup()) this.createZoomToolbar(); // debug //this.setShowInspector(true); this.uiLayoutChanged(); }, /** @private */ doFinalize: function(/*$super*/) { //this.getPainter().finalize(); var issueInspector = this.getIssueInspector(); if (issueInspector) issueInspector.finalize(); var structTreeView = this.getStructureTreeView(); if (structTreeView) structTreeView.finalize(); var objInspector = this.getObjInspector(); if (objInspector) objInspector.finalize(); var toolBar = this.getCommonBtnGroup(); if (toolBar) toolBar.finalize(); var toolBar = this.getChemBtnGroup(); if (toolBar) toolBar.finalize(); var editor = this.getPropStoreFieldValue('editor'); if (editor) editor.finalize(); this.getEditorNexus().finalize(); this.tryApplySuper('doFinalize') /* $super() */; }, /** @private */ initProperties: function() { this.defineProp('editor', {'dataType': 'Kekule.Editor.BaseEditor', 'serializable': false, 'setter': null, 'getter': function() { var result = this.getPropStoreFieldValue('editor'); if (!result) { result = this.createDefaultEditor(); this.setPropStoreFieldValue('editor', result); } return result; } }); this.defineProp('autoSetMinDimension', {'dataType': DataType.BOOL}); this.defineProp('showObjInspector', {'dataType': DataType.BOOL, 'getter': function() { return (this.getAdvPanelDisplayedComponents() || []).indexOf('objInspector') >= 0; }, 'setter': function(value) { if (this.getShowObjInspector() !== value) { /* this.setPropStoreFieldValue('showObjInspector', value); this.showObjInspectorChanged(); */ var comps = this.getAdvPanelDisplayedComponents() || []; if (value) //comps.push('objInspector'); comps = ['objInspector']; else comps = AU.exclude(comps, 'objInspector'); this.setAdvPanelDisplayedComponents(comps); } } }); this.defineProp('showIssueInspector', {'dataType': DataType.BOOL, 'serializable': false, 'getter': function() { return (this.getAdvPanelDisplayedComponents() || []).indexOf('issueInspector') >= 0; }, 'setter': function(value) { if (this.getShowIssueInspector() !== value) { var comps = this.getAdvPanelDisplayedComponents() || []; if (value) comps = ['issueInspector']; else comps = AU.exclude(comps, 'issueInspector'); this.setAdvPanelDisplayedComponents(comps); if (value) // when showing issue inspector { var editor = this.getEditor(); if (editor) { if (!editor.getEnableAutoIssueCheck()) // issue is not auto checked, manually do a check when opening the inspector editor.checkIssues(); if (editor.getIssueCheckResults() && editor.getIssueCheckResults().length) // has issues, deselect the selection to make the issue markers more clear editor.deselectAll(); } } else // when close, deselect active issue { var issueInspector = this.getIssueInspector(); issueInspector.deselect(); } } } }); this.defineProp('enableIssueInspectorSolutions', {'dataType': DataType.BOOL, 'setter': function(value) { this.setPropStoreFieldValue('enableIssueInspectorSolutions', !!value); if (this.getIssueInspector()) this.getIssueInspector().setEnableIssueSolutions(this.getActualEnableIssueInspectorSolutions()); } }); // for backward compatibility, alias of property showObjInspector this.defineProp('showInspector', {'dataType': DataType.BOOL, 'getter': function() { return this.getShowObjInspector(); }, 'setter': function(value) { this.setShowObjInspector(value); } }); // private this.defineProp('advPanelDisplayedComponents', {'dataType': DataType.ARRAY, 'serializable': false, 'setter': function(value) { this.setPropStoreFieldValue('advPanelDisplayedComponents', value); this.updateAdvPanelDisplayedComponents(value); } }); // private property this.defineProp('editorStageElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('advPanelElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('objInspectorHolderElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('issueInspectorHolderElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('topRegionElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('leftRegionElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('bottomRegionElem', {'dataType': DataType.OBJECT, 'serializable': false, 'setter': null}); this.defineProp('editorNexus', {'dataType': 'Kekule.Editor.EditorNexus', 'serializable': false, 'setter': null}); this.defineProp('objInspector', {'dataType': 'Kekule.Widget.ObjectInspector', 'serializable': false, 'setter': null}); this.defineProp('structureTreeView', {'dataType': 'Kekule.ChemWidget.StructureTreeView', 'serializable': false, 'setter': null}); this.defineProp('issueInspector', {'dataType': 'Kekule.Editor.IssueInspector', 'serializable': false, 'setter': null}); // a private property, toolbar of common tasks (such as save/load) this.defineProp('commonBtnGroup', {'dataType': 'Kekule.Widget.ButtonGroup', 'serializable': false}); // a private property, toolbar of zoom tasks (such as zoomin/out) this.defineProp('zoomBtnGroup', {'dataType': 'Kekule.Widget.ButtonGroup', 'serializable': false}); // a private property, toolbar of chem tools (such as atom/bond) this.defineProp('chemBtnGroup', {'dataType': 'Kekule.Widget.ButtonGroup', 'serializable': false}); // a private property, toolbar of association chem tools (such as single, double bound form for bond tool) this.defineProp('assocBtnGroup', {'dataType': 'Kekule.Widget.ButtonGroup', 'serializable': false}); // a private property, toolbar of style settings (such as font name, font size, color) this.defineProp('styleToolbar', {'dataType': 'Kekule.Widget.Toolbar', 'serializable': false, 'getter': function() { var result = this.getPropStoreFieldValue('styleToolbar'); if (!result) { if (this.getEnableStyleToolbar()) { result = this.createStyleToolbar(); this.setPropStoreFieldValue('styleToolbar', result); } } return result; } }); this.defineProp('styleToolComponentNames', {'dataType': DataType.ARRAY, 'serializable': false, 'getter': function() { var toolbar = this.getStyleToolbar(); return toolbar? toolbar.getComponentNames(): null; }, 'setter': function(value) { var toolbar = this.getStyleToolbar(); if (toolbar) toolbar.setComponentNames(value); return this; } }); this.defineProp('enableStyleToolbar', {'dataType': DataType.BOOL, 'getter': function() { // if obj modifier toolbar is enabled, old fashioned style toolbar will not be displayed return this.getPropStoreFieldValue('enableStyleToolbar') && !this.getEnableObjModifierToolbar(); }, 'setter': function(value) { this.setPropStoreFieldValue('enableStyleToolbar', value); if (value) // enable style bar should disable modifier bar this.setPropStoreFieldValue('enableObjModifierToolbar', false); this.updateSelectionAssocToolbarState(); } }); // a private property, toolbar of style settings (such as font name, font size, color) this.defineProp('objModifierToolbar', {'dataType': 'Kekule.Widget.Toolbar', 'serializable': false, 'getter': function() { var result = this.getPropStoreFieldValue('objModifierToolbar'); if (!result) { if (this.getEnableObjModifierToolbar()) { result = this.createObjModifierToolbar(); this.setPropStoreFieldValue('objModifierToolbar', result); } } return result; } }); this.defineProp('enableObjModifierToolbar', {'dataType': DataType.BOOL, 'setter': function(value) { this.setPropStoreFieldValue('enableObjModifierToolbar', value); if (value) // enable modifier bar should disable style bar this.setPropStoreFieldValue('enableStyleToolbar', false); this.updateSelectionAssocToolbarState(); } }); this.defineProp('allowedObjModifierCategories', {'dataType': DataType.ARRAY, 'setter': function(value) { this.setPropStoreFieldValue('allowedObjModifierCategories', value); this.updateObjModifi