kekule
Version:
Open source JavaScript toolkit for chemoinformatics
1,396 lines (1,346 loc) • 42.7 kB
JavaScript
/**
* @fileoverview
* Object modifier to change property of path glyphs in chem editor.
* @author Partridge Jiang
*/
/*
* requires /lan/classes.js
* requires /utils/kekule.utils.js
* requires /chemdoc/kekule.glyph.pathGlyphs.js
* requires /widgets/kekule.widget.base.js
* requires /widgets/commonCtrls/kekule.widget.buttons.js
* requires /widgets/chem/editor/kekule.chemEditor.editorUtils.js
* requires /widgets/chem/editor/kekule.chemEditor.baseEditor.js
* requires /widgets/chem/editor/kekule.chemEditor.objModifiers.js
* requires /widgets/chem/editor/kekule.chemEditor.utilWidgets.js
*/
(function(){
"use strict";
/*
* requires /lan/classes.js
* requires /utils/kekule.utils.js
* requires /widgets/kekule.widget.base.js
* requires /widgets/commonCtrls/kekule.widget.buttons.js
* requires /widgets/chem/editor/kekule.chemEditor.baseEditor.js
* requires /widgets/chem/editor/kekule.chemEditor.objModifiers.js
* requires /widgets/chem/editor/kekule.chemEditor.utilWidgets.js
*/
var OU = Kekule.ObjUtils;
var AU = Kekule.ArrayUtils;
var DU = Kekule.DomUtils;
var EU = Kekule.HtmlElementUtils;
var CNS = Kekule.Widget.HtmlClassNames;
var CCNS = Kekule.ChemWidget.HtmlClassNames;
Kekule.ChemWidget.HtmlClassNames = Object.extend(Kekule.ChemWidget.HtmlClassNames, {
COMPOSER_GLYPH_PATH_MODIFIER_BUTTON: 'K-Chem-Composer-GlyphPathModifier-Button',
COMPOSER_Glyph_PATH_MODIFIER_DROPDOWN: 'K-Chem-Composer-GlyphPathModifier-DropDown',
COMPOSER_GLYPH_REACTION_ARROW_MODIFIER_BUTTON: 'K-Chem-Composer-ReactionArrowModifier-Button',
COMPOSER_GLYPH_ARC_PATH_MODIFIER_BUTTON: 'K-Chem-Composer-ArcPathModifier-Button',
COMPOSER_GLYPH_MULTI_ARC_PATH_MODIFIER_BUTTON: 'K-Chem-Composer-MultiArcPathModifier-Button',
COMPOSER_GLYPH_ELECTRON_PUSHING_ARROW_MODIFIER_BUTTON: 'K-Chem-Composer-ElectronPushingArrowModifier-Button',
COMPOSER_GLYPH_BOND_FORMING_ELECTRON_PUSHING_ARROW_MODIFIER_BUTTON: 'K-Chem-Composer-BondFormingElectronPushingArrowModifier-Button',
});
/**
* Base modifier class to change the glyphs in editor.
* @class
* @augments Kekule.Editor.ObjModifier.Base
*/
Kekule.Editor.ObjModifier.GlyphModifier = Class.create(Kekule.Editor.ObjModifier.Base,
/** @lends Kekule.Editor.ObjModifier.GlyphModifier# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.GlyphModifier'
});
/** @ignore */
Kekule.Editor.ObjModifier.GlyphModifier.getCategories = function()
{
return [Kekule.Editor.ObjModifier.Category.GLYPH];
};
/**
* A modifier to change the params of a path.
* @class
* @augments Kekule.Editor.ObjModifier.GlyphModifier
*/
Kekule.Editor.ObjModifier.GlyphPath = Class.create(Kekule.Editor.ObjModifier.GlyphModifier,
/** @lends Kekule.Editor.ObjModifier.GlyphPath# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.GlyphPath',
/** @private */
MIX_VALUE: '[mixed]',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
this._valueStorage = {};
},
/** @private */
initProperties: function()
{
// private
this.defineProp('pathParamSetter', {
'dataType': 'Kekule.Widget.BaseWidget', 'serializable': false, 'setter': null
});
},
/** @ignore */
doCreateWidget: function()
{
var result = new Kekule.Widget.DropDownButton(this.getEditor());
result.setHint(this.getModifierHint());
result.setText(this.getModifierCaption());
result.setShowText(true);
result.setButtonKind(Kekule.Widget.Button.Kinds.DROPDOWN);
result.addClassName(CCNS.COMPOSER_GLYPH_PATH_MODIFIER_BUTTON + ' ' + this.getModifierClassName());
//var atomSetter = this._createAtomSetter(this.getEditor());
//result.setDropDownWidget(atomSetter);
result.setDropDownWidgetGetter(this._createPathParamSetter.bind(this));
return result;
},
/** @private */
_createPathParamSetter: function(parentWidget)
{
if (!parentWidget)
parentWidget = this.getEditor();
var widgetClass = this.getPathParamSetterClass();
var result = new widgetClass(parentWidget);
result.setCaption(this.getModifierCaption());
result.addClassName(CCNS.COMPOSER_GLYPH_PATH_MODIFIER_DROPDOWN);
this.setPropStoreFieldValue('pathParamSetter', result);
if (this._valueStorage.pathParams)
{
/*
this._updatePathParamSetterComponents(result, {
'showOppositeStartArrowSlides': this._valueStorage.pathParams._hasOppositeStartArrowSides,
'showOppositeEndArrowSlides': this._valueStorage.pathParams._hasOppositeEndArrowSides
});
*/
result.setValue(this._valueStorage.pathParams);
this._valueStorage.pathParams = null;
}
// react to value change of setter
var self = this;
result.addEventListener('showStateChange', function(e){
var w = e.widget;
//console.log(w.getClassName(), e.isShown, w === result);
if (w === result)
{
if (e.isShown) // when the setter popups, clear the original operations
{
self._lastOperation = null;
}
else if (e.isDismissed) // when closing and dismissed, ensure operation is undo
{
if (self._lastOperation)
self._lastOperation.reverse();
self._lastOperation = null;
}
}
});
result.addEventListener('valueChange', function(e){
if (e.widget === result)
{
//self.applyToTargets();
self.doModification(self.getEditor(), self.getTargetObjs(), !true);
self._lastOperation = null;
//result.dismiss();
e.stopPropagation();
}
});
result.addEventListener('valueInput', function(e){
if (e.widget === result)
{
//self.applyToTargets();
self.doModification(self.getEditor(), self.getTargetObjs(), !true);
//result.dismiss();
e.stopPropagation();
}
});
return result;
},
/* @private */
/*
_updatePathParamSetterComponents: function(setter, options)
{
if (setter.setShowContinousStartArrowSidesSetter)
setter.setShowContinousStartArrowSidesSetter(options.showOppositeStartArrowSlides);
if (setter.setShowContinousEndArrowSidesSetter)
setter.setShowContinousEndArrowSidesSetter(options.showOppositeEndArrowSlides);
},
*/
/** @private */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphPathSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_GLYPH_PATH_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_GLYPH_PATH_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return '';
},
/** @private */
_mergeHashValues: function(hash1, hash2)
{
if (!hash1)
return hash2;
if (!hash2)
return hash1;
else
{
var propNames1 = OU.getOwnedFieldNames(hash1, false);
var propNames2 = OU.getOwnedFieldNames(hash2, false);
var propNames = AU.clone(propNames1);
AU.pushUnique(propNames, propNames2);
if (propNames.length)
{
var result = {};
for (var i = 0, l = propNames.length; i < l; ++i)
{
var pname = propNames[i];
var value1 = hash1[pname];
var value2 = hash2[pname];
if (value1 === value2)
result[pname] = value1;
else
result[pname] = this.MIX_VALUE; // a special value not matching all ordinary param values
}
return result;
}
else
return null;
}
},
/** @private */
_extractPathParamsOfObjs: function(objs)
{
var glyphPathParams = null;
var connectorPathParams = null;
//var hasOppositeStartArrowSides = false;
//var hasOppositeEndArrowSides = false;
for (var i = 0, ii = objs.length; i < ii; ++i)
{
var obj = objs[i];
var connectors = (obj instanceof Kekule.Glyph.PathGlyphConnector) ? [obj] :
(obj instanceof Kekule.Glyph.PathGlyph) ? obj.getConnectors() :
null;
//var glyph = (obj instanceof Kekule.Glyph.PathGlyph)? obj: null;
if (connectors)
{
var param = this._extractPathParamOfConnectors(connectors);
connectorPathParams = this._mergeHashValues(connectorPathParams, param);
}
/*
if (glyph)
{
var oppositeArrowSidesValue = {};
hasOppositeStartArrowSides = hasOppositeStartArrowSides || !!glyph.getOppositePathStartArrowSides;
if (glyph.getOppositePathStartArrowSides)
{
oppositeArrowSidesValue.startOppositeContinuousArrowSides = glyph.getOppositePathStartArrowSides();
}
hasOppositeEndArrowSides = hasOppositeEndArrowSides || !!glyph.getOppositePathEndArrowSides;
if (glyph.getOppositePathEndArrowSides)
{
oppositeArrowSidesValue.endOppositeContinuousArrowSides = glyph.getOppositePathEndArrowSides && glyph.getOppositePathEndArrowSides();
}
glyphPathParams = this._mergeHashValues(glyphPathParams, oppositeArrowSidesValue);
}
*/
}
var result = connectorPathParams;
//var result = Object.extend(connectorPathParams, glyphPathParams);
//result._hasOppositeStartArrowSides = hasOppositeStartArrowSides; // special flag, indicating whether this property exists in glyphs
//result._hasOppositeEndArrowSides = hasOppositeEndArrowSides;
return result;
},
/** @private */
_extractPathParamOfConnectors: function(connectors)
{
var connectorPathParams = null;
for (var j = 0, jj = connectors.length; j < jj; ++j)
{
var param = this._extractPathParamOfConnector(connectors[j]);
if (param)
connectorPathParams = this._mergeHashValues(connectorPathParams, param);
}
return connectorPathParams;
},
/** @private */
_extractPathParamOfConnector: function(connector)
{
return connector.getPathParams && connector.getPathParams();
},
/**
* Returns the glyph classes that this modified can be applied to.
* Descendants may override this method.
* @private
*/
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.PathGlyph];
},
/** @private */
isApplicableGlyph: function(obj)
{
var checkObj = this.getTargetPathGlyph(obj);
if (checkObj)
{
var classes = this.getApplicableGlyphClasses();
if (classes)
{
for (var i = 0, l = classes.length; i < l; ++i)
{
if (obj instanceof classes[i])
return true;
}
return false;
}
else
return true;
}
else
return false;
},
/** @private */
getTargetPathGlyph: function(obj)
{
return (obj instanceof Kekule.Glyph.PathGlyph)? obj:
(obj instanceof Kekule.Glyph.PathGlyphConnector)? obj.getParent():
null
},
/** @private */
_getActualModificationObjs: function(targets)
{
var result = [];
for (var i = 0, l = targets.length; i < l; ++i)
{
var obj = targets[i];
//if (obj instanceof Kekule.Glyph.PathGlyph || obj instanceof Kekule.Glyph.PathGlyphConnector)
if (this.isApplicableGlyph(obj))
AU.pushUnique(result, obj);
}
return result;
},
/** @private */
_getActualModificationConnectors: function(targets)
{
var result = [];
var actualTargets = this._getActualModificationObjs(targets);
for (var i = 0, l = actualTargets.length; i < l; ++i)
{
var obj = actualTargets[i];
if (obj instanceof Kekule.Glyph.PathGlyphConnector)
result.push(obj);
else if (obj instanceof Kekule.Glyph.PathGlyph)
AU.pushUnique(result, obj.getConnectors());
}
return result;
},
/** @private */
_getActualModificationGlyphs: function(targets)
{
var result = [];
var actualTargets = this._getActualModificationObjs(targets);
for (var i = 0, l = actualTargets.length; i < l; ++i)
{
var obj = actualTargets[i];
var glyph = this.getTargetPathGlyph(obj);
if (glyph)
AU.pushUnique(result, glyph);
}
return result;
},
/** @private */
_filterAppliableParams: function(params)
{
var result = {};
var props = OU.getOwnedFieldNames(params);
for (var i = 0, l = props.length; i < l; ++i)
{
var value = params[props[i]];
if (value !== undefined && value !== this.MIX_VALUE)
result[props[i]] = value;
}
return result;
},
/** @private */
_splitPathParamValues: function(pathParams) // extract params into connector and glyph sets
{
var result = {};
var connectorParams = {};
var fieldNames = OU.getOwnedFieldNames(pathParams);
//var glyphFields = ['endOppositeContinuousArrowSides', 'startOppositeContinuousArrowSides'];
for (var i = 0, l = fieldNames.length; i < l; ++i)
{
var fname = fieldNames[i];
if (fname.startsWith('_')) // internal special field, bypass
continue;
/*
else if (glyphFields.indexOf(fname) >= 0)
glyphParams[fname] = pathParams[fname];
*/
else
{
var fieldCategory = this._getPathParamFieldCategory(fname);
if (!result[fieldCategory])
result[fieldCategory] = {};
result[fieldCategory][fname] = pathParams[fname];
}
}
//console.log('extracted', result);
return result;
},
/** @private */
_getPathParamFieldCategory: function(fieldName)
{
return 'connectorParams';
},
/* @private */
/*
_buildNewGlyphPropValues: function(target, pathParams, glyphParams)
{
var propValues = {};
if (pathParams._hasOppositeEndArrowSides && target.hasProperty('oppositePathEndArrowSides')
&& OU.notUnset(glyphParams.endOppositeContinuousArrowSides) && glyphParams.endOppositeContinuousArrowSides !== this.MIX_VALUE)
{
propValues.oppositePathEndArrowSides = glyphParams.endOppositeContinuousArrowSides;
}
if (pathParams._hasOppositeStartArrowSides && target.hasProperty('oppositePathStartArrowSides')
&& OU.notUnset(glyphParams.startOppositeContinuousArrowSides) && glyphParams.startOppositeContinuousArrowSides !== this.MIX_VALUE)
{
propValues.oppositePathStartArrowSides = glyphParams.startOppositeContinuousArrowSides;
}
return propValues;
},
*/
/** @private */
createModificationOperations: function(editor, targets, pathParams)
{
var paramGroup = this._splitPathParamValues(pathParams);
var opers = this.doCreateModificationOperations(editor, targets, paramGroup);
/*
if ((pathParams._hasOppositeEndArrowSides || pathParams._hasOppositeStartArrowSides) && (paramGroup.glyphParams))
{
var glyphParams = paramGroup.glyphParams;
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var target = glyphs[i];
if (target instanceof Kekule.Glyph.PathGlyph)
{
var op;
var propValues = this._buildNewGlyphPropValues(target, pathParams, glyphParams);
op = new Kekule.ChemObjOperation.Modify(target, propValues, editor);
if (op)
opers.push(op);
}
}
}
*/
return opers;
},
/** @private */
doCreateModificationOperations: function(editor, targets, paramGroup)
{
if (paramGroup.connectorParams)
{
// console.log('create', paramGroup.connectorParams);
var connectors = this._getActualModificationConnectors(targets);
var connectorOpers = this._createModificationOperationsOnConnectors(editor, connectors, paramGroup.connectorParams);
return connectorOpers;
}
return null;
},
/** @private */
updateModificationOperations: function(editor, targets, pathParams, lastOperation)
{
var paramGroup = this._splitPathParamValues(pathParams);
var operations;
if (lastOperation.length)
operations = lastOperation;
else if (lastOperation instanceof Kekule.MacroOperation)
operations = lastOperation.getChildren();
else
operations = [lastOperation];
return this.doUpdateModificationOperations(editor, operations, targets, paramGroup);
},
/** @private */
doUpdateModificationOperations: function(editor, operations, targets, paramGroup)
{
this._updateModificationOperationsOnConnectors(editor, targets, paramGroup.connectorParams, operations);
return operations;
},
/** @private */
_updateModificationOperationsOnConnectors: function(editor, targets, connectorParams, operations)
{
for (var i = 0, l = operations.length; i < l; ++i)
{
var operation = operations[i];
var target = operation.getTarget();
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
if (operation instanceof Kekule.ChemObjOperation.ModifyHashProp)
{
//console.log('update', paramGroup, operation);
//operation.setNewPropValue(pathParams);
this._updateModificationOperationOnConnector(editor, target, operation, connectorParams);
}
}
/*
else if (target instanceof Kekule.Glyph.PathGlyph)
{
if (operation instanceof Kekule.ChemObjOperation.Modify)
{
var propValues = this._buildNewGlyphPropValues(target, pathParams, paramGroup.glyphParams);
operation.setNewPropValues(propValues);
}
}
*/
}
},
/** @private */
_updateModificationOperationOnConnector: function(editor, target, operation, connectorPathParams)
{
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
if (operation instanceof Kekule.ChemObjOperation.ModifyHashProp)
{
operation.setNewPropValue(connectorPathParams);
}
}
},
/** @private */
_createModificationOperationsOnConnectors: function(editor, connectors, connectorPathParams)
{
var opers = [];
for (var i = 0, l = connectors.length; i < l; ++i)
{
var target = connectors[i];
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
//var op = new Kekule.ChemObjOperation.ModifyHashProp(target, 'pathParams', /*pathParams*/paramGroup.connectorParams, editor);
var op = this._createModificationOperationOnConnector(editor, target, connectorPathParams);
if (op)
opers.push(op);
}
}
return opers;
},
/** @private */
_createModificationOperationOnConnector: function(editor, target, connectorPathParams)
{
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
return new Kekule.ChemObjOperation.ModifyHashProp(target, 'pathParams', connectorPathParams, editor);
}
else
return null;
},
/** @private */
_createWrapperOperation: function(childOpers)
{
var operation;
if (childOpers && childOpers.length > 1)
operation = new Kekule.MacroOperation(childOpers);
else
operation = childOpers[0];
return operation;
},
/** @private */
_execModificationOperationInEditor: function(operation)
{
var isNewOperation = !this._lastOperation;
var editor = this.getEditor();
editor.beginManipulateAndUpdateObject();
try
{
if (operation) // only execute when there is real modification
{
if (/*doNotAddOperToHistory &&*/ !isNewOperation) // operation already added to history, do not add again
operation.execute();
else
{
editor.execOperation(operation);
}
}
}
finally
{
editor.endManipulateAndUpdateObject();
this._lastOperation = operation;
}
},
/** @private */
doModification: function(editor, targets, doNotAddOperToHistory)
{
var pathParams = this.getPathParamSetter().getValue();
//console.log('do apply begin', pathParams);
pathParams = this._filterAppliableParams(pathParams);
/*
var opers = [];
var connectors = this._getActualModificationConnectors(targets);
var editor = editor || this.getEditor();
for (var i = 0, l = connectors.length; i < l; ++i)
{
var target = connectors[i];
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
var op = new Kekule.ChemObjOperation.ModifyHashProp(target, 'pathParams', pathParams, editor);
if (op)
opers.push(op);
}
}
*/
var opers;
//var isNewOperation = !this._lastOperation;
if (this._lastOperation)
{
opers = this.updateModificationOperations(editor, targets, pathParams, this._lastOperation);
}
else
{
opers = this.createModificationOperations(editor, targets, pathParams);
}
/*
var operation;
if (opers && opers.length > 1)
operation = new Kekule.MacroOperation(opers);
else
operation = opers[0];
*/
var operation = this._createWrapperOperation(opers);
/*
var editor = this.getEditor();
//editor.beginUpdateObject();
editor.beginManipulateAndUpdateObject();
try
{
if (operation) // only execute when there is real modification
{
if (!isNewOperation) // operation already added to history, do not add again
operation.execute();
else
{
editor.execOperation(operation);
this._lastOperation = operation;
}
}
}
finally
{
//editor.endUpdateObject();
editor.endManipulateAndUpdateObject();
}
*/
this._execModificationOperationInEditor(operation);
//console.log('do apply end');
},
/** @ignore */
doLoadFromTargets: function(editor, targets)
{
var objs = this._getActualModificationObjs(targets);
var showModifier = (objs.length > 0);
this._lastOperation = null;
//console.log('clear last loadFromTarget');
if (showModifier)
{
var pathParams = this._extractPathParamsOfObjs(objs);
this._valueStorage.pathParams = pathParams;
//console.log('pathParams', pathParams);
var pathParamSetter = this.getPathParamSetter();
if (pathParamSetter)
{
//console.log(pathParams);
/*
this._updatePathParamSetterComponents(pathParamSetter, {
'showOppositeStartArrowSlides': pathParams._hasOppositeStartArrowSides,
'showOppositeEndArrowSlides': pathParams._hasOppositeEndArrowSides
});
*/
pathParamSetter.setValue(pathParams);
}
}
this.getWidget().setDisplayed(showModifier);
},
/** @ignore */
doApplyToTargets: function(/*$super, */editor, targets)
{
this.doModification(editor, targets, false);
}
});
/**
* A modifier to change the path params of reaction arrow and line segment.
* @class
* @augments Kekule.Editor.ObjModifier.GlyphPath
*/
Kekule.Editor.ObjModifier.ReactionArrowAndSegmentPath = Class.create(Kekule.Editor.ObjModifier.GlyphPath,
/** @lends Kekule.Editor.ObjModifier.ReactionArrowAndSegmentPath# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.ReactionArrowAndSegmentPath',
/** @private */
MIX_VALUE: '[mixed]',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
},
/** @ignore */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphReactionArrowPathSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_REACTION_ARROW_AND_SEGMENT_PATH_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_REACTION_ARROW_AND_SEGMENT_PATH_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return CCNS.COMPOSER_GLYPH_REACTION_ARROW_MODIFIER_BUTTON;
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.StraightLine, Kekule.Glyph.Segment, Kekule.Glyph.ReactionArrow];
},
/** @ignore */
_extractPathParamsOfObjs: function(/*$super, */objs)
{
var reactionArrowType;
var result = this.tryApplySuper('_extractPathParamsOfObjs', [objs]) /* $super(objs) */;
for (var i = 0, ii = objs.length; i < ii; ++i)
{
var obj = objs[i];
var glyph = this.getTargetPathGlyph(obj);
if (glyph)
{
if (glyph.getReactionType)
{
var rt = glyph.getReactionType();
if (!reactionArrowType)
reactionArrowType = rt;
else if (reactionArrowType !== rt)
{
reactionArrowType = Kekule.Glyph.ReactionArrowType.CUSTOM;
break;
}
}
}
}
result.reactionArrowType = reactionArrowType;
return result;
},
/** @ignore */
createModificationOperations_OLD: function(/*$super, */editor, targets, pathParams)
{
var opers = [];
if (/*pathParams.reactionArrowType &&*/ pathParams.reactionArrowType !== this.MIX_VALUE)
{
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var glyph = glyphs[i];
if (glyph.setReactionType)
{
if (!pathParams.reactionArrowType) // explicit none, change reaction arrow to line segment
{
if (glyph instanceof Kekule.Glyph.ReactionArrow)
{
opers.push(new Kekule.ChemObjOperation.ChangeClass(glyph, Kekule.Glyph.Segment, editor));
}
}
}
else
{
if (!!pathParams.reactionArrowType)
{
if (glyph instanceof Kekule.Glyph.StraightLine)
{
opers.push(new Kekule.ChemObjOperation.ChangeClass(glyph, Kekule.Glyph.ReactionArrow, editor));
}
}
}
}
opers.push(new Kekule.ChemObjOperation.Modify(glyph, {'reactionType': pathParams.reactionArrowType}, editor));
}
var otherOpers = this.tryApplySuper('createModificationOperations_OLD', [editor, targets, pathParams]) /* $super(editor, targets, pathParams) */ || [];
opers = opers.concat(otherOpers); // the reaction type operation must before pathParam modification operations, since it may changes pathParams
return opers;
},
/** @ignore */
doCreateModificationOperations: function(/*$super, */editor, targets, paramGroup)
{
var opers = [];
var connectorParams = paramGroup.connectorParams;
if (/*connectorParams.reactionArrowType &&*/ connectorParams.reactionArrowType !== this.MIX_VALUE)
{
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var glyph = glyphs[i];
if (glyph.setReactionType)
{
if (!connectorParams.reactionArrowType) // explicit none, change reaction arrow to line segment
{
if (glyph instanceof Kekule.Glyph.ReactionArrow)
{
opers.push(new Kekule.ChemObjOperation.ChangeClass(glyph, Kekule.Glyph.Segment, editor));
}
}
}
else
{
if (!!connectorParams.reactionArrowType)
{
if (glyph instanceof Kekule.Glyph.StraightLine)
{
opers.push(new Kekule.ChemObjOperation.ChangeClass(glyph, Kekule.Glyph.ReactionArrow, editor));
}
}
}
}
opers.push(new Kekule.ChemObjOperation.Modify(glyph, {'reactionType': connectorParams.reactionArrowType}, editor));
}
var otherOpers = this.tryApplySuper('doCreateModificationOperations', [editor, targets, paramGroup]) /* $super(editor, targets, paramGroup) */ || [];
opers = opers.concat(otherOpers); // the reaction type operation must before pathParam modification operations, since it may changes pathParams
return opers;
},
});
/**
* A modifier to change the path params of arc segment.
* @class
* @augments Kekule.Editor.ObjModifier.GlyphPath
*/
Kekule.Editor.ObjModifier.ArcPath = Class.create(Kekule.Editor.ObjModifier.GlyphPath,
/** @lends Kekule.Editor.ObjModifier.ArcPath# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.ArcPath',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
},
/** @ignore */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphArcPathSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_ARC_PATH_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_ARC_PATH_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return CCNS.COMPOSER_GLYPH_ARC_PATH_MODIFIER_BUTTON;
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.Arc];
}
});
/**
* A modifier to change the path params of multi arc segment.
* @class
* @augments Kekule.Editor.ObjModifier.GlyphPath
*/
Kekule.Editor.ObjModifier.MultiArcPath = Class.create(Kekule.Editor.ObjModifier.GlyphPath,
/** @lends Kekule.Editor.ObjModifier.MultiArcPath# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.MultiArcPath',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
},
/** @ignore */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphMultiArcPathSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_MULTI_ARC_PATH_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_MULTI_ARC_PATH_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return CCNS.COMPOSER_GLYPH_MULTI_ARC_PATH_MODIFIER_BUTTON;
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.TwinArc];
},
/** @ignore */
_filterAppliableParams: function(/*$super, */params)
{
if (DataType.isArrayValue(params))
{
var result = [];
for (var i = 0, l = params.length; i < l; ++i)
{
result.push(this.tryApplySuper('_filterAppliableParams', [params[i]]) /* $super(params[i]) */);
}
return result;
}
else
return this.tryApplySuper('_filterAppliableParams', [params]) /* $super(params) */;
},
/** @private */
_buildConnectorGroup: function(targetObjs, createMap)
{
var group = [];
var getGroup = function(index)
{
var result = group[index];
if (!result)
{
result = [];
group[index] = result;
}
return result;
};
var map;
if (createMap)
{
map = new Kekule.MapEx();
group.map = map;
}
for (var i = 0, ii = targetObjs.length; i < ii; ++i)
{
var obj = targetObjs[i];
var connectors = (obj instanceof Kekule.Glyph.PathGlyphConnector) ? [obj] :
(obj instanceof Kekule.Glyph.PathGlyph) ? obj.getConnectors() :
[];
for (var j = 0, jj = connectors.length; j < jj; ++j)
{
var connector = connectors[j];
getGroup(j).push(connector);
if (createMap)
map.set(connector, j);
}
}
return group;
},
/** @ignore */
_extractPathParamsOfObjs: function(objs)
{
var result = [];
var connectorGroup = this._buildConnectorGroup(objs);
for (var i = 0, l = connectorGroup.length; i < l; ++i)
{
var connectors = connectorGroup[i] || [];
var params = this._extractPathParamOfConnectors(connectors) || null;
result.push(params);
}
return result;
},
/** @ignore */
_splitPathParamValues: function(/*$super, */pathParams)
{
if (DataType.isArrayValue(pathParams))
{
var result = [];
for (var i = 0, l = pathParams.length; i < l; ++i)
{
var group = this.tryApplySuper('_splitPathParamValues', [pathParams[i]]) /* $super(pathParams[i]) */;
if (group)
{
var categories = OU.getOwnedFieldNames(group);
for (var j = 0, jj = categories.length; j < jj; ++j)
{
var category = categories[j];
if (!result[category])
result[category] = [];
result[category][i] = group[category];
}
//result[i] = group;
}
}
return result;
}
else
return this.tryApplySuper('_splitPathParamValues', [pathParams]) /* $super(pathParams) */;
//return {connectorParams: pathParams};
},
/** @ignore */
_updateModificationOperationsOnConnectors: function(editor, targets, connectorParams, operations)
{
var connectorMap = this._buildConnectorGroup(targets, true).map;
for (var i = 0, l = operations.length; i < l; ++i)
{
var operation = operations[i];
var target = operation.getTarget();
if (target instanceof Kekule.Glyph.PathGlyphConnector)
{
if (operation instanceof Kekule.ChemObjOperation.ModifyHashProp)
{
//console.log('update', paramGroup, operation);
var groupIndex = connectorMap.get(target);
if (groupIndex >= 0)
this._updateModificationOperationOnConnector(editor, target, operation, connectorParams[groupIndex]);
}
}
}
},
/** @ignore */
doCreateModificationOperations: function(editor, targets, paramGroup)
{
var opers = [];
if (paramGroup.connectorParams)
{
var connectorParamGroup = AU.toArray(paramGroup.connectorParams);
var connectorGroup = this._buildConnectorGroup(targets);
for (var i = 0, l = connectorGroup.length; i < l; ++i)
{
var param = connectorParamGroup[i];
if (param)
{
var connectors = connectorGroup[i] || [];
var subOpers = this._createModificationOperationsOnConnectors(editor, connectors, param);
if (subOpers)
opers = opers.concat(subOpers);
}
}
}
return opers;
},
});
/**
* A base modifier to change properties of electron pushing arrow.
* @class
* @augments Kekule.Editor.ObjModifier.GlyphPath
*/
Kekule.Editor.ObjModifier.BaseElectronPushingArrow = Class.create(Kekule.Editor.ObjModifier.GlyphPath,
/** @lends Kekule.Editor.ObjModifier.BaseElectronPushingArrow# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.BaseElectronPushingArrow',
/** @ignore */
getPathParamSetterClass: function()
{
return null; // should be override by descendants
},
/** @private */
getModifierCaption: function()
{
return null; // should be override by descendants
},
/** @private */
getModifierHint: function()
{
return null; // should be override by descendants
},
/** @private */
getModifierClassName: function()
{
return ''; // should be override by descendants
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return []; // should be override by descendants
},
/** @ignore */
_extractPathParamsOfObjs: function(/*$super, */objs)
{
var electronCount;
var result = this.tryApplySuper('_extractPathParamsOfObjs', [objs]) /* $super(objs) */;
for (var i = 0, ii = objs.length; i < ii; ++i)
{
var obj = objs[i];
var glyph = this.getTargetPathGlyph(obj);
if (glyph)
{
if (glyph.getElectronCount)
{
var eCount = glyph.getElectronCount();
if (OU.isUnset(electronCount))
electronCount = eCount;
else if (electronCount !== eCount)
{
electronCount = 0; // Mix value
break;
}
}
}
}
result.electronCount = electronCount;
return result;
},
/** @ignore */
_getPathParamFieldCategory: function(/*$super, */fieldName)
{
if (fieldName === 'electronCount')
return 'glyphParams';
else
return this.tryApplySuper('_getPathParamFieldCategory', [fieldName]) /* $super(fieldName) */;
},
/* @ignore */
/*
createModificationOperations: function($super, editor, targets, pathParams)
{
var opers = $super(editor, targets, pathParams) || []; // arrow param must be set first, since e-count may changes the arrow side
if (!!pathParams.electronCount)
{
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var glyph = glyphs[i];
if (glyph.hasProperty('electronCount'))
{
opers.push(new Kekule.ChemObjOperation.Modify(glyph, {'electronCount': pathParams.electronCount}, editor));
}
}
}
return opers;
},
*/
/** @ignore */
doCreateModificationOperations: function(/*$super, */editor, targets, paramGroup)
{
var opers = this.tryApplySuper('doCreateModificationOperations', [editor, targets, paramGroup]) /* $super(editor, targets, paramGroup) */ || []; // arrow param must be set first, since e-count may changes the arrow side
if (paramGroup.glyphParams && paramGroup.glyphParams.electronCount)
{
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var glyph = glyphs[i];
if (glyph.hasProperty('electronCount'))
{
opers.push(new Kekule.ChemObjOperation.Modify(glyph, {'electronCount': paramGroup.glyphParams.electronCount}, editor));
}
}
}
return opers;
},
/** @ignore */
doUpdateModificationOperations: function(/*$super, */editor, operations, targets, paramGroup)
{
this.tryApplySuper('doUpdateModificationOperations', [editor, operations, targets, paramGroup]) /* $super(editor, operations, targets, paramGroup) */;
this._updateGlyphModificationOperations(editor, operations, paramGroup);
return operations;
},
/* @private */
_updateGlyphModificationOperations: function(editor, operations, paramGroup)
{
// TODO: pending here
/*
console.log('paramGroup', paramGroup);
for (var i = 0, l = operations.length; i < l; ++i)
{
var oper = operations[i];
if (oper instanceof Kekule.ChemObjOperation.Modify)
{
var target = oper.getTarget();
if (target instanceof Kekule.Glyph.PathGlyph && target.hasProperty('electronCount'))
{
}
}
}
*/
}
});
/**
* A modifier to change the properties of normal electron pushing arrow
* @class
* @augments Kekule.Editor.ObjModifier.BaseElectronPushingArrow
*/
Kekule.Editor.ObjModifier.ElectronPushingArrow = Class.create(Kekule.Editor.ObjModifier.BaseElectronPushingArrow,
/** @lends Kekule.Editor.ObjModifier.ElectronPushingArrow# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.ElectronPushingArrow',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
},
/** @ignore */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphElectronPushingArrowSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_ELECTRON_PUSHING_ARROW_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_ELECTRON_PUSHING_ARROW_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return CCNS.COMPOSER_GLYPH_ELECTRON_PUSHING_ARROW_MODIFIER_BUTTON;
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.ElectronPushingArrow];
}
});
/**
* A modifier to change the properties of bond forming electron pushing arrow
* @class
* @augments Kekule.Editor.ObjModifier.MultiArcPath
*/
Kekule.Editor.ObjModifier.BondFormingElectronPushingArrow = Class.create(Kekule.Editor.ObjModifier.MultiArcPath,
/** @lends Kekule.Editor.ObjModifier.BondFormingElectronPushingArrow# */
{
/** @private */
CLASS_NAME: 'Kekule.Editor.ObjModifier.BondFormingElectronPushingArrow',
/** @construct */
initialize: function(/*$super, */editor)
{
this.tryApplySuper('initialize', [editor]) /* $super(editor) */;
},
/** @ignore */
getPathParamSetterClass: function()
{
return Kekule.ChemWidget.GlyphMultiElectronPushingArrowSettingPanel;
},
/** @private */
getModifierCaption: function()
{
return Kekule.$L('ChemWidgetTexts.CAPTION_BOND_FORMING_ELECTRON_PUSHING_ARROW_MODIFIER');
},
/** @private */
getModifierHint: function()
{
return Kekule.$L('ChemWidgetTexts.HINT_BOND_FORMING_ELECTRON_PUSHING_ARROW_MODIFIER');
},
/** @private */
getModifierClassName: function()
{
return CCNS.COMPOSER_GLYPH_BOND_FORMING_ELECTRON_PUSHING_ARROW_MODIFIER_BUTTON;
},
/** @ignore */
getApplicableGlyphClasses: function()
{
return [Kekule.Glyph.BondFormingElectronPushingArrow];
},
/** @ignore */
_extractPathParamsOfObjs: function(/*$super, */objs)
{
var electronCount;
var result = this.tryApplySuper('_extractPathParamsOfObjs', [objs]) /* $super(objs) */;
for (var i = 0, ii = objs.length; i < ii; ++i)
{
var obj = objs[i];
var glyph = this.getTargetPathGlyph(obj);
if (glyph)
{
if (glyph.getElectronCount)
{
var connectorCount = glyph.getConnectorCount() || 1;
var eCount = Math.round((glyph.getElectronCount() || 0) / connectorCount);
if (OU.isUnset(electronCount))
{
electronCount = eCount;
if (electronCount <= 0)
electronCount = 1;
}
else if (electronCount !== eCount)
{
electronCount = 0; // Mix value
break;
}
}
}
}
result.electronCount = electronCount;
return result;
},
/** @ignore */
_getPathParamFieldCategory: function(/*$super, */fieldName)
{
if (fieldName === 'electronCount')
return 'glyphParams';
else
return this.tryApplySuper('_getPathParamFieldCategory', [fieldName]) /* $super(fieldName) */;
},
/** @ignore */
_filterAppliableParams: function(/*$super, */params)
{
var result = this.tryApplySuper('_filterAppliableParams', [params]) /* $super(params) */ || [];
if (params.electronCount)
result.electronCount = params.electronCount;
return result;
},
/** @ignore */
_splitPathParamValues: function(/*$super, */pathParams)
{
var result = this.tryApplySuper('_splitPathParamValues', [pathParams]) /* $super(pathParams) */ || [];
if (pathParams.electronCount)
{
if (!result.glyphParams)
result.glyphParams = {};
result.glyphParams.electronCount = pathParams.electronCount;
}
return result;
},
/** @ignore */
doCreateModificationOperations: function(/*$super, */editor, targets, paramGroup)
{
var opers = this.tryApplySuper('doCreateModificationOperations', [editor, targets, paramGroup]) /* $super(editor, targets, paramGroup) */ || []; // arrow param must be set first, since e-count may changes the arrow side
if (paramGroup.glyphParams && paramGroup.glyphParams.electronCount)
{
var glyphs = this._getActualModificationGlyphs(targets);
for (var i = 0, l = glyphs.length; i < l; ++i)
{
var glyph = glyphs[i];
if (glyph.hasProperty('electronCount'))
{
var connectorCount = glyph.getConnectorCount() || 1;
var perECount = Math.round(paramGroup.glyphParams.electronCount * connectorCount);
if (perECount <= 0)
perECount = 1;
opers.push(new Kekule.ChemObjOperation.Modify(glyph, {'electronCount': perECount}, editor));
}
}
}
return opers;
}
});
var OMM = Kekule.Editor.ObjModifierManager;
OMM.register([Kekule.Glyph.StraightLine, Kekule.Glyph.PathGlyphConnector], [Kekule.Editor.ObjModifier.ReactionArrowAndSegmentPath]);
OMM.register([Kekule.Glyph.Arc], [Kekule.Editor.ObjModifier.ArcPath]);
OMM.register([Kekule.Glyph.TwinArc], [Kekule.Editor.ObjModifier.MultiArcPath]);
OMM.register([Kekule.Glyph.ElectronPushingArrow], [Kekule.Editor.ObjModifier.ElectronPushingArrow]);
OMM.register([Kekule.Glyph.BondFormingElectronPushingArrow], [Kekule.Editor.ObjModifier.BondFormingElectronPushingArrow]);
})();