You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1366 lines
50 KiB
Plaintext
1366 lines
50 KiB
Plaintext
function Builder() {
|
|
|
|
}
|
|
|
|
/**Image base path*/
|
|
Builder.IMAGE_BASE_PATH = './assets/images/';
|
|
|
|
/**Path to fill icon image*/
|
|
Builder.IMAGE_FILL_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-fill.png';
|
|
|
|
/**Path to stroke icon image*/
|
|
Builder.IMAGE_STROKE_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-stroke.png';
|
|
|
|
/**Path to line width icon image*/
|
|
Builder.IMAGE_LINEWIDTH_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-linewidth.png';
|
|
|
|
/**Line (dashed) style icon image*/
|
|
Builder.IMAGE_LINESTYLE_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-linestyle.png';
|
|
|
|
/**Path to start style icon image*/
|
|
Builder.IMAGE_STARTSTYLE_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-startstyle.png';
|
|
|
|
/**Path to end style icon image*/
|
|
Builder.IMAGE_ENDSTYLE_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-endstyle.png';
|
|
|
|
/**Path to width icon image*/
|
|
Builder.IMAGE_WIDTH_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-h-resize.png';
|
|
|
|
/**Path to height icon image*/
|
|
Builder.IMAGE_HEIGHT_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-v-resize.png';
|
|
|
|
/**Path to URL style icon image*/
|
|
Builder.IMAGE_URL_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-url.png';
|
|
|
|
/**Path to text style icon image*/
|
|
Builder.IMAGE_TEXT_ICON_PATH = Builder.IMAGE_BASE_PATH + 'prop-icon-text.png';
|
|
|
|
|
|
/**Creates a {Builder} out of JSON parsed object
|
|
*@param {JSONObject} o - the JSON parsed object
|
|
*@return {Builder} a newly constructed Builder
|
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
|
**/
|
|
//Builder.load = function(o){
|
|
// var newBuilder = new Builder();
|
|
// newBuilder.properties = BuilderProperty.loadArray(o.properties);
|
|
// newBuilder.figureId = o.figureId;
|
|
// return newBuilder;
|
|
//}
|
|
|
|
/**
|
|
*Creates the property panel for a shape {Figure} or {Connector}
|
|
*@param {DOMObject} DOMObject - the div of the properties panel
|
|
*@param {Figure} shape - the figure for which the properties will be displayed
|
|
**/
|
|
Builder.constructPropertiesPanel = function (DOMObject, shape) {
|
|
for (var i = 0; i < shape.properties.length; i++) {
|
|
// regExp to avoid properties of Text editor
|
|
//if (/(primitives\.\d+|middleText)\.(str|size|font|align|underlined|style\.fillStyle)/g.test(shape.properties[i].property) === false) {
|
|
//}
|
|
shape.properties[i].injectInputArea(DOMObject, shape.id);
|
|
}
|
|
};
|
|
|
|
/**
|
|
*Creates the property panel for a Text primitive of shape {Figure} and returns it
|
|
*@param {DOMObject} textEditor - the <div> of the properties panel (declared inside editor page)
|
|
*@param {DOMObject} textEditorTools - the <div> of the text editor's tools (declared insider editor page)
|
|
*@param {Figure} shape - the figure - parent of Text primitive
|
|
*@param {Number} textPrimitiveId - the id value of Text primitive child of figure for which the properties will be displayed
|
|
*
|
|
*@return {TextEditorPopup} - new instance of TextEditorPopup after init
|
|
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
Builder.constructTextPropertiesPanel = function (textEditor, textEditorTools, shape, textPrimitiveId) {
|
|
var textEditor = new TextEditorPopup(textEditor, textEditorTools, shape, textPrimitiveId);
|
|
textEditor.init();
|
|
|
|
return textEditor;
|
|
};
|
|
|
|
/**
|
|
*Creates the properties for main CanvasProps
|
|
*@param {DOMObject} DOMObject - the div of the properties panel
|
|
*@param {CanvasProps} canvasProps - the CanvasProps for which the properties will be displayed
|
|
**/
|
|
Builder.constructCanvasPropertiesPanel = function (DOMObject, canvasProps) {
|
|
var div = document.createElement("div");
|
|
var icon;
|
|
|
|
// colorPicker plugin requires div to be already appended to the DOM
|
|
DOMObject.appendChild(div);
|
|
|
|
//title
|
|
var titleDiv = document.createElement("div");
|
|
titleDiv.className = 'GroupLabel';
|
|
titleDiv.textContent = '画板设置';
|
|
div.appendChild(titleDiv);
|
|
|
|
//separator
|
|
var separator = document.createElement("hr");
|
|
div.appendChild(separator);
|
|
|
|
//fill color
|
|
var colorDiv = document.createElement("div");
|
|
colorDiv.className = "line";
|
|
|
|
var currentColor = canvasProps.getFillColor();
|
|
var uniqueId = new Date().getTime();
|
|
|
|
// var labelDiv = document.createElement("div");
|
|
// labelDiv.className = "label";
|
|
// labelDiv.textContent = "背景颜色";
|
|
|
|
// icon = new Image();
|
|
// icon.className = 'prop-icon';
|
|
// icon.src = Builder.IMAGE_FILL_ICON_PATH;
|
|
// labelDiv.appendChild(icon);
|
|
|
|
// colorDiv.appendChild(labelDiv);
|
|
|
|
// var colorSelectorDiv = document.createElement("div");
|
|
// colorSelectorDiv.id = 'colorSelector' + uniqueId;
|
|
// colorSelectorDiv.className = 'color-selector';
|
|
|
|
// var colorInput = document.createElement("input");
|
|
// colorInput.type = "text";
|
|
// colorInput.id = 'colorpickerHolder' + uniqueId;
|
|
// colorInput.value = currentColor;
|
|
// colorSelectorDiv.appendChild(colorInput);
|
|
|
|
// colorDiv.appendChild(colorSelectorDiv);
|
|
|
|
// div.appendChild(colorDiv);
|
|
|
|
// var colorPicker = document.getElementById('colorpickerHolder' + uniqueId);
|
|
|
|
// //let plugin do the job
|
|
// $(colorPicker).colorPicker();
|
|
|
|
// //on change update the canvasProps
|
|
// colorPicker.onchange = function () {
|
|
// var newColor = colorPicker.value;
|
|
// //Did we change fill color?
|
|
// if (canvasProps.getFillColor() !== newColor) {
|
|
// var cmd = new CanvasChangeColorCommand(newColor);
|
|
// cmd.execute();
|
|
// History.addUndo(cmd);
|
|
|
|
// //trigger a repaint;
|
|
// draw();
|
|
// }
|
|
// };
|
|
|
|
//width
|
|
var divWidth = document.createElement("div");
|
|
divWidth.className = 'label';
|
|
divWidth.textContent = '宽度';
|
|
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_WIDTH_ICON_PATH;
|
|
divWidth.appendChild(icon);
|
|
|
|
var inputWidth = document.createElement("input");
|
|
inputWidth.type = "text";
|
|
inputWidth.className = "text"; //required for onkeydown
|
|
inputWidth.value = canvasProps.getWidth();
|
|
divWidth.appendChild(inputWidth);
|
|
|
|
div.appendChild(divWidth);
|
|
|
|
//height
|
|
var divHeight = document.createElement("div");
|
|
divHeight.className = 'label';
|
|
divHeight.textContent = '高度';
|
|
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_HEIGHT_ICON_PATH;
|
|
divHeight.appendChild(icon);
|
|
|
|
var inputHeight = document.createElement("input");
|
|
inputHeight.type = "text";
|
|
inputHeight.className = "text"; //required for onkeydown
|
|
inputHeight.value = canvasProps.getHeight();
|
|
divHeight.appendChild(inputHeight);
|
|
|
|
div.appendChild(divHeight);
|
|
|
|
//button block: Update and Fit options
|
|
var divButton = document.createElement("div");
|
|
|
|
//update button
|
|
var btnUpdate = document.createElement("input");
|
|
btnUpdate.setAttribute("type", "button");
|
|
btnUpdate.setAttribute("value", "应用");
|
|
|
|
btnUpdate.onclick = function () {
|
|
//update canvas props
|
|
// Did we entered number value for width?
|
|
var widthVal = Number(inputWidth.value);
|
|
if (isNaN(widthVal)) {
|
|
widthVal = canvasProps.getWidth();
|
|
inputWidth.value = widthVal;
|
|
}
|
|
|
|
var heightVal = Number(inputHeight.value);
|
|
if (isNaN(heightVal)) {
|
|
heightVal = canvasProps.getHeight();
|
|
inputHeight.value = heightVal;
|
|
}
|
|
|
|
//Did we change width or height?
|
|
if (canvasProps.getWidth() !== widthVal || canvasProps.getHeight() !== heightVal) {
|
|
var undo = new CanvasChangeSizeCommand(widthVal, heightVal);
|
|
undo.execute();
|
|
History.addUndo(undo);
|
|
}
|
|
//执行保存到数据库MapData--CCForm_FK_MapData
|
|
|
|
draw();
|
|
};
|
|
|
|
divButton.appendChild(btnUpdate);
|
|
|
|
//fit button
|
|
// var btnFit = document.createElement("input");
|
|
// btnFit.setAttribute("type", "button");
|
|
// btnFit.setAttribute("value", "Fit");
|
|
|
|
// btnFit.onclick = function () {
|
|
// /* Algorithm
|
|
// * 1) Find border points of Figure/Container/Connector bounds
|
|
// * 2) Get new width and height of canvas from 1)
|
|
// * 3) If canvas size changed -> Use CanvasChangeSizeCommand to change canvas size
|
|
// */
|
|
|
|
// var workAreaBounds = STACK.getWorkAreaBounds();
|
|
// var newCanvasWidth = workAreaBounds[2] - workAreaBounds[0];
|
|
// var newCanvasHeight = workAreaBounds[3] - workAreaBounds[1];
|
|
|
|
// // Did canvas size changed?
|
|
// if (newCanvasWidth !== canvasProps.getWidth() || newCanvasHeight !== canvasProps.getHeight()) {
|
|
// var cmdCanvasFit = new CanvasFitCommand(
|
|
// newCanvasWidth + DIAGRAMO.CANVAS_FIT_PADDING * 2,
|
|
// newCanvasHeight + DIAGRAMO.CANVAS_FIT_PADDING * 2,
|
|
// workAreaBounds[0] - DIAGRAMO.CANVAS_FIT_PADDING, // new (0,0) point goes this X coordinate
|
|
// workAreaBounds[1] - DIAGRAMO.CANVAS_FIT_PADDING // new (0,0) point goes this Y coordinate
|
|
// );
|
|
// cmdCanvasFit.execute();
|
|
// History.addUndo(cmdCanvasFit);
|
|
// // redraw canvas
|
|
// draw();
|
|
// }
|
|
// };
|
|
// divButton.appendChild(btnFit);
|
|
|
|
div.appendChild(divButton);
|
|
}
|
|
|
|
|
|
|
|
/** The structure that will declare any visible and changable property of a shape.
|
|
*
|
|
* Note: A {BuilderProperty} DOES NOT STORE THE VALUE OF THE PROPERTY but only
|
|
* describe what properties of a {Style} are exposed and how the {Builder} will
|
|
* create interface (fragments) for user in properties panel.
|
|
*
|
|
* @constructor
|
|
* @this {Builder}
|
|
* @param {String} name - the name of the property
|
|
* @param {String} property - the property (in dot notation) we are using in the form of 'primitives.0.style.strokeStyle'
|
|
* @param {Object} type - could be either, 'Color', 'Boolean', 'Text' or {Array}
|
|
* In case it's an {Array} it is of type [{Text,Value}] and is used to generate a DD menu
|
|
*/
|
|
function BuilderProperty(name, property, type, value) {
|
|
this.name = name;
|
|
this.property = property;
|
|
this.type = type;
|
|
this.PropertyValue = value ? value : null;
|
|
}
|
|
|
|
/**Color property type*/
|
|
BuilderProperty.TYPE_COLOR = 'Color';
|
|
|
|
/**Text property type*/
|
|
BuilderProperty.TYPE_TEXT = 'Text';
|
|
|
|
/**SingleText property type*/
|
|
BuilderProperty.TYPE_SINGLE_TEXT = 'SingleText';
|
|
|
|
/**Text size property type*/
|
|
BuilderProperty.TYPE_TEXT_FONT_SIZE = 'TextFontSize';
|
|
|
|
/**Font family property type*/
|
|
BuilderProperty.TYPE_TEXT_FONT_FAMILY = 'TextFontFamily';
|
|
|
|
/**Text aligment property type*/
|
|
BuilderProperty.TYPE_TEXT_FONT_ALIGNMENT = 'TextFontAlignment';
|
|
|
|
/**Text underlined property type*/
|
|
BuilderProperty.TYPE_TEXT_UNDERLINED = 'TextUnderlined';
|
|
|
|
/**Boolean property type*/
|
|
BuilderProperty.TYPE_BOOLEAN = 'Boolean';
|
|
|
|
/**Line width property type*/
|
|
BuilderProperty.TYPE_LINE_WIDTH = 'LineWidth';
|
|
|
|
/**Line width property style*/
|
|
BuilderProperty.TYPE_LINE_STYLE = 'LineStyle';
|
|
|
|
/**Image Fill type*/
|
|
BuilderProperty.TYPE_IMAGE_FILL = 'ImageFill';
|
|
|
|
/**File Upload type*/
|
|
BuilderProperty.TYPE_IMAGE_UPLOAD = "ImageUpload";
|
|
|
|
/**Connector's end property type*/
|
|
BuilderProperty.TYPE_CONNECTOR_END = 'ConnectorEnd';
|
|
|
|
/** CCForm Propertys **/
|
|
BuilderProperty.TYPE_SINGLE_TEXT_ReadOnly = "SingleTextReadOnly";
|
|
BuilderProperty.TYPE_GROUP_LABEL = 'GroupLabel';
|
|
BuilderProperty.CCFormEnum = "Combobox";
|
|
BuilderProperty.CCFormUpload = "UploadFile";
|
|
BuilderProperty.TYPE_TEXT_FONTWEIGHT = 'FontWeight';
|
|
BuilderProperty.TYPE_TEXT_FONTWEIGHTS = [
|
|
{ Text: 'normal', Value: 'normal' },
|
|
{ Text: 'bold', Value: 'bold' },
|
|
{ Text: 'bolder', Value: 'bolder' },
|
|
{ Text: 'lighter', Value: 'lighter' }
|
|
];
|
|
BuilderProperty.CCFormLink = 'linkButton';
|
|
/**URL attached to a figure*/
|
|
BuilderProperty.TYPE_URL = 'URL';
|
|
|
|
|
|
|
|
//BuilderProperty.IMAGE_FILL = [{Text: 'No Scaling', Value: CanvasImage.FIXED_NONE},{Text: 'Fit to Area', Value: CanvasImage.FIXED_BOTH},{Text: 'Fit to Width',Value: CanvasImage.FIXED_WIDTH},{Text: 'Fit to Height',Value: CanvasImage.FIXED_HEIGHT},{Text: ' Auto Fit',Value: CanvasImage.FIXED_AUTO}]
|
|
|
|
/**Line widths*/
|
|
BuilderProperty.LINE_WIDTHS = [
|
|
{ Text: '0.5px', Value: '0.5' }, { Text: '1px', Value: '1' }, { Text: '2px', Value: '2' }, { Text: '3px', Value: '3' },
|
|
{ Text: '4px', Value: '4' }, { Text: '5px', Value: '5' }, { Text: '6px', Value: '6' },
|
|
{ Text: '7px', Value: '7' }, { Text: '8px', Value: '8' }, { Text: '9px', Value: '9' },
|
|
{ Text: '10px', Value: '10'}];
|
|
|
|
|
|
/**Line styles*/
|
|
BuilderProperty.LINE_STYLES = [
|
|
{ Text: 'Continous', Value: 'continuous' },
|
|
{ Text: 'Dotted', Value: 'dotted' },
|
|
{ Text: 'Dashed', Value: 'dashed' }
|
|
];
|
|
|
|
/**Font sizes*/
|
|
BuilderProperty.FONT_SIZES = [];
|
|
for (var i = 0; i < 73; i++) {
|
|
BuilderProperty.FONT_SIZES.push({ Text: i + 'px', Value: i });
|
|
}
|
|
|
|
/**Connector ends*/
|
|
BuilderProperty.CONNECTOR_ENDS = [{ Text: 'Normal', Value: 'Normal' }, { Text: 'Arrow', Value: 'Arrow' },
|
|
{ Text: 'Empty Triangle', Value: 'Empty' }, { Text: 'Filled Triangle', Value: 'Filled'}];
|
|
|
|
/**Display separator*/
|
|
BuilderProperty.SEPARATOR = 'SEPARATOR';
|
|
|
|
/**Css class for button checking control*/
|
|
BuilderProperty.BUTTON_CHECKER_CLASS = 'button-checker';
|
|
|
|
/**Name of attribute to define is property checked or not*/
|
|
BuilderProperty.BUTTON_CHECKED_ATTRIBUTE = 'button-checked';
|
|
|
|
/**Label for text underlined property*/
|
|
BuilderProperty.TEXT_UNDERLINED_LABEL = 'U';
|
|
|
|
|
|
/**Creates a {BuilderProperty} out of JSON parsed object
|
|
*@param {JSONObject} o - the JSON parsed object
|
|
*@return {BuilderProperty} a newly constructed Point
|
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
|
**/
|
|
BuilderProperty.load = function (o) {
|
|
var prop = new BuilderProperty();
|
|
prop.name = o.name;
|
|
prop.property = o.property;
|
|
prop.type = o.type;
|
|
prop.PropertyValue = o.PropertyValue;
|
|
return prop;
|
|
}
|
|
|
|
|
|
/**Creates an array of BuilderProperties from an array of {JSONObject}s
|
|
*@param {Array} v - the array of JSONObjects
|
|
*@return an {Array} of {BuilderProperty}-ies
|
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
|
**/
|
|
BuilderProperty.loadArray = function (v) {
|
|
var newProps = [];
|
|
for (var i = 0; i < v.length; i++) {
|
|
newProps.push(BuilderProperty.load(v[i]));
|
|
}
|
|
return newProps;
|
|
}
|
|
|
|
BuilderProperty.prototype = {
|
|
|
|
constructor: BuilderProperty,
|
|
|
|
toString: function () {
|
|
return 'Propery type: ' + this.type + ' name: ' + this.name + ' property: ' + this.property;
|
|
},
|
|
|
|
equals: function (anotherBuilderProperty) {
|
|
return this.type == anotherBuilderProperty.type
|
|
&& this.name == anotherBuilderProperty.name
|
|
&& this.property == anotherBuilderProperty.property;
|
|
},
|
|
|
|
/**
|
|
*Generates a HTML fragment to allow to edit its property.
|
|
*For example if current property is a color then this method will
|
|
*inject a color picker in the specified DOMObject
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
*/
|
|
injectInputArea: function (DOMObject, figureId) {
|
|
if (this.name == BuilderProperty.SEPARATOR) {
|
|
DOMObject.appendChild(document.createElement("hr"));
|
|
return;
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_COLOR) {
|
|
this.generateColorCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT) {
|
|
this.generateTextCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_SINGLE_TEXT) {
|
|
this.generateSingleTextCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_SINGLE_TEXT_ReadOnly) {
|
|
this.generateSingleTextReadOnlyCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT_FONT_SIZE) {
|
|
this.generateArrayCode(DOMObject, figureId, BuilderProperty.FONT_SIZES);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT_FONT_FAMILY) {
|
|
this.generateArrayCode(DOMObject, figureId, Text.FONTS);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT_FONT_ALIGNMENT) {
|
|
this.generateArrayCode(DOMObject, figureId, Text.ALIGNMENTS);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT_UNDERLINED) {
|
|
this.generateButtonCheckerCode(DOMObject, figureId, BuilderProperty.TEXT_UNDERLINED_LABEL);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_TEXT_FONTWEIGHT) {
|
|
this.generateArrayCode(DOMObject, figureId, BuilderProperty.TYPE_TEXT_FONTWEIGHTS);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_CONNECTOR_END) {
|
|
this.generateArrayCode(DOMObject, figureId, BuilderProperty.CONNECTOR_ENDS);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_LINE_WIDTH) {
|
|
this.generateArrayCode(DOMObject, figureId, BuilderProperty.LINE_WIDTHS);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_LINE_STYLE) {
|
|
this.generateArrayCode(DOMObject, figureId, BuilderProperty.LINE_STYLES);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_URL) {
|
|
this.generateURLCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.TYPE_GROUP_LABEL) {
|
|
this.generateGroupLabelCode(DOMObject, figureId);
|
|
return;
|
|
}
|
|
else if (this.type == BuilderProperty.CCFormEnum) {
|
|
var items = CCForm_Control_Enum[this.property];
|
|
this.generateArrayCode(DOMObject, figureId, items);
|
|
}
|
|
else if (this.type == BuilderProperty.CCFormUpload) {
|
|
this.generateUploadCode(DOMObject, figureId);
|
|
}
|
|
else if (this.type == BuilderProperty.CCFormLink) {
|
|
this.generateCCFormLinkCode(DOMObject, figureId);
|
|
}
|
|
|
|
//ccbpm 控件下面增加虚线
|
|
this.generateControlUnderLine(DOMObject);
|
|
},
|
|
|
|
/**
|
|
*Creates a boolean editor; usually a chechbox
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
**/
|
|
generateBooleanCode: function (DOMObject, figureId) {
|
|
var d = new Date();
|
|
var uniqueId = d.getTime();
|
|
var value = this.getValue(figureId);
|
|
var div = document.createElement("div");
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var check = document.createElement("input");
|
|
check.type = "checkbox"
|
|
check.className = "text"; //required for onkeydown
|
|
check.checked = value;
|
|
div.children[0].appendChild(check);
|
|
check.onclick = function (figureId, property) {
|
|
return function () {
|
|
updateShape(figureId, property, this.checked)
|
|
}
|
|
} (figureId, this.property);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
generateControlUnderLine: function (DOMObject) {
|
|
var uLine = document.createElement("hr");
|
|
uLine.className = "editLine";
|
|
DOMObject.appendChild(uLine);
|
|
},
|
|
|
|
/**Generate the code to edit the text.
|
|
*The text got updated when you leave the input area
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} shapeId - the id of the {Figure} or {Connector} we are using
|
|
**/
|
|
generateTextCode: function (DOMObject, shapeId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(shapeId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "textLine";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var text = document.createElement("textarea");
|
|
text.className = "text"; //required for onkeydown
|
|
text.value = value;
|
|
text.spellcheck = false;
|
|
text.className = "textarea";
|
|
div.appendChild(document.createElement("br"));
|
|
div.appendChild(text);
|
|
|
|
// used to change Text property
|
|
text.onchange = function (shapeId, property, scorpe) {
|
|
return function () {
|
|
// update shape but without adding {Command} to the {History}
|
|
scorpe.PropertyValue = this.value;
|
|
updateShape(shapeId, property, this.value);
|
|
};
|
|
} (shapeId, this.property, this);
|
|
|
|
text.onmouseout = text.onchange;
|
|
text.onkeyup = text.onchange;
|
|
DOMObject.appendChild(div);
|
|
},
|
|
|
|
|
|
/**Generate the code to edit the text.
|
|
*The text got updated when you leave the input area
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
**/
|
|
generateSingleTextCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
// var icon = new Image();
|
|
// icon.className = 'prop-icon';
|
|
// icon.src = Builder.IMAGE_TEXT_ICON_PATH;
|
|
// labelDiv.appendChild(icon);
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var text = document.createElement("input");
|
|
text.type = "text";
|
|
text.className = "text"; //required for onkeydown
|
|
text.value = value;
|
|
div.appendChild(text);
|
|
|
|
text.onchange = function (figureId, property, scop) {
|
|
return function () {
|
|
scop.PropertyValue = this.value;
|
|
updateShape(figureId, property, this.value);
|
|
}
|
|
} (figureId, this.property, this);
|
|
|
|
text.onmouseout = text.onchange;
|
|
text.onkeyup = text.onchange;
|
|
DOMObject.appendChild(div);
|
|
},
|
|
generateSingleTextReadOnlyCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var text = document.createElement("input");
|
|
text.type = "text";
|
|
text.className = "textReadOnly"; //required for onkeydown
|
|
text.value = value;
|
|
text.setAttribute("readOnly", true);
|
|
div.appendChild(text);
|
|
|
|
text.onchange = function (figureId, property, scop) {
|
|
return function () {
|
|
scop.PropertyValue = this.value;
|
|
updateShape(figureId, property, this.value);
|
|
}
|
|
} (figureId, this.property, this);
|
|
|
|
text.onmouseout = text.onchange;
|
|
text.onkeyup = text.onchange;
|
|
DOMObject.appendChild(div);
|
|
},
|
|
|
|
/**Generate the code to edit the URL.
|
|
*The URL got updated when you leave the input area
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
**/
|
|
generateURLCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
var icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_URL_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var text = document.createElement("input");
|
|
text.type = "text";
|
|
text.className = "text"; //required for onkeydown
|
|
text.value = value;
|
|
div.appendChild(text);
|
|
|
|
text.onchange = function (figureId, property) {
|
|
return function () {
|
|
Log.info("Builder.generateURLCode() value: " + this.value);
|
|
updateShape(figureId, property, this.value);
|
|
}
|
|
} (figureId, this.property);
|
|
|
|
|
|
text.onmouseout = text.onchange;
|
|
text.onkeyup = text.onchange;
|
|
DOMObject.appendChild(div);
|
|
},
|
|
generateGroupLabelCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "GroupLabel";
|
|
labelDiv.textContent = this.name;
|
|
div.appendChild(labelDiv);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
/**Used to generate a upload file
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
*/
|
|
generateUploadCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var upload = document.createElement("input");
|
|
upload.type = "button";
|
|
upload.className = BuilderProperty.BUTTON_CHECKER_CLASS;
|
|
upload.value = "选择文件";
|
|
div.appendChild(upload);
|
|
|
|
upload.onclick = function (figureId, property) {
|
|
return function () {
|
|
showInsertImageDialog();
|
|
// property value stores in custom attribute
|
|
var currentValue = this.getAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE);
|
|
// new value is inverse of the current one
|
|
var newValue = currentValue == "true" ? false : true;
|
|
// update control first
|
|
this.setAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE, newValue);
|
|
Log.info("Builder.generateButtonCheckerCode() value: " + newValue);
|
|
updateShape(figureId, property, newValue);
|
|
};
|
|
} (figureId, this.property);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
/**Used to generate a linkbutton for open window
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
*/
|
|
generateCCFormLinkCode: function (DOMObject, figureId) {
|
|
var uniqueId = new Date().getTime();
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var href = document.createElement("a");
|
|
|
|
href.href = "javascript:CCForm_ShowDialog('" + this.PropertyValue + "','" + this.name + "');";
|
|
div.appendChild(href);
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
href.appendChild(labelDiv);
|
|
|
|
var icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = "Img/iconLink.png";
|
|
labelDiv.appendChild(icon);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
/**Used to generate a drop down menu
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
*@param {Array} v - a vector or hashes ex: [{Text:'Normal', Value:'Normal'},{Text:'Arrow', Value:'Arrow'}]
|
|
*/
|
|
generateArrayCode: function (DOMObject, figureId, v) {
|
|
// Log.info("Font size length: " + v.length);
|
|
var uniqueId = new Date().getTime();
|
|
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
// get last name of property to define it's icon
|
|
var propNames = this.property.split('.');
|
|
var propLastName = propNames.pop();
|
|
|
|
var icon;
|
|
switch (propLastName) {
|
|
case "lineWidth":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_LINEWIDTH_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
case "startStyle":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_STARTSTYLE_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
case "endStyle":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_ENDSTYLE_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
case "lineStyle":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_LINESTYLE_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
}
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var select = document.createElement("select");
|
|
select.style.cssText = "float: right;";
|
|
select.id = this.property; // for DOM manipulation
|
|
div.appendChild(select);
|
|
|
|
for (var i = 0; i < v.length; i++) {
|
|
var option = document.createElement("option");
|
|
option.value = v[i].Value;
|
|
// Log.info("\t Text : " + v[i].Text + " Value : " + v[i].Value);
|
|
option.text = v[i].Text; //see: http://www.w3schools.com/jsref/coll_select_options.asp
|
|
select.options.add(option); //push does not exist in the options array
|
|
if (option.value == value) {
|
|
option.selected = true;
|
|
}
|
|
}
|
|
|
|
select.onchange = function (figureId, property, scorpe) {
|
|
return function () {
|
|
var selecedValue = this.options[this.selectedIndex].value;
|
|
scorpe.PropertyValue = selecedValue;
|
|
updateShape(figureId, property, selecedValue);
|
|
};
|
|
} (figureId, this.property, this);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
|
|
|
|
/**
|
|
*Used to generate a color picker
|
|
*
|
|
*@param{HTMLElement} DOMObject - the div of the properties panel
|
|
*@param{Number} figureId - the id of the figure we are using
|
|
*/
|
|
generateColorCode: function (DOMObject, figureId) {
|
|
var value = this.getValue(figureId);
|
|
|
|
var uniqueId = new Date().getTime();
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
|
|
// get last name of property to define it's icon
|
|
var propNames = this.property.split('.');
|
|
var propLastName = propNames.pop();
|
|
|
|
var icon;
|
|
switch (propLastName) {
|
|
case "fillStyle":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_FILL_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
case "strokeStyle":
|
|
icon = new Image();
|
|
icon.className = 'prop-icon';
|
|
icon.src = Builder.IMAGE_STROKE_ICON_PATH;
|
|
labelDiv.appendChild(icon);
|
|
break;
|
|
}
|
|
|
|
div.appendChild(labelDiv);
|
|
|
|
var colorSelectorDiv = document.createElement("div");
|
|
colorSelectorDiv.id = 'colorSelector' + uniqueId;
|
|
colorSelectorDiv.className = 'color-selector';
|
|
|
|
var colorInput = document.createElement("input");
|
|
colorInput.type = "text";
|
|
colorInput.id = 'colorpickerHolder' + uniqueId;
|
|
colorInput.value = value;
|
|
colorSelectorDiv.appendChild(colorInput);
|
|
|
|
div.appendChild(colorSelectorDiv);
|
|
|
|
DOMObject.appendChild(div);
|
|
|
|
var colorPicker = document.getElementById('colorpickerHolder' + uniqueId);
|
|
|
|
//let plugin do the job
|
|
$(colorPicker).colorPicker();
|
|
|
|
//on change update the figure
|
|
//var propExposedToAnonymous = this.property;
|
|
colorPicker.onchange = function (figureId, property, scorpe) {
|
|
return function () {
|
|
var selecedValue = colorPicker.value.toUpperCase();
|
|
scorpe.PropertyValue = selecedValue;
|
|
updateShape(figureId, property, selecedValue);
|
|
};
|
|
} (figureId, this.property, this);
|
|
},
|
|
|
|
/**Generate the code to edit the boolean property with button.
|
|
*Result control has 2 modes: checked/unchecked.
|
|
*The property got updated on click
|
|
*
|
|
*@param {HTMLElement} DOMObject - the div of the properties panel
|
|
*@param {Number} figureId - the id of the figure we are using
|
|
**/
|
|
generateButtonCheckerCode: function (DOMObject, figureId, buttonLabel) {
|
|
var value = this.getValue(figureId);
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "line";
|
|
|
|
var labelDiv = document.createElement("div");
|
|
labelDiv.className = "label";
|
|
labelDiv.textContent = this.name;
|
|
div.appendChild(labelDiv);
|
|
|
|
var buttonChecker = document.createElement("input");
|
|
buttonChecker.type = "button";
|
|
buttonChecker.id = this.property; // for DOM manipulation
|
|
buttonChecker.className = BuilderProperty.BUTTON_CHECKER_CLASS;
|
|
buttonChecker.value = buttonLabel; // for now we have button checking only for underlined text property
|
|
// property value stores in custom attribute
|
|
buttonChecker.setAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE, value);
|
|
div.appendChild(buttonChecker);
|
|
|
|
buttonChecker.onclick = function (figureId, property) {
|
|
return function () {
|
|
// property value stores in custom attribute
|
|
var currentValue = this.getAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE);
|
|
// new value is inverse of the current one
|
|
var newValue = currentValue == "true" ? false : true;
|
|
// update control first
|
|
this.setAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE, newValue);
|
|
Log.info("Builder.generateButtonCheckerCode() value: " + newValue);
|
|
updateShape(figureId, property, newValue);
|
|
};
|
|
} (figureId, this.property);
|
|
|
|
DOMObject.appendChild(div);
|
|
},
|
|
|
|
|
|
/**We use this to return a value of the property for a figure,
|
|
*Similar to Javas Class.forname...sort of anyway
|
|
*We need this because passing direct references to simple data types (including strings)
|
|
*only passes the value, not a reference to that value (call by value not by reference)
|
|
*
|
|
*@param{Number} figureId - the id of the shape {Figure} or {Connector} we are using, could also be the canvas (figureId = 'a')
|
|
*/
|
|
getValue: function (figureId) {
|
|
//Is it a Figure?
|
|
var obj = STACK.figureGetById(figureId);
|
|
|
|
//Is it a Connector ?
|
|
if (obj == null) { //ok so it's not a Figure...so it should be a Connector
|
|
obj = CONNECTOR_MANAGER.connectorGetById(figureId);
|
|
}
|
|
|
|
//Is it the Canvas?
|
|
if (obj == null) {
|
|
if (figureId == "canvas") {
|
|
obj = canvas;
|
|
}
|
|
}
|
|
|
|
//Is it a Container?
|
|
if (obj == null) {
|
|
obj = STACK.containerGetById(figureId);
|
|
}
|
|
Log.debug("Unsplit property: " + this.property);
|
|
|
|
var propertyAccessors = this.property.split(".");
|
|
// Log.info("BuilderProperty::getValue() : propertyAccessors : " + propertyAccessors );
|
|
for (var i = 0; i < propertyAccessors.length - 1; i++) {
|
|
// Log.info("\tBuilderProperty::getValue() : i = " + i + ' name= ' + propertyAccessors[i]);
|
|
obj = obj[propertyAccessors[i]];
|
|
}
|
|
|
|
//Log.info("Object type: " + obj.oType);
|
|
|
|
|
|
var propName = propertyAccessors[propertyAccessors.length - 1];
|
|
//Log.info("Property name: " + propName);
|
|
|
|
var propGet = "get" + Util.capitaliseFirstLetter(propName);
|
|
|
|
//null is allowed, undefined is not
|
|
if (propGet in obj) { //@see https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special_Operators/in_Operator
|
|
var returnValue = obj[propGet]();
|
|
if (typeof (returnValue) == "undefined") return this.PropertyValue;
|
|
return obj[propGet]();
|
|
}
|
|
else {
|
|
//Access the object property's
|
|
var returnValue = obj[propertyAccessors[propertyAccessors.length - 1]];
|
|
if (typeof (returnValue) == "undefined") return this.PropertyValue;
|
|
return obj[propertyAccessors[propertyAccessors.length - 1]];
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* This instance is responsible for creating and updating Text Editor Popup.
|
|
* Text Editor Popup is made out of:
|
|
* - editor - a <div> (inside #container <div>) that contains the text and reflects the
|
|
* - tools - a <div> (inside #container <div>) that will contain all the buttons and options to format text
|
|
*
|
|
* @constructor
|
|
* @this {TextEditorPopup}
|
|
* @param {HTMLElement} editor - the DOM object (a <div> inside editor page) to create Text Editor Popup
|
|
* @param {HTMLElement} tools - the DOM object (a <div> inside editor page) to create Text Editor Tools
|
|
* @param shape - the {Figure} or {Connector} - parent of Text primitive
|
|
* @param {Number} textPrimitiveId - the id value of Text primitive child of shape for which the properties will be displayed
|
|
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
*/
|
|
function TextEditorPopup(editor, tools, shape, textPrimitiveId) {
|
|
this.editor = editor;
|
|
this.tools = tools;
|
|
this.shape = shape;
|
|
this.textPrimitiveId = textPrimitiveId;
|
|
|
|
/*We need to construct the full path to the properties of Text*/
|
|
// beginning of property string of BuilderProperty for primitive
|
|
var propertyPrefix;
|
|
|
|
if (this.shapeIsAConnector()) {
|
|
// in case of connector with primitive = middleText
|
|
propertyPrefix = "middleText.";
|
|
} else {
|
|
// in case of figure with primitive.id = textPrimitiveId
|
|
propertyPrefix = "primitives." + this.textPrimitiveId + ".";
|
|
}
|
|
|
|
// value of BuiderProperty::property
|
|
this.stringPropertyName = propertyPrefix + TextEditorPopup.STRING_PROPERTY_ENDING;
|
|
this.sizePropertyName = propertyPrefix + TextEditorPopup.SIZE_PROPERTY_ENDING;
|
|
this.fontPropertyName = propertyPrefix + TextEditorPopup.FONT_PROPERTY_ENDING;
|
|
this.alignPropertyName = propertyPrefix + TextEditorPopup.ALIGN_PROPERTY_ENDING;
|
|
this.colorPropertyName = propertyPrefix + TextEditorPopup.COLOR_PROPERTY_ENDING;
|
|
this.underlinedPropertyName = propertyPrefix + TextEditorPopup.UNDERLINED_PROPERTY_ENDING;
|
|
}
|
|
|
|
/**A set of predefined properties fragments*/
|
|
TextEditorPopup.STRING_PROPERTY_ENDING = 'str';
|
|
TextEditorPopup.SIZE_PROPERTY_ENDING = 'size';
|
|
TextEditorPopup.FONT_PROPERTY_ENDING = 'font';
|
|
TextEditorPopup.ALIGN_PROPERTY_ENDING = 'align';
|
|
TextEditorPopup.COLOR_PROPERTY_ENDING = 'style.fillStyle';
|
|
TextEditorPopup.UNDERLINED_PROPERTY_ENDING = 'underlined';
|
|
|
|
TextEditorPopup.prototype = {
|
|
|
|
constructor: TextEditorPopup,
|
|
|
|
/**
|
|
*Returns true if target shape of TextEditorPopup is a Connector
|
|
*@return {Boolean} - true shape property is a connector
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
shapeIsAConnector: function () {
|
|
return this.shape.oType === "Connector";
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
*Creates DOM structure and bind events
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
init: function () {
|
|
var textarea;
|
|
|
|
// <div> for text tools contains font size, font family, alignment and color
|
|
for (var i = 0; i < this.shape.properties.length; i++) {
|
|
var curProperty = this.shape.properties[i].property; //get property in long format ex: primitives.1.style.fillStyle
|
|
if (curProperty != null) {
|
|
var curValue = this.shape.properties[i].getValue(this.shape.id);
|
|
switch (curProperty) {
|
|
case this.stringPropertyName:
|
|
this.shape.properties[i].injectInputArea(this.editor, this.shape.id);
|
|
textarea = this.editor.getElementsByTagName('textarea')[0];
|
|
|
|
// remove all <br> tags from text-editor as they were added by injectInputArea method
|
|
removeNodeList(this.editor.getElementsByTagName('br')); //defined in util.js
|
|
|
|
// set Text editor properties on initialization
|
|
this.setProperty(curProperty, curValue);
|
|
|
|
break;
|
|
|
|
case this.sizePropertyName:
|
|
case this.fontPropertyName:
|
|
case this.alignPropertyName:
|
|
case this.colorPropertyName:
|
|
case this.underlinedPropertyName:
|
|
this.shape.properties[i].injectInputArea(this.tools, this.shape.id);
|
|
|
|
// set Text editor properties on initialization
|
|
this.setProperty(curProperty, curValue);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
this.editor.className = 'active';
|
|
this.tools.className = 'active';
|
|
|
|
this.placeAndAutoSize();
|
|
|
|
// select all text inside textarea (like in Visio)
|
|
setSelectionRange(textarea, 0, textarea.value.length);
|
|
},
|
|
|
|
|
|
/**
|
|
* Changing property inside Text Editor
|
|
* provides WYSIWYG functionality
|
|
* @param {String} property - property name that is being edited (in dotted notation)
|
|
* @param {Object} value - the value to set the property to
|
|
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
setProperty: function (property, value) {
|
|
var textarea = this.editor.getElementsByTagName('textarea')[0];
|
|
switch (property) {
|
|
|
|
case this.sizePropertyName:
|
|
// set new property value to editor's textarea
|
|
textarea.style.fontSize = value + 'px';
|
|
|
|
// set new property value to editor's tool
|
|
document.getElementById(property).value = value;
|
|
break;
|
|
|
|
case this.fontPropertyName:
|
|
// set new property value to editor's textarea
|
|
textarea.style.fontFamily = value;
|
|
|
|
// set new property value to editor's tool
|
|
document.getElementById(property).value = value.toLowerCase();
|
|
break;
|
|
|
|
case this.alignPropertyName:
|
|
// set new property value to editor's textarea
|
|
textarea.style.textAlign = value;
|
|
|
|
// IE doesn't apply text-align property correctly to all lines of the textarea on a fly
|
|
// that is why we just copy it's text and paste it back to refresh text rendering
|
|
if (Browser.msie) {
|
|
textarea.value = textarea.value;
|
|
}
|
|
|
|
// set new property value to editor's tool
|
|
document.getElementById(property).value = value;
|
|
break;
|
|
|
|
case this.underlinedPropertyName:
|
|
// set new property value to editor's textarea
|
|
textarea.style.textDecoration = value == true ? 'underline' : '';
|
|
|
|
// set new property value to editor's tool
|
|
document.getElementById(property).setAttribute(BuilderProperty.BUTTON_CHECKED_ATTRIBUTE, value);
|
|
break;
|
|
|
|
case this.colorPropertyName:
|
|
// set new property value to editor's textarea
|
|
textarea.style['color'] = value;
|
|
|
|
// set new property value to editor's tool (colorPicker)
|
|
var colorPicker = this.tools.getElementsByClassName('color_picker')[0];
|
|
colorPicker.style['background-color'] = value; //change the color to the proper one
|
|
colorPicker.previousSibling.value = value; //set the value to the "hidden" text field
|
|
break;
|
|
}
|
|
|
|
this.placeAndAutoSize();
|
|
},
|
|
|
|
|
|
/**
|
|
*Places and sets size to the property panel
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
placeAndAutoSize: function () {
|
|
var textarea = this.editor.getElementsByTagName('textarea')[0];
|
|
|
|
// set edit dialog position to top left (first) bound point of Text primitive
|
|
var textBounds;
|
|
|
|
if (this.shapeIsAConnector()) {
|
|
// in case of connector primitive is a middleText property
|
|
textBounds = this.shape.middleText.getBounds();
|
|
} else {
|
|
// in case of connector primitive is a primitives[this.textPrimitiveId] property
|
|
textBounds = this.shape.primitives[this.textPrimitiveId].getBounds();
|
|
}
|
|
|
|
// change coordinates of editing Text primitive to include padding and border of Text Editor
|
|
var leftCoord = textBounds[0] - defaultEditorBorderWidth - defaultEditorPadding;
|
|
var topCoord = textBounds[1] - defaultEditorBorderWidth - defaultEditorPadding;
|
|
|
|
var textareaWidth = textBounds[2] - textBounds[0];
|
|
var textareaHeight = textBounds[3] - textBounds[1];
|
|
|
|
// Firefox includes border & padding as part of width and height,
|
|
// so width and height should additionally include border and padding twice
|
|
// (similar to "feather" option in Fireworks)
|
|
if (Browser.mozilla) {
|
|
textareaHeight += (defaultEditorPadding) * 2;
|
|
topCoord -= (defaultEditorPadding);
|
|
textareaWidth += (defaultEditorPadding) * 2;
|
|
leftCoord -= (defaultEditorPadding);
|
|
}
|
|
|
|
// some of IE magic:
|
|
// enough to add half of font-size to textarea's width to prevent auto-breaking to next line
|
|
// which is wrong in our case
|
|
// (similar to "feather" option in Fireworks)
|
|
if (Browser.msie) {
|
|
var fontSize = parseInt(textarea.style['font-size'], 10);
|
|
textareaWidth += fontSize / 2;
|
|
leftCoord -= fontSize / 4;
|
|
}
|
|
|
|
this.editor.style.left = leftCoord + "px";
|
|
this.editor.style.top = topCoord + "px";
|
|
|
|
|
|
// visibility: 'hidden' allows us to get proper size but
|
|
// without getting strange visual artefacts (tiggered by settings positions & other)
|
|
this.tools.style.visibility = 'hidden';
|
|
|
|
// We set it to the left upper corner to get it's objective size
|
|
this.tools.style.left = '0px';
|
|
this.tools.style.top = '0px';
|
|
|
|
// Get toolbox height and width. Notice that clientHeight differs from offsetHeight.
|
|
//@see https://developer.mozilla.org/en/docs/DOM/element.offsetHeight
|
|
//@see http://stackoverflow.com/questions/4106538/difference-between-offsetheight-and-clientheight
|
|
var toolboxHeight = this.tools.offsetHeight;
|
|
var toolboxWidth = this.tools.offsetWidth;
|
|
|
|
// define toolbox left position
|
|
var toolboxLeft = leftCoord;
|
|
|
|
// get width of work area (#container <div> from editor)
|
|
var workAreaWidth = getWorkAreaContainer().offsetWidth;
|
|
|
|
// If it's not enough place for toolbox at the page right side
|
|
if (toolboxLeft + toolboxWidth >= workAreaWidth - scrollBarWidth) {
|
|
// then shift toolbox to left before it can be placed
|
|
toolboxLeft = workAreaWidth - toolboxWidth - scrollBarWidth;
|
|
}
|
|
|
|
// define toolbox top position
|
|
var toolboxTop = topCoord - toolboxHeight;
|
|
// If it's not enough place for toolbox at the page top
|
|
if (toolboxTop <= 0) {
|
|
// then place toolbox below textarea
|
|
toolboxTop = topCoord + toolboxHeight + defaultEditorBorderWidth + defaultEditorPadding;
|
|
}
|
|
|
|
this.tools.style.left = toolboxLeft + "px";
|
|
this.tools.style.top = toolboxTop + "px";
|
|
|
|
// return normal visibility to toolbox
|
|
this.tools.style.visibility = 'visible';
|
|
|
|
textarea.style.width = textareaWidth + "px";
|
|
textarea.style.height = textareaHeight + "px";
|
|
},
|
|
|
|
/**
|
|
*Removes DOM structure of editor and it's tools
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
destroy: function () {
|
|
this.editor.className = '';
|
|
this.editor.style.cssText = '';
|
|
this.editor.innerHTML = '';
|
|
|
|
this.tools.className = '';
|
|
this.tools.style.cssText = '';
|
|
this.tools.innerHTML = '';
|
|
},
|
|
|
|
|
|
/**
|
|
*Returns true if mouse clicked inside TextEditorPopup
|
|
*@param {Event} e - mouseDown event object
|
|
*@return {boolean} - true if clicked inside
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
mouseClickedInside: function (e) {
|
|
var target = e.target;
|
|
|
|
// check if user fired mouse down on the part of editor, it's tools or active color picker
|
|
// actually active color picker in that moment can be only for Text edit
|
|
var inside = target.id === this.editor.id
|
|
|| target.parentNode.id === this.editor.id
|
|
|| target.parentNode.parentNode.id === this.editor.id
|
|
|
|
|| target.id === this.tools.id
|
|
|| target.parentNode.id === this.tools.id
|
|
|| target.parentNode.parentNode.id === this.tools.id
|
|
|
|
|| target.className === 'color_picker'
|
|
|
|
|| target.id === 'color_selector'
|
|
|| target.parentNode.id === 'color_selector'
|
|
|| target.parentNode.parentNode.id === 'color_selector';
|
|
|
|
return inside;
|
|
},
|
|
|
|
/**
|
|
* Checks if TextEditorPopup refers to target shape and id of Text primitive
|
|
* @param shape - target figure or connector to check
|
|
* @param {Number} textPrimitiveId - the id value of a target Text primitive
|
|
*
|
|
*@return {Boolean} - true if refers to target objects
|
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
refersTo: function (shape, textPrimitiveId) {
|
|
var result = this.shape.equals(shape);
|
|
|
|
// in case of connector textPrimitiveId will be underfined
|
|
if (textPrimitiveId != null) {
|
|
result &= this.textPrimitiveId === textPrimitiveId;
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Manually triggers onblur event of textarea inside TextEditor.
|
|
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
|
**/
|
|
blurTextArea: function () {
|
|
var textarea = this.editor.getElementsByTagName('textarea')[0];
|
|
textarea.onblur();
|
|
}
|
|
|
|
}; |