mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Merge branch 'refs/heads/paperscript-refactoring'
Conflicts: src/core/PaperScope.js
This commit is contained in:
commit
57f1763abe
10 changed files with 192 additions and 166 deletions
|
@ -1,7 +1,7 @@
|
|||
require('paper');
|
||||
var paper = require('./Tadpoles.pjs');
|
||||
var paper = require('paper');
|
||||
var scope = require('./Tadpoles.pjs')(new paper.Size(1024, 768));
|
||||
|
||||
paper.view.exportFrames({
|
||||
scope.view.exportFrames({
|
||||
amount: 400,
|
||||
directory: __dirname,
|
||||
onComplete: function() {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
paper.setup(new Canvas(1024, 768));
|
||||
|
||||
// Adapted from Flocking Processing example by Daniel Schiffman:
|
||||
// http://processing.org/learning/topics/flocking.html
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"uglify-js": "~2.3.6",
|
||||
"prepro": "~0.8.0",
|
||||
"prepro": "~0.8.1",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-uglify": "~0.2.2"
|
||||
},
|
||||
|
|
|
@ -102,16 +102,9 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
|
||||
/**
|
||||
* The reference to the active tool.
|
||||
* @name PaperScope#tool
|
||||
* @type Tool
|
||||
* @bean
|
||||
*/
|
||||
getTool: function() {
|
||||
// If no tool exists yet but one is requested, produce it now on the fly
|
||||
// so it can be used in PaperScript.
|
||||
if (!this._tool)
|
||||
this._tool = new Tool();
|
||||
return this._tool;
|
||||
},
|
||||
|
||||
/**
|
||||
* The list of available tools.
|
||||
|
@ -131,10 +124,9 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
return this;
|
||||
},
|
||||
|
||||
evaluate: function(code) {
|
||||
var res = paper.PaperScript.evaluate(code, this);
|
||||
execute: function(code) {
|
||||
paper.PaperScript.execute(code, this);
|
||||
View.updateFocus();
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -166,10 +158,10 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
// Copy over all fields from this scope to the destination.
|
||||
// Do not use Base.each, since we also want to enumerate over
|
||||
// fields on PaperScope.prototype, e.g. all classes
|
||||
for (var key in this) {
|
||||
if (!/^(version|_id)/.test(key))
|
||||
for (var key in this)
|
||||
// Exclude all 'hidden' fields
|
||||
if (!/^_/.test(key))
|
||||
scope[key] = this[key];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -228,14 +220,14 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
_id: 0,
|
||||
|
||||
/**
|
||||
* Retrieves a PaperScope object with the given id or associated with
|
||||
* the passed canvas element.
|
||||
* Retrieves a PaperScope object with the given id or associated
|
||||
* with the passed canvas element.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
get: function(id) {
|
||||
// If a script tag is passed, get the id from it.
|
||||
if (typeof id === 'object')
|
||||
if (id && id.getAttribute)
|
||||
id = id.getAttribute('id');
|
||||
return this._scopes[id] || null;
|
||||
},
|
||||
|
|
|
@ -14,19 +14,10 @@
|
|||
* @name PaperScript
|
||||
* @namespace
|
||||
*/
|
||||
// Note that due to the use of with(), PaperScript gets compiled outside the
|
||||
// main paper scope, and is added to the PaperScope class. This allows for
|
||||
// better minification and the future use of strict mode once it makes sense
|
||||
// in terms of performance.
|
||||
paper.PaperScope.prototype.PaperScript = (function(root) {
|
||||
var Base = paper.Base,
|
||||
PaperScope = paper.PaperScope,
|
||||
// For local reference, for now only when setting lineNumberBase on
|
||||
// Firefox.
|
||||
PaperScript,
|
||||
// Locally turn of exports and define for inlined acorn / esprima.
|
||||
// Just declaring the local vars is enough, as they will be undefined.
|
||||
exports, define,
|
||||
var PaperScript = Base.exports.PaperScript = (function(root) {
|
||||
// Locally turn of exports and define for inlined acorn / esprima.
|
||||
// Just declaring the local vars is enough, as they will be undefined.
|
||||
var exports, define,
|
||||
// The scope into which the library is loaded.
|
||||
scope = this;
|
||||
/*#*/ if (__options.version == 'dev') {
|
||||
|
@ -69,9 +60,9 @@ paper.PaperScope.prototype.PaperScript = (function(root) {
|
|||
},
|
||||
{}
|
||||
);
|
||||
paper.Point.inject(fields);
|
||||
paper.Size.inject(fields);
|
||||
paper.Color.inject(fields);
|
||||
Point.inject(fields);
|
||||
Size.inject(fields);
|
||||
Color.inject(fields);
|
||||
|
||||
// Use very short name for the binary operator (_$_) as well as the
|
||||
// unary operator ($_), as operations will be replaced with then.
|
||||
|
@ -238,97 +229,117 @@ paper.PaperScope.prototype.PaperScript = (function(root) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Evaluates parsed PaperScript code in the passed {@link PaperScope}
|
||||
* object. It also installs handlers automatically for us.
|
||||
* Executes the parsed PaperScript code in a compiled function that receives
|
||||
* all properties of the passed {@link PaperScope} as arguments, to emulate
|
||||
* a global scope with unaffected performance. It also installs global view
|
||||
* and tool handlers automatically for you.
|
||||
*
|
||||
* @name PaperScript.evaluate
|
||||
* @name PaperScript.execute
|
||||
* @function
|
||||
* @param {String} code The PaperScript code
|
||||
* @param {PaperScript} scope The scope in which the code is executed
|
||||
* @return {Object} the result of the code evaluation
|
||||
* @param {PaperScript} scope The scope for which the code is executed
|
||||
*/
|
||||
function evaluate(code, scope) {
|
||||
function execute(code, scope) {
|
||||
// Set currently active scope.
|
||||
paper = scope;
|
||||
var view = scope.project && scope.project.view,
|
||||
var view = scope.getView(),
|
||||
// Only create a tool object if something resembling a tool handler
|
||||
// definition is contained in the code.
|
||||
tool = /\s+on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)
|
||||
? new Tool()
|
||||
: null,
|
||||
toolHandlers = tool ? tool._events : [],
|
||||
// Compile a list of all handlers that can be defined globally
|
||||
// inside the PaperScript. These are passed on to the function as
|
||||
// undefined arguments, so that their name exists, rather than
|
||||
// injecting a code line that defines them as variables.
|
||||
// They are exported again at the end of the function.
|
||||
handlers = ['onFrame', 'onResize'].concat(toolHandlers),
|
||||
res;
|
||||
// Define variables for potential handlers, so eval() calls below to
|
||||
// fetch their values do not require try-catch around them.
|
||||
// Use with() {} in order to make the scope the current 'global' scope
|
||||
// instead of window.
|
||||
with (scope) {
|
||||
// Within this, use a function scope, so local variables to not try
|
||||
// and set themselves on the scope object.
|
||||
(function() {
|
||||
var onActivate, onDeactivate, onEditOptions,
|
||||
onMouseDown, onMouseUp, onMouseDrag, onMouseMove,
|
||||
onKeyDown, onKeyUp, onFrame, onResize;
|
||||
code = compile(code);
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
if (root.InstallTrigger) { // Firefox
|
||||
// On Firefox, all error numbers inside evaled code are
|
||||
// relative to the line where the eval happened. Totally
|
||||
// silly, but that's how it is. So we're calculating the
|
||||
// base of lineNumbers, to remove it again from reported
|
||||
// errors. Luckily, Firefox is the only browser where we can
|
||||
// define the lineNumber for exceptions.
|
||||
var handle = PaperScript.handleException;
|
||||
if (!handle) {
|
||||
handle = PaperScript.handleException = function(e) {
|
||||
throw e.lineNumber >= lineNumber
|
||||
? new Error(e.message, e.fileName,
|
||||
e.lineNumber - lineNumber)
|
||||
: e;
|
||||
}
|
||||
// We're using a crazy hack to detect wether the library
|
||||
// is minified or not: By generating a second error on
|
||||
// the 2nd line and using the difference in line numbers
|
||||
// to calculate the offset to the eval, it works in both
|
||||
// casees.
|
||||
var lineNumber = new Error().lineNumber;
|
||||
lineNumber += (new Error().lineNumber - lineNumber) * 3;
|
||||
}
|
||||
try {
|
||||
// Add a semi-colon at the start so Firefox doesn't
|
||||
// swallow empty lines and shift error messages.
|
||||
res = eval(';' + code);
|
||||
} catch (e) {
|
||||
handle(e);
|
||||
}
|
||||
} else {
|
||||
res = eval(code);
|
||||
}
|
||||
/*#*/ } else { // !__options.environment == 'browser'
|
||||
res = eval(code);
|
||||
/*#*/ } // !__options.environment == 'browser'
|
||||
// Only look for tool handlers if something resembling their
|
||||
// name is contained in the code.
|
||||
if (/on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)) {
|
||||
Base.each(paper.Tool.prototype._events, function(key) {
|
||||
var value = eval(key);
|
||||
if (value) {
|
||||
// Use the getTool accessor that handles auto tool
|
||||
// creation for us:
|
||||
scope.getTool()[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (view) {
|
||||
view.setOnResize(onResize);
|
||||
// Fire resize event directly, so any user
|
||||
// defined resize handlers are called.
|
||||
view.fire('resize', {
|
||||
size: view.size,
|
||||
delta: new Point()
|
||||
});
|
||||
if (onFrame)
|
||||
view.setOnFrame(onFrame);
|
||||
// Automatically update view at the end.
|
||||
view.update();
|
||||
}
|
||||
}).call(scope);
|
||||
code = compile(code);
|
||||
// compile a list of paramter names for all variables that need to
|
||||
// appear as globals inside the script. At the same time, also collect
|
||||
// their values, so we can pass them on as arguments in the function
|
||||
// call.
|
||||
var params = ['_$_', '$_', 'view', 'tool'],
|
||||
args = [_$_, $_ , view, tool];
|
||||
// Look through all enumerable properties on the scope and expose these
|
||||
// too as pseudo-globals.
|
||||
for (var key in scope) {
|
||||
if (!/^_/.test(key)) {
|
||||
params.push(key);
|
||||
args.push(scope[key]);
|
||||
}
|
||||
}
|
||||
// Finally define the handler variable names as parameters and compose
|
||||
// the string describing the properties for the returned object at the
|
||||
// end of the code execution, so we can retrieve their values from the
|
||||
// function call.
|
||||
handlers = Base.each(handlers, function(key) {
|
||||
params.push(key);
|
||||
this.push(key + ': ' + key);
|
||||
}, []).join(', ');
|
||||
// We need an additional line that returns the handlers in one object.
|
||||
code += '\nreturn { ' + handlers + ' };';
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
if (root.InstallTrigger) { // Firefox
|
||||
// Add a semi-colon at the start so Firefox doesn't swallow empty
|
||||
// lines and shift error messages.
|
||||
code = ';' + code;
|
||||
// On Firefox, all error numbers inside evaled code are relative to
|
||||
// the line where the eval happened. Totally silly, but that's how
|
||||
// it is. So we're calculating the base of lineNumbers, to remove it
|
||||
// again from reported errors. Luckily, Firefox is the only browser
|
||||
// where we can define the lineNumber for exceptions.
|
||||
var handle = PaperScript.handleException;
|
||||
if (!handle) {
|
||||
handle = PaperScript.handleException = function(e) {
|
||||
throw e.lineNumber >= lineNumber
|
||||
? new Error(e.message, e.fileName,
|
||||
e.lineNumber - lineNumber)
|
||||
: e;
|
||||
};
|
||||
// We're using a crazy hack to detect wether the library is
|
||||
// minified or not: By generating a second error on the 2nd line
|
||||
// and using the difference in line numbers to calculate the
|
||||
// offset to the eval, it works in both casees.
|
||||
var lineNumber = new Error().lineNumber;
|
||||
lineNumber += (new Error().lineNumber - lineNumber) * 3;
|
||||
}
|
||||
try {
|
||||
res = new Function(params, code).apply(scope, args);
|
||||
// NOTE: in order for the calculation of the above lineNumber
|
||||
// offset to work, we cannot add any statements before the above
|
||||
// line of code, nor can we put it into a separate function.
|
||||
} catch (e) {
|
||||
handle(e);
|
||||
}
|
||||
} else {
|
||||
res = new Function(params, code).apply(scope, args);
|
||||
}
|
||||
/*#*/ } else { // !__options.environment == 'browser'
|
||||
res = new Function(params, code).apply(scope, args);
|
||||
/*#*/ } // !__options.environment == 'browser'
|
||||
// Now install the 'global' tool and view handlers, and we're done!
|
||||
Base.each(toolHandlers, function(key) {
|
||||
var value = res[key];
|
||||
if (value)
|
||||
tool[key] = value;
|
||||
});
|
||||
if (view) {
|
||||
if (res.onResize)
|
||||
view.setOnResize(res.onResize);
|
||||
// Fire resize event directly, so any user
|
||||
// defined resize handlers are called.
|
||||
view.fire('resize', {
|
||||
size: view.size,
|
||||
delta: new Point()
|
||||
});
|
||||
if (res.onFrame)
|
||||
view.setOnFrame(res.onFrame);
|
||||
// Automatically update view at the end.
|
||||
view.update();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
|
@ -356,12 +367,12 @@ paper.PaperScope.prototype.PaperScript = (function(root) {
|
|||
if (src) {
|
||||
// If we're loading from a source, request that first and
|
||||
// then run later.
|
||||
paper.Http.request('get', src, function(code) {
|
||||
evaluate(code, scope);
|
||||
Http.request('get', src, function(code) {
|
||||
execute(code, scope);
|
||||
});
|
||||
} else {
|
||||
// We can simply get the code form the script tag.
|
||||
evaluate(script.innerHTML, scope);
|
||||
execute(script.innerHTML, scope);
|
||||
}
|
||||
// Mark script as loaded now.
|
||||
script.setAttribute('data-paper-ignore', true);
|
||||
|
@ -375,12 +386,12 @@ paper.PaperScope.prototype.PaperScript = (function(root) {
|
|||
// Handle it asynchronously
|
||||
setTimeout(load);
|
||||
} else {
|
||||
paper.DomEvent.add(window, { load: load });
|
||||
DomEvent.add(window, { load: load });
|
||||
}
|
||||
|
||||
return PaperScript = {
|
||||
return {
|
||||
compile: compile,
|
||||
evaluate: evaluate,
|
||||
execute: execute,
|
||||
load: load,
|
||||
lineNumberBase: 0
|
||||
};
|
||||
|
@ -393,22 +404,28 @@ paper.PaperScope.prototype.PaperScript = (function(root) {
|
|||
path = require('path');
|
||||
|
||||
require.extensions['.pjs'] = function(module, uri) {
|
||||
var source = compile(fs.readFileSync(uri, 'utf8')),
|
||||
scope = new PaperScope();
|
||||
scope.__filename = uri;
|
||||
scope.__dirname = path.dirname(uri);
|
||||
// Expose core methods and values
|
||||
scope.require = require;
|
||||
scope.console = console;
|
||||
evaluate(source, scope);
|
||||
module.exports = scope;
|
||||
// Requiring a PaperScript on Node.js returns an initialize method which
|
||||
// needs to receive a Canvas object when called and returns the
|
||||
// PaperScope.
|
||||
module.exports = function(canvas) {
|
||||
var source = compile(fs.readFileSync(uri, 'utf8')),
|
||||
scope = new PaperScope();
|
||||
scope.setup(canvas);
|
||||
scope.__filename = uri;
|
||||
scope.__dirname = path.dirname(uri);
|
||||
// Expose core methods and values
|
||||
scope.require = require;
|
||||
scope.console = console;
|
||||
execute(source, scope);
|
||||
return scope;
|
||||
};
|
||||
};
|
||||
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
|
||||
return PaperScript = {
|
||||
return {
|
||||
compile: compile,
|
||||
evaluate: evaluate
|
||||
execute: execute
|
||||
};
|
||||
|
||||
/*#*/ } // !__options.environment == 'browser'
|
||||
|
|
|
@ -10,16 +10,19 @@
|
|||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** @scope _global_ */ {
|
||||
|
||||
// DOCS: Find a way to put this description into _global_
|
||||
|
||||
/**
|
||||
* In a PaperScript context, the global scope is populated with all
|
||||
* fields of the currently active {@link PaperScope} object. In a JavaScript
|
||||
* context, it only contains the {@link #paper} reference to the currently
|
||||
* active {@link PaperScope} object, which also exposes all Paper classes.
|
||||
*/
|
||||
/**
|
||||
* @name _global_
|
||||
* @namespace
|
||||
*
|
||||
* When code is executed as PaperScript, the script's scope is populated with
|
||||
* all fields of the currently active {@link PaperScope} object, which within
|
||||
* the script appear to be global.
|
||||
*
|
||||
* In a JavaScript context, only the {@link paper} variable is added to the
|
||||
* global scope, referencing the currently active {@link PaperScope} object,
|
||||
* through which all properties and Paper.js classes can be accessed.
|
||||
*/
|
||||
/** @scope _global_ */{
|
||||
|
||||
/**
|
||||
* A reference to the currently active {@link PaperScope} object.
|
||||
|
@ -32,40 +35,58 @@
|
|||
// DOCS: This does not work: @borrows PaperScope#version as _global_#version,
|
||||
// so we're repeating documentation here form PaperScope:
|
||||
/**
|
||||
* {@grouptitle Global PaperScope Properties (for PaperScript)}
|
||||
* {@grouptitle Global PaperScript Properties}
|
||||
*
|
||||
* The project for which the PaperScript is executed.
|
||||
*
|
||||
* Note that when working with mulitple projects, this does not necessarily
|
||||
* reflect the currently active project. For this, use
|
||||
* {@link PaperScope#project} instead.
|
||||
*
|
||||
* The currently active project.
|
||||
* @name project
|
||||
* @type Project
|
||||
*/
|
||||
|
||||
/**
|
||||
* The list of all open projects within the current Paper.js context.
|
||||
*
|
||||
* @name projects
|
||||
* @type Project[]
|
||||
*/
|
||||
|
||||
/**
|
||||
* The reference to the active project's view.
|
||||
* The reference to the project's view.
|
||||
*
|
||||
* Note that when working with mulitple projects, this does not necessarily
|
||||
* reflect the view of the currently active project. For this, use
|
||||
* {@link PaperScope#view} instead.
|
||||
*
|
||||
* @name view
|
||||
* @type View
|
||||
*/
|
||||
|
||||
/**
|
||||
* The reference to the active tool.
|
||||
* The reference to the tool object which is automatically created when global
|
||||
* tool event handlers are defined.
|
||||
*
|
||||
* Note that when working with mulitple tools, this does not necessarily
|
||||
* reflect the currently active tool. For this, use {@link PaperScope#tool}
|
||||
* instead.
|
||||
*
|
||||
* @name tool
|
||||
* @type Tool
|
||||
*/
|
||||
|
||||
/**
|
||||
* The list of available tools.
|
||||
*
|
||||
* @name tools
|
||||
* @type Tool[]
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@grouptitle View Event Handlers (for PaperScript)}
|
||||
* A reference to the {@link View#onFrame} handler function.
|
||||
* {@grouptitle PaperScript View Event Handlers}
|
||||
* A global reference to the {@link View#onFrame} handler function.
|
||||
*
|
||||
* @name onFrame
|
||||
* @property
|
||||
|
@ -81,7 +102,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* {@grouptitle Mouse Event Handlers (for PaperScript)}
|
||||
* {@grouptitle PaperScript Tool Event Handlers}
|
||||
* A reference to the {@link Tool#onMouseDown} handler function.
|
||||
* @name onMouseDown
|
||||
* @property
|
||||
|
|
10
src/paper.js
10
src/paper.js
|
@ -138,12 +138,10 @@ var paper = new function(undefined) {
|
|||
/*#*/ include('svg/SVGImport.js');
|
||||
/*#*/ } // __options.svg
|
||||
|
||||
/*#*/ include('export.js');
|
||||
return paper;
|
||||
};
|
||||
|
||||
// include PaperScript separately outside the main paper scope, due to its use
|
||||
// of with(). This also simplifies making its inclusion optional.
|
||||
/*#*/ if (__options.paperscript) {
|
||||
/*#*/ include('core/PaperScript.js');
|
||||
/*#*/ } // __options.paperscript
|
||||
|
||||
/*#*/ include('export.js');
|
||||
return paper;
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
var Tool = PaperScopeItem.extend(/** @lends Tool# */{
|
||||
_class: 'Tool',
|
||||
_list: 'tools',
|
||||
_reference: '_tool', // PaperScope has accessor for #tool
|
||||
_reference: 'tool',
|
||||
_events: [ 'onActivate', 'onDeactivate', 'onEditOptions',
|
||||
'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove',
|
||||
'onKeyDown', 'onKeyUp' ],
|
||||
|
|
|
@ -74,7 +74,7 @@ var Key = new function() {
|
|||
type = down ? 'keydown' : 'keyup',
|
||||
view = View._focused,
|
||||
scope = view && view.isVisible() && view._scope,
|
||||
tool = scope && scope._tool,
|
||||
tool = scope && scope.tool,
|
||||
name;
|
||||
keyMap[key] = down;
|
||||
// Detect modifiers and mark them as pressed / released
|
||||
|
|
|
@ -664,7 +664,7 @@ var View = Base.extend(Callback, /** @lends View# */{
|
|||
// Always first call the view's mouse handlers, as required by
|
||||
// CanvasView, and then handle the active tool, if any.
|
||||
view._handleEvent('mousedown', point, event);
|
||||
if (tool = view._scope._tool)
|
||||
if (tool = view._scope.tool)
|
||||
tool._handleEvent('mousedown', point, event);
|
||||
// In the end we always call update(), which only updates the view if
|
||||
// anything has changed in the above calls.
|
||||
|
@ -673,7 +673,7 @@ var View = Base.extend(Callback, /** @lends View# */{
|
|||
|
||||
function handleMouseMove(view, point, event) {
|
||||
view._handleEvent('mousemove', point, event);
|
||||
var tool = view._scope._tool;
|
||||
var tool = view._scope.tool;
|
||||
if (tool) {
|
||||
// If there's no onMouseDrag, fire onMouseMove while dragging.
|
||||
tool._handleEvent(dragging && tool.responds('mousedrag')
|
||||
|
|
Loading…
Reference in a new issue