From 8db9e73ca68c006769af3997034959f6b7008add Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Thu, 21 Jun 2012 11:02:55 -0700 Subject: - added io api to generate file from binary - refactoring and cleanup Signed-off-by: Ananya Sen --- js/clipboard/external-apps-clipboard-agent.js | 220 ++++++++ .../internal-ops/component-clipboard-agent.js | 40 ++ js/clipboard/internal-ops/css-clipboard-agent.js | 40 ++ .../internal-ops/elements-clipboard-agent.js | 364 ++++++++++++ .../internal-ops/timeline-clipboard-agent.js | 40 ++ js/clipboard/util.js | 28 + js/controllers/clipboard-controller.js | 624 +-------------------- js/mediators/drag-drop-mediator.js | 108 ++-- js/mediators/io-mediator.js | 53 +- 9 files changed, 844 insertions(+), 673 deletions(-) create mode 100644 js/clipboard/external-apps-clipboard-agent.js create mode 100644 js/clipboard/internal-ops/component-clipboard-agent.js create mode 100644 js/clipboard/internal-ops/css-clipboard-agent.js create mode 100644 js/clipboard/internal-ops/elements-clipboard-agent.js create mode 100644 js/clipboard/internal-ops/timeline-clipboard-agent.js create mode 100644 js/clipboard/util.js diff --git a/js/clipboard/external-apps-clipboard-agent.js b/js/clipboard/external-apps-clipboard-agent.js new file mode 100644 index 00000000..7e55cf08 --- /dev/null +++ b/js/clipboard/external-apps-clipboard-agent.js @@ -0,0 +1,220 @@ +/* +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, + ClipboardUtil = require("js/clipboard/util").ClipboardUtil; + +var ExternalAppsClipboardAgent = exports.ExternalAppsClipboardAgent = Montage.create(Component, { + + paste:{ + value: function(clipboardEvent){ + var clipboardData = clipboardEvent.clipboardData, + htmlData = clipboardData.getData("text/html"), + textData = clipboardData.getData("text/plain"), + i=0, + imageMime, imageData, imageElement; + + //handle image blobs + if(clipboardData.items && (clipboardData.items.length > 0)){ + for(i=0; i < clipboardData.items.length; i++ ){ + if((clipboardData.items[i].kind === "file") && (clipboardData.items[i].type.indexOf("image") === 0)){//example type -> "image/png" + imageMime = clipboardData.items[i].type; + imageData = clipboardData.items[i].getAsFile(); + try{ + imageElement = this.pasteImageBinary(imageData); + }catch(e){ + console.log(""+e.stack); + } + this.application.ninja.selectionController.selectElements(imageElement); + this.application.ninja.currentDocument.model.needsSave = true; + + } + } + } + + try{ + if(!!htmlData || !!textData){ + this.pasteHtml(htmlData, textData); + } + }catch(e){ + console.log(""+e.stack); + } + + } + }, + + //todo: this will be moved to a seperate api + pasteImageBinary:{ + value: function(imageBlob){ + var element, self = this, + fileType = imageBlob.type; + + element = this.application.ninja.ioMediator.createFileFromBinary(imageBlob, {"addFileToStage" : self.addImageElement.bind(self)}); + + return element; + + } + }, + + addImageElement:{ + value: function(status){ + var save = status.save, + fileName = status.filename, + url = status.url, + fileType = status.fileType, + element, rules, self = this; + + if (save && save.success && save.status === 201) { + // + if (fileType.indexOf('svg') !== -1) { + element = document.application.njUtils.make('embed', null, this.application.ninja.currentDocument);//TODO: Verify this is proper + element.type = 'image/svg+xml'; + element.src = url+'/'+fileName; + } else { + element = document.application.njUtils.make('image', null, this.application.ninja.currentDocument); + element.src = url+'/'+fileName; + } + //Adding element once it is loaded + element.onload = function () { + element.onload = null; + self.application.ninja.elementMediator.addElements(element, rules, true); + }; + //Setting rules of element + rules = { + 'position': 'absolute', + 'top' : '100px', + 'left' : '100px' + }; + // + self.application.ninja.elementMediator.addElements(element, rules, false); + } else { + //TODO: HANDLE ERROR ON SAVING FILE TO BE ADDED AS ELEMENT + } + + return element; + } + }, + + //paste from external applicaitons + pasteHtml:{//todo: change to pasteNinja, pasteHTML, etc + value: function(htmlData, textData){ + var i=0, j=0, + pasteDataObject=null, + pastedElements = [], + node = null, nodeList = null, + styles = null, + divWrapper = null, + spanWrapper = null, + metaEl = null, + self = this; + + if(htmlData){ + + //TODO: cleanse HTML + + htmlData.replace(/["+ textData +"")[0]; + styles = {"position":"absolute", "top":"100px", "left":"100px"}; + this.pastePositioned(node, styles); + } + + NJevent("elementAdded", pastedElements); + this.application.ninja.currentDocument.model.needsSave = true; + + } + }, + + pastePositioned:{ + value: function(element, styles, fromCopy){// for now can wok for both in-place and centered paste + var modObject = [], x,y, newX, newY, counter; + + if((typeof fromCopy === "undefined") || (fromCopy && fromCopy === true)){ + counter = this.pasteCounter; + }else{ + counter = this.pasteCounter - 1; + } + + x = styles ? ("" + styles.left + "px") : "100px"; + y = styles ? ("" + styles.top + "px") : "100px"; + newX = styles ? ("" + (styles.left + (25 * counter)) + "px") : "100px"; + newY = styles ? ("" + (styles.top + (25 * counter)) + "px") : "100px"; + + if(!styles || (styles && !styles.position)){ + this.application.ninja.elementMediator.addElements(element, null, false); + }else if(styles && (styles.position === "absolute")){ + this.application.ninja.elementMediator.addElements(element, {"top" : newY, "left" : newX}, false);//displace + } + } + } + +}); \ No newline at end of file diff --git a/js/clipboard/internal-ops/component-clipboard-agent.js b/js/clipboard/internal-ops/component-clipboard-agent.js new file mode 100644 index 00000000..8b589a27 --- /dev/null +++ b/js/clipboard/internal-ops/component-clipboard-agent.js @@ -0,0 +1,40 @@ +/* +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; + +var ComponentsClipboardAgent = exports.ComponentsClipboardAgent = Montage.create(Component, { + + copy:{ + value: function(clipboardEvent){ + + } + }, + + cut:{ + value:function(clipboardEvent){ + + } + + }, + + pasteFromCopy:{ + value:function(){ + + } + }, + + pasteFromCut:{ + value:function(){ + + } + } + +}); \ No newline at end of file diff --git a/js/clipboard/internal-ops/css-clipboard-agent.js b/js/clipboard/internal-ops/css-clipboard-agent.js new file mode 100644 index 00000000..690a3a84 --- /dev/null +++ b/js/clipboard/internal-ops/css-clipboard-agent.js @@ -0,0 +1,40 @@ +/* +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; + +var CssClipboardAgent = exports.CssClipboardAgent = Montage.create(Component, { + + copy:{ + value: function(clipboardEvent){ + + } + }, + + cut:{ + value:function(clipboardEvent){ + + } + + }, + + pasteFromCopy:{ + value:function(){ + + } + }, + + pasteFromCut:{ + value:function(){ + + } + } + +}); \ No newline at end of file diff --git a/js/clipboard/internal-ops/elements-clipboard-agent.js b/js/clipboard/internal-ops/elements-clipboard-agent.js new file mode 100644 index 00000000..cd8de46e --- /dev/null +++ b/js/clipboard/internal-ops/elements-clipboard-agent.js @@ -0,0 +1,364 @@ +/* +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, + ClipboardUtil = require("js/clipboard/util").ClipboardUtil, + World = require("js/lib/drawing/world").World; + +var ElementsClipboardAgent = exports.ElementsClipboardAgent = Montage.create(Component, { + + //count how many times pasted + //used to move multiple pastes of same copy + pasteCounter:{ + value: 0 + }, + + copiedObjects:{ + value: {} + }, + + copy:{ + value: function(clipboardEvent){ + var j=0, htmlToClipboard = "", ninjaClipboardObj = {}, textToClipboard = ""; + this.copiedObjects = {}; + this.pasteCounter = 0; + this.copiedObjects["copy"] = []; + + if(clipboardEvent){ + for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage + this.copiedObjects.copy.push(this.application.ninja.selectedElements[j]); + + if(this.application.ninja.selectedElements[j].tagName === "CANVAS"){ + if(!ninjaClipboardObj.canvas){ + ninjaClipboardObj.canvas = true; + } + }else{ + htmlToClipboard = htmlToClipboard + this.serializeHTMLElement(this.application.ninja.selectedElements[j]); + if(!ninjaClipboardObj.plainHtml){ + ninjaClipboardObj.plainHtml = true; + } + textToClipboard = textToClipboard + this.getText(this.application.ninja.selectedElements[j]) + " "; + } + + } + //set clipboard data + clipboardEvent.clipboardData.setData('ninja', ''+ JSON.stringify(ninjaClipboardObj)); + clipboardEvent.clipboardData.setData('text/html', '' + htmlToClipboard + ''); + clipboardEvent.clipboardData.setData('text/plain', textToClipboard); + } + } + }, + + cut:{ + value:function(clipboardEvent){ + var j=0, htmlToClipboard = "", ninjaClipboardObj = {}, textToClipboard = "", elObj = null; + this.copiedObjects = {}; this.pasteCounter = 0; + this.copiedObjects["cut"] = []; + + if(clipboardEvent){ + for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage + elObj = {}; + elObj["outerhtml"] = this.application.ninja.selectedElements[j].outerHTML; + + if(this.application.ninja.selectedElements[j].tagName === "CANVAS"){ + elObj["styles"] = this.getDominantStyles(this.application.ninja.selectedElements[j], true); + if(!ninjaClipboardObj.canvas){ + ninjaClipboardObj.canvas = true; + } + elObj["worldJson"] = this.application.ninja.selectedElements[j].elementModel.shapeModel ? this.application.ninja.selectedElements[j].elementModel.shapeModel.GLWorld.exportJSON(): null; + elObj["className"] = this.application.ninja.selectedElements[j].className; + }else{ + elObj["styles"] = this.getDominantStyles(this.application.ninja.selectedElements[j], false); + htmlToClipboard = htmlToClipboard + this.serializeHTMLElement(this.application.ninja.selectedElements[j]); + if(!ninjaClipboardObj.plainHtml){ + ninjaClipboardObj.plainHtml = true; + } + textToClipboard = textToClipboard + this.getText(this.application.ninja.selectedElements[j]) + " "; + } + this.copiedObjects.cut.push(elObj); + } + //set clipboard data + clipboardEvent.clipboardData.setData('ninja', ''+ JSON.stringify(ninjaClipboardObj)); + clipboardEvent.clipboardData.setData('text/html', '' + htmlToClipboard + ''); + clipboardEvent.clipboardData.setData('text/plain', textToClipboard); + + } + + this.application.ninja.elementMediator.removeElements(this.application.ninja.selectedElements); + + clipboardEvent.preventDefault(); + } + }, + + pasteInternal:{ + value:function(){ + if(this.copiedObjects.copy){ + try{ + this.pasteFromCopy(); + }catch(e){ + console.log(""+e.stack); + } + } + else if(this.copiedObjects.cut){ + try{ + this.pasteFromCut(); + }catch(e){ + console.log(""+e.stack); + } + } + + } + }, + + pasteFromCopy:{//todo: change to appropriate name + value:function(){ + var i=0, j=0, + pastedElements = [],//array of te pastes clones - for selection + node = null, + styles = null, + copiedElement = null; + + this.pasteCounter++; + + //TODO: cleanse HTML + + for(j=0; j< this.copiedObjects.copy.length; j++){ + copiedElement = this.copiedObjects.copy[j]; + styles = null; + + if (copiedElement.tagName === "CANVAS"){ + //clone copied canvas + var canvas = this.cloneCanvas(copiedElement); + pastedElements.push(canvas); + } + else { + node = copiedElement.cloneNode(true); + + if(copiedElement.ownerDocument.defaultView.getComputedStyle(copiedElement).getPropertyValue("position") === "absolute"){ + styles = {}; + styles.top = this.application.ninja.elementMediator.getProperty(copiedElement, "top", parseInt); + styles.left = this.application.ninja.elementMediator.getProperty(copiedElement, "left", parseInt); + styles.position = "absolute"; + }else{ + styles = null; + } + this.pastePositioned(node, styles); + pastedElements.push(node); + } + + } + + NJevent("elementAdded", pastedElements); + + this.application.ninja.currentDocument.model.needsSave = true; + } + }, + + pasteFromCut:{ + value:function(){ + var i=0, j=0, + node = null, canvas = null, + styles=null, + pastedElements = [];//array of te pastes clones - for selection + + this.pasteCounter++; + + for(j=0; j< this.copiedObjects.cut.length; j++){ + node = ClipboardUtil.deserializeHtmlString(this.copiedObjects.cut[j].outerhtml)[0]; + + if (node.tagName === "CANVAS"){ + //paste canvas + canvas = this.generateNewCanvas(this.copiedObjects.cut[j].outerhtml, this.copiedObjects.cut[j].styles, this.copiedObjects.cut[j].className, this.copiedObjects.cut[j].worldJson); + pastedElements.push(canvas); + node = null; + } + else if((node.nodeType === 3) || (node.tagName === "A")){//TextNode + + node = null; + } + else { + this.pastePositioned(node, this.copiedObjects.cut[j].styles, false/*fromCopy*/); + pastedElements.push(node); + } + } + + NJevent("elementAdded", pastedElements); + this.application.ninja.currentDocument.model.needsSave = true; + } + }, + + + serializeHTMLElement:{ + value: function(elem){ + var computedStyles = null, originalStyleAttr = null, computedStylesStr = "", i=0, stylePropertyName="", outerHtml = ""; + + originalStyleAttr = elem.getAttribute("style");//preserve the current styles + elem.removeAttribute("style"); + + //build the computed style attribute + computedStyles = elem.ownerDocument.defaultView.getComputedStyle(elem); + + //todo: consider cleaning up the position data [or making position:relative with 0,0] from the computed styles, + // so that the object is pasted onto expernal applicaitons [like gmail] with no offset + + for (i = 0; i < computedStyles.length; i++) { + stylePropertyName = computedStyles[i]; + computedStylesStr = computedStylesStr + stylePropertyName + ":" + computedStyles.getPropertyValue(stylePropertyName) + ";"; + } + elem.setAttribute("style", computedStylesStr); + + outerHtml = elem.outerHTML; + + elem.setAttribute("style", originalStyleAttr);//reset style after copying to clipboard + + + return outerHtml; + } + }, + + cloneCanvas:{ + value: function(sourceCanvas){ + var canvas, styles, world, worldData; + + canvas = document.application.njUtils.make("canvas", sourceCanvas.className, this.application.ninja.currentDocument); + canvas.width = sourceCanvas.width; + canvas.height = sourceCanvas.height; + //end - clone copied canvas + + if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", document.application.njUtils.generateRandom() ); + + if(sourceCanvas.ownerDocument.defaultView.getComputedStyle(sourceCanvas).getPropertyValue("position") === "absolute"){ + styles = canvas.elementModel.data || {}; + styles.top = "" + (this.application.ninja.elementMediator.getProperty(sourceCanvas, "top", parseInt) + (25 * this.pasteCounter))+"px"; + styles.left = "" + (this.application.ninja.elementMediator.getProperty(sourceCanvas, "left", parseInt) + (25 * this.pasteCounter)) + "px"; + }else{ + styles = null; + } + + this.application.ninja.elementMediator.addElements(canvas, styles, false); + + worldData = sourceCanvas.elementModel.shapeModel ? sourceCanvas.elementModel.shapeModel.GLWorld.exportJSON(): null; + if(worldData) + { + var jObj; + var index = worldData.indexOf( ';' ); + if ((worldData[0] === 'v') && (index < 24)) + { + // JSON format. separate the version info from the JSON info + var jStr = worldData.substr( index+1 ); + jObj = JSON.parse( jStr ); + + world = new World(canvas, jObj.webGL); + canvas.elementModel.shapeModel.GLWorld = world; + canvas.elementModel.shapeModel.useWebGl = jObj.webGL; + world.importJSON(jObj); + this.application.ninja.currentDocument.model.webGlHelper.buildShapeModel( canvas.elementModel, world ); + } + } + + return canvas; + } + }, + + generateNewCanvas: { + value: function(outerhtml, styles, className, worldJson){ + var canvas, newCanvasStyles, world, worldData; + + canvas = document.application.njUtils.make("canvas", className, this.application.ninja.currentDocument); + canvas.width = styles.width; + canvas.height = styles.height; + + if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", document.application.njUtils.generateRandom() ); + + this.pastePositioned(canvas, styles, false/*from copy*/); + + worldData = worldJson; + + if(worldData) + { + var jObj; + var index = worldData.indexOf( ';' ); + if ((worldData[0] === 'v') && (index < 24)) + { + // JSON format. separate the version info from the JSON info + var jStr = worldData.substr( index+1 ); + jObj = JSON.parse( jStr ); + + world = new World(canvas, jObj.webGL); + canvas.elementModel.shapeModel.GLWorld = world; + canvas.elementModel.shapeModel.useWebGl = jObj.webGL; + world.importJSON(jObj); + this.application.ninja.currentDocument.model.webGlHelper.buildShapeModel( canvas.elementModel, world ); + } + } + + return canvas; + } + }, + + serializeCanvas:{ + value:function(sourceCanvas){ + + } + }, + + getText:{ + value: function(element){ + var nodeList = element.getElementsByTagName("*"), allText = "", i=0; + + for(i=0; i < nodeList.length; i++){ + if(nodeList[i].nodeType === 3){//text node + allText = allText + nodeList[i].innerText + " "; + } + } + } + }, + + pastePositioned:{ + value: function(element, styles, fromCopy){// for now can wok for both in-place and centered paste + var modObject = [], x,y, newX, newY, counter; + + if((typeof fromCopy === "undefined") || (fromCopy && fromCopy === true)){ + counter = this.pasteCounter; + }else{ + counter = this.pasteCounter - 1; + } + + x = styles ? ("" + styles.left + "px") : "100px"; + y = styles ? ("" + styles.top + "px") : "100px"; + newX = styles ? ("" + (styles.left + (25 * counter)) + "px") : "100px"; + newY = styles ? ("" + (styles.top + (25 * counter)) + "px") : "100px"; + + if(!styles || (styles && !styles.position)){ + this.application.ninja.elementMediator.addElements(element, null, false); + }else if(styles && (styles.position === "absolute")){ + this.application.ninja.elementMediator.addElements(element, {"top" : newY, "left" : newX}, false);//displace + } + } + }, + + getDominantStyles:{ + value: function(el, isCanvas){ + var styles = {}; + styles.top = this.application.ninja.elementMediator.getProperty(el, "top", parseInt); + styles.left = this.application.ninja.elementMediator.getProperty(el, "left", parseInt); + if(el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue("position") === "absolute"){ + styles.position = "absolute"; + } + if(isCanvas){ + styles.width = (el.getAttribute("width") ? el.getAttribute("width") : null); + styles.height = (el.getAttribute("height") ? el.getAttribute("height") : null); + } + return styles; + } + } + + +}); \ No newline at end of file diff --git a/js/clipboard/internal-ops/timeline-clipboard-agent.js b/js/clipboard/internal-ops/timeline-clipboard-agent.js new file mode 100644 index 00000000..c086431e --- /dev/null +++ b/js/clipboard/internal-ops/timeline-clipboard-agent.js @@ -0,0 +1,40 @@ +/* +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; + +var TimelineClipboardAgent = exports.TimelineClipboardAgent = Montage.create(Component, { + + copy:{ + value: function(clipboardEvent){ + + } + }, + + cut:{ + value:function(clipboardEvent){ + + } + + }, + + pasteFromCopy:{ + value:function(){ + + } + }, + + pasteFromCut:{ + value:function(){ + + } + } + +}); \ No newline at end of file diff --git a/js/clipboard/util.js b/js/clipboard/util.js new file mode 100644 index 00000000..a0813855 --- /dev/null +++ b/js/clipboard/util.js @@ -0,0 +1,28 @@ +/* +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; + +var ClipboardUtil = exports.ClipboardUtil = Montage.create(Component, { + + deserializeHtmlString:{ + value:function(htmlString){ + var doc = (this.application.ninja.currentDocument.currentView === "design") ? this.application.ninja.currentDocument.model.views.design.document : document, + clipboardHelper=doc.createElement("div"), + nodeList = null; + + clipboardHelper.innerHTML = htmlString; + nodeList = clipboardHelper.childNodes; + clipboardHelper = null; //for garbage collection + return nodeList; + } + } + +}); \ No newline at end of file diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index afa9cbdb..259d916e 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -8,13 +8,10 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot // var Montage = require("montage/core/core").Montage, Component = require("montage/ui/component").Component, - NJUtils = require("js/lib/NJUtils").NJUtils, - World = require("js/lib/drawing/world").World; + ElementsClipboardAgent = require("js/clipboard/internal-ops/elements-clipboard-agent").ElementsClipboardAgent, + ExternalAppsClipboardAgent= require("js/clipboard/external-apps-clipboard-agent").ExternalAppsClipboardAgent; var ClipboardController = exports.ClipboardController = Montage.create(Component, { - hasTemplate: { - value: false - }, deserializedFromTemplate: { value: function() { @@ -30,36 +27,12 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component } }, - clipboardOperationsAgent:{//appropriate agent instant required for execution of cut/copy/paste - value: null - }, - - //count how many times pasted - //used to move multiple pastes of same copy - pasteCounter:{ - value: 0 - }, - - copiedObjects:{ - value: {} - }, - - _copyFlag:{ - value:false - }, - - copyFlag:{ - get:function(){return this._copyFlag;}, - set:function(value){this._copyFlag = value;} - }, - - _newCopyFlag:{ - value:true + clipboardContext:{ + value : "stage" /* cleanup: formulate better context representation */ }, - newCopyFlag:{ - get:function(){return this._newCopyFlag;}, - set:function(value){this._newCopyFlag = value;} + operationsAgent:{//appropriate agent instant required for execution of cut/copy/paste + value: null }, handleExecuteCopy:{ @@ -87,7 +60,9 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component return; } - this.copy(clipboardEvent); + if(this.clipboardContext === "stage"){ + ElementsClipboardAgent.copy(clipboardEvent); + } clipboardEvent.preventDefault(); } @@ -102,7 +77,9 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component return; } - this.cut(clipboardEvent); + if(this.clipboardContext === "stage"){ + ElementsClipboardAgent.cut(clipboardEvent); + } clipboardEvent.preventDefault(); } @@ -111,11 +88,7 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component handlePaste:{ value:function(clipboardEvent){ var clipboardData = clipboardEvent.clipboardData, - ninjaData = clipboardData.getData("ninja"), - htmlData = clipboardData.getData("text/html"), - textData = clipboardData.getData("text/plain"), - i=0, - imageMime, imageData, imageElement; + ninjaData = clipboardData.getData("ninja"); if(!this.application.ninja.currentDocument || (this.application.ninja.currentDocument && this.application.ninja.currentDocument.currentView === "code")){ @@ -130,577 +103,18 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component //TODO: return if stage is not focussed - this.pasteCounter++; - - if(ninjaData){ - if(this.copiedObjects.copy){ - try{ - this.pasteFromCopy(); - }catch(e){ - console.log(""+e.stack); - } - } - else if(this.copiedObjects.cut){ - try{ - this.pasteFromCut(); - }catch(e){ - console.log(""+e.stack); - } - } - } - else{ - - //handle image blobs - if(clipboardData.items && (clipboardData.items.length > 0)){ - for(i=0; i < clipboardData.items.length; i++ ){ - if((clipboardData.items[i].kind === "file") && (clipboardData.items[i].type.indexOf("image") === 0)){//example type -> "image/png" - imageMime = clipboardData.items[i].type; - imageData = clipboardData.items[i].getAsFile(); - try{ - imageElement = this.generateImageElement(imageData); - }catch(e){ - console.log(""+e.stack); - } - this.application.ninja.selectionController.selectElements(imageElement); - this.application.ninja.currentDocument.model.needsSave = true; - - } - } + if(this.clipboardContext === "stage"){ + if(ninjaData){ + ElementsClipboardAgent.pasteInternal(); } - - try{ - this.pasteFromExternalSource(htmlData, textData); - }catch(e){ - console.log(""+e.stack); + else{ + ExternalAppsClipboardAgent.paste(clipboardEvent); } } clipboardEvent.preventDefault(); } - }, - - /* - parameters: - */ - copy:{ - value: function(clipboardEvent){ - var j=0, htmlToClipboard = "", ninjaClipboardObj = {}, textToClipboard = ""; - this.copiedObjects = {}; this.pasteCounter = 0; - this.copiedObjects["copy"] = []; - - if(clipboardEvent){ - for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage - this.copiedObjects.copy.push(this.application.ninja.selectedElements[j]); - - if(this.application.ninja.selectedElements[j].tagName === "CANVAS"){ - if(!ninjaClipboardObj.canvas){ - ninjaClipboardObj.canvas = true; - } - }else{ - htmlToClipboard = htmlToClipboard + this.serializeHTMLElement(this.application.ninja.selectedElements[j]); - if(!ninjaClipboardObj.plainHtml){ - ninjaClipboardObj.plainHtml = true; - } - textToClipboard = textToClipboard + this.getText(this.application.ninja.selectedElements[j]) + " "; - } - - } - //set clipboard data - clipboardEvent.clipboardData.setData('ninja', ''+ JSON.stringify(ninjaClipboardObj)); - clipboardEvent.clipboardData.setData('text/html', '' + htmlToClipboard + ''); - clipboardEvent.clipboardData.setData('text/plain', textToClipboard); - } - else{ - //TODO: custom copy/paste, ex: css, animation, materials - } - } - }, - - pasteFromCopy:{//todo: change to appropriate name - value:function(){ - var i=0, j=0, - pastedElements = [],//array of te pastes clones - for selection - node = null, - styles = null, - copiedElement = null; - - //TODO: cleanse HTML - - for(j=0; j< this.copiedObjects.copy.length; j++){ - copiedElement = this.copiedObjects.copy[j]; - styles = null; - - if (copiedElement.tagName === "CANVAS"){ - //clone copied canvas - var canvas = this.cloneCanvas(copiedElement); - pastedElements.push(canvas); - } - else { - node = copiedElement.cloneNode(true); - - if(copiedElement.ownerDocument.defaultView.getComputedStyle(copiedElement).getPropertyValue("position") === "absolute"){ - styles = {}; - styles.top = this.application.ninja.elementMediator.getProperty(copiedElement, "top", parseInt); - styles.left = this.application.ninja.elementMediator.getProperty(copiedElement, "left", parseInt); - styles.position = "absolute"; - }else{ - styles = null; - } - this.pastePositioned(node, styles); - pastedElements.push(node); - } - - } - - NJevent("elementAdded", pastedElements); - - this.application.ninja.currentDocument.model.needsSave = true; - } - }, - - pasteFromCut:{ - value:function(){ - var i=0, j=0, - node = null, canvas = null, - styles=null, - pastedElements = [];//array of te pastes clones - for selection - - for(j=0; j< this.copiedObjects.cut.length; j++){ - node = this.deserializeHtmlString(this.copiedObjects.cut[j].outerhtml)[0]; - - if (node.tagName === "CANVAS"){ - //paste canvas - canvas = this.generateNewCanvas(this.copiedObjects.cut[j].outerhtml, this.copiedObjects.cut[j].styles, this.copiedObjects.cut[j].className, this.copiedObjects.cut[j].worldJson); - pastedElements.push(canvas); - node = null; - } - else if((node.nodeType === 3) || (node.tagName === "A")){//TextNode - - node = null; - } - else { - this.pastePositioned(node, this.copiedObjects.cut[j].styles, false/*fromCopy*/); - pastedElements.push(node); - } - } - - NJevent("elementAdded", pastedElements); - this.application.ninja.currentDocument.model.needsSave = true; - } - }, - - //paste from external applicaitons - pasteFromExternalSource:{//todo: change to pasteNinja, pasteHTML, etc - value: function(htmlData, textData){ - var i=0, j=0, - pasteDataObject=null, - pastedElements = null, - node = null, nodeList = null, - styles = null, - divWrapper = null, - spanWrapper = null, - metaEl = null, - self = this; - - if(htmlData){ - - //TODO: cleanse HTML - - htmlData.replace(/["+ textData +"")[0]; - styles = {"position":"absolute", "top":"100px", "left":"100px"}; - this.pastePositioned(node, styles); - } - - } - }, - - cut:{ - value:function(clipboardEvent){ - var j=0, htmlToClipboard = "", ninjaClipboardObj = {}, textToClipboard = "", elObj = null; - this.copiedObjects = {}; this.pasteCounter = 0; - this.copiedObjects["cut"] = []; - - if(clipboardEvent){ - for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage - elObj = {}; - elObj["outerhtml"] = this.application.ninja.selectedElements[j].outerHTML; - - if(this.application.ninja.selectedElements[j].tagName === "CANVAS"){ - elObj["styles"] = this.getDominantStyles(this.application.ninja.selectedElements[j], true); - if(!ninjaClipboardObj.canvas){ - ninjaClipboardObj.canvas = true; - } - elObj["worldJson"] = this.application.ninja.selectedElements[j].elementModel.shapeModel ? this.application.ninja.selectedElements[j].elementModel.shapeModel.GLWorld.exportJSON(): null; - elObj["className"] = this.application.ninja.selectedElements[j].className; - }else{ - elObj["styles"] = this.getDominantStyles(this.application.ninja.selectedElements[j], false); - htmlToClipboard = htmlToClipboard + this.serializeHTMLElement(this.application.ninja.selectedElements[j]); - if(!ninjaClipboardObj.plainHtml){ - ninjaClipboardObj.plainHtml = true; - } - textToClipboard = textToClipboard + this.getText(this.application.ninja.selectedElements[j]) + " "; - } - this.copiedObjects.cut.push(elObj); - } - //set clipboard data - clipboardEvent.clipboardData.setData('ninja', ''+ JSON.stringify(ninjaClipboardObj)); - clipboardEvent.clipboardData.setData('text/html', '' + htmlToClipboard + ''); - clipboardEvent.clipboardData.setData('text/plain', textToClipboard); - - } - else{ - //TODO: custom copy/paste, ex: css, animation, materials - } - - this.application.ninja.elementMediator.removeElements(this.application.ninja.selectedElements); - - clipboardEvent.preventDefault(); - } - }, - - deserializeHtmlString:{ - value:function(htmlString){ - var doc = (this.application.ninja.currentDocument.currentView === "design") ? this.application.ninja.currentDocument.model.views.design.document : document, - clipboardHelper=doc.createElement("div"), - nodeList = null; - - clipboardHelper.innerHTML = htmlString; - - nodeList = clipboardHelper.childNodes; - - clipboardHelper = null; //for garbage collection - - return nodeList; - } - }, - - serializeHTMLElement:{ - value: function(elem){ - var computedStyles = null, originalStyleAttr = null, computedStylesStr = "", i=0, stylePropertyName="", outerHtml = ""; - - originalStyleAttr = elem.getAttribute("style");//preserve the current styles - elem.removeAttribute("style"); - - //build the computed style attribute - computedStyles = elem.ownerDocument.defaultView.getComputedStyle(elem); - - //todo: consider cleaning up the position data [or making position:relative with 0,0] from the computed styles, - // so that the object is pasted onto expernal applicaitons [like gmail] with no offset - - for (i = 0; i < computedStyles.length; i++) { - stylePropertyName = computedStyles[i]; - computedStylesStr = computedStylesStr + stylePropertyName + ":" + computedStyles.getPropertyValue(stylePropertyName) + ";"; - } - elem.setAttribute("style", computedStylesStr); - - outerHtml = elem.outerHTML; - - elem.setAttribute("style", originalStyleAttr);//reset style after copying to clipboard - - - return outerHtml; - } - }, - - cloneCanvas:{ - value: function(sourceCanvas){ - var canvas, styles, world, worldData; - - canvas = document.application.njUtils.make("canvas", sourceCanvas.className, this.application.ninja.currentDocument); - canvas.width = sourceCanvas.width; - canvas.height = sourceCanvas.height; - //end - clone copied canvas - - if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); - - if(sourceCanvas.ownerDocument.defaultView.getComputedStyle(sourceCanvas).getPropertyValue("position") === "absolute"){ - styles = canvas.elementModel.data || {}; - styles.top = "" + (this.application.ninja.elementMediator.getProperty(sourceCanvas, "top", parseInt) + (25 * this.pasteCounter))+"px"; - styles.left = "" + (this.application.ninja.elementMediator.getProperty(sourceCanvas, "left", parseInt) + (25 * this.pasteCounter)) + "px"; - }else{ - styles = null; - } - - this.application.ninja.elementMediator.addElements(canvas, styles, false); - - worldData = sourceCanvas.elementModel.shapeModel ? sourceCanvas.elementModel.shapeModel.GLWorld.exportJSON(): null; - if(worldData) - { - var jObj; - var index = worldData.indexOf( ';' ); - if ((worldData[0] === 'v') && (index < 24)) - { - // JSON format. separate the version info from the JSON info - var jStr = worldData.substr( index+1 ); - jObj = JSON.parse( jStr ); - - world = new World(canvas, jObj.webGL); - canvas.elementModel.shapeModel.GLWorld = world; - canvas.elementModel.shapeModel.useWebGl = jObj.webGL; - world.importJSON(jObj); - this.application.ninja.currentDocument.model.webGlHelper.buildShapeModel( canvas.elementModel, world ); - } - } - - return canvas; - } - }, - - generateNewCanvas: { - value: function(outerhtml, styles, className, worldJson){ - var canvas, newCanvasStyles, world, worldData; - - canvas = document.application.njUtils.make("canvas", className, this.application.ninja.currentDocument); - canvas.width = styles.width; - canvas.height = styles.height; - - if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); - - this.pastePositioned(canvas, styles, false/*from copy*/); - - worldData = worldJson; - - if(worldData) - { - var jObj; - var index = worldData.indexOf( ';' ); - if ((worldData[0] === 'v') && (index < 24)) - { - // JSON format. separate the version info from the JSON info - var jStr = worldData.substr( index+1 ); - jObj = JSON.parse( jStr ); - - world = new World(canvas, jObj.webGL); - canvas.elementModel.shapeModel.GLWorld = world; - canvas.elementModel.shapeModel.useWebGl = jObj.webGL; - world.importJSON(jObj); - this.application.ninja.currentDocument.model.webGlHelper.buildShapeModel( canvas.elementModel, world ); - } - } - - return canvas; - } - }, - - serializeCanvas:{ - value:function(sourceCanvas){ - - } - }, - - copyMontageComponents:{ - value: function(){ - - } - }, - - pasteImage:{ - value:function(imageData){ - - } - }, - - pasteMontageComponents:{ - value: function(){ - - } - }, - - getText:{ - value: function(element){ - var nodeList = element.getElementsByTagName("*"), allText = "", i=0; - - for(i=0; i < nodeList.length; i++){ - if(nodeList[i].nodeType === 3){//text node - allText = allText + nodeList[i].innerText + " "; - } - } - } - }, - - - pastePositioned:{ - value: function(element, styles, fromCopy){// for now can wok for both in-place and centered paste - var modObject = [], x,y, newX, newY, counter; - - if((typeof fromCopy === "undefined") || (fromCopy && fromCopy === true)){ - counter = this.pasteCounter; - }else{ - counter = this.pasteCounter - 1; - } - - x = styles ? ("" + styles.left + "px") : "100px"; - y = styles ? ("" + styles.top + "px") : "100px"; - newX = styles ? ("" + (styles.left + (25 * counter)) + "px") : "100px"; - newY = styles ? ("" + (styles.top + (25 * counter)) + "px") : "100px"; - - if(!styles || (styles && !styles.position)){ - this.application.ninja.elementMediator.addElements(element, null, false); - }else if(styles && (styles.position === "absolute")){ - this.application.ninja.elementMediator.addElements(element, {"top" : newY, "left" : newX}, false);//displace - } - } - }, - - getDominantStyles:{ - value: function(el, isCanvas){ - var styles = {}; - styles.top = this.application.ninja.elementMediator.getProperty(el, "top", parseInt); - styles.left = this.application.ninja.elementMediator.getProperty(el, "left", parseInt); - if(el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue("position") === "absolute"){ - styles.position = "absolute"; - } - if(isCanvas){ - styles.width = (el.getAttribute("width") ? el.getAttribute("width") : null); - styles.height = (el.getAttribute("height") ? el.getAttribute("height") : null); - } - return styles; - } - }, - - //todo: this will be moved to a seperate api - generateImageElement:{ - value: function(imageBlob){ - var reader = new FileReader(), file = reader.readAsArrayBuffer(imageBlob), url, uri, dir, save, counter, tempName, element, rules, fileName, fileNameOverride, - rootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1])), - rootUri = this.application.ninja.documentController.documentHackReference.root; - - reader.fileName = imageBlob.name, reader.fileType = imageBlob.type, reader.rootUrl = rootUrl, reader.rootUri = rootUri; - reader.onload = function (e) { - - if (this.application.ninja.coreIoApi.directoryExists({uri: e.currentTarget.rootUri+'images'}).status === 204) { - uri = e.currentTarget.rootUri+'images'; - url = e.currentTarget.rootUrl+'images'; - } else if (this.application.ninja.coreIoApi.directoryExists({uri: e.currentTarget.rootUri+'img'}).status === 204) { - uri = e.currentTarget.rootUri+'img'; - url = e.currentTarget.rootUrl+'img'; - } else { - dir = this.application.ninja.coreIoApi.createDirectory({uri: e.currentTarget.rootUri+'images'}); - if (dir.success && dir.status === 201) { - uri = e.currentTarget.rootUri+'images'; - url = e.currentTarget.rootUrl+'images'; - } else { - //TODO: HANDLE ERROR ON CREATING FOLDER - } - } - // - - //// - - //fileName is undefined while pasting image from clipboard - - fileNameOverride = e.currentTarget.fileName ? e.currentTarget.fileName : ("image." + e.currentTarget.fileType.substring((e.currentTarget.fileType.indexOf("/")+1), e.currentTarget.fileType.length));//like image.png - - //// - - if (this.application.ninja.coreIoApi.fileExists({uri: uri+'/'+fileNameOverride}).status === 404) { - save = this.application.ninja.coreIoApi.createFile({uri: uri+'/'+fileNameOverride, contents: e.currentTarget.result, contentType: e.currentTarget.fileType}); - fileName = fileNameOverride; - } else { - counter = 1; - tempName = fileNameOverride.split('.'+(fileNameOverride.split('.')[fileNameOverride.split('.').length-1]))[0]; - tempName += '_'+counter+'.'+(fileNameOverride.split('.')[fileNameOverride.split('.').length-1]); - while (this.application.ninja.coreIoApi.fileExists({uri: uri+'/'+tempName}).status !== 404) { - counter++; - tempName = fileNameOverride.split('.'+(fileNameOverride.split('.')[fileNameOverride.split('.').length-1]))[0]; - tempName += '_'+counter+'.'+(fileNameOverride.split('.')[fileNameOverride.split('.').length-1]); - } - save = this.application.ninja.coreIoApi.createFile({uri: uri+'/'+tempName, contents: e.currentTarget.result, contentType: e.currentTarget.fileType}); - fileName = tempName; - } - if (save && save.success && save.status === 201) { - var self = this; - // - if (e.currentTarget.fileType.indexOf('svg') !== -1) { - element = NJUtils.make('embed', null, this.application.ninja.currentDocument);//TODO: Verify this is proper - element.type = 'image/svg+xml'; - element.src = url+'/'+fileName; - } else { - element = NJUtils.make('image', null, this.application.ninja.currentDocument); - element.src = url+'/'+fileName; - } - //Adding element once it is loaded - element.onload = function () { - element.onload = null; - self.application.ninja.elementMediator.addElements(element, rules, true); - }; - //Setting rules of element - rules = { - 'position': 'absolute', - 'top' : '100px', - 'left' : '100px' - }; - // - self.application.ninja.elementMediator.addElements(element, rules, false); - } else { - //TODO: HANDLE ERROR ON SAVING FILE TO BE ADDED AS ELEMENT - } - }.bind(this); - - return element; - - } } + }); \ No newline at end of file diff --git a/js/mediators/drag-drop-mediator.js b/js/mediators/drag-drop-mediator.js index 14bdb0eb..049424f3 100755 --- a/js/mediators/drag-drop-mediator.js +++ b/js/mediators/drag-drop-mediator.js @@ -57,9 +57,7 @@ exports.DragDropMediator = Montage.create(Component, { handleDropEvent: { value: function(e){ // - var i, files = e.dataTransfer.files, position = {x: e.offsetX, y: e.offsetY}, - rootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1])), - rootUri = this.application.ninja.documentController.documentHackReference.root; + var i, files = e.dataTransfer.files, position = {x: e.offsetX, y: e.offsetY}, self = this; var xferString = e.dataTransfer.getData("text/plain"); if(xferString) { @@ -74,70 +72,8 @@ exports.DragDropMediator = Montage.create(Component, { // for (i=0; files[i]; i++) { if (files[i].type.indexOf('image') !== -1) { - var reader = new FileReader(), file = reader.readAsArrayBuffer(files[i]); - reader.fileName = files[i].name, reader.fileType = files[i].type, reader.rootUrl = rootUrl, reader.rootUri = rootUri, reader.filePosition = position; - reader.onload = function (e) { - // - var url, uri, dir, save, counter, tempName, element, rules, fileName; - if (this.application.ninja.coreIoApi.directoryExists({uri: e.currentTarget.rootUri+'images'}).status === 204) { - uri = e.currentTarget.rootUri+'images'; - url = e.currentTarget.rootUrl+'images'; - } else if (this.application.ninja.coreIoApi.directoryExists({uri: e.currentTarget.rootUri+'img'}).status === 204) { - uri = e.currentTarget.rootUri+'img'; - url = e.currentTarget.rootUrl+'img'; - } else { - dir = this.application.ninja.coreIoApi.createDirectory({uri: e.currentTarget.rootUri+'images'}); - if (dir.success && dir.status === 201) { - uri = e.currentTarget.rootUri+'images'; - url = e.currentTarget.rootUrl+'images'; - } else { - //TODO: HANDLE ERROR ON CREATING FOLDER - } - } - // - if (this.application.ninja.coreIoApi.fileExists({uri: uri+'/'+e.currentTarget.fileName}).status === 404) { - save = this.application.ninja.coreIoApi.createFile({uri: uri+'/'+e.currentTarget.fileName, contents: e.currentTarget.result, contentType: e.currentTarget.fileType}); - fileName = e.currentTarget.fileName; - } else { - counter = 1; - tempName = e.currentTarget.fileName.split('.'+(e.currentTarget.fileName.split('.')[e.currentTarget.fileName.split('.').length-1]))[0]; - tempName += '_'+counter+'.'+(e.currentTarget.fileName.split('.')[e.currentTarget.fileName.split('.').length-1]); - while (this.application.ninja.coreIoApi.fileExists({uri: uri+'/'+tempName}).status !== 404) { - counter++; - tempName = e.currentTarget.fileName.split('.'+(e.currentTarget.fileName.split('.')[e.currentTarget.fileName.split('.').length-1]))[0]; - tempName += '_'+counter+'.'+(e.currentTarget.fileName.split('.')[e.currentTarget.fileName.split('.').length-1]); - } - save = this.application.ninja.coreIoApi.createFile({uri: uri+'/'+tempName, contents: e.currentTarget.result, contentType: e.currentTarget.fileType}); - fileName = tempName; - } - if (save && save.success && save.status === 201) { - var self = this; - // - if (e.currentTarget.fileType.indexOf('svg') !== -1) { - element = NJUtils.make('embed', null, this.application.ninja.currentDocument);//TODO: Verify this is proper - element.type = 'image/svg+xml'; - element.src = url+'/'+fileName; - } else { - element = NJUtils.make('image', null, this.application.ninja.currentDocument); - element.src = url+'/'+fileName; - } - //Adding element once it is loaded -