From 518803f492940aafc0be95ddea3e65f41e8746e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sat, 14 May 2011 14:15:31 +0300 Subject: [PATCH] Add support for switching PaperScope contexts in PaperScript code exeuction and callback handling. This should add proper support for multiple PaperScript instances in one site. --- src/core/PaperScope.js | 14 ++++++ src/document/Document.js | 2 +- src/tool/Tool.js | 45 +++++++++++--------- src/tool/ToolHandler.js | 3 ++ src/util/PaperScript.js | 92 +++++++++++++++++++++++----------------- 5 files changed, 95 insertions(+), 61 deletions(-) diff --git a/src/core/PaperScope.js b/src/core/PaperScope.js index 6c25586e..68812b96 100644 --- a/src/core/PaperScope.js +++ b/src/core/PaperScope.js @@ -38,5 +38,19 @@ var PaperScope = this.PaperScope = Base.extend({ return Base.each(this, function(value, key) { this[key] = value; }, scope); + }, + + // Methods for setting and restoring paper scopes: + statics: { + scopes: [], + + set: function(scope) { + this.scopes.push(paper); + paper = scope; + }, + + restore: function() { + paper = this.scopes.pop(); + } } }); diff --git a/src/document/Document.js b/src/document/Document.js index e7976884..38eb9f8e 100644 --- a/src/document/Document.js +++ b/src/document/Document.js @@ -18,7 +18,7 @@ var Document = this.Document = Base.extend({ beans: true, initialize: function(canvas) { - // Store reference to currently active global paper scope: + // Store reference to the currently active global paper scope: this._scope = paper; if (canvas && canvas instanceof HTMLCanvasElement) { this.canvas = canvas; diff --git a/src/tool/Tool.js b/src/tool/Tool.js index 0717fccd..869c97e6 100644 --- a/src/tool/Tool.js +++ b/src/tool/Tool.js @@ -24,18 +24,22 @@ var Tool = this.Tool = ToolHandler.extend(new function() { beans: true, initialize: function(handlers, doc) { - this.base(handlers); - // Create events once, so they can be removed easily too. - var that = this, curPoint; + this.base(handlers, doc._scope); + this._document = doc; + + var curPoint; var dragging = false; - this.events = { + var that = this; + // TODO: Move event handling to DocumentView + var events = { mousedown: function(event) { curPoint = viewToArtwork(event, that._document); that.onHandleEvent('mousedown', curPoint, event); - if (that.onMouseDown) + if (that.onMouseDown) { that._document.redraw(); + } if (that.eventInterval != null) { - this.timer = setInterval(that.events.mousemove, + this.timer = setInterval(events.mousemove, that.eventInterval); } dragging = true; @@ -45,54 +49,55 @@ var Tool = this.Tool = ToolHandler.extend(new function() { // If the event was triggered by a touch screen device, // prevent the default behaviour, as it will otherwise // scroll the page: - if (event && event.targetTouches) - event.preventDefault(); + if (event && event.targetTouches) { + DomEvent.preventDefault(event); + } var point = event && viewToArtwork(event, that._document); // If there is only an onMouseMove handler, call it when // the user is dragging var onlyMove = !!(!that.onMouseDrag && that.onMouseMove); if (dragging && !onlyMove) { curPoint = point || curPoint; - if (curPoint) + if (curPoint) { that.onHandleEvent('mousedrag', curPoint, event); + } } else if (!dragging || onlyMove) { that.onHandleEvent('mousemove', point, event); } - if (that.onMouseMove || that.onMouseDrag) + if (that.onMouseMove || that.onMouseDrag) { that._document.redraw(); + } }, mouseup: function(event) { if (dragging) { curPoint = null; - if (that.eventInterval != null) + if (that.eventInterval != null) { clearInterval(this.timer); + } that.onHandleEvent('mouseup', viewToArtwork(event, that._document), event); - if (that.onMouseUp) + if (that.onMouseUp) { that._document.redraw(); + } dragging = false; } }, touchmove: function(event) { - that.events.mousemove(event); + events.mousemove(event); }, touchstart: function(event) { - that.events.mousedown(event); + events.mousedown(event); }, touchend: function(event) { - that.events.mouseup(event); + events.mouseup(event); } }; - // Remove old events first. - if (this._document) - DomEvent.remove(this._document.canvas, this.events); - this._document = doc; - DomEvent.add(doc.canvas, this.events); + DomEvent.add(doc.canvas, events); }, getDocument: function() { diff --git a/src/tool/ToolHandler.js b/src/tool/ToolHandler.js index 7c4debf2..8a3510b2 100644 --- a/src/tool/ToolHandler.js +++ b/src/tool/ToolHandler.js @@ -21,6 +21,7 @@ var ToolHandler = this.ToolHandler = Base.extend({ * Initializes the tool's settings, so a new tool can be assigned to it */ initialize: function(handlers, scope) { + this._scope = scope; this._firstMove = true; this._count = 0; this._downCount = 0; @@ -120,6 +121,7 @@ var ToolHandler = this.ToolHandler = Base.extend({ }, onHandleEvent: function(type, pt, event) { + PaperScope.set(this._scope); switch (type) { case 'mousedown': this.updateEvent(type, pt, null, null, true, false, false); @@ -176,5 +178,6 @@ var ToolHandler = this.ToolHandler = Base.extend({ } break; } + PaperScope.restore(); } }); diff --git a/src/util/PaperScript.js b/src/util/PaperScript.js index 58b1d1e9..e04dc35a 100644 --- a/src/util/PaperScript.js +++ b/src/util/PaperScript.js @@ -129,14 +129,19 @@ var PaperScript = this.PaperScript = new function() { return parse_js.stringify(ast, true); } - function run(code) { - with (paper) { - var doc = paper.document, - tool = paper.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) - && new Tool(null, doc), - onEditOptions, onSelect, onDeselect, onReselect, onMouseDown, - onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp, - res = eval(compile(code)); + function run(code, scope) { + try { with (scope) { // Safe one indentation by grouping try and with + PaperScope.set(scope); + var doc = scope.document; + // TODO: Add support for multiple tools + var tool = scope.tool = + /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) + && new Tool(null, doc); + // Define variables for potential handlers, so eval() calls below to + // fetch their values do not require try-catch around them. + var onEditOptions, onSelect, onDeselect, onReselect, onMouseDown, + onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp, onFrame; + var res = eval(compile(code)); if (tool) { Base.each(['onEditOptions', 'onSelect', 'onDeselect', 'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag', @@ -146,44 +151,44 @@ var PaperScript = this.PaperScript = new function() { } ); } - try { - var onFrame = eval('onFrame'); - if (onFrame) { - var lastTime; - var totalTime = 0; - function frame() { - // Request next frame already - DomEvent.requestAnimationFrame(frame, doc && doc.canvas); - var time = Date.now() / 1000; - // Time elapsed since last redraw in seconds: - var delta = lastTime ? time - lastTime : 0; - // Time since first call of frame() in seconds: - totalTime += delta; - onFrame({ - delta: delta, - time: totalTime - }); - // Automatically redraw document each frame. - if (doc) - doc.redraw(); - lastTime = time; - }; - // Call the onFrame handler and redraw the document: - frame(); - } else { - // Automatically redraw document at the end. + // TODO: Move onFrame support to DocumentView + var onFrame = eval('onFrame'); + if (onFrame) { + var lastTime; + var totalTime = 0; + function frame() { + // Request next frame already + DomEvent.requestAnimationFrame(frame, doc && doc.canvas); + var time = Date.now() / 1000; + // Time elapsed since last redraw in seconds: + var delta = lastTime ? time - lastTime : 0; + // Time since first call of frame() in seconds: + totalTime += delta; + onFrame({ + delta: delta, + time: totalTime + }); + // Automatically redraw document each frame. if (doc) doc.redraw(); - } - } catch (e) { + lastTime = time; + }; + // Call the onFrame handler and redraw the document: + frame(); + } else { + // Automatically redraw document at the end. + if (doc) + doc.redraw(); } return res; + } } finally { + PaperScope.restore(); } } //#ifdef BROWSER // Code borrowed from Coffee Script: - function request(url) { + function request(url, scope) { var xhr = new (window.ActiveXObject || XMLHttpRequest)( 'Microsoft.XMLHTTP'); xhr.open('GET', url, true); @@ -192,7 +197,7 @@ var PaperScript = this.PaperScript = new function() { } xhr.onreadystatechange = function() { if (xhr.readyState === 4) { - return run(xhr.responseText); + return run(xhr.responseText, scope); } }; return xhr.send(null); @@ -205,16 +210,23 @@ var PaperScript = this.PaperScript = new function() { // Only load this cript if it not loaded already. if (script.type === 'text/paperscript' && !script.getAttribute('loaded')) { + // Produce a new PaperScope for this script now. Scopes are + // cheap so let's not worry about the initial one that was + // already created. + var scope = new PaperScope(); // If a canvas id is provided, create a document for it now, // so the active document is defined. var canvas = script.getAttribute('canvas'); if (canvas = canvas && document.getElementById(canvas)) { + // Create a Document for this canvas, using the right scope + PaperScope.set(scope); new Document(canvas); + PaperScope.restore(); } if (script.src) { - request(script.src); + request(script.src, scope); } else { - run(script.innerHTML); + run(script.innerHTML, scope); } // Mark script as loaded now. script.setAttribute('loaded', true);