From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/controllers/color-controller.js | 442 ++++++++ js/controllers/elements/block-controller.js | 35 + js/controllers/elements/canvas-controller.js | 37 + js/controllers/elements/component-controller.js | 12 + js/controllers/elements/controller-factory.js | 49 + js/controllers/elements/element-controller.js | 263 +++++ js/controllers/elements/image-controller.js | 41 + js/controllers/elements/shapes-controller.js | 238 +++++ js/controllers/elements/stage-controller.js | 125 +++ js/controllers/elements/video-controller.js | 56 + js/controllers/local-storage-controller.js | 50 + js/controllers/selection-controller.js | 299 ++++++ js/controllers/styles-controller.js | 1302 +++++++++++++++++++++++ js/controllers/undo-controller.js | 206 ++++ 14 files changed, 3155 insertions(+) create mode 100644 js/controllers/color-controller.js create mode 100644 js/controllers/elements/block-controller.js create mode 100644 js/controllers/elements/canvas-controller.js create mode 100644 js/controllers/elements/component-controller.js create mode 100644 js/controllers/elements/controller-factory.js create mode 100644 js/controllers/elements/element-controller.js create mode 100644 js/controllers/elements/image-controller.js create mode 100644 js/controllers/elements/shapes-controller.js create mode 100644 js/controllers/elements/stage-controller.js create mode 100644 js/controllers/elements/video-controller.js create mode 100644 js/controllers/local-storage-controller.js create mode 100644 js/controllers/selection-controller.js create mode 100644 js/controllers/styles-controller.js create mode 100644 js/controllers/undo-controller.js (limited to 'js/controllers') diff --git a/js/controllers/color-controller.js b/js/controllers/color-controller.js new file mode 100644 index 00000000..87180873 --- /dev/null +++ b/js/controllers/color-controller.js @@ -0,0 +1,442 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +//////////////////////////////////////////////////////////////////////// +// +var Montage = require("montage/core/core").Montage, + Component = require("montage/ui/component").Component, + ColorModel = require("js/models/color-model").ColorModel, + ColorToolbar = require("js/panels/Color/colortoolbar.reel").ColorToolbar, + ColorPanelBase = require("js/panels/Color/colorpanelbase.reel").ColorPanelBase, + ElementsMediator = require("js/mediators/element-mediator").ElementMediator, + ColorPopupManager = require("js/panels/Color/colorpopup-manager").ColorPopupManager, + ColorButtonManager = require("js/panels/Color/colorbutton-manager").ColorButtonManager; +//////////////////////////////////////////////////////////////////////// +//Exporting as ColorController +exports.ColorController = Montage.create(Component, { + //////////////////////////////////////////////////////////////////// + // + hasTemplate: { + enumerable: true, + value: false + }, + //////////////////////////////////////////////////////////////////// + // + deserializedFromTemplate: { + enumerable: true, + value: function () { + //Setting up colorManager in other classes + this.colorPanelBase.colorManager = this.colorModel; + this.colorPopupManager.colorManager = this.colorModel; + this.colorButtonManager.colorManager = this.colorModel; + //Listening for color changes + this.colorModel.addEventListener('change', this, false); + } + }, + //////////////////////////////////////////////////////////////////// + // + colorModel: { + enumerable: true, + value: ColorModel + }, + //////////////////////////////////////////////////////////////////// + // + colorPanelBase: { + enumerable: true, + value: ColorPanelBase + }, + //////////////////////////////////////////////////////////////////// + // + colorPopupManager: { + enumerable: true, + value: ColorPopupManager + }, + //////////////////////////////////////////////////////////////////// + // + colorButtonManager: { + enumerable: true, + value: ColorPopupManager + }, + //////////////////////////////////////////////////////////////////// + // + colorView: { + enumerable: true, + value: null + }, + //////////////////////////////////////////////////////////////////// + // + colorToolbar: { + enumerable: true, + value: null + }, + //////////////////////////////////////////////////////////////////// + // + _popupTab: { + enumerable: false, + value: 'wheel' + }, + //////////////////////////////////////////////////////////////////// + // + popupTab: { + enumerable: true, + get: function() { + return this._popupTab; + }, + set: function(value) { + this._popupTab = value.toLowerCase(); + } + }, + //////////////////////////////////////////////////////////////////// + // + addButton: { + enumerable: true, + value: function (type, button) { + if (this.colorView) { + this.colorView.addButton(type, button); + return true; + } else if (this.ColorPanelBase) { + this.ColorPanelBase.addButton(type, button); + return true; + } else { + return false; + } + } + }, + //////////////////////////////////////////////////////////////////// + // + removeButton: { + enumerable: true, + value: function (type, button) { + if (this.colorView) { + this.colorView.removeButton(type, button); + return true; + } else if (this.ColorPanelBase) { + this.ColorPanelBase.removeButton(type, button); + return true; + } else { + return false; + } + } + }, + //////////////////////////////////////////////////////////////////// + // + _fill: { + enumerable: false, + value: null + }, + //////////////////////////////////////////////////////////////////// + // + fill: { + enumerable: true, + get: function() { + return this._fill; + }, + set: function(value) { + this._fill = value; + } + }, + //////////////////////////////////////////////////////////////////// + // + _stroke: { + enumerable: false, + value: null + }, + //////////////////////////////////////////////////////////////////// + // + stroke: { + enumerable: true, + get: function() { + return this._stroke; + }, + set: function(value) { + this._stroke = value; + } + }, + //////////////////////////////////////////////////////////////////// + // + getBackground: { + enumerable: true, + value: function (element) { + //TODO: Return object with all background properties + console.log(ElementsMediator.getProperty(element, 'background-color')); + console.log(ElementsMediator.getProperty(element, 'background-image')); + } + }, + //////////////////////////////////////////////////////////////////// + // + getBorder: { + enumerable: true, + value: function (element) { + + } + }, + //////////////////////////////////////////////////////////////////// + // + setBackground: { + enumerable: true, + value: function (type, background, selection) { + //TODO: Remove hack + var elements, i, hack = [], hackNone = []; + //The selection is optional, if none, it asks for the currently selected elements + if (selection) { + elements = selection; + } else { + elements = this.application.ninja.selectedElements; + } + // + for (i=0; elements[i]; i++) { + hack[i] = background; + hackNone[i] = 'none'; + } + // + if (elements && elements.length > 0) { + switch (type) { + case 'image': + ElementsMediator.setProperty(elements, "background-image", hack, {"background-image": background}, "Change", "color-controller"); + ElementsMediator.setProperty(elements, "background-color", hackNone, {"background-color": 'none'}, "Change", "color-controller"); + break; + case 'color': + //TODO: Add logic to handle setting color when image (like gradients) is applied + //TODO: Handle applying to multiple items, currently, we need to create a dummy array of the same value + ElementsMediator.setProperty(elements, "background-image", hackNone, {"background-image": 'none'}, "Change", "color-controller"); + ElementsMediator.setProperty(elements, "background-color", hack, {"background-color": background}, "Change", "color-controller"); + break; + case 'background': + break; + } + // + //console.log(this.getColorObjFromCss('#333')); + } + } + }, + //////////////////////////////////////////////////////////////////// + // + setBorder: { + enumerable: true, + value: function (type, border, selection) { + // + var elements, i, hack = [], hackNone = []; + //The selection is optional, if none, it asks for the currently selected elements + if (selection) { + elements = selection; + } else { + elements = this.application.ninja.selectedElements; + } + // + for (i=0; elements[i]; i++) { + hack[i] = border; + hackNone[i] = 'none'; + } + // + if (elements && elements.length > 0) { + switch (type) { + case 'image': + //TODO: Figure out why color must be removed, might be related to the CSS + ElementsMediator.setProperty(elements, "border-color", hackNone, {"border-color": 'none'}, "Change", "color-controller"); + ElementsMediator.setProperty(elements, "border-image", hack, {"border-image": border}, "Change", "color-controller"); + break; + case 'color': + ElementsMediator.setProperty(elements, "border-image", hackNone, {"border-image": 'none'}, "Change", "color-controller"); + ElementsMediator.setProperty(elements, "border-color", hack, {"border-color": border}, "Change", "color-controller"); + break; + case 'border': + break; + } + } + } + }, + //////////////////////////////////////////////////////////////////// + // + handleChange: { + enumerable: true, + value: function (e) { + + // + var actionEvent, color, input = e._event.input, panelMode, mode = e._event.mode; + if (this.colorView) { + panelMode = this.colorView.panelMode; + } + // + if (mode === 'nocolor') { + color = {value: null, css: 'none'}; + } else if (panelMode === 'rgb' && e._event.rgba && mode !== 'gradient') { + color = e._event.rgba; + } else if (panelMode === 'hsl' && e._event.hsla && mode !== 'gradient') { + color = e._event.hsla; + } else if (mode !== 'gradient'){ + color = {value: e._event.hex, css: '#'+e._event.hex}; + } else if (mode === 'gradient'){ + color = e._event.value.value; + } + //////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////// + // + if (input === 'fill') { + // + this.fill = color; + // + if(e._event.wasSetByCode) return; + // + if (mode === 'nocolor') { + //TODO: Add a check instead of setting properties + this.setBackground('image', color.css, false); + this.setBackground('color', color.css, false); + this.setBackground('background', color.css, false); + } else if (mode === 'gradient') { + this.setBackground('image', color.css, false); + } else { + this.setBackground('color', color.css, false); + } + } else if (input === 'stroke') { + // + this.stroke = color; + // + if(e._event.wasSetByCode) return; + // + if (mode === 'nocolor') { + //TODO: Add a check instead of setting properties + this.setBorder('image', color.css, false); + this.setBorder('color', color.css, false); + this.setBorder('border', color.css, false); + } else if (mode === 'gradient') { + this.setBorder('image', color.css, false); + } else { + this.setBorder('color', color.css, false); + } + } + //////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////// + } + }, + //////////////////////////////////////////////////////////////////// + //Converts CSS to a color object to be used by the color model + getColorObjFromCss: { + enumerable: true, + value: function (css) { + // + var color, arr, i, j, temp, c, gradient; + //console.log(css.indexOf('-webkit'), css); + if (css && css.indexOf('-webkit') >= 0) { + // + gradient = {mode: null, stops: null}; + //Checking for gradient type + if (css.indexOf('-webkit-radial-gradient') >= 0) { + //Radial gradient + gradient.stops = []; + gradient.mode = 'radial'; + gradient.css = css; + // + arr = css.split('%,'); + // + for (j=1; arr[j]; j++) { + //TODO: Add HSL support + if (arr[j].indexOf('rgb') >= 0 && arr[j].indexOf('rgba') < 0) { + temp = arr[j].split('rgb'); + temp = temp[1].replace(/\(/i, ""); + temp = temp.split(')'); + c = this.parseCssToColor('rgb('+temp[0]+')'); + gradient.stops.push({css: c.css, value: c.value, mode: c.mode, position: parseInt(temp[1].replace(/\%/i, ""))}); + } else if (css.indexOf('rgba') >= 0) { + + temp = arr[j].split('rgba'); + temp = temp[1].replace(/\(/i, ""); + temp = temp.split(')'); + c = this.parseCssToColor('rgba('+temp[0]+')'); + gradient.stops.push({css: c.css, value: c.value, mode: c.mode, position: parseInt(temp[1].replace(/\%/i, ""))}); + } + } + } else if (css.indexOf('-webkit-gradient') >= 0) { + //Linear gradient + gradient.stops = []; + gradient.mode = 'linear'; + gradient.css = css; + // + arr = css.split('from('); + arr = arr[1].split('),'); + // + for (i=0; arr[i]; i++) { + arr[i] = arr[i].replace(/ color-stop\(/i, ""); + // + if (arr[i].indexOf('to(') >= 0) { + arr[i] = arr[i].replace(/ to\(/i, ""); + arr[i] = arr[i].replace(/\)\)/i, ""); + } + // + if (i === 0) { + arr[i] = {css: arr[i], percent: 0}; + } else if (i === arr.length-1) { + arr[i] = {css: arr[i], percent: 100}; + } else { + // + if (arr[i].indexOf('rgb') >= 0 && arr[i].indexOf('rgba') < 0) { + temp = arr[i].split(', rgb'); + arr[i] = {css: 'rgb'+temp[1], percent: Math.round(parseFloat(temp[0])*100)}; + } else if (arr[i].indexOf('rgba') >= 0) { + temp = arr[i].split(', rgba'); + arr[i] = {css: 'rgba'+temp[1], percent: Math.round(parseFloat(temp[0])*100)}; + } + } + // + c = this.parseCssToColor(arr[i].css); + gradient.stops.push({css: c.css, value: c.value, mode: c.mode, position: arr[i].percent}); + } + } + //Creating gradient object + color = {mode: 'gradient', value: {stops: gradient.stops, mode: gradient.mode, css: css}}; + } else if (css){ + //Simple solid color + color = this.parseCssToColor(css); + } + //Returning color object (or null if none) + return color; + } + }, + //////////////////////////////////////////////////////////////////// + //Parses simple solid CSS string into color object + parseCssToColor: { + enumerable: true, + value: function (css) { + var color, r, p; + //Parsing string and converting into color object + if (css.indexOf('#') >= 0) { + color = {mode: 'hex', css: css, value: css.split('#')[1]}; + } else if (css.indexOf('rgb') >= 0 && css.indexOf('rgba') < 0) { + r = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/; + p = css.match(r); + color = {mode: 'rgb', css: css, value: {css: css, r: parseInt(p[1]), g: parseInt(p[2]), b: parseInt(p[3]), a: 1}}; + } else if (css.indexOf('rgba') >= 0) { + r = /^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)\)$/; + p = css.match(r); + color = {mode: 'rgb', css: css, value: {css: css, r: parseInt(p[1]), g: parseInt(p[2]), b: parseInt(p[3]), a: parseFloat(p[4])}}; + } else if (css.indexOf('hsl') >= 0 && css.indexOf('hsla') < 0) { + r = /^hsl\((\d+),\s*(\d+),\s*(\d+)\)$/; + p = css.match(r); + color = {mode: 'hsl', css: css, value: {css: css, h: parseInt(p[1]), s: parseInt(p[2]), l: parseInt(p[3]), a: 1}}; + } if (css.indexOf('hsla') >= 0) { + r = /^hsla\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)\)$/; + p = css.match(r); + color = {mode: 'hsl', css: css, value: {css: css, h: parseInt(p[1]), s: parseInt(p[2]), l: parseInt(p[3]), a: parseFloat(p[4])}}; + } + //Must be a valid CSS or null will be returned + return color; + } + }, + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// + //TODO: Remove, add via toolbar repetition + createToolbar: { + enumerable: true, + value: function () { + this.colorToolbar = ColorToolbar.create(); + this.colorToolbar.element = document.getElementById("colortoolbar"); + this.colorToolbar.needsDraw = true; + } + } + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// +}); \ No newline at end of file diff --git a/js/controllers/elements/block-controller.js b/js/controllers/elements/block-controller.js new file mode 100644 index 00000000..395a1a4d --- /dev/null +++ b/js/controllers/elements/block-controller.js @@ -0,0 +1,35 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.BlockController = Montage.create(ElementController, { + + /** + If the base method needs to be sub-classed + setProperty: { + value: function(el, p, value) { + switch(p) { + case "width": + console.log("width"); + break; + default: + ElementController.setProperty(el, p, value); + } + } + }, + */ + + /* + setProperties: { + value: function(el, newProps, currentProps, index, eventType, notify, redraw) { + ElementController.setProperties(el, newProps, currentProps, index, eventType, notify, redraw); + } + }, + */ + +}); \ No newline at end of file diff --git a/js/controllers/elements/canvas-controller.js b/js/controllers/elements/canvas-controller.js new file mode 100644 index 00000000..7af7e824 --- /dev/null +++ b/js/controllers/elements/canvas-controller.js @@ -0,0 +1,37 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.CanvasController = Montage.create(ElementController, { + + getProperty: { + value: function(el, prop) { + switch(prop) { + case "height": + case "width": + return el.getAttribute(prop); + break; + default: + return ElementController.getProperty(el, prop); + } + } + }, + + setProperty: { + value: function(el, p, value) { + switch(p) { + case "height": + case "width": + el.setAttribute(p, parseInt(value)); + break; + default: + ElementController.setProperty(el, p, value); + } + } + } +}); \ No newline at end of file diff --git a/js/controllers/elements/component-controller.js b/js/controllers/elements/component-controller.js new file mode 100644 index 00000000..458e6b46 --- /dev/null +++ b/js/controllers/elements/component-controller.js @@ -0,0 +1,12 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.ComponentController = Montage.create(ElementController, { + +}); diff --git a/js/controllers/elements/controller-factory.js b/js/controllers/elements/controller-factory.js new file mode 100644 index 00000000..a772eb16 --- /dev/null +++ b/js/controllers/elements/controller-factory.js @@ -0,0 +1,49 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage; + +var BlockController = require("js/controllers/elements/block-controller").BlockController, + StageController = require("js/controllers/elements/stage-controller").StageController, + ShapesController = require("js/controllers/elements/shapes-controller").ShapesController, + ImageController = require("js/controllers/elements/image-controller").ImageController, + VideoController = require("js/controllers/elements/video-controller").VideoController, + ComponentController = require("js/controllers/elements/component-controller").ComponentController, + CanvasController = require("js/controllers/elements/canvas-controller").CanvasController; + +exports.ControllerFactory = Montage.create(Montage, { + + getController: { + value: function(value) { + if(!value) return; + + try { + value = value.toLowerCase(); + + if(value.indexOf("block") !== -1) { + return BlockController; + } else if(value.indexOf("stage") !== -1) { + return StageController; + } else if(value.indexOf("shape") !== -1) { + return ShapesController; + } else if(value.indexOf("canvas") !== -1) { + return CanvasController; + } else if(value.indexOf("component") !== -1) { + return ComponentController; + } else if(value.indexOf("media") !== -1) { + console.log("create media controller"); + } else if(value.indexOf("image") !== -1) { + return ImageController; + } else if(value.indexOf("video") !== -1) { + return VideoController; + } + } catch (err) { + console.log("Could not create Controller Factory " + err); + } + } + } + +}); \ No newline at end of file diff --git a/js/controllers/elements/element-controller.js b/js/controllers/elements/element-controller.js new file mode 100644 index 00000000..f254220c --- /dev/null +++ b/js/controllers/elements/element-controller.js @@ -0,0 +1,263 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + NJComponent = require("js/lib/nj-base").NJComponent; + +var ElementController = exports.ElementController = Montage.create(NJComponent, { + + addElement: { + value: function(el, styles) { + this.application.ninja.currentDocument.documentRoot.appendChild(el); + this.application.ninja.stylesController.setElementStyles(el, styles); + } + }, + + removeElement: { + value: function(el) { + el.parentNode.removeChild(el); + } + }, + + getProperty: { + value: function(el, prop, fallbackOnComputed, isStageElement) { + return this.application.ninja.stylesController.getElementStyle(el, prop, fallbackOnComputed, isStageElement); + } + }, + + setProperty: { + value: function(el, p, value) { + this.application.ninja.stylesController.setElementStyle(el, p, value); + } + }, + + setProperties: { + value: function(el, props, index) { + for(var p in props) { + this.application.ninja.stylesController.setElementStyle(el, p, props[p][index]); + } + } + }, + + setAttribute: { + value: function(el, att, value) { + if(att === "id") { + if(value === "") { + el.setAttribute(att, value); + return; + } + + // Then check if this is a valid id by the following spec: http://www.w3.org/TR/REC-html40/types.html#h-6.2 + var regexID = /^([a-zA-Z])+([a-zA-Z0-9_\.\:\-])+/; + if(!regexID.test(value)) { + alert("Invalid ID"); + return; + } else if (this.application.ninja.currentDocument._document.getElementById(value) !== null) { + alert("The following ID: " + value + " is already in Use"); + } + + } + + el.setAttribute(att, value); + } + }, + + //-------------------------------------------------------------------------------------------------------- + // Routines to get/set color properties + getColor: { + value: function(el, isFill) { + if(isFill) + { + return this.application.ninja.stylesController.getElementStyle(el, "background-color"); + } + else + { + // TODO - Need to figure out which border side user wants + return this.application.ninja.stylesController.getElementStyle(el, "border-color"); + } + } + }, + + setColor: { + value: function(el, color, isFill) { + if(isFill) + { + this.application.ninja.stylesController.setElementStyle(el, "background-color", color.color.css); + } + else + { + this.application.ninja.stylesController.setElementStyle(el, "border-color", color.color.css); + } + } + }, + + getStroke: { + value: function(el) { + // TODO - Need to figure out which border side user wants + return this.application.ninja.stylesController.getElementStyle(el, "border"); + } + }, + + setStroke: { + value: function(el, stroke) { + var border = stroke.borderWidth + stroke.borderUnits + " " + stroke.borderStyle + " " + stroke.color.color.css; + this.application.ninja.stylesController.setElementStyle(el, "border", border); + } + }, + + //-------------------------------------------------------------------------------------------------------- + // Routines to get/set 3D properties + get3DProperty: { + value: function(el, prop) { + if(el.elementModel && el.elementModel.props3D) + { + return el.elementModel.props3D[prop]; + } + } + }, + + getMatrix: { + value: function(el) { + if(el.elementModel && el.elementModel.props3D && el.elementModel.props3D.matrix3d) + { + return el.elementModel.props3D.matrix3d.slice(0); + } + else + { + // TODO - for now, just return the identity matrix + return Matrix.I(4); +// var mat; +// +// if (elt) +// { +// var xformStr = ElementsMediator.getProperty(elt, "-webkit-transform"); +// if (xformStr) +// mat = this.transformStringToMat( xformStr ); +// if (!mat) +// mat = Matrix.I(4); +// +// if (elt.style && elt.style.zoom) +// { +// var zoom = Number(elt.style.zoom); +// if (zoom != 1) +// { +// var zoomMat = Matrix.create( [ +// [ zoom, 0, 0, 0], +// [ 0, zoom, 0, 0], +// [ 0, 0, zoom, 0], +// [ 0, 0, 0, 1] +// ] ); +// glmat4.multiply( zoomMat, mat, mat ); +// } +// } +// } +// +// elt.elementModel.props3D.matrix3d = mat; +// return mat; + } + } + }, + + getPerspectiveDist: { + value: function(el) { + if(el.elementModel && el.elementModel.props3D && el.elementModel.props3D.perspectiveDist) + { + return el.elementModel.props3D.perspectiveDist; + } + else + { + var dist = 1400; + + var str = this.getProperty(el, "-webkit-transform"); + if (str) + { + var index1 = str.indexOf( "perspective("); + if (index1 >= 0) + { + index1 += 12; // do not include 'perspective(' + var index2 = str.indexOf( ")", index1 ); + if (index2 >= 0) + { + var substr = str.substr( index1, (index2-index1)); + if (substr && (substr.length > 0)) + dist = MathUtils.styleToNumber( substr ); + } + } + } + + el.elementModel.props3D.perspectiveDist = dist; + return dist; + } + } + }, + + // TODO - perspective distance needs to be passed in as "dist" and matrix3d needs to be passed in as "mat" + set3DProperties: { + value: function(el, props, index, update3DModel) { + var dist = props[index]["dist"], + mat = props[index]["mat"]; + this.application.ninja.stylesController.setElementStyle(el, + "-webkit-transform", + "perspective(" + dist + ") " + + "matrix3d(" + MathUtils.scientificToDecimal(mat, 5) + ")"); + + el.elementModel.props3D.matrix3d = mat; + el.elementModel.props3D.perspectiveDist = dist; + +// if(update3DModel) + { + this._update3DProperties(el, mat, dist); + } + } + }, + + _update3DProperties: { + value: function(elt, mat, dist) { + var elt3DInfo = MathUtils.decomposeMatrix2(mat); + if(elt3DInfo) + { + elt.elementModel.props3D.xAngle = elt3DInfo.rotation[0] * MathUtils.RAD_TO_DEG; + elt.elementModel.props3D.yAngle = elt3DInfo.rotation[1] * MathUtils.RAD_TO_DEG; + elt.elementModel.props3D.zAngle = elt3DInfo.rotation[2] * MathUtils.RAD_TO_DEG; + + elt.elementModel.props3D.x3D = ~~(elt3DInfo.translation[0]); + elt.elementModel.props3D.y3D = ~~(elt3DInfo.translation[1]); + elt.elementModel.props3D.z3D = ~~(elt3DInfo.translation[2]); + } + } + }, + + transformStringToMat: { + value: function( str ) { + var rtnMat; + + var index1 = str.indexOf( "matrix3d("); + if (index1 >= 0) + { + index1 += 9; // do not include 'matrix3d(' + var index2 = str.indexOf( ")", index1 ); + if (index2 >= 0) + { + var substr = str.substr( index1, (index2-index1)); + if (substr && (substr.length > 0)) + { + var numArray = substr.split(','); + var nNums = numArray.length; + if (nNums == 16) + { + // gl-matrix wants row order + rtnMat = numArray; + for (var i=0; i<16; i++) + rtnMat[i] = Number( rtnMat[i] ); + } + } + } + } + + return rtnMat; + } + } +}); \ No newline at end of file diff --git a/js/controllers/elements/image-controller.js b/js/controllers/elements/image-controller.js new file mode 100644 index 00000000..5abce13e --- /dev/null +++ b/js/controllers/elements/image-controller.js @@ -0,0 +1,41 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.ImageController = Montage.create(ElementController, { + + getProperty: { + value: function(el, prop) { + switch(prop) { + case "src": + return el.getAttribute(prop); + break; + case "alt": + return el.getAttribute(prop); + break; + default: + return ElementController.getProperty(el, prop); + } + } + }, + + setProperty: { + value: function(el, p, value) { + switch(p) { + case "src": + el.setAttribute(p, value); + break; + case "alt": + el.setAttribute(p, value); + break; + default: + ElementController.setProperty(el, p, value); + } + } + } +}); \ No newline at end of file diff --git a/js/controllers/elements/shapes-controller.js b/js/controllers/elements/shapes-controller.js new file mode 100644 index 00000000..d34644a7 --- /dev/null +++ b/js/controllers/elements/shapes-controller.js @@ -0,0 +1,238 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + CanvasController = require("js/controllers/elements/canvas-controller").CanvasController; + +exports.ShapesController = Montage.create(CanvasController, { + + setProperty: { + value: function(el, p, value) { + var val = parseInt(value); + switch(p) { + case "strokeSize": + // TODO - For now, just handling px units. + this.setShapeProperty(el, "strokeSize", value); + el.elementModel.shapeModel.GLGeomObj.setStrokeWidth(val); + el.elementModel.shapeModel.GLGeomObj.buildBuffers(); + break; + case "innerRadius": + this.setShapeProperty(el, "innerRadius", value); + el.elementModel.shapeModel.GLGeomObj.setInnerRadius(val/100); + el.elementModel.shapeModel.GLGeomObj.buildBuffers(); + break; + case "width": + el.elementModel.shapeModel.GLGeomObj.setWidth(val); + CanvasController.setProperty(el, p, value); + el.elementModel.shapeModel.GLWorld.setViewportFromCanvas(el); + el.elementModel.shapeModel.GLGeomObj.buildBuffers(); + break; + case "height": + el.elementModel.shapeModel.GLGeomObj.setHeight(val); + CanvasController.setProperty(el, p, value); + el.elementModel.shapeModel.GLWorld.setViewportFromCanvas(el); + el.elementModel.shapeModel.GLGeomObj.buildBuffers(); + break; + default: + CanvasController.setProperty(el, p, value); + } + el.elementModel.shapeModel.GLWorld.render(); + } + }, + + getProperty: { + value: function(el, p) { + switch(p) { + case "strokeSize": + case "innerRadius": + return this.getShapeProperty(el, p); + default: + return CanvasController.getProperty(el, p); + } + } + }, + + getShapeProperty: { + value: function(el, prop) { + if(el.elementModel && el.elementModel.shapeModel) + { + return el.elementModel.shapeModel[prop]; + } + else + { + console.log("No shapeModel, one should have been created already"); + return null; + } + } + }, + + setShapeProperty: { + value: function(el, prop, value) { + if(el.elementModel && el.elementModel.shapeModel) + { + el.elementModel.shapeModel[prop] = value; + } + else + { + console.log("No shapeModel, one should have been created already"); + } + } + }, + + GetValueInPixels: { + value: function(value, units, h) + { + switch(units) + { + case "px": + { + return value; + } + case "pt": + { + return ~~(value*4/3); + } + case "%": + { + if(h) + { + return ~~(value/100*h); + } + else + { + console.warn("Can't use % for a line's stroke size, using 10 for the value."); + return 10; + } + } + } + } + }, + + CapWorldPercentFromValue: { + value: function(value, units, h) + { + return Math.min(this.GetWorldPercentFromValue(value, units, h), 2); + } + }, + + GetWorldPercentFromValue: { + value: function(value, units, h) + { + switch(units) + { + case "pt": + { + value = Math.round(value*4/3); + return 4*value/h; + } + case "px": + { + return 4*value/h; + } + case "%": + { + // Our calculations in GLWorld use 2 = 100%, so our calculations would usually be value/50, + // but in order to get values other than 0, 1, and 2, we need to multiply by 10, round that value, + // and then divide by 50*10 again. + // 100*10 = 1000/500 = 2 + // 20*10 = 200/500 = 0.4 + // 50*10 = 500/500 = 1 + return Math.round(value*10)/500; + } + default: + { + console.warn("Unhandled units " + units); + } + } + } + }, + + //-------------------------------------------------------------------------------------------------------- + // Routines to get/set color properties + getColor: { + value: function(el, isFill) { + if(isFill) + { + return this.getShapeProperty(el, "fill"); + } + else + { + return this.getShapeProperty(el, "stroke"); + } + } + }, + + setColor: { + value: function(el, color, isFill) { + // TODO - Format color for webGL before setting + color = color.webGlColor; + if(isFill) + { + el.elementModel.shapeModel.GLGeomObj.setFillColor(color); + this.setShapeProperty(el, "fill", color); + } + else + { + el.elementModel.shapeModel.GLGeomObj.setStrokeColor(color); + this.setShapeProperty(el, "stroke", color); + } + el.elementModel.shapeModel.GLWorld.render(); + } + }, + + getStroke: { + value: function(el) { + // TODO - Need to figure out which border side user wants + var size = this.getShapeProperty(el, "strokeSize"); + var color = this.getShapeProperty(el, "stroke"); + return {stroke:color, strokeSize:size}; + } + }, + + setStroke: { + value: function(el, stroke) { + el.elementModel.shapeModel.GLGeomObj.setStrokeColor(stroke.color.webGlColor); + var strokeWidth = this.GetValueInPixels(stroke.strokeSize, stroke.strokeUnits); + el.elementModel.shapeModel.GLGeomObj.setStrokeWidth(strokeWidth); + this.setShapeProperty(el, "stroke", stroke.color.webGlColor); + this.setShapeProperty(el, "strokeSize", stroke.strokeSize + " " + stroke.strokeUnits); + el.elementModel.shapeModel.GLGeomObj.buildBuffers(); + el.elementModel.shapeModel.GLWorld.render(); + } + }, + + DisplayMaterials: { + value: function (cb) + { + + var optionItem = document.createElement("option"); + optionItem.value = 0; + optionItem.innerText = "Default"; + cb.appendChild(optionItem); + + var materials = MaterialsLibrary.materials; + var len = materials.length; + + var i; + for (i = 0; i < len; i++) + { + var current = materials[i]; + optionItem = document.createElement("option"); + optionItem.value = i+1; + optionItem.innerText = current.getName(); + cb.appendChild(optionItem); + } + } + }, + + isElementAShape: { + value: function(el) + { + return (el.elementModel && el.elementModel.isShape); + } + } + +}); diff --git a/js/controllers/elements/stage-controller.js b/js/controllers/elements/stage-controller.js new file mode 100644 index 00000000..b8170826 --- /dev/null +++ b/js/controllers/elements/stage-controller.js @@ -0,0 +1,125 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.StageController = Montage.create(ElementController, { + + // TODO - This is a simple routine, may not always be correct + _isRotated: { + value: function(mat) { + + if(mat[1] !== 0) return true; + if(mat[2] !== 0) return true; + if(mat[3] !== 0) return true; + + if(mat[4] !== 0) return true; + + if(mat[6] !== 0) return true; + if(mat[7] !== 0) return true; + + if(mat[8] !== 0) return true; + if(mat[9] !== 0) return true; + + if(mat[11] !== 0) return true; + + return false; + } + }, + + // TODO - perspective distance needs to be passed in as "dist" and matrix3d needs to be passed in as "mat" + set3DProperties: { + value: function(el, props, index, update3DModel) { + var dist = props[index]["dist"], + mat = props[index]["mat"]; + this.application.ninja.stylesController.setElementStyle(el, + "-webkit-transform", + "perspective(" + dist + ") " + + "matrix3d(" + MathUtils.scientificToDecimal(mat, 5) + ")", + true); + + el.elementModel.props3D.matrix3d = mat; + el.elementModel.props3D.perspectiveDist = dist; + + // TODO - Move this to matrix class + if(this._isRotated(mat)) + { + this.application.ninja.currentDocument.stageBG.style.display = "none"; + } + else + { + this.application.ninja.stylesController.setElementStyle(this.application.ninja.currentDocument.stageBG, + "-webkit-transform", + "perspective(" + dist + ") " + + "matrix3d(" + MathUtils.scientificToDecimal(mat, 5) + ")", + true); + + this.application.ninja.currentDocument.stageBG.elementModel.props3D.matrix3d = mat; + this.application.ninja.currentDocument.stageBG.elementModel.props3D.perspectiveDist = dist; + this.application.ninja.currentDocument.stageBG.style.display = "block"; + } + + this.application.ninja.stage.updatedStage = true; + + if(update3DModel) + { + this._update3DProperties(el, mat, dist); + } + } + }, + + getProperty: { + value: function(el, p) { + switch(p) { + case "border": + return el.elementModel.stageView.style.getProperty(p); + case "height": + return el.elementModel.stageDimension.style.getProperty(p); + case "width": + return el.elementModel.stageDimension.style.getProperty(p); + default: + return ElementController.getProperty(el, p, false, true); + //console.log("Undefined Stage property ", p); + } + } + }, + + setProperty: { + value: function(el, p, value) { + switch(p) { + case "background": + el.elementModel.body.style.setProperty(p, value); + break; + case "overflow": + el.elementModel.viewPort.style.setProperty(p, value); + break; + case "width": + el.elementModel.stageDimension.style.setProperty(p, value); + break; + case "height": + el.elementModel.stageDimension.style.setProperty(p, value); + break; + default: + console.log("Undefined property ", p, "for the Stage Controller"); + } + } + }, + + setAttribute: { + value: function(el, att, value) { + if(att === "id") { + el.elementModel.id = value; + } + } + }, + + changeSelector: { + value: function(el, rule, selector) { + el.elementModel.transitionStopRule.selectorText = selector; + } + } +}); diff --git a/js/controllers/elements/video-controller.js b/js/controllers/elements/video-controller.js new file mode 100644 index 00000000..c36752f5 --- /dev/null +++ b/js/controllers/elements/video-controller.js @@ -0,0 +1,56 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.VideoController = Montage.create(ElementController, { + getProperty: { + value: function(el, prop) { + switch(prop) { + case "src": + case "poster": + case "autoplay": + case "controls": + case "loop": + case "muted": + return el.getAttribute(prop); + default: + return ElementController.getProperty(el, prop); + } + } + }, + + setProperty: { + value: function(el, p, value) { + switch(p) { + case "src": + el.setAttribute(p, value); + break; + case "poster": + el.setAttribute(p, value); + break; + case "autoplay": + value ? el.setAttribute(p, "autoplay") : el.removeAttribute(p); + break; + case "preload": + value ? el.setAttribute(p, "preload") : el.removeAttribute(p); + break; + case "controls": + value ? el.setAttribute(p, "controls") : el.removeAttribute(p); + break; + case "loop": + value ? el.setAttribute(p, "loop") : el.removeAttribute(p); + break; + case "muted": + value ? el.setAttribute(p, "muted") : el.removeAttribute(p); + break; + default: + ElementController.setProperty(el, p, value); + } + } + } +}); \ No newline at end of file diff --git a/js/controllers/local-storage-controller.js b/js/controllers/local-storage-controller.js new file mode 100644 index 00000000..6963b245 --- /dev/null +++ b/js/controllers/local-storage-controller.js @@ -0,0 +1,50 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + Component = require("montage/ui/component").Component; + +exports.LocalStorage = Montage.create( Montage, { + + getItem: { + value: function(item) { + var item; + + if (window.localStorage) { + item = window.localStorage.getItem(item); + if(item !== null) return JSON.parse(item) + return null; + } else { + alert("Local Storage is not supported on your browser"); + return null; + } + + /* + if (window.localStorage) { + this.getItem = function(item) { + return window.localStorage.getItem(item); + }(item); + } else { + alert("Local Storage is not supported on your browser"); + + } + */ + } + }, + + setItem: { + value: function(item, value) { + if (window.localStorage) { + window.localStorage.setItem(item, JSON.stringify(value)); + return true; + } else { + alert("Local Storage is not supported on your browser"); + return false; + } + } + } + +}); \ No newline at end of file diff --git a/js/controllers/selection-controller.js b/js/controllers/selection-controller.js new file mode 100644 index 00000000..833e6f04 --- /dev/null +++ b/js/controllers/selection-controller.js @@ -0,0 +1,299 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + + +var Montage = require("montage/core/core").Montage, + Component = require("montage/ui/component").Component; + +exports.SelectionController = Montage.create(Component, { + + _isDocument: { + value: true + }, + + isDocument: { + get: function() { + return this._isDocument; + } + }, + + deserializedFromTemplate: { + value: function() { + this.eventManager.addEventListener("openDocument", this, false); + this.eventManager.addEventListener("elementAdded", this, false); + this.eventManager.addEventListener("elementDeleted", this, false); + this.eventManager.addEventListener("selectAll", this, false); + this.eventManager.addEventListener("deleteSelection", this, false); +// defaultEventManager.addEventListener( "undo", this, false); +// defaultEventManager.addEventListener( "redo", this, false); + } + }, + + /** + * Get the current document selection array. If nothing is selected the currentSelectionArray should be null + */ + handleOpenDocument: { + value: function() { + // Handle initializing the selection array here. + } + }, + + initWithDocument: { + value: function(currentSelectionArray) { + this._selectedItems = []; + this._isDocument = true; + + if(currentSelectionArray) { + if(currentSelectionArray.length >= 1) { + this._selectedItems = currentSelectionArray; + this._isDocument = false; + } + } + + this.dispatchEvent(selectionEvent.event); + } + }, + + handleElementAdded: { + value: function(event) { + this.executeSelectElement(event.detail); + } + }, + + handleElementDeleted: { + value: function(event) { + if(!this._isDocument) { + + if(this.findSelectedElement(event.detail) !== -1) { + this.executeSelectElement(); + } + + } + + } + }, + + handleSelectAll: { + value: function(event) { + var selected = [], childNodes = []; + + childNodes = this.application.ninja.currentDocument.documentRoot.childNodes; + childNodes = Array.prototype.slice.call(childNodes, 0); + childNodes.forEach(function(item) { + if(item.nodeType == 1) { + selected.push(item); + } + }); + + this.selectElements(selected); + } + }, + + handleDeleteSelection: { + value: function(event) { + this.application.ninja.selectedElements = []; + this._isDocument = true; + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": this._isDocument} ); + } + }, + + /** + * Select Element. This function will not check that element, it will simply add it to the selection array. + */ + executeSelectElement: { + value: function(item) { + this.application.ninja.selectedElements = []; + + if(item) { + this.application.ninja.selectedElements.push({_element: item, uuid: item.uuid}); + this._isDocument = false; + } else { + this._isDocument = true; + } + + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": this._isDocument} ); + + } + + }, + + selectElement: { + value: function(item) { + + if(this.findSelectedElement(item) === -1) { + + if(this.application.ninja.currentDocument.inExclusion(item) !== -1){ + if(this.isDocument) return; // If the stage is already selected do nothing. + this.executeSelectElement(); // Else execute selection with no item + } else { + + if(item.parentNode.id == "UserContent") { + this.executeSelectElement(item); + } else { + var outerElement = item.parentNode; + + while(outerElement.parentNode && outerElement.parentNode.id !== "UserContent") { + outerElement = outerElement.parentNode; + } + + this.executeSelectElement(outerElement); + } + } + } + } + }, + + selectElements: { + value: function(items) { + if(items && items.length > 0) { + var that = this; + this.application.ninja.selectedElements = []; + + items.forEach(function(item) { + that.application.ninja.selectedElements.push({_element: item, uuid: item.uuid}); + that._isDocument = false; + }); + + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": this._isDocument} ); + } + } + }, + + shiftSelectElement: { + value: function(item) { + if(this.application.ninja.currentDocument.inExclusion(item) !== -1) return; + + (this.findSelectedElement(item) !== -1 ) ? this.removeElement(item) : this.insertElement(item); + } + }, + + insertElement: { + value: function(item) { + if(item) { + if(this._isDocument) { + this.application.ninja.selectedElements = []; + this._isDocument = false; + } + + this.application.ninja.selectedElements.push({_element: item, uuid: item.uuid}); + + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": this._isDocument} ); + } + } + }, + + removeElement: { + value: function(item) { + if(item){ + try{ + if(this.application.ninja.selectedElements.length > 1) { + var idx = this.findSelectedElement(item); + if(idx != -1){ + this.application.ninja.selectedElements.splice(idx, 1); + } + } else { + this.application.ninja.selectedElements = []; + this._isDocument = true; + } + + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": this._isDocument} ); + + } catch (err) { + console.log("Fault: " + err); + } + } + + } + }, + + + + + + handleUndo: { + value: function(event) { + this._applySelectionAfterUndoRedo(event.detail); + } + }, + + handleRedo: { + value: function(event) { + this._applySelectionAfterUndoRedo(event.detail); + } + }, + + _applySelectionAfterUndoRedo: { + value: function(items) { + if(items) { + if(items instanceof Array) { + if(items.length > 1) + { + this.clearSelection(); + this.setMultipleObjects(items); + documentControllerModule.DocumentController.DispatchElementChangedEvent(items); + } + else if(this._selectedItems.length === 0 || this.findSelectedElement(items) === -1) { + this.setSingleSelection(items[0]); + documentControllerModule.DocumentController.DispatchElementChangedEvent(items[0]); + } + } else { + if(this._selectedItems.length === 0 || this.findSelectedElement(items) === -1) { + this.setSingleSelection(items); + //documentControllerModule.DocumentController.DispatchElementChangedEvent([items]); + } + } + + } else { + this.clearSelection(); + } + } + }, + + isObjectSelected: + { + value: function( elt ) + { + return this.findSelectedElement(elt) > -1; + } + }, + + /** + * Looks into the selectionObject for the item to be found using it's id + * + * @return: Item index in the selectionObject if found + * -1 if not found + */ + findSelectedEleme