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.

This commit is contained in:
Jürg Lehni 2011-05-14 14:15:31 +03:00
parent 3072eed91d
commit 518803f492
5 changed files with 95 additions and 61 deletions

View file

@ -38,5 +38,19 @@ var PaperScope = this.PaperScope = Base.extend({
return Base.each(this, function(value, key) { return Base.each(this, function(value, key) {
this[key] = value; this[key] = value;
}, scope); }, 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();
}
} }
}); });

View file

@ -18,7 +18,7 @@ var Document = this.Document = Base.extend({
beans: true, beans: true,
initialize: function(canvas) { initialize: function(canvas) {
// Store reference to currently active global paper scope: // Store reference to the currently active global paper scope:
this._scope = paper; this._scope = paper;
if (canvas && canvas instanceof HTMLCanvasElement) { if (canvas && canvas instanceof HTMLCanvasElement) {
this.canvas = canvas; this.canvas = canvas;

View file

@ -24,18 +24,22 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
beans: true, beans: true,
initialize: function(handlers, doc) { initialize: function(handlers, doc) {
this.base(handlers); this.base(handlers, doc._scope);
// Create events once, so they can be removed easily too. this._document = doc;
var that = this, curPoint;
var curPoint;
var dragging = false; var dragging = false;
this.events = { var that = this;
// TODO: Move event handling to DocumentView
var events = {
mousedown: function(event) { mousedown: function(event) {
curPoint = viewToArtwork(event, that._document); curPoint = viewToArtwork(event, that._document);
that.onHandleEvent('mousedown', curPoint, event); that.onHandleEvent('mousedown', curPoint, event);
if (that.onMouseDown) if (that.onMouseDown) {
that._document.redraw(); that._document.redraw();
}
if (that.eventInterval != null) { if (that.eventInterval != null) {
this.timer = setInterval(that.events.mousemove, this.timer = setInterval(events.mousemove,
that.eventInterval); that.eventInterval);
} }
dragging = true; dragging = true;
@ -45,54 +49,55 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
// If the event was triggered by a touch screen device, // If the event was triggered by a touch screen device,
// prevent the default behaviour, as it will otherwise // prevent the default behaviour, as it will otherwise
// scroll the page: // scroll the page:
if (event && event.targetTouches) if (event && event.targetTouches) {
event.preventDefault(); DomEvent.preventDefault(event);
}
var point = event && viewToArtwork(event, that._document); var point = event && viewToArtwork(event, that._document);
// If there is only an onMouseMove handler, call it when // If there is only an onMouseMove handler, call it when
// the user is dragging // the user is dragging
var onlyMove = !!(!that.onMouseDrag && that.onMouseMove); var onlyMove = !!(!that.onMouseDrag && that.onMouseMove);
if (dragging && !onlyMove) { if (dragging && !onlyMove) {
curPoint = point || curPoint; curPoint = point || curPoint;
if (curPoint) if (curPoint) {
that.onHandleEvent('mousedrag', curPoint, event); that.onHandleEvent('mousedrag', curPoint, event);
}
} else if (!dragging || onlyMove) { } else if (!dragging || onlyMove) {
that.onHandleEvent('mousemove', point, event); that.onHandleEvent('mousemove', point, event);
} }
if (that.onMouseMove || that.onMouseDrag) if (that.onMouseMove || that.onMouseDrag) {
that._document.redraw(); that._document.redraw();
}
}, },
mouseup: function(event) { mouseup: function(event) {
if (dragging) { if (dragging) {
curPoint = null; curPoint = null;
if (that.eventInterval != null) if (that.eventInterval != null) {
clearInterval(this.timer); clearInterval(this.timer);
}
that.onHandleEvent('mouseup', that.onHandleEvent('mouseup',
viewToArtwork(event, that._document), event); viewToArtwork(event, that._document), event);
if (that.onMouseUp) if (that.onMouseUp) {
that._document.redraw(); that._document.redraw();
}
dragging = false; dragging = false;
} }
}, },
touchmove: function(event) { touchmove: function(event) {
that.events.mousemove(event); events.mousemove(event);
}, },
touchstart: function(event) { touchstart: function(event) {
that.events.mousedown(event); events.mousedown(event);
}, },
touchend: function(event) { touchend: function(event) {
that.events.mouseup(event); events.mouseup(event);
} }
}; };
// Remove old events first. DomEvent.add(doc.canvas, events);
if (this._document)
DomEvent.remove(this._document.canvas, this.events);
this._document = doc;
DomEvent.add(doc.canvas, this.events);
}, },
getDocument: function() { getDocument: function() {

View file

@ -21,6 +21,7 @@ var ToolHandler = this.ToolHandler = Base.extend({
* Initializes the tool's settings, so a new tool can be assigned to it * Initializes the tool's settings, so a new tool can be assigned to it
*/ */
initialize: function(handlers, scope) { initialize: function(handlers, scope) {
this._scope = scope;
this._firstMove = true; this._firstMove = true;
this._count = 0; this._count = 0;
this._downCount = 0; this._downCount = 0;
@ -120,6 +121,7 @@ var ToolHandler = this.ToolHandler = Base.extend({
}, },
onHandleEvent: function(type, pt, event) { onHandleEvent: function(type, pt, event) {
PaperScope.set(this._scope);
switch (type) { switch (type) {
case 'mousedown': case 'mousedown':
this.updateEvent(type, pt, null, null, true, false, false); this.updateEvent(type, pt, null, null, true, false, false);
@ -176,5 +178,6 @@ var ToolHandler = this.ToolHandler = Base.extend({
} }
break; break;
} }
PaperScope.restore();
} }
}); });

View file

@ -129,14 +129,19 @@ var PaperScript = this.PaperScript = new function() {
return parse_js.stringify(ast, true); return parse_js.stringify(ast, true);
} }
function run(code) { function run(code, scope) {
with (paper) { try { with (scope) { // Safe one indentation by grouping try and with
var doc = paper.document, PaperScope.set(scope);
tool = paper.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) var doc = scope.document;
&& new Tool(null, doc), // TODO: Add support for multiple tools
onEditOptions, onSelect, onDeselect, onReselect, onMouseDown, var tool = scope.tool =
onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp, /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)
res = eval(compile(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) { if (tool) {
Base.each(['onEditOptions', 'onSelect', 'onDeselect', Base.each(['onEditOptions', 'onSelect', 'onDeselect',
'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag',
@ -146,44 +151,44 @@ var PaperScript = this.PaperScript = new function() {
} }
); );
} }
try { // TODO: Move onFrame support to DocumentView
var onFrame = eval('onFrame'); var onFrame = eval('onFrame');
if (onFrame) { if (onFrame) {
var lastTime; var lastTime;
var totalTime = 0; var totalTime = 0;
function frame() { function frame() {
// Request next frame already // Request next frame already
DomEvent.requestAnimationFrame(frame, doc && doc.canvas); DomEvent.requestAnimationFrame(frame, doc && doc.canvas);
var time = Date.now() / 1000; var time = Date.now() / 1000;
// Time elapsed since last redraw in seconds: // Time elapsed since last redraw in seconds:
var delta = lastTime ? time - lastTime : 0; var delta = lastTime ? time - lastTime : 0;
// Time since first call of frame() in seconds: // Time since first call of frame() in seconds:
totalTime += delta; totalTime += delta;
onFrame({ onFrame({
delta: delta, delta: delta,
time: totalTime time: totalTime
}); });
// Automatically redraw document each frame. // 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.
if (doc) if (doc)
doc.redraw(); doc.redraw();
} lastTime = time;
} catch (e) { };
// Call the onFrame handler and redraw the document:
frame();
} else {
// Automatically redraw document at the end.
if (doc)
doc.redraw();
} }
return res; return res;
} } finally {
PaperScope.restore();
} }
} }
//#ifdef BROWSER //#ifdef BROWSER
// Code borrowed from Coffee Script: // Code borrowed from Coffee Script:
function request(url) { function request(url, scope) {
var xhr = new (window.ActiveXObject || XMLHttpRequest)( var xhr = new (window.ActiveXObject || XMLHttpRequest)(
'Microsoft.XMLHTTP'); 'Microsoft.XMLHTTP');
xhr.open('GET', url, true); xhr.open('GET', url, true);
@ -192,7 +197,7 @@ var PaperScript = this.PaperScript = new function() {
} }
xhr.onreadystatechange = function() { xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
return run(xhr.responseText); return run(xhr.responseText, scope);
} }
}; };
return xhr.send(null); return xhr.send(null);
@ -205,16 +210,23 @@ var PaperScript = this.PaperScript = new function() {
// Only load this cript if it not loaded already. // Only load this cript if it not loaded already.
if (script.type === 'text/paperscript' if (script.type === 'text/paperscript'
&& !script.getAttribute('loaded')) { && !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, // If a canvas id is provided, create a document for it now,
// so the active document is defined. // so the active document is defined.
var canvas = script.getAttribute('canvas'); var canvas = script.getAttribute('canvas');
if (canvas = canvas && document.getElementById(canvas)) { if (canvas = canvas && document.getElementById(canvas)) {
// Create a Document for this canvas, using the right scope
PaperScope.set(scope);
new Document(canvas); new Document(canvas);
PaperScope.restore();
} }
if (script.src) { if (script.src) {
request(script.src); request(script.src, scope);
} else { } else {
run(script.innerHTML); run(script.innerHTML, scope);
} }
// Mark script as loaded now. // Mark script as loaded now.
script.setAttribute('loaded', true); script.setAttribute('loaded', true);