From f6e4436b024bddae92348fc975b5fd6c4595cb61 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Mon, 7 May 2012 11:07:45 -0700 Subject: copy/paste POC Signed-off-by: Ananya Sen Conflicts: js/ninja.reel/ninja.html Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 151 +++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 js/controllers/clipboard-controller.js (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js new file mode 100644 index 00000000..b2e5a33b --- /dev/null +++ b/js/controllers/clipboard-controller.js @@ -0,0 +1,151 @@ +/* +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 ClipboardController = exports.ClipboardController = Montage.create(Component, { + hasTemplate: { + value: false + }, + + deserializedFromTemplate: { + value: function() { + document.body.addEventListener("copy", this, false); + document.body.addEventListener("cut", this, false); + document.body.addEventListener("paste", this, false); + + //ninja menu events + this.eventManager.addEventListener("executeCut", this, false); + this.eventManager.addEventListener("executeCopy", this, false); + this.eventManager.addEventListener("executePaste", this, false); + } + }, + + _copyFlag:{ + value:false + }, + + copyFlag:{ + get:function(){return this._copyFlag;}, + set:function(value){this._copyFlag = value;} + }, + + _newCopyFlag:{ + value:true + }, + + newCopyFlag:{ + get:function(){return this._newCopyFlag;}, + set:function(value){this._newCopyFlag = value;} + }, + + handleExecuteCopy:{ + value: function(){document.execCommand('copy',false,null);} + }, + + handleExecuteCut:{ + value: function(){document.execCommand('cut',false,null);} + }, + + handleExecutePaste:{ + value: function(){document.execCommand('paste',false,null);} + }, + + handleCopy:{ + value:function(clipboardEvent){ + //depends on the clipboard event + if(this.application.ninja.selectedElements.length > 0){ + clipboardEvent.clipboardData.setData('text/html', ''+this.application.ninja.selectedElements[0].outerHTML);//copying first selected element for POC + + clipboardEvent.preventDefault(); + } + } + }, + + handleCut:{ + value:function(clipboardEvent){ + var clipboardData = clipboardEvent.clipboardData, + htmlData = clipboardData.getData("text/html"), + textData = clipboardData.getData("text/plain"); + + console.log("$$$ handleCut ", textData); + + + clipboardEvent.preventDefault(); + clipboardEvent.stopPropagation(); + } + }, + + handlePaste:{ + value:function(clipboardEvent){ + var clipboardData = clipboardEvent.clipboardData, + htmlData = clipboardData.getData("text/html"), + textData = clipboardData.getData("text/plain"), + data = null; + + data = htmlData || textData; + + if(data){ + //hack - to avoid parsing html code now + + this.application.ninja.documentController.activeDocument.documentRoot.innerHTML = data + this.application.ninja.documentController.activeDocument.documentRoot.innerHTML; + + } + + clipboardEvent.preventDefault(); + } + }, + + /* + does not preserve the css class / html structure while copying + */ + copyUsingContenteditable:{ + value:function(){ + var clipboardHelper=document.getElementById("clipboardHelper"),copyElement = null, textData = ""; + if((this.copyFlag === true) ) { + if(!clipboardHelper) clipboardHelper.innerHTML = "";//clear + this.copyFlag = false; + return;//break infinite loop + } + + //dynamically create editable div for execCommand->copy + if(!clipboardHelper){ + clipboardHelper = document.createElement ("div"); + clipboardHelper.id = "clipboardHelper"; + // place outside the visible area + clipboardHelper.style.position = "absolute"; + clipboardHelper.style.left = "-10000px"; + clipboardHelper.style.top = "-10000px"; + clipboardHelper.setAttribute("contenteditable", "true"); + clipboardHelper.style.webkitUserSelect = "auto"; + +// clipboardHelper.style.width = "500px"; +// clipboardHelper.style.height = "125px"; +// clipboardHelper.style.overflow = "visible"; +// clipboardHelper.style.zIndex = "10000"; +// clipboardHelper.style.border = "1px solid red"; +// clipboardHelper.style.backgroundColor = "yellow"; + + document.body.appendChild (clipboardHelper); + } + + clipboardHelper.focus(); + //copy single selection for POC + if(this.application.ninja.selectedElements.length > 0){ + clipboardHelper.innerHTML = this.application.ninja.selectedElements[0].outerHTML; + } + //do selection + document.execCommand('selectAll',false,null); + this.copyFlag = true;//flag to prevent infinite loop + document.execCommand('copy',false,null); + + } + } + +}); \ No newline at end of file -- cgit v1.2.3 From 8e7528f672900fb50bd624439261b4402e2fd883 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Tue, 8 May 2012 12:13:55 -0700 Subject: removed unnecessary function Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 52 ++-------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index b2e5a33b..d26aaa80 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -61,9 +61,9 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component value:function(clipboardEvent){ //depends on the clipboard event if(this.application.ninja.selectedElements.length > 0){ - clipboardEvent.clipboardData.setData('text/html', ''+this.application.ninja.selectedElements[0].outerHTML);//copying first selected element for POC + clipboardEvent.clipboardData.setData('text/html', ''+this.application.ninja.selectedElements[0].outerHTML);//copying first selected element for POC - clipboardEvent.preventDefault(); + clipboardEvent.preventDefault(); } } }, @@ -78,7 +78,6 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component clipboardEvent.preventDefault(); - clipboardEvent.stopPropagation(); } }, @@ -100,52 +99,5 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component clipboardEvent.preventDefault(); } - }, - - /* - does not preserve the css class / html structure while copying - */ - copyUsingContenteditable:{ - value:function(){ - var clipboardHelper=document.getElementById("clipboardHelper"),copyElement = null, textData = ""; - if((this.copyFlag === true) ) { - if(!clipboardHelper) clipboardHelper.innerHTML = "";//clear - this.copyFlag = false; - return;//break infinite loop - } - - //dynamically create editable div for execCommand->copy - if(!clipboardHelper){ - clipboardHelper = document.createElement ("div"); - clipboardHelper.id = "clipboardHelper"; - // place outside the visible area - clipboardHelper.style.position = "absolute"; - clipboardHelper.style.left = "-10000px"; - clipboardHelper.style.top = "-10000px"; - clipboardHelper.setAttribute("contenteditable", "true"); - clipboardHelper.style.webkitUserSelect = "auto"; - -// clipboardHelper.style.width = "500px"; -// clipboardHelper.style.height = "125px"; -// clipboardHelper.style.overflow = "visible"; -// clipboardHelper.style.zIndex = "10000"; -// clipboardHelper.style.border = "1px solid red"; -// clipboardHelper.style.backgroundColor = "yellow"; - - document.body.appendChild (clipboardHelper); - } - - clipboardHelper.focus(); - //copy single selection for POC - if(this.application.ninja.selectedElements.length > 0){ - clipboardHelper.innerHTML = this.application.ninja.selectedElements[0].outerHTML; - } - //do selection - document.execCommand('selectAll',false,null); - this.copyFlag = true;//flag to prevent infinite loop - document.execCommand('copy',false,null); - - } } - }); \ No newline at end of file -- cgit v1.2.3 From e503f067e8f4eb2477fb516ae00ffc6a297fc2a0 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Fri, 11 May 2012 12:24:26 -0700 Subject: Prototype of copy and pasting basic html elements. Also provides ability to paste ninja elements to external applications, and to paste html content from external applications to Ninja. Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 146 ++++++++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 13 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index d26aaa80..b023d37c 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -7,7 +7,8 @@ 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; + Component = require("montage/ui/component").Component, + NJUtils = require("js/lib/NJUtils").NJUtils; var ClipboardController = exports.ClipboardController = Montage.create(Component, { hasTemplate: { @@ -24,6 +25,7 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component this.eventManager.addEventListener("executeCut", this, false); this.eventManager.addEventListener("executeCopy", this, false); this.eventManager.addEventListener("executePaste", this, false); + } }, @@ -59,45 +61,163 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component handleCopy:{ value:function(clipboardEvent){ - //depends on the clipboard event + var elem = null, computedStyles = null, originalStyleAttr = null, computedStylesStr = "", i=0, stylePropertyName=""; + if(this.application.ninja.documentController.activeDocument.currentView === "code") return; + if(this.application.ninja.selectedElements.length > 0){ + //handling 1 selected element + + elem = this.application.ninja.selectedElements[0]; + 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 posiiton: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); + + //set clipboard data clipboardEvent.clipboardData.setData('text/html', ''+this.application.ninja.selectedElements[0].outerHTML);//copying first selected element for POC + //clipboardEvent.clipboardData.setData('ninja', 'test');//works + + elem.setAttribute("style", originalStyleAttr);//reset style after copying to clipboard + + //end - handling 1 selected element clipboardEvent.preventDefault(); } } }, - handleCut:{ + handlePaste:{ value:function(clipboardEvent){ + if(this.application.ninja.documentController.activeDocument.currentView === "code") return; + var clipboardData = clipboardEvent.clipboardData, htmlData = clipboardData.getData("text/html"), textData = clipboardData.getData("text/plain"); - console.log("$$$ handleCut ", textData); - + this.pasteItems(htmlData, textData); clipboardEvent.preventDefault(); } }, - handlePaste:{ - value:function(clipboardEvent){ - var clipboardData = clipboardEvent.clipboardData, - htmlData = clipboardData.getData("text/html"), - textData = clipboardData.getData("text/plain"), - data = null; + pasteItems:{ + value: function(htmlData, textData){ + var data = null, i=0, + pasteDataObject=null, + clipboardHelper=this.createClipboardHelper(), + pastedElements = null, + node = null, + styles = null; data = htmlData || textData; if(data){ - //hack - to avoid parsing html code now + //TODO: cleanse HTML + + this.application.ninja.selectedElements.length = 0; + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": true} ); + + clipboardHelper.innerHTML = data;//add the copied html to generate the nodes + + while(clipboardHelper.hasChildNodes()){ + if(clipboardHelper.lastChild.tagName !== "META") { + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + + node.removeAttribute("style");//remove the computed styles attribute which is placed only for pasting to external applications + + //get class string while copying .... generate styles from class + styles = {"top":"100px", "left":"100px"};//get real stage center coordinates + this.pastePositioned(node, styles); + + + + + //this.pasteInPlace(temp);//does not work now + - this.application.ninja.documentController.activeDocument.documentRoot.innerHTML = data + this.application.ninja.documentController.activeDocument.documentRoot.innerHTML; +// this.application.ninja.documentController.activeDocument.documentRoot.insertBefore(temp, this.application.ninja.documentController.activeDocument.documentRoot.firstChild); +// NJUtils.makeModelFromElement(temp); +// NJevent("elementAdded", temp); + } + else { + clipboardHelper.removeChild(clipboardHelper.lastChild);//remove unnecesary meta tag + } + } + + this.application.ninja.documentController.activeDocument.needsSave = true; } + } + }, + + pastePositioned:{ + value: function(element, styles){// for now can wok for both in-place and centered paste + NJUtils.createModel(element); + this.application.ninja.elementMediator.addElements(element, styles); + } + }, + + pasteInPlace:{ + value: function(element){ + NJUtils.createModel(element); + this.application.ninja.elementMediator.addElements(element, null);//does not work now + } + }, + + handleCut:{ + value:function(clipboardEvent){ + var clipboardData = clipboardEvent.clipboardData, + htmlData = clipboardData.getData("text/html"), + textData = clipboardData.getData("text/plain"); + + console.log("$$$ handleCut ", textData); + + clipboardEvent.preventDefault(); } + }, + + samplePasteJson:{ + value:{ + "htmlString" : "
", + "styles": {"position": "absolute", + "top": "304px", + "left": "318px", + "width": "125px", + "height": "71px", + "background-image": "none", + "background-color": "#2EFF5B"} + + } + }, + + createClipboardHelper:{ + value:function(){ + var doc = this.application.ninja.currentDocument ? this.application.ninja.currentDocument._document : document, + clipboardHelper=doc.getElementById("clipboardHelper"); + //dynamically create editable div for execCommand->copy + if(!clipboardHelper){ + clipboardHelper = doc.createElement ("div"); + clipboardHelper.id = "clipboardHelper"; + //clipboardHelper.style.display="none"; + clipboardHelper.style.position = "absolute"; + clipboardHelper.style.right = "0px"; + clipboardHelper.style.top = "0px"; + + document.body.appendChild (clipboardHelper); + } + return clipboardHelper; + } } }); \ No newline at end of file -- cgit v1.2.3 From 9e1ee9114e5364199acf1abb54798c81c14b9cbe Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Wed, 16 May 2012 11:01:20 -0700 Subject: single selection copy/paste canvas 2d shapes [rectangle and circle] Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 105 ++++++++++++++++++++++++++++----- js/controllers/styles-controller.js | 70 +++++++++++++++++----- 2 files changed, 144 insertions(+), 31 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index b023d37c..6ac90d96 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -8,7 +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; + NJUtils = require("js/lib/NJUtils").NJUtils, + World = require("js/lib/drawing/world").World, + ShapesController = require("js/controllers/elements/shapes-controller").ShapesController, + ShapeModel = require("js/models/shape-model").ShapeModel; var ClipboardController = exports.ClipboardController = Montage.create(Component, { hasTemplate: { @@ -29,6 +32,10 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component } }, + copiedObjects:{ + value: null + }, + _copyFlag:{ value:false }, @@ -65,7 +72,11 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component if(this.application.ninja.documentController.activeDocument.currentView === "code") return; if(this.application.ninja.selectedElements.length > 0){ - //handling 1 selected element + //handling 1 selected element for now + + if(this.application.ninja.selectedElements[0].tagName === "CANVAS"){ + this.copiedObjects = this.application.ninja.selectedElements[0]; + } elem = this.application.ninja.selectedElements[0]; originalStyleAttr = elem.getAttribute("style");//preserve the current styles @@ -100,6 +111,8 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component value:function(clipboardEvent){ if(this.application.ninja.documentController.activeDocument.currentView === "code") return; + //TODO: return if stage is not focussed + var clipboardData = clipboardEvent.clipboardData, htmlData = clipboardData.getData("text/html"), textData = clipboardData.getData("text/plain"); @@ -121,41 +134,103 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component data = htmlData || textData; - if(data){ + if(htmlData){ //TODO: cleanse HTML this.application.ninja.selectedElements.length = 0; NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": true} ); - clipboardHelper.innerHTML = data;//add the copied html to generate the nodes + clipboardHelper.innerHTML = htmlData;//add the copied html to generate the nodes while(clipboardHelper.hasChildNodes()){ - if(clipboardHelper.lastChild.tagName !== "META") { - node = clipboardHelper.removeChild(clipboardHelper.lastChild); + if(clipboardHelper.lastChild.tagName === "META") { + clipboardHelper.removeChild(clipboardHelper.lastChild);//remove unnecesary meta tag + } + else if (clipboardHelper.lastChild.tagName === "CANVAS"){//temporary - we probably won't need to serialize this to the system clipboard - node.removeAttribute("style");//remove the computed styles attribute which is placed only for pasting to external applications + //only handling 1 canvas for POC - //get class string while copying .... generate styles from class - styles = {"top":"100px", "left":"100px"};//get real stage center coordinates - this.pastePositioned(node, styles); + //clone copied canvas + var canvas = document.application.njUtils.make("canvas", this.copiedObjects.className, this.application.ninja.currentDocument); + canvas.width = this.copiedObjects.width; + canvas.height = this.copiedObjects.height; + //end - clone copied canvas + + if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); + document.application.njUtils.createModelWithShape(canvas); +// canvas.elementModel.controller = ShapesController; +// if(!canvas.elementModel.shapeModel) { +// canvas.elementModel.shapeModel = Montage.create(ShapeModel); +// } + styles = canvas.elementModel.data || {}; + styles.top = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "top", parseInt) - 50) + "px"; + styles.left = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "left", parseInt) - 50) + "px"; + + this.application.ninja.elementMediator.addElements(canvas, styles, false); + + var world, worldData = this.copiedObjects.elementModel.shapeModel.GLWorld.exportJSON(); + 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 vStr = importStr.substr( 0, index+1 ); + var jStr = worldData.substr( index+1 ); + jObj = JSON.parse( jStr ); + world = new World(canvas, jObj.useWebGl); + canvas.elementModel.shapeModel.GLWorld = world; + canvas.elementModel.shapeModel.useWebGl = jObj.useWebGl; + world.importJSON(jObj); + this.application.ninja.currentDocument.buildShapeModel( canvas.elementModel, world ); + } + } - //this.pasteInPlace(temp);//does not work now + NJevent("elementAdded", canvas); -// this.application.ninja.documentController.activeDocument.documentRoot.insertBefore(temp, this.application.ninja.documentController.activeDocument.documentRoot.firstChild); -// NJUtils.makeModelFromElement(temp); -// NJevent("elementAdded", temp); + clipboardHelper.removeChild(clipboardHelper.lastChild); + } + else if(clipboardHelper.lastChild.nodeType === 3){//TextNode + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + + //USE styles controller to create the styles of the div and span + var doc = this.application.ninja.currentDocument ? this.application.ninja.currentDocument._document : document; + var aspan = doc.createElement("span"); + aspan.appendChild(node); + var adiv = doc.createElement("div"); + adiv.appendChild(aspan); + styles = {"top":"100px", "left":"100px"}; + + this.pastePositioned(node, styles); } else { - clipboardHelper.removeChild(clipboardHelper.lastChild);//remove unnecesary meta tag + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + + if(node.removeAttribute) {node.removeAttribute("style");}//remove the computed styles attribute which is placed only for pasting to external applications + + //get class string while copying .... generate styles from class + //styles = {"top":"100px", "left":"100px"}; + + this.pastePositioned(node, styles); } + } this.application.ninja.documentController.activeDocument.needsSave = true; + }else if(textData){ + + //USE styles controller to create the styles of the div and span + clipboardHelper.innerHTML = "
"+ textData +"
";//add the copied html to generate the nodes + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + styles = {"top":"100px", "left":"100px"};//get real stage center coordinates + this.pastePositioned(node, styles); } } diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js index 647c0870..cbc00676 100755 --- a/js/controllers/styles-controller.js +++ b/js/controllers/styles-controller.js @@ -94,11 +94,18 @@ var stylesController = exports.StylesController = Montage.create(Component, { // Returns null if sheet not found (as in non-ninja projects) // Setter will handle null case this.defaultStylesheet = this.getSheetFromElement(this.CONST.DEFAULT_SHEET_ID); - - //debugger; + + this.userStyleSheets = nj.toArray(document._document.styleSheets).filter(function(sheet) { + return sheet !== this._stageStylesheet; + }, this); + + NJevent('styleSheetsReady', this); }, enumerable : false }, + userStyleSheets : { + value : null + }, _stageStylesheet : { value : null }, @@ -183,6 +190,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { ///// attach specificity to rule object ///// if rule is css keyframes, return rule and don't attach specificity if (rule instanceof WebKitCSSKeyframesRule) { + return rule; } rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); @@ -209,10 +217,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { } var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), - overrideData, rule; + overrideData, rule, isRuleLocked; + + isRuleLocked = this.isSheetLocked(ruleToOverride.parentStyleSheet); ///// Get the overriding selector and className - overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); + overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName, isRuleLocked); ///// Create new rule with selector and insert it after the rule we're overriding rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); @@ -226,7 +236,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { }, createOverrideSelector : { - value: function(selectorToOverride, classPrefix, className) { + value: function(selectorToOverride, classPrefix, increaseSpecificity, className) { var tokens = selectorToOverride.split(/\s/), newClass = className || this.generateClassName(classPrefix, true), lastToken, pseudoSplit, base, pseudo, newToken, newSelector; @@ -247,10 +257,19 @@ var stylesController = exports.StylesController = Montage.create(Component, { if(base.indexOf('#') !== -1) { newToken = base + '.' + newClass + pseudo; } else { - ///// Replace last class or attribute selector - ///// Get everything right before the last class or attribute selector - ///// to support compound selector values: (i.e. .firstClass.secondClass) - newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); + if(increaseSpecificity) { + ///// Increases specificity by one class selector + ///// We'll do a direct append to the base class + ///// if we want to increase the specificity + newToken = base; + } else { + ///// Maintains original specificity + ///// Replace last class or attribute selector + ///// Get everything right before the last class or attribute selector + ///// to support compound selector values: (i.e. .firstClass.secondClass) + newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); + } + ///// Append the generated class newToken += '.' + newClass + pseudo; } @@ -795,7 +814,9 @@ var stylesController = exports.StylesController = Montage.create(Component, { ///// method to apply/test the new value dec.setProperty(property, value, priority); - this.styleSheetModified(rule.parentStyleSheet); + if(rule.parentStyleSheet) { + this.styleSheetModified(rule.parentStyleSheet); + } ///// Return browser value for value we just set return dec.getPropertyValue(property); @@ -969,12 +990,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { var doc = element.ownerDocument, useImportant = false, cache = this._getCachedRuleForProperty(element, property), - dominantRule, override, className, browserValue; + dominantRule, override, className, browserValue, cacheMatchesMany; if(cache) { ///// We've cached the rule for this property! //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); dominantRule = cache; + cacheMatchesMany = this.matchesMultipleElements(dominantRule, doc); } else { ///// Use Dominant Rule logic to find the right place to add the style ///// Pass "true" to method to return an override object, which @@ -982,7 +1004,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); } - + ///// Did we find a dominant rule? if(!dominantRule) { ///// No. This means there was no rule with this property, and no @@ -1000,6 +1022,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { useImportant = dominantRule.useImportant; dominantRule = override.rule; this.addClass(element, override.className); + } else if(cacheMatchesMany) { + ///// Only happens when the cached rule applies to multiple + ///// elements - we must create override + override = this.createOverrideRule(dominantRule, element); + useImportant = !!dominantRule.style.getPropertyPriority(property); + dominantRule = override.rule; + this.addClass(element, override.className); } @@ -1007,7 +1036,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { browserValue = this.setStyle(dominantRule, property, value, useImportant); ///// Only cache the dominant rule if the style value was valid, and not already cached - if(browserValue && !cache) { + if(browserValue && (!cache || cacheMatchesMany)) { this._setCachedRuleForProperty(element, property, dominantRule); } @@ -1242,8 +1271,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { doc.head.appendChild(sheetElement); sheet = this.getSheetFromElement(sheetElement, doc); + this.userStyleSheets.push(sheet); + this.styleSheetModified(sheet); + NJevent('newStyleSheet', sheet); + return sheet; } }, @@ -1266,6 +1299,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { } }, + isSheetLocked : { + value: function(sheet) { + return !!sheet.ownerNode.dataset['ninjaFileReadOnly']; + } + }, + ///// Style Sheet Modified ///// Method to call whenever a stylesheet change is made ///// Dispatches an event, and keeps list of dirty style sheets @@ -1306,11 +1345,10 @@ var stylesController = exports.StylesController = Montage.create(Component, { this.dirtyStyleSheets.length = 0; if(doc) { - var stillDirty = this.dirtyStyleSheets.filter(function(sheet) { + this.dirtyStyleSheets = null; + this.dirtyStyleSheets = this.dirtyStyleSheets.filter(function(sheet) { return sheet.document !== doc; }); - this.dirtyStyleSheets = null; - this.dirtyStyleSheets = stillDirty; } -- cgit v1.2.3 From dbab843c68c784579c369a64fb4f2a76c88de582 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Wed, 16 May 2012 11:51:18 -0700 Subject: copy/paste single webGL shape Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index 6ac90d96..e84fcac7 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -159,10 +159,7 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); document.application.njUtils.createModelWithShape(canvas); -// canvas.elementModel.controller = ShapesController; -// if(!canvas.elementModel.shapeModel) { -// canvas.elementModel.shapeModel = Montage.create(ShapeModel); -// } + styles = canvas.elementModel.data || {}; styles.top = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "top", parseInt) - 50) + "px"; styles.left = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "left", parseInt) - 50) + "px"; @@ -182,9 +179,9 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component var jStr = worldData.substr( index+1 ); jObj = JSON.parse( jStr ); - world = new World(canvas, jObj.useWebGl); + world = new World(canvas, jObj.webGL); canvas.elementModel.shapeModel.GLWorld = world; - canvas.elementModel.shapeModel.useWebGl = jObj.useWebGl; + canvas.elementModel.shapeModel.useWebGl = jObj.webGL; world.importJSON(jObj); this.application.ninja.currentDocument.buildShapeModel( canvas.elementModel, world ); } -- cgit v1.2.3 From c23f34ccc9a1624ab81b0cad04020fe7d1590b27 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Thu, 17 May 2012 10:12:21 -0700 Subject: cleanup Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index e84fcac7..7b4f8f32 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -175,7 +175,6 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component if ((worldData[0] === 'v') && (index < 24)) { // JSON format. separate the version info from the JSON info - //var vStr = importStr.substr( 0, index+1 ); var jStr = worldData.substr( index+1 ); jObj = JSON.parse( jStr ); -- cgit v1.2.3 From 11f3f8c02a3af6d59751235c3523cdab238f595c Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Thu, 24 May 2012 16:50:01 -0700 Subject: - multiple element copy/paste - in progress Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 268 ++++++++++++++++++++++++++------- 1 file changed, 210 insertions(+), 58 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index 7b4f8f32..354933a1 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -9,9 +9,7 @@ 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, - ShapesController = require("js/controllers/elements/shapes-controller").ShapesController, - ShapeModel = require("js/models/shape-model").ShapeModel; + World = require("js/lib/drawing/world").World; var ClipboardController = exports.ClipboardController = Montage.create(Component, { hasTemplate: { @@ -33,7 +31,7 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component }, copiedObjects:{ - value: null + value: [] }, _copyFlag:{ @@ -67,43 +65,12 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component }, handleCopy:{ - value:function(clipboardEvent){ - var elem = null, computedStyles = null, originalStyleAttr = null, computedStylesStr = "", i=0, stylePropertyName=""; + value:function(clipboardEvent, test){ if(this.application.ninja.documentController.activeDocument.currentView === "code") return; - if(this.application.ninja.selectedElements.length > 0){ - //handling 1 selected element for now - - if(this.application.ninja.selectedElements[0].tagName === "CANVAS"){ - this.copiedObjects = this.application.ninja.selectedElements[0]; - } - - elem = this.application.ninja.selectedElements[0]; - originalStyleAttr = elem.getAttribute("style");//preserve the current styles - elem.removeAttribute("style"); + this.copy(clipboardEvent); - //build the computed style attribute - computedStyles = elem.ownerDocument.defaultView.getComputedStyle(elem); - - //todo: consider cleaning up the position data [or making posiiton: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); - - //set clipboard data - clipboardEvent.clipboardData.setData('text/html', ''+this.application.ninja.selectedElements[0].outerHTML);//copying first selected element for POC - //clipboardEvent.clipboardData.setData('ninja', 'test');//works - - elem.setAttribute("style", originalStyleAttr);//reset style after copying to clipboard - - //end - handling 1 selected element - - clipboardEvent.preventDefault(); - } + clipboardEvent.preventDefault(); } }, @@ -114,27 +81,125 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component //TODO: return if stage is not focussed var clipboardData = clipboardEvent.clipboardData, + ninjaData = clipboardData.getData("ninja"), htmlData = clipboardData.getData("text/html"), textData = clipboardData.getData("text/plain"); - this.pasteItems(htmlData, textData); + this.pasteItems(ninjaData, htmlData, textData); clipboardEvent.preventDefault(); } }, - pasteItems:{ - value: function(htmlData, textData){ - var data = null, i=0, + pasteItems:{//todo: change to pasteNinja, pasteHTML, etc + value: function(ninjaData, htmlData, textData){ + var i=0, pasteDataObject=null, clipboardHelper=this.createClipboardHelper(), pastedElements = null, node = null, styles = null; - data = htmlData || textData; + if(ninjaData){//=> copy from ninja + //paste using in-memory clipboard helper + + + - if(htmlData){ + //TODO: cleanse HTML + + this.application.ninja.selectedElements.length = 0; + NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": true} ); + + clipboardHelper.innerHTML = htmlData;//add the copied html to generate the nodes + + while(clipboardHelper.hasChildNodes()){ + if(clipboardHelper.lastChild.tagName === "META") { + clipboardHelper.removeChild(clipboardHelper.lastChild);//remove unnecesary meta tag + } + else if (clipboardHelper.lastChild.tagName === "CANVAS"){//temporary - we probably won't need to serialize this to the system clipboard + + //only handling 1 canvas for POC + + + //clone copied canvas + var canvas = document.application.njUtils.make("canvas", this.copiedObjects.className, this.application.ninja.currentDocument); + canvas.width = this.copiedObjects.width; + canvas.height = this.copiedObjects.height; + //end - clone copied canvas + + if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); + document.application.njUtils.createModelWithShape(canvas); + + styles = canvas.elementModel.data || {}; + styles.top = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "top", parseInt) - 50) + "px"; + styles.left = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "left", parseInt) - 50) + "px"; + + this.application.ninja.elementMediator.addElements(canvas, styles, false); + + var world, worldData = this.copiedObjects.elementModel.shapeModel.GLWorld.exportJSON(); + 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.buildShapeModel( canvas.elementModel, world ); + } + + } + + NJevent("elementAdded", canvas); + + + clipboardHelper.removeChild(clipboardHelper.lastChild); + } + else if(clipboardHelper.lastChild.nodeType === 3){//TextNode + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + + //USE styles controller to create the styles of the div and span + var doc = this.application.ninja.currentDocument ? this.application.ninja.currentDocument._document : document; + var aspan = doc.createElement("span"); + aspan.appendChild(node); + var adiv = doc.createElement("div"); + adiv.appendChild(aspan); + styles = {"top":"100px", "left":"100px"}; + + + this.pastePositioned(node, styles); + } + else { + node = clipboardHelper.removeChild(clipboardHelper.lastChild); + + if(node.removeAttribute) {node.removeAttribute("style");}//remove the computed styles attribute which is placed only for pasting to external applications + + //get class string while copying .... generate styles from class + //styles = {"top":"100px", "left":"100px"}; + + this.pastePositioned(node, styles); + } + + } + + this.application.ninja.documentController.activeDocument.needsSave = true; + + + + + + + return; + } + else if(htmlData){ //TODO: cleanse HTML this.application.ninja.selectedElements.length = 0; @@ -259,20 +324,6 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component } }, - samplePasteJson:{ - value:{ - "htmlString" : "
", - "styles": {"position": "absolute", - "top": "304px", - "left": "318px", - "width": "125px", - "height": "71px", - "background-image": "none", - "background-color": "#2EFF5B"} - - } - }, - createClipboardHelper:{ value:function(){ var doc = this.application.ninja.currentDocument ? this.application.ninja.currentDocument._document : document, @@ -290,5 +341,106 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component } return clipboardHelper; } + }, + + /* + parameters: + */ + copy:{ + value: function(clipboardEvent){ + var j=0, htmlToClipboard = "", ninjaClipboardObj = {}; + this.copiedObjects.length = 0; + + if(clipboardEvent){ + for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage + this.copiedObjects.push(this.application.ninja.selectedElements[j]); + + if(this.application.ninja.selectedElements[0].tagName === "CANVAS"){ + if(!ninjaClipboardObj.canvas){ + ninjaClipboardObj.canvas = true; + } + }else{ + htmlToClipboard = htmlToClipboard + this.prepareOuterHtml(this.application.ninja.selectedElements[j]); + if(!ninjaClipboardObj.plainHtml){ + ninjaClipboardObj.plainHtml = true; + } + } + + } + //set clipboard data + clipboardEvent.clipboardData.setData('ninja', '' + JSON.stringify(ninjaClipboardObj)); + clipboardEvent.clipboardData.setData('text/html', '' + htmlToClipboard + '');//copying first selected element for POC + } + } + }, + + prepareOuterHtml:{ + 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; + } + }, + + copyMontageComponents:{ + value: function(){ + + } + }, + + /* + parameters: + */ + paste:{ + value: function(){ + + } + }, + + pasteHTML:{ + value: function(){ + + } + }, + + pasteImage:{ + value:function(){ + + } + }, + + pasteCanvasObjects:{ + value:function(){ + + } + }, + + pasteMontageComponents:{ + value: function(){ + + } } + + + }); \ No newline at end of file -- cgit v1.2.3 From c298c1d5f7e5e53206211717c832091a9a80ddb6 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Fri, 25 May 2012 17:31:58 -0700 Subject: multiple objects copy/paste - in progress Signed-off-by: Ananya Sen --- js/controllers/clipboard-controller.js | 236 ++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 110 deletions(-) (limited to 'js/controllers') diff --git a/js/controllers/clipboard-controller.js b/js/controllers/clipboard-controller.js index 354933a1..51f4ad14 100644 --- a/js/controllers/clipboard-controller.js +++ b/js/controllers/clipboard-controller.js @@ -30,6 +30,10 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component } }, + clipboardOperationsAgent:{//appropriate agent instant required for execution of cut/copy/paste + value: null + }, + copiedObjects:{ value: [] }, @@ -76,16 +80,25 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component handlePaste:{ value:function(clipboardEvent){ - if(this.application.ninja.documentController.activeDocument.currentView === "code") return; + if(this.application.ninja.documentController.activeDocument.currentView === "code") return;//for design view only //TODO: return if stage is not focussed + //identify all types of clipboard data + var clipboardData = clipboardEvent.clipboardData, ninjaData = clipboardData.getData("ninja"), htmlData = clipboardData.getData("text/html"), - textData = clipboardData.getData("text/plain"); + textData = clipboardData.getData("text/plain"), + imageData = clipboardData.getData("image/png"),//TODO: other img types, tiff, jpeg..... + svgData = clipboardData.getData("image/svg"); + + if(ninjaData){ + this.pasteFromNinja(); + }else { + this.pasteItems(null, htmlData, textData); + } - this.pasteItems(ninjaData, htmlData, textData); clipboardEvent.preventDefault(); } @@ -100,106 +113,7 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component node = null, styles = null; - if(ninjaData){//=> copy from ninja - //paste using in-memory clipboard helper - - - - - //TODO: cleanse HTML - - this.application.ninja.selectedElements.length = 0; - NJevent("selectionChange", {"elements": this.application.ninja.selectedElements, "isDocument": true} ); - - clipboardHelper.innerHTML = htmlData;//add the copied html to generate the nodes - - while(clipboardHelper.hasChildNodes()){ - if(clipboardHelper.lastChild.tagName === "META") { - clipboardHelper.removeChild(clipboardHelper.lastChild);//remove unnecesary meta tag - } - else if (clipboardHelper.lastChild.tagName === "CANVAS"){//temporary - we probably won't need to serialize this to the system clipboard - - //only handling 1 canvas for POC - - - //clone copied canvas - var canvas = document.application.njUtils.make("canvas", this.copiedObjects.className, this.application.ninja.currentDocument); - canvas.width = this.copiedObjects.width; - canvas.height = this.copiedObjects.height; - //end - clone copied canvas - - if (!canvas.getAttribute( "data-RDGE-id" )) canvas.setAttribute( "data-RDGE-id", NJUtils.generateRandom() ); - document.application.njUtils.createModelWithShape(canvas); - - styles = canvas.elementModel.data || {}; - styles.top = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "top", parseInt) - 50) + "px"; - styles.left = "" + (this.application.ninja.elementMediator.getProperty(this.copiedObjects, "left", parseInt) - 50) + "px"; - - this.application.ninja.elementMediator.addElements(canvas, styles, false); - - var world, worldData = this.copiedObjects.elementModel.shapeModel.GLWorld.exportJSON(); - 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.buildShapeModel( canvas.elementModel, world ); - } - - } - - NJevent("elementAdded", canvas); - - - clipboardHelper.removeChild(clipboardHelper.lastChild); - } - else if(clipboardHelper.lastChild.nodeType === 3){//TextNode - node = clipboardHelper.removeChild(clipboardHelper.lastChild); - - //USE styles controller to create the styles of the div and span - var doc = this.application.ninja.currentDocument ? this.application.ninja.currentDocument._document : document; - var aspan = doc.createElement("span"); - aspan.appendChild(node); - var adiv = doc.createElement("div"); - adiv.appendChild(aspan); - styles = {"top":"100px", "left":"100px"}; - - - this.pastePositioned(node, styles); - } - else { - node = clipboardHelper.removeChild(clipboardHelper.lastChild); - - if(node.removeAttribute) {node.removeAttribute("style");}//remove the computed styles attribute which is placed only for pasting to external applications - - //get class string while copying .... generate styles from class - //styles = {"top":"100px", "left":"100px"}; - - this.pastePositioned(node, styles); - } - - } - - this.application.ninja.documentController.activeDocument.needsSave = true; - - - - - - - return; - } - else if(htmlData){ + if(htmlData){ //TODO: cleanse HTML this.application.ninja.selectedElements.length = 0; @@ -348,33 +262,38 @@ var ClipboardController = exports.ClipboardController = Montage.create(Component */ copy:{ value: function(clipboardEvent){ - var j=0, htmlToClipboard = "", ninjaClipboardObj = {}; + var j=0, htmlToClipboard = "", ninjaClipboardObj = {}, textToClipboard = ""; this.copiedObjects.length = 0; if(clipboardEvent){ for(j=0; j < this.application.ninja.selectedElements.length; j++){//copying from stage this.copiedObjects.push(this.application.ninja.selectedElements[j]); - if(this.application.ninja.selectedElements[0].tagName === "CANVAS"){ + if(this.application.ninja.selectedElements[j].tagName === "CANVAS"){ if(!ninjaClipboardObj.canvas){ ninjaClipboardObj.canvas = true; } }else{ - htmlToClipboard = htmlToClipboard + this.prepareOuterHtml(this.application.ninja.selectedElements[j]); + htmlToClipboard = htmlToClipboard + this.serialize(this.application.ninja.selectedElements[j]); if(!ninjaClipboardObj.plainHtml){ ninjaClipboardObj.plainHtml = true; } + textToClipboard = textToClipboard + this.getText(this.application.ninja.selectedElements[j]) + " "; } }