/* <copyright> This file contains proprietary software owned by Motorola Mobility, Inc.<br/> No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. </copyright> */ var Montage = require("montage/core/core").Montage, Component = require("montage/ui/component").Component; var ElementController = require("js/controllers/elements/element-controller").ElementController, Command = require("js/controllers/undo-controller").Command, NJUtils = require("js/lib/NJUtils").NJUtils; exports.ElementMediator = Montage.create(Component, { addDelegate: { enumerable: false, value: null }, deleteDelegate: { enumerable: false, value: null }, addElements: { value: function(elements, rules, notify) { if(Array.isArray(elements)) { elements.forEach(function(element) { ElementController.addElement(element, rules); if(element.elementModel && element.elementModel.props3D) { element.elementModel.props3D.init(element, false); } }); } else { ElementController.addElement(elements, rules); if(elements.elementModel && elements.elementModel.props3D) { elements.elementModel.props3D.init(elements, false); } } if(this.addDelegate && typeof (this.addDelegate['onAddElements']) === "function") { this.addDelegate['onAddElements'].call(this.addDelegate, elements); } var undoLabel = "add element"; document.application.undoManager.add(undoLabel, this.removeElements, this, elements, notify); this.application.ninja.documentController.activeDocument.model.needsSave = true; if(notify || notify === undefined) { NJevent("elementAdded", elements); } } }, removeElements: { value: function(elements, notify /* Used for the add undo */) { if(this.deleteDelegate && (typeof this.deleteDelegate.handleDelete === 'function')) { return this.deleteDelegate.handleDelete(); // this.handleDelete.call(deleteDelegate); } if(Array.isArray(elements)) { elements = Array.prototype.slice.call(elements, 0); elements.forEach(function(element) { ElementController.removeElement(element); }); } else { ElementController.removeElement(elements); } var undoLabel = "add element"; document.application.undoManager.add(undoLabel, this.addElements, this, elements, null, notify); this.application.ninja.documentController.activeDocument.model.needsSave = true; NJevent("elementsRemoved", elements); } }, replaceElement: { value: function(newChild, oldChild, notify) { this.application.ninja.currentDocument.documentRoot.replaceChild(newChild, oldChild); var undoLabel = "replace element"; document.application.undoManager.add(undoLabel, this.replaceElement, this, oldChild, newChild); this.application.ninja.documentController.activeDocument.model.needsSave = true; if(notify || notify === undefined) { NJevent("elementReplaced", {type : "replaceElement", data: {"newChild": newChild, "oldChild": oldChild}}); } } }, getProperty: { value: function(el, prop, valueMutator) { if(!el.elementModel) { console.log("Element has no Model -> One should have been created"); NJUtils.makeElementModel(el, "Div", "block"); } if(valueMutator && typeof valueMutator === "function") { return valueMutator(el.elementModel.controller["getProperty"](el, prop)); } else { return el.elementModel.controller["getProperty"](el, prop, valueMutator); } } }, getShapeProperty: { value: function(el, prop) { if(!el.elementModel) { console.log("Element has no Model -> One should have been created"); NJUtils.makeElementModel(el, "Canvas", "block", true); } return el.elementModel.controller["getShapeProperty"](el, prop); } }, setShapeProperty: { value: function(el, prop, value) { if(!el.elementModel) { console.log("Element has no Model -> One should have been created"); NJUtils.makeElementModel(el, "Canvas", "block", true); } return el.elementModel.controller["setShapeProperty"](el, prop, value); } }, /** Set a property change command for an element or array of elements @param element: Element @param attribute: Attribute to set @param value: Value to be set. @param currentValue: current value @param source: String for the source object making the call */ setAttribute: { value: function(element, attribute, value, currentValue, source) { element.elementModel.controller["setAttribute"](element, attribute, value); // Add to the undo var undoLabel = "Attribute change"; document.application.undoManager.add(undoLabel, this.setAttribute, this, element, attribute, currentValue, value, source); NJevent("attributeChange"); } }, /** Set a property change command for an element or array of elements @param els: Array of elements. Can contain 1 or more elements @param p: Property to set @param value: Value to be set. This is an array of values corresponding to the array of elements @param eventType: Change/Changing. Will be passed to the dispatched event @param source: String for the source object making the call @param currentValue *OPTIONAL*: current value array. If not found the current value is calculated @param stageRedraw: *OPTIONAL*: True. If set to false the stage will not redraw the selection/outline */ setProperty: { value: function(els, p, value, eventType, source, currentValue) { if(eventType === "Changing") { this._setProperty(els, p, value, eventType, source); } else { // Calculate currentValue if not found for each element if(!currentValue) { var that = this; currentValue = els.map(function(item) { return that.getProperty((item), p); }); } var command = Montage.create(Command, { _els: { value: els }, _p: { value: p }, _value: { value: value }, _previous: { value: currentValue }, _eventType: { value: eventType}, _source: { value: "undo-redo"}, description: { value: "Set Property"}, receiver: { value: this}, execute: { value: function(senderObject) { if(senderObject) this._source = senderObject; this.receiver._setProperty(this._els, this._p, this._value, this._eventType, this._source); this._source = "undo-redo"; return ""; } }, unexecute: { value: function() { this.receiver._setProperty(this._els, this._p, this._previous, this._eventType, this._source); return ""; } } }); NJevent("sendToUndo", command); command.execute(source); } } }, _setProperty: { value: function(els, p, value, eventType, source) { var el; for(var i=0, item; item = els[i]; i++) { item.elementModel.controller["setProperty"](item, p, value[i], eventType, source); } NJevent("element" + eventType, {type : "setProperty", source: source, data: {"els": els, "prop": p, "value": value}, redraw: null}); } }, /** Sets a property object for an element or array of elements. The same properties object gets applied to all the elements @param elements: Array of elements objects: element, properties and previousProperties @param eventType: Change/Changing. Will be passed to the dispatched event @param source: String for the source object making the call */ setProperties: { value: function(elements, eventType, source) { elements.forEach(function(elementObject) { elementObject.element.elementModel.controller["setProperties"](elementObject.element, elementObject.properties); }); if(eventType !== "Changing") { var undoLabel = "Properties change"; elements.forEach(function(elementObject) { var swap = elementObject.properties; elementObject.properties = elementObject.previousProperties; elementObject.previousProperties = swap; }); document.application.undoManager.add(undoLabel, this.setProperties, this, elements, eventType, source); } // Map the elements for the event data // TODO: Clean this up var els = elements.map(function(element) { return element.element; }); // Dispatch the element change/changing event. NJevent("element" + eventType, {type : "setProperties", source: source, data: {"els": els, "prop": elements[0].properties, "value": elements}, redraw: null}); } }, set3DProperties: { value: function(elements, eventType, source) { var update3DModel = false; if(eventType === "Change") { update3DModel = true; } for(var i=0, item; item = elements[i]; i++) { item.element.elementModel.controller["set3DProperties"](item.element, item.properties, update3DModel); } /* if(eventType === "Change") { var undoLabel = "3D Properties change"; elements.forEach(function(elementObject) { var swap = elementObject.properties; elementObject.properties = elementObject.previousProperties; elementObject.previousProperties = swap; }); document.application.undoManager.add(undoLabel, this.set3DProperties, this, elements, eventType, source); } */ var els = elements.map(function(element) { return element.element; }); NJevent("element" + eventType, {type : "set3DProperties", source: source, data: {"els": els, "prop": "matrix", "value": elements}, redraw: null}); } }, //-------------------------------------------------------------------------------------------------------- // Routines to get/set color getColor: { value: function(el, isFill, borderSide) { if(!el.elementModel) { NJUtils.makeModelFromElement(el); } return el.elementModel.controller["getColor"](el, isFill, borderSide); } }, /** Set a property change command for an element or array of elements @param els: Array of elements. Can contain 1 or more elements @param value: Value to be set. This is the color @param isFill: Specifies if setting fill (background) or stroke (border) @param eventType: Change/Changing. Will be passed to the dispatched event @param source: String for the source object making the call @param currentValue *OPTIONAL*: current value array. If not found the current value is calculated @param stageRedraw: *OPTIONAL*: True. If set to false the stage will not redraw the selection/outline */ setColor: { value: function(els, value, isFill, eventType, source, currentValue) { if(eventType === "Changing") { this._setColor(els, value, isFill, eventType, source); } else { // Calculate currentValue if not found for each element if(!currentValue) { var that = this; currentValue = els.map(function(item) { return that.getColor(item, isFill); }); } var command = Montage.create(Command, { _els: { value: els }, _value: { value: value }, _isFill: { value: isFill }, _previous: { value: currentValue }, _eventType: { value: eventType}, _source: { value: "undo-redo"}, description: { value: "Set Color"}, receiver: { value: this}, execute: { value: function(senderObject) { if(senderObject) this._source = senderObject; this.receiver._setColor(this._els, this._value, this._isFill, this._eventType, this._source); this._source = "undo-redo"; return ""; } }, unexecute: { value: function() { this.receiver._setColor(this._els, this._previous, this._isFill, this._eventType, this._source); return ""; } } }); NJevent("sendToUndo", command); command.execute(source); } } }, _setColor: { value: function(els, value, isFill, eventType, source) { for(var i=0, item; item = els[i]; i++) { item.elementModel.controller["setColor"](item, value, isFill); } NJevent("element" + eventType, {type : "setColor", source: source, data: {"els": els, "prop": "color", "value": value, "isFill": isFill}, redraw: null}); } }, getStroke: { value: function(el) { if(!el.elementModel) { NJUtils.makeElementModel(el, "Div", "block"); } return el.elementModel.controller["getStroke"](el); } }, /** Set a property change command for an element or array of elements @param els: Array of elements. Can contain 1 or more elements @param value: Value to be set. This is the stroke info @param eventType: Change/Changing. Will be passed to the dispatched event @param source: String for the source object making the call @param currentValue *OPTIONAL*: current value array. If not found the current value is calculated @param stageRedraw: *OPTIONAL*: True. If set to false the stage will not redraw the selection/outline */ setStroke: { value: function(els, value, eventType, source, currentValue) { if(eventType === "Changing") { this._setStroke(els, value, isFill, eventType, source); } else { // Calculate currentValue if not found for each element if(!currentValue) { var that = this; currentValue = els.map(function(item) { return that.getStroke(item); }); } var command = Montage.create(Command, { _els: { value: els }, _value: { value: value }, _previous: { value: currentValue }, _eventType: { value: eventType}, _source: { value: "undo-redo"}, description: { value: "Set Color"}, receiver: { value: this}, execute: { value: function(senderObject) { if(senderObject) this._source = senderObject; this.receiver._setStroke(this._els, this._value, this._eventType, this._source); this._source = "undo-redo"; return ""; } }, unexecute: { value: function() { this.receiver._setStroke(this._els, this._previous, this._eventType, this._source); return ""; } } }); NJevent("sendToUndo", command); command.execute(source); } } }, _setStroke: { value: function(els, value, eventType, source) { for(var i=0, item; item = els[i]; i++) { item.elementModel.controller["setStroke"](item, value); } NJevent("element" + eventType, {type : "setStroke", source: source, data: {"els": els, "prop": "stroke", "value": value}, redraw: null}); } }, //-------------------------------------------------------------------------------------------------------- // Routines to get/set 3D properties get3DProperty: { value: function(el, prop) { if(!el.elementModel) { NJUtils.makeModelFromElement(el); } return el.elementModel.controller["get3DProperty"](el, prop); } }, get3DProperties: { value: function(el) { if(!el.elementModel) { NJUtils.makeModelFromElement(el); } // var mat = this.getMatrix(el); // var dist = this.getPerspectiveDist(el); var mat = el.elementModel.controller["getMatrix"](el); var dist = el.elementModel.controller["getPerspectiveDist"](el); return {mat:mat, dist:dist}; } }, getMatrix: { value: function(el) { if(!el.elementModel) { NJUtils.makeModelFromElement(el); } return el.elementModel.controller["getMatrix"](el); } }, getPerspectiveDist: { value: function(el) { if(!el.elementModel) { NJUtils.makeModelFromElement(el); } return el.elementModel.controller["getPerspectiveDist"](el); } }, getPerspectiveMode: { value: function(el) { return this.getProperty(el, "-webkit-transform-style"); } }, setMatrix: { value: function(el, mat, isChanging, source) { var dist = el.elementModel.controller["getPerspectiveDist"](el); el.elementModel.controller["set3DProperties"](el, {mat:mat, dist:dist}, !isChanging); if(isChanging) { NJevent("elementChanging", {type : "setMatrix", source: source, data: {"els": [el], "prop": "matrix", "value": mat}, redraw: null}); } else { NJevent("elementChange", {type : "setMatrix", source: source, data: {"els": [el], "prop": "matrix", "value": mat}, redraw: null}); } } }, has3D: { value: function(el) { var str = this.getProperty(el, "-webkit-transform"); return str && str.length; } }, reArrangeDOM:{ value: function(layersDraggedArray, layerDroppedAfter) { var documentRoot,length; documentRoot = this.application.ninja.currentDocument.documentRoot; length = layersDraggedArray.length; for(var i=0; documentRoot.children[i]; i++) { if(documentRoot.children[i] === layerDroppedAfter.layerData.elementsList[0]) { if(length >0){ documentRoot.children[i].parentNode.insertBefore(layersDraggedArray[length-1].layerData.elementsList[0], documentRoot.children[i]); } /* Will require for Multiple Drag n Drop */ //length = length-1; //index = i; //if(length>0) { //while(layersDraggedArray[length]) { //documentRoot.children[index].parentNode.insertBefore(layersDraggedArray[length-1].layerData.elementsList[0],documentRoot.children[k].nextSibling); //length--; //index++; //} //} } } } } });