From 1ccd5199b5d7c00f5dec7bdf3a753edeff5fb805 Mon Sep 17 00:00:00 2001 From: Jt Whissel Date: Thu, 13 Sep 2012 20:45:27 -0400 Subject: [PATCH 01/51] Added the new classes to work with, that also have the method stubs inside. --- src/paper.js | 3 ++ src/svg/ExportSVG.js | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/svg/ImportSVG.js | 55 +++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/svg/ExportSVG.js create mode 100644 src/svg/ImportSVG.js diff --git a/src/paper.js b/src/paper.js index 3052ee61..757274f8 100644 --- a/src/paper.js +++ b/src/paper.js @@ -93,6 +93,9 @@ var paper = new function() { /*#*/ include('text/TextItem.js'); /*#*/ include('text/PointText.js'); +/*#*/ include('svg/ExportSVG.js'); +/*#*/ include('svg/ImportSVG.js'); + /*#*/ include('style/Style.js'); /*#*/ include('style/PathStyle.js'); /*#*/ include('style/ParagraphStyle.js'); diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js new file mode 100644 index 00000000..79d88b78 --- /dev/null +++ b/src/svg/ExportSVG.js @@ -0,0 +1,90 @@ +/** + * Exports items, layers or whole projects as a svg + * Stetson Alpha - Paper.js + * + * var NS="http://www.w3.org/2000/svg"; + * var svg=document.createElementNS(NS,"svg"); + */ + + +var ExportSVG = function() +{ + var svgObj = null; // xml dom object (svg typed) + + //initialize the svgObj and what ever else. + function initialize() + { + + }; + + /** + * + * Takes the whole project and parses + * all the layers to be put into svg groups and + * groups into svg groups making all the projects + * items into one svg. + * + * takes in a Paper.js Project + * returns svg object (xml dom) + */ + this.exportProject = function(project) + { + return svgObj; + }; + + + /** + * + * Takes the layer and then parses all groups + * and items into one svg + * + * takes in a Paper.js Layer + * returns svg object (xml dom) + */ + this.exportLayer = function(layer) + { + return svgObj; + }; + + + /** + * + * Takes the group and puts it's items + * in a svg file. + * + * takes in a Paper.js Group + * returns svg object (xml dom) + */ + this.exportGroup = function(group) + { + return svgObj; + }; + + /** + * + * Takes the item and puts it in + * a svg file. + * + * takes in a Paper.js Item + * returns svg object (xml dom) + */ + this.exportItem = function(item) + { + return svgObj; + }; + + /** + * + * Takes the path and puts it in + * a svg file. + * + * takes in a Paper.js Path + * returns svg object (xml dom) + */ + this.exportPath = function(path) + { + return svgObj; + }; + + initialize(); // calls the init function after class is loaded +}; \ No newline at end of file diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js new file mode 100644 index 00000000..08f6f557 --- /dev/null +++ b/src/svg/ImportSVG.js @@ -0,0 +1,55 @@ +/** + * Imports svg into items with groups + * Stetson Alpha - Paper.js + * + */ + +var ImportSVG = function() +{ + //initialize + function initialize() + { + + }; + + /** + * + * Takes the svg dom obj and parses the data + * to create a layer with groups (if needed) with + * items inside. Should support nested groups. + * + * takes in a svg object (xml dom) + * returns Paper.js Layer + */ + this.importSVG = function(svg) + { + return layer; + }; + + /** + * Creates a Paper.js Group by parsing + * a specific svg g node + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + function importGroup(svg) + { + return group; + }; + + /** + * Creates a Paper.js Path by parsing + * a specific svg node (rect, path, circle, polygon, etc) + * and creating the right path object based on the svg type. + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + function importPath(svg) + { + return path; + }; + + initialize(); // calls the init function after class is loaded +}; \ No newline at end of file From 1efd36c179ab470fdec49904e0a3cc7546b7ffcc Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 19:58:44 -0400 Subject: [PATCH 02/51] Strip trailing whitespace --- src/svg/ImportSVG.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 08f6f557..d1dfa3a3 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -1,7 +1,7 @@ /** * Imports svg into items with groups * Stetson Alpha - Paper.js - * + * */ var ImportSVG = function() @@ -9,27 +9,27 @@ var ImportSVG = function() //initialize function initialize() { - + }; - + /** - * + * * Takes the svg dom obj and parses the data * to create a layer with groups (if needed) with * items inside. Should support nested groups. - * + * * takes in a svg object (xml dom) - * returns Paper.js Layer + * returns Paper.js Layer */ this.importSVG = function(svg) { return layer; }; - + /** * Creates a Paper.js Group by parsing * a specific svg g node - * + * * takes in a svg object (xml dom) * returns Paper.js Group */ @@ -37,12 +37,12 @@ var ImportSVG = function() { return group; }; - + /** * Creates a Paper.js Path by parsing * a specific svg node (rect, path, circle, polygon, etc) * and creating the right path object based on the svg type. - * + * * takes in a svg object (xml dom) * returns Paper.js Group */ @@ -50,6 +50,6 @@ var ImportSVG = function() { return path; }; - + initialize(); // calls the init function after class is loaded }; \ No newline at end of file From 24f0535bb6444ffd701680375bf254906cc9c7f3 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 19:59:53 -0400 Subject: [PATCH 03/51] Convert tabs to 4 spaces --- src/svg/ImportSVG.js | 62 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index d1dfa3a3..6951f521 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -6,49 +6,49 @@ var ImportSVG = function() { - //initialize - function initialize() - { + //initialize + function initialize() + { - }; + }; - /** - * - * Takes the svg dom obj and parses the data - * to create a layer with groups (if needed) with - * items inside. Should support nested groups. - * - * takes in a svg object (xml dom) - * returns Paper.js Layer - */ + /** + * + * Takes the svg dom obj and parses the data + * to create a layer with groups (if needed) with + * items inside. Should support nested groups. + * + * takes in a svg object (xml dom) + * returns Paper.js Layer + */ this.importSVG = function(svg) { - return layer; + return layer; }; - /** - * Creates a Paper.js Group by parsing - * a specific svg g node - * - * takes in a svg object (xml dom) - * returns Paper.js Group - */ + /** + * Creates a Paper.js Group by parsing + * a specific svg g node + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ function importGroup(svg) { - return group; + return group; }; - /** - * Creates a Paper.js Path by parsing - * a specific svg node (rect, path, circle, polygon, etc) - * and creating the right path object based on the svg type. - * - * takes in a svg object (xml dom) - * returns Paper.js Group - */ + /** + * Creates a Paper.js Path by parsing + * a specific svg node (rect, path, circle, polygon, etc) + * and creating the right path object based on the svg type. + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ function importPath(svg) { - return path; + return path; }; initialize(); // calls the init function after class is loaded From d978520ba30cf5fe863c411ae437e62f40ecc05b Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 22:16:07 -0400 Subject: [PATCH 04/51] Reformat code to match the rest of Paper.js --- src/svg/ImportSVG.js | 123 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 16 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 6951f521..a4a1c496 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -4,13 +4,12 @@ * */ -var ImportSVG = function() -{ +var ImportSVG = this.ImportSVG = Base.extend({ //initialize - function initialize() + initialize: function() { - - }; + + }, /** * @@ -21,10 +20,10 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Layer */ - this.importSVG = function(svg) + importSVG: function(svg) { - return layer; - }; + // return layer; + }, /** * Creates a Paper.js Group by parsing @@ -33,10 +32,10 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Group */ - function importGroup(svg) + importGroup: function(svg) { - return group; - }; + // return group; + }, /** * Creates a Paper.js Path by parsing @@ -46,10 +45,102 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Group */ - function importPath(svg) + importPath: function(svg) { - return path; - }; + // return path; + }, - initialize(); // calls the init function after class is loaded -}; \ No newline at end of file + /** + * Creates a Path.Circle Paper.js item + * + * takes a svg circle node (xml dom) + * returns Paper.js Path.Circle item + */ + createCircle: function(svgCircle) + { + var cx = svgCircle.cx.baseVal.value || 0; + var cy = svgCircle.cy.baseVal.value || 0; + var r = svgCircle.r.baseVal.value || 0; + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + return circle; + }, + + /** + * Creates a Path.Oval Paper.js item + * + * takes a svg ellipse node (xml dom) + * returns Paper.js Path.Oval item + */ + createOval: function(svgOval) + { + var cx = svgOval.cx.baseVal.value || 0; + var cy = svgOval.cy.baseVal.value || 0; + var rx = svgOval.rx.baseVal.value || 0; + var ry = svgOval.ry.baseVal.value || 0; + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + return oval; + }, + + /** + * Creates a "rectangle" Paper.js item + * + * takes a svg rect node (xml dom) + * returns either a + * - Path.Rectangle item + * - Path.RoundRectangle item (if the rectangle has rounded corners) + */ + createRectangle: function(svgRectangle) + { + var x = svgRectangle.x.baseVal.value || 0; + var y = svgRectangle.y.baseVal.value || 0; + var rx = svgRectangle.rx.baseVal.value || 0; + var ry = svgRectangle.ry.baseVal.value || 0; + var width = svgRectangle.width.baseVal.value || 0; + var height = svgRectangle.height.baseVal.value || 0; + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + + if (rx > 0 || ry > 0) { + var cornerSize = new Size(rx, ry); + rectangle = new Path.RoundRectangle(rectangle, cornerSize); + } else { + rectangle = new Path.Rectangle(rectangle); + } + + return rectangle; + }, + + /** + * Creates a Path.Line Paper.js item + * + * takes a svg line node (xml dom) + * returns a Path.Line item + */ + createLine: function(svgLine) + { + var x1 = svgLine.x1.baseVal.value || 0; + var y1 = svgLine.y1.baseVal.value || 0; + var x2 = svgLine.x2.baseVal.value || 0; + var y2 = svgLine.y2.baseVal.value || 0; + + var from = new Point(x1, y1); + var to = new Point(x2, y2); + var line = new Path.Line(from, to); + + return line; + } + + // initialize(); // calls the init function after class is loaded +}); \ No newline at end of file From 9f1d840ada27964f4f104d98c0693d5ada62dee8 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 22:17:06 -0400 Subject: [PATCH 05/51] Todos --- src/svg/ImportSVG.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index a4a1c496..29e1f120 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -8,7 +8,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ //initialize initialize: function() { - + }, /** @@ -22,7 +22,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ */ importSVG: function(svg) { - // return layer; + //TODO: return layer; }, /** @@ -34,7 +34,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ */ importGroup: function(svg) { - // return group; + //TODO: return group; }, /** @@ -47,7 +47,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ */ importPath: function(svg) { - // return path; + //TODO: return path; }, /** @@ -141,6 +141,4 @@ var ImportSVG = this.ImportSVG = Base.extend({ return line; } - - // initialize(); // calls the init function after class is loaded }); \ No newline at end of file From 8659c6b44c1b5247ec0793df742e784d5a409402 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 22:25:19 -0400 Subject: [PATCH 06/51] Reformat the code to match the rest of Paper.js --- src/svg/ImportSVG.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 6951f521..3a25c6fa 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -4,13 +4,13 @@ * */ -var ImportSVG = function() +var ImportSVG = this.ImportSVG = Base.extend({ { //initialize - function initialize() + initialize: function() { - }; + }, /** * @@ -21,10 +21,10 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Layer */ - this.importSVG = function(svg) + importSVG: function(svg) { - return layer; - }; + //TODO: return layer; + }, /** * Creates a Paper.js Group by parsing @@ -33,10 +33,10 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Group */ - function importGroup(svg) + importGroup: function(svg) { - return group; - }; + //TODO: return group; + }, /** * Creates a Paper.js Path by parsing @@ -46,10 +46,8 @@ var ImportSVG = function() * takes in a svg object (xml dom) * returns Paper.js Group */ - function importPath(svg) + importPath: function(svg) { - return path; - }; - - initialize(); // calls the init function after class is loaded -}; \ No newline at end of file + //TODO: return path; + } +}); \ No newline at end of file From bbef9a9594aed2fd47224200bf9e00bdcbe752c4 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 22:26:43 -0400 Subject: [PATCH 07/51] Add a few helper functions These will convert directly from SVG objects to Paper.js equivalents. --- src/svg/ImportSVG.js | 92 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 3a25c6fa..6b15f02c 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -49,5 +49,97 @@ var ImportSVG = this.ImportSVG = Base.extend({ importPath: function(svg) { //TODO: return path; + }, + + /** + * Creates a Path.Circle Paper.js item + * + * takes a svg circle node (xml dom) + * returns Paper.js Path.Circle item + */ + createCircle: function(svgCircle) + { + var cx = svgCircle.cx.baseVal.value || 0; + var cy = svgCircle.cy.baseVal.value || 0; + var r = svgCircle.r.baseVal.value || 0; + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + return circle; + }, + + /** + * Creates a Path.Oval Paper.js item + * + * takes a svg ellipse node (xml dom) + * returns Paper.js Path.Oval item + */ + createOval: function(svgOval) + { + var cx = svgOval.cx.baseVal.value || 0; + var cy = svgOval.cy.baseVal.value || 0; + var rx = svgOval.rx.baseVal.value || 0; + var ry = svgOval.ry.baseVal.value || 0; + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + return oval; + }, + + /** + * Creates a "rectangle" Paper.js item + * + * takes a svg rect node (xml dom) + * returns either a + * - Path.Rectangle item + * - Path.RoundRectangle item (if the rectangle has rounded corners) + */ + createRectangle: function(svgRectangle) + { + var x = svgRectangle.x.baseVal.value || 0; + var y = svgRectangle.y.baseVal.value || 0; + var rx = svgRectangle.rx.baseVal.value || 0; + var ry = svgRectangle.ry.baseVal.value || 0; + var width = svgRectangle.width.baseVal.value || 0; + var height = svgRectangle.height.baseVal.value || 0; + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + + if (rx > 0 || ry > 0) { + var cornerSize = new Size(rx, ry); + rectangle = new Path.RoundRectangle(rectangle, cornerSize); + } else { + rectangle = new Path.Rectangle(rectangle); + } + + return rectangle; + }, + + /** + * Creates a Path.Line Paper.js item + * + * takes a svg line node (xml dom) + * returns a Path.Line item + */ + createLine: function(svgLine) + { + var x1 = svgLine.x1.baseVal.value || 0; + var y1 = svgLine.y1.baseVal.value || 0; + var x2 = svgLine.x2.baseVal.value || 0; + var y2 = svgLine.y2.baseVal.value || 0; + + var from = new Point(x1, y1); + var to = new Point(x2, y2); + var line = new Path.Line(from, to); + + return line; } }); \ No newline at end of file From 7879b4b61b462036ce85d5c3740547d8cc38c12c Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 15 Sep 2012 23:58:39 -0400 Subject: [PATCH 08/51] Convert from 4 spaces to tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oops. Paper.js uses tabs… --- src/svg/ImportSVG.js | 238 +++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 6b15f02c..268c4a75 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -6,140 +6,140 @@ var ImportSVG = this.ImportSVG = Base.extend({ { - //initialize - initialize: function() - { + //initialize + initialize: function() + { - }, + }, - /** - * - * Takes the svg dom obj and parses the data - * to create a layer with groups (if needed) with - * items inside. Should support nested groups. - * - * takes in a svg object (xml dom) - * returns Paper.js Layer - */ - importSVG: function(svg) - { - //TODO: return layer; - }, + /** + * + * Takes the svg dom obj and parses the data + * to create a layer with groups (if needed) with + * items inside. Should support nested groups. + * + * takes in a svg object (xml dom) + * returns Paper.js Layer + */ + importSVG: function(svg) + { + //TODO: return layer; + }, - /** - * Creates a Paper.js Group by parsing - * a specific svg g node - * - * takes in a svg object (xml dom) - * returns Paper.js Group - */ - importGroup: function(svg) - { - //TODO: return group; - }, + /** + * Creates a Paper.js Group by parsing + * a specific svg g node + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + importGroup: function(svg) + { + //TODO: return group; + }, - /** - * Creates a Paper.js Path by parsing - * a specific svg node (rect, path, circle, polygon, etc) - * and creating the right path object based on the svg type. - * - * takes in a svg object (xml dom) - * returns Paper.js Group - */ - importPath: function(svg) - { - //TODO: return path; - }, + /** + * Creates a Paper.js Path by parsing + * a specific svg node (rect, path, circle, polygon, etc) + * and creating the right path object based on the svg type. + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + importPath: function(svg) + { + //TODO: return path; + }, - /** - * Creates a Path.Circle Paper.js item - * - * takes a svg circle node (xml dom) - * returns Paper.js Path.Circle item - */ - createCircle: function(svgCircle) - { - var cx = svgCircle.cx.baseVal.value || 0; - var cy = svgCircle.cy.baseVal.value || 0; - var r = svgCircle.r.baseVal.value || 0; - var center = new Point(cx, cy); - var circle = new Path.Circle(center, r); + /** + * Creates a Path.Circle Paper.js item + * + * takes a svg circle node (xml dom) + * returns Paper.js Path.Circle item + */ + createCircle: function(svgCircle) + { + var cx = svgCircle.cx.baseVal.value || 0; + var cy = svgCircle.cy.baseVal.value || 0; + var r = svgCircle.r.baseVal.value || 0; + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); - return circle; - }, + return circle; + }, - /** - * Creates a Path.Oval Paper.js item - * - * takes a svg ellipse node (xml dom) - * returns Paper.js Path.Oval item - */ - createOval: function(svgOval) - { - var cx = svgOval.cx.baseVal.value || 0; - var cy = svgOval.cy.baseVal.value || 0; - var rx = svgOval.rx.baseVal.value || 0; - var ry = svgOval.ry.baseVal.value || 0; + /** + * Creates a Path.Oval Paper.js item + * + * takes a svg ellipse node (xml dom) + * returns Paper.js Path.Oval item + */ + createOval: function(svgOval) + { + var cx = svgOval.cx.baseVal.value || 0; + var cy = svgOval.cy.baseVal.value || 0; + var rx = svgOval.rx.baseVal.value || 0; + var ry = svgOval.ry.baseVal.value || 0; - var center = new Point(cx, cy); - var offset = new Point(rx, ry); - var topLeft = center.subtract(offset); - var bottomRight = center.add(offset); + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); - var rect = new Rectangle(topLeft, bottomRight); - var oval = new Path.Oval(rect); + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); - return oval; - }, + return oval; + }, - /** - * Creates a "rectangle" Paper.js item - * - * takes a svg rect node (xml dom) - * returns either a - * - Path.Rectangle item - * - Path.RoundRectangle item (if the rectangle has rounded corners) - */ - createRectangle: function(svgRectangle) - { - var x = svgRectangle.x.baseVal.value || 0; - var y = svgRectangle.y.baseVal.value || 0; - var rx = svgRectangle.rx.baseVal.value || 0; - var ry = svgRectangle.ry.baseVal.value || 0; - var width = svgRectangle.width.baseVal.value || 0; - var height = svgRectangle.height.baseVal.value || 0; + /** + * Creates a "rectangle" Paper.js item + * + * takes a svg rect node (xml dom) + * returns either a + * - Path.Rectangle item + * - Path.RoundRectangle item (if the rectangle has rounded corners) + */ + createRectangle: function(svgRectangle) + { + var x = svgRectangle.x.baseVal.value || 0; + var y = svgRectangle.y.baseVal.value || 0; + var rx = svgRectangle.rx.baseVal.value || 0; + var ry = svgRectangle.ry.baseVal.value || 0; + var width = svgRectangle.width.baseVal.value || 0; + var height = svgRectangle.height.baseVal.value || 0; - var topLeft = new Point(x, y); - var size = new Size(width, height); - var rectangle = new Rectangle(topLeft, size); + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); - if (rx > 0 || ry > 0) { - var cornerSize = new Size(rx, ry); - rectangle = new Path.RoundRectangle(rectangle, cornerSize); - } else { - rectangle = new Path.Rectangle(rectangle); - } + if (rx > 0 || ry > 0) { + var cornerSize = new Size(rx, ry); + rectangle = new Path.RoundRectangle(rectangle, cornerSize); + } else { + rectangle = new Path.Rectangle(rectangle); + } - return rectangle; - }, + return rectangle; + }, - /** - * Creates a Path.Line Paper.js item - * - * takes a svg line node (xml dom) - * returns a Path.Line item - */ - createLine: function(svgLine) - { - var x1 = svgLine.x1.baseVal.value || 0; - var y1 = svgLine.y1.baseVal.value || 0; - var x2 = svgLine.x2.baseVal.value || 0; - var y2 = svgLine.y2.baseVal.value || 0; + /** + * Creates a Path.Line Paper.js item + * + * takes a svg line node (xml dom) + * returns a Path.Line item + */ + createLine: function(svgLine) + { + var x1 = svgLine.x1.baseVal.value || 0; + var y1 = svgLine.y1.baseVal.value || 0; + var x2 = svgLine.x2.baseVal.value || 0; + var y2 = svgLine.y2.baseVal.value || 0; - var from = new Point(x1, y1); - var to = new Point(x2, y2); - var line = new Path.Line(from, to); + var from = new Point(x1, y1); + var to = new Point(x2, y2); + var line = new Path.Line(from, to); - return line; - } + return line; + } }); \ No newline at end of file From edd8f67f8dc1493f5908f6aefe7f21e3e316f08b Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 00:09:02 -0400 Subject: [PATCH 09/51] Fix error Shouldn't have two of these... --- src/svg/ImportSVG.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 268c4a75..4793faae 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -5,7 +5,6 @@ */ var ImportSVG = this.ImportSVG = Base.extend({ -{ //initialize initialize: function() { @@ -13,7 +12,6 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * * Takes the svg dom obj and parses the data * to create a layer with groups (if needed) with * items inside. Should support nested groups. From 8cf70ca6e1f73e6fe43c64487aa91efe9edb8d44 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 00:09:39 -0400 Subject: [PATCH 10/51] Rename the create* functions to import* Keeps in line with the naming of the other functions --- src/svg/ImportSVG.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 4793faae..2e2b74e0 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -55,7 +55,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg circle node (xml dom) * returns Paper.js Path.Circle item */ - createCircle: function(svgCircle) + importCircle: function(svgCircle) { var cx = svgCircle.cx.baseVal.value || 0; var cy = svgCircle.cy.baseVal.value || 0; @@ -72,7 +72,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg ellipse node (xml dom) * returns Paper.js Path.Oval item */ - createOval: function(svgOval) + importOval: function(svgOval) { var cx = svgOval.cx.baseVal.value || 0; var cy = svgOval.cy.baseVal.value || 0; @@ -98,7 +98,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * - Path.Rectangle item * - Path.RoundRectangle item (if the rectangle has rounded corners) */ - createRectangle: function(svgRectangle) + importRectangle: function(svgRectangle) { var x = svgRectangle.x.baseVal.value || 0; var y = svgRectangle.y.baseVal.value || 0; @@ -127,7 +127,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg line node (xml dom) * returns a Path.Line item */ - createLine: function(svgLine) + importLine: function(svgLine) { var x1 = svgLine.x1.baseVal.value || 0; var y1 = svgLine.y1.baseVal.value || 0; From 2ce23aacc2f4e5c9788ef0370932ee80e7cb9fac Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 00:10:14 -0400 Subject: [PATCH 11/51] Implement importSVG, importGroup, and importPath --- src/svg/ImportSVG.js | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 2e2b74e0..d7c09643 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -21,7 +21,11 @@ var ImportSVG = this.ImportSVG = Base.extend({ */ importSVG: function(svg) { - //TODO: return layer; + var layer = new Layer(); + groups = this.importGroup(svg); + layer.addChild(groups); + + return layer; }, /** @@ -33,7 +37,18 @@ var ImportSVG = this.ImportSVG = Base.extend({ */ importGroup: function(svg) { - //TODO: return group; + var group = new Group(); + var child; + for (var i in svg.childNodes) { + child = svg.childNodes[i]; + if (child.nodeType != 1) { + continue; + } + item = this.importPath(child); + group.addChild(item); + } + + return group; }, /** @@ -42,11 +57,28 @@ var ImportSVG = this.ImportSVG = Base.extend({ * and creating the right path object based on the svg type. * * takes in a svg object (xml dom) - * returns Paper.js Group + * returns Paper.js Item */ importPath: function(svg) { - //TODO: return path; + switch (svg.nodeName.toLowerCase()) { + case 'line': + item = this.importLine(svg); + break; + case 'rect': + item = this.importRectangle(svg); + break; + case 'ellipse': + item = this.importOval(svg); + break; + case 'g': + item = this.importGroup(svg); + break; + default: + break; + } + + return item; }, /** From 2f5dcce61d81c7bb159d9824a225530cacd8c41a Mon Sep 17 00:00:00 2001 From: skierons Date: Sun, 16 Sep 2012 00:13:14 -0400 Subject: [PATCH 12/51] Jacob and I added a bit to the exportPath class. The initialize function was not working correctly and JT said he would fix that. So we initialized svgObj in the function for the meantime. We added svgRect and svgPoint objects for testing purposes to figure out the xml svg format. Recovered points, strokecolor, fillcolor, and stroke width from the input path. The last thing we need to do for extracting path data is to find the point definitions for each point in the path. Waiting on response from head coders to find out what type of path is passed in for simple conversions (such as: Rectangle path, Circle path, etc.). We added a method called RGBConverter to covnert colors into hexadecimal format for xml. --- examples/Tools/SVGCircles.html | 35 +++++++++++++ examples/Tools/SVGStars.html | 34 +++++++++++++ src/svg/ExportSVG.js | 89 ++++++++++++++++++++++++++++++++-- 3 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 examples/Tools/SVGCircles.html create mode 100644 examples/Tools/SVGStars.html diff --git a/examples/Tools/SVGCircles.html b/examples/Tools/SVGCircles.html new file mode 100644 index 00000000..1878f18a --- /dev/null +++ b/examples/Tools/SVGCircles.html @@ -0,0 +1,35 @@ + + + + + Circles + + + + + + + + + diff --git a/examples/Tools/SVGStars.html b/examples/Tools/SVGStars.html new file mode 100644 index 00000000..b0550020 --- /dev/null +++ b/examples/Tools/SVGStars.html @@ -0,0 +1,34 @@ + + + + + Stars + + + + + + + + + diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 79d88b78..064caead 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -6,16 +6,23 @@ * var svg=document.createElementNS(NS,"svg"); */ + + var ExportSVG = function() { var svgObj = null; // xml dom object (svg typed) + //var blarg = this; //initialize the svgObj and what ever else. - function initialize() + /*function initialize() { + var NS = "http://www.w3.org/2000/svg"; + svgObj = document.createElementNS(NS,"svg"); - }; + console.log(svgObj); + + };*/ /** * @@ -83,8 +90,80 @@ var ExportSVG = function() */ this.exportPath = function(path) { - return svgObj; + //this.initialize(); + //console.log(blarg.svgObj); + var NS = "http://www.w3.org/2000/svg"; + svgObj = document.createElementNS(NS,"svg"); + svgRect = document.createElementNS(NS,"rect"); + svgRect.height.baseVal.value = 50; + svgRect.width.baseVal.value = 60; + svgRect.x.baseVal.value = 50; + svgObj.appendChild(svgRect); + + svgPoint = document.createElementNS(NS,"point"); + svgPoint.setAttribute("x",50); + svgPoint.setAttribute("y",100); + svgObj.appendChild(svgPoint); + + svgPath = document.createElementNS(NS, "path"); + + console.log(svgObj); + var pathClone = path.clone(); + var segArray = pathClone.getSegments(); + + var pointArray = new Array(); + for(i = 0; i < segArray.length; i++) + { + pointArray[i] = segArray[i].getPoint(); + } + var pointString = ""; + for(i = 0; i < pointArray.length; i++) + { + var x = pointArray[i].getX(); + x = x - (x % 1); + var y = pointArray[i].getY(); + y = y - (y % 1); + if(i === 0) + { + pointString+= "M " + x + " " + y + " "; + } + else + { + pointString+= "L " + x + " " + y + " "; + } + } + if(pathClone.getClosed()) + { + pointString += "z"; + } + + var strokeRed = RGBconverter(pathClone.strokeColor.red); + var strokeGreen = RGBconverter(pathClone.strokeColor.green); + var strokeBlue = RGBconverter(pathClone.strokeColor.blue); + var strokeRGB = "#" + strokeRed + strokeGreen + strokeBlue; + + var fillRed = RGBconverter(pathClone.fillColor.red); + var fillGreen = RGBconverter(pathClone.fillColor.green); + var fillBlue = RGBconverter(pathClone.fillColor.blue); + var fillRGB = "#" + fillRed + fillGreen + fillBlue; + + svgPath.setAttribute("d", pointString); + svgPath.setAttribute("stroke", strokeRGB); + svgPath.setAttribute("fill", fillRGB); + svgPath.setAttribute("stroke-width",pathClone.strokeWidth); + svgObj.appendChild(svgPath);i + + console.log(svgObj); + return svgObj; }; - initialize(); // calls the init function after class is loaded -}; \ No newline at end of file + function RGBconverter(deciColor) + { + var decColor = Math.round(deciColor * 255); + var hexColor = decColor.toString(16); + hexColor = hexColor.length > 1? hexColor : "0" + hexColor; + return hexColor; + }; + + //initialize(); // calls the init function after class is loaded +}; From 9218664a67edd224a4dabd1ce909da42ed827f5a Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 01:01:28 -0400 Subject: [PATCH 13/51] Remove the initialize function I'm not using it for anything --- src/svg/ImportSVG.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index d7c09643..2c583e54 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -5,12 +5,6 @@ */ var ImportSVG = this.ImportSVG = Base.extend({ - //initialize - initialize: function() - { - - }, - /** * Takes the svg dom obj and parses the data * to create a layer with groups (if needed) with From 2952e01fc596618fd45f69fa39fd1f5e97fd8178 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 01:02:00 -0400 Subject: [PATCH 14/51] Change the import* functions to private --- src/svg/ImportSVG.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 2c583e54..6b92b44f 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -57,13 +57,13 @@ var ImportSVG = this.ImportSVG = Base.extend({ { switch (svg.nodeName.toLowerCase()) { case 'line': - item = this.importLine(svg); + item = this._importLine(svg); break; case 'rect': - item = this.importRectangle(svg); + item = this._importRectangle(svg); break; case 'ellipse': - item = this.importOval(svg); + item = this._importOval(svg); break; case 'g': item = this.importGroup(svg); @@ -81,7 +81,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg circle node (xml dom) * returns Paper.js Path.Circle item */ - importCircle: function(svgCircle) + _importCircle: function(svgCircle) { var cx = svgCircle.cx.baseVal.value || 0; var cy = svgCircle.cy.baseVal.value || 0; @@ -98,7 +98,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg ellipse node (xml dom) * returns Paper.js Path.Oval item */ - importOval: function(svgOval) + _importOval: function(svgOval) { var cx = svgOval.cx.baseVal.value || 0; var cy = svgOval.cy.baseVal.value || 0; @@ -124,7 +124,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * - Path.Rectangle item * - Path.RoundRectangle item (if the rectangle has rounded corners) */ - importRectangle: function(svgRectangle) + _importRectangle: function(svgRectangle) { var x = svgRectangle.x.baseVal.value || 0; var y = svgRectangle.y.baseVal.value || 0; @@ -153,7 +153,7 @@ var ImportSVG = this.ImportSVG = Base.extend({ * takes a svg line node (xml dom) * returns a Path.Line item */ - importLine: function(svgLine) + _importLine: function(svgLine) { var x1 = svgLine.x1.baseVal.value || 0; var y1 = svgLine.y1.baseVal.value || 0; From 64f34e6dfd4e8935a0c49c85957042e2349de438 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 01:02:23 -0400 Subject: [PATCH 15/51] Add _importText --- src/svg/ImportSVG.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 6b92b44f..7653034a 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -68,6 +68,9 @@ var ImportSVG = this.ImportSVG = Base.extend({ case 'g': item = this.importGroup(svg); break; + case 'text': + item = this._importText(svg); + break; default: break; } @@ -165,5 +168,31 @@ var ImportSVG = this.ImportSVG = Base.extend({ var line = new Path.Line(from, to); return line; + }, + + /** + * Creates a PointText Paper.js item + * + * takes a svg text node (xml dom) + * returns a PointText item + */ + _importText: function(svgText) + { + //TODO: Extend this for multiple values + var x = svgText.x.baseVal.getItem(0).value || 0; + var y = svgText.y.baseVal.getItem(0).value || 0; + //END:Todo + + var dx; //character kerning + var dy; //character baseline + var rotate; //character rotation + var textLength; //the width of the containing box + var lengthAdjust; // + var textContent = svgText.textContent || ""; + + var topLeft = new Point(x, y); + var text = new PointText(topLeft); + text.content = textContent; + return text; } }); \ No newline at end of file From 0b8e9407989f6608466ecd0dfadcc7c868ac4605 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 16 Sep 2012 01:02:40 -0400 Subject: [PATCH 16/51] Create an example page for ImportSVG --- examples/Scripts/ImportSVG.html | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/Scripts/ImportSVG.html diff --git a/examples/Scripts/ImportSVG.html b/examples/Scripts/ImportSVG.html new file mode 100644 index 00000000..da8d79cc --- /dev/null +++ b/examples/Scripts/ImportSVG.html @@ -0,0 +1,32 @@ + + + + + Stroke Bounds + + + + + + + + + + + + + + + I love SVG + + + + \ No newline at end of file From f43abe2f32311125c54c6b18a86043d323cabf2a Mon Sep 17 00:00:00 2001 From: jnighlight Date: Sun, 16 Sep 2012 15:38:22 -0400 Subject: [PATCH 17/51] Mostly more Experimenting, commiting it for practicing across computers. Noticed that curveto and quadratic bezier curveto can be differentiated by format of the handleIn/handleOut variables in each segment (we think) If either handleIn.x and handleOut.x = 0 OR handleIn.y and handleOut.y = 0, then that means the curve is a simple curveTo tag in SVG. If handleIn.x = -handleOut.x AND handleIn.y = -handleOut.y, then you have a quadriatic Bezier Curveto in SVG (using the Q tag). We *HOPE* and think that that curveTo(through, to) (a method creating an arc that passes through the "through" point and ends at the "to" point) simply creates 2 segments, each with a handleIn and Out, which can be read and put into SVG seperately, making our lives a lot easier. Created more SVG test files. Made RGBConverter more efficient with another method to help reduce copied lines of code. --- examples/Tools/SVGBezierTool.html | 89 +++++++++++++++++++++++++++++++ examples/Tools/SVGGrid.html | 48 +++++++++++++++++ src/svg/ExportSVG.js | 53 +++++++++++++----- 3 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 examples/Tools/SVGBezierTool.html create mode 100644 examples/Tools/SVGGrid.html diff --git a/examples/Tools/SVGBezierTool.html b/examples/Tools/SVGBezierTool.html new file mode 100644 index 00000000..e09541a1 --- /dev/null +++ b/examples/Tools/SVGBezierTool.html @@ -0,0 +1,89 @@ + + + + + Bezier Tool + + + + + + +

+ An emulation of a vector pen tool. + Click and drag to add a points.
+ Drag segment handles and points to manipulate them. + Close the path to start a new one. +

+ + + \ No newline at end of file diff --git a/examples/Tools/SVGGrid.html b/examples/Tools/SVGGrid.html new file mode 100644 index 00000000..0fd8e5a9 --- /dev/null +++ b/examples/Tools/SVGGrid.html @@ -0,0 +1,48 @@ + + + + + Grid + + + + + + + + + \ No newline at end of file diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 064caead..20b36802 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -112,9 +112,17 @@ var ExportSVG = function() var segArray = pathClone.getSegments(); var pointArray = new Array(); + var handleInArray = new Array(); + var handleOutArray = new Array(); for(i = 0; i < segArray.length; i++) { pointArray[i] = segArray[i].getPoint(); + handleInArray[i] = segArray[i].getHandleIn(); + handleOutArray[i] = segArray[i].getHandleOut(); + + console.log("point " + i + ": " + pointArray[i]); + console.log("HI " + i + ": " + handleInArray[i]); + console.log("HO " + i + ": " + handleOutArray[i]); } var pointString = ""; for(i = 0; i < pointArray.length; i++) @@ -137,19 +145,29 @@ var ExportSVG = function() pointString += "z"; } - var strokeRed = RGBconverter(pathClone.strokeColor.red); - var strokeGreen = RGBconverter(pathClone.strokeColor.green); - var strokeBlue = RGBconverter(pathClone.strokeColor.blue); - var strokeRGB = "#" + strokeRed + strokeGreen + strokeBlue; - - var fillRed = RGBconverter(pathClone.fillColor.red); - var fillGreen = RGBconverter(pathClone.fillColor.green); - var fillBlue = RGBconverter(pathClone.fillColor.blue); - var fillRGB = "#" + fillRed + fillGreen + fillBlue; + svgPath.setAttribute("d",pointString); - svgPath.setAttribute("d", pointString); - svgPath.setAttribute("stroke", strokeRGB); - svgPath.setAttribute("fill", fillRGB); + if(pathClone.strokeColor != undefined) + { + var strokeRed = pathClone.strokeColor.red; + var strokeGreen = pathClone.strokeColor.green; + var strokeBlue = pathClone.strokeColor.blue; + var strokeRGB = RGBtoHex(strokeRed, strokeGreen, strokeBlue); + svgPath.setAttribute("stroke", strokeRGB); + } + + if(pathClone.fillColor != undefined) + { + var fillRed = pathClone.fillColor.red; + var fillGreen = pathClone.fillColor.green; + var fillBlue = pathClone.fillColor.blue; + var fillRGB = RGBtoHex(fillRed, fillGreen, fillBlue); + svgPath.setAttribute("fill", fillRGB); + } + + //svgPath.setAttribute("d", pointString); + //svgPath.setAttribute("stroke", strokeRGB); + //svgPath.setAttribute("fill", fillRGB); svgPath.setAttribute("stroke-width",pathClone.strokeWidth); svgObj.appendChild(svgPath);i @@ -157,7 +175,7 @@ var ExportSVG = function() return svgObj; }; - function RGBconverter(deciColor) + function RGBConverter(deciColor) { var decColor = Math.round(deciColor * 255); var hexColor = decColor.toString(16); @@ -165,5 +183,14 @@ var ExportSVG = function() return hexColor; }; + function RGBtoHex(red, green, blue) + { + var redVal = RGBConverter(red); + var greenVal = RGBConverter(green); + var blueVal = RGBConverter(blue); + return "#" + redVal + greenVal + blueVal; + } + + //initialize(); // calls the init function after class is loaded }; From b582e96d76973921de990116645ca4895e269da0 Mon Sep 17 00:00:00 2001 From: skierons Date: Sun, 16 Sep 2012 23:52:09 -0400 Subject: [PATCH 18/51] Made changes to SVGCircles to be able to have an easier time reading the data from the circle. Also, made an SVGRect html to test rectangles. No other changes than that. Still working on telling the types of points from Paths that we make. The curveTo's and arcTo's are giving us the most trouble. LineTo's are points with 0 values for the handles. Jacob will clean up the code for the walkthrough tomorrow. There we can figure out how to solve this problem and hopefully finish up the exportPath method. --- src/svg/ExportSVG.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 20b36802..68d35811 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -115,7 +115,8 @@ var ExportSVG = function() var handleInArray = new Array(); var handleOutArray = new Array(); for(i = 0; i < segArray.length; i++) - { + { + console.log(segArray[i].toString()); pointArray[i] = segArray[i].getPoint(); handleInArray[i] = segArray[i].getHandleIn(); handleOutArray[i] = segArray[i].getHandleOut(); @@ -128,9 +129,9 @@ var ExportSVG = function() for(i = 0; i < pointArray.length; i++) { var x = pointArray[i].getX(); - x = x - (x % 1); + //x = x - (x % 1); var y = pointArray[i].getY(); - y = y - (y % 1); + //y = y - (x % 1); if(i === 0) { pointString+= "M " + x + " " + y + " "; @@ -169,7 +170,7 @@ var ExportSVG = function() //svgPath.setAttribute("stroke", strokeRGB); //svgPath.setAttribute("fill", fillRGB); svgPath.setAttribute("stroke-width",pathClone.strokeWidth); - svgObj.appendChild(svgPath);i + svgObj.appendChild(svgPath); console.log(svgObj); return svgObj; From aca3ed67a2411b5c87203a768ab156661beab238 Mon Sep 17 00:00:00 2001 From: jnighlight Date: Mon, 17 Sep 2012 00:34:55 -0400 Subject: [PATCH 19/51] Cleaned up ExportSVG for general purpose. Removed all lines written for testing purposes, saved them in a text document for possible future reference. Code should look a lot more clean and linear with all the stuff removed. --- src/svg/ExportSVG.js | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 68d35811..26168ee9 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -92,23 +92,11 @@ var ExportSVG = function() { //this.initialize(); //console.log(blarg.svgObj); + var pathClone = path.clone(); var NS = "http://www.w3.org/2000/svg"; svgObj = document.createElementNS(NS,"svg"); - svgRect = document.createElementNS(NS,"rect"); - svgRect.height.baseVal.value = 50; - svgRect.width.baseVal.value = 60; - svgRect.x.baseVal.value = 50; - svgObj.appendChild(svgRect); - - svgPoint = document.createElementNS(NS,"point"); - svgPoint.setAttribute("x",50); - svgPoint.setAttribute("y",100); - svgObj.appendChild(svgPoint); - svgPath = document.createElementNS(NS, "path"); - - console.log(svgObj); - var pathClone = path.clone(); + var segArray = pathClone.getSegments(); var pointArray = new Array(); @@ -120,10 +108,6 @@ var ExportSVG = function() pointArray[i] = segArray[i].getPoint(); handleInArray[i] = segArray[i].getHandleIn(); handleOutArray[i] = segArray[i].getHandleOut(); - - console.log("point " + i + ": " + pointArray[i]); - console.log("HI " + i + ": " + handleInArray[i]); - console.log("HO " + i + ": " + handleOutArray[i]); } var pointString = ""; for(i = 0; i < pointArray.length; i++) @@ -165,14 +149,8 @@ var ExportSVG = function() var fillRGB = RGBtoHex(fillRed, fillGreen, fillBlue); svgPath.setAttribute("fill", fillRGB); } - - //svgPath.setAttribute("d", pointString); - //svgPath.setAttribute("stroke", strokeRGB); - //svgPath.setAttribute("fill", fillRGB); svgPath.setAttribute("stroke-width",pathClone.strokeWidth); svgObj.appendChild(svgPath); - - console.log(svgObj); return svgObj; }; From 67f7ece09e999be716a2aa3a4560c74d494635c8 Mon Sep 17 00:00:00 2001 From: jnighlight Date: Mon, 17 Sep 2012 01:30:51 -0400 Subject: [PATCH 20/51] Added comments Code should be easier to understand. --- src/svg/ExportSVG.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 26168ee9..e4906664 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -97,6 +97,7 @@ var ExportSVG = function() svgObj = document.createElementNS(NS,"svg"); svgPath = document.createElementNS(NS, "path"); + //Getting all of the segments(a point, a HandleIn and a HandleOut) in the path var segArray = pathClone.getSegments(); var pointArray = new Array(); @@ -104,36 +105,44 @@ var ExportSVG = function() var handleOutArray = new Array(); for(i = 0; i < segArray.length; i++) { + console.log(segArray[i].toString()); pointArray[i] = segArray[i].getPoint(); handleInArray[i] = segArray[i].getHandleIn(); handleOutArray[i] = segArray[i].getHandleOut(); } + //pointstring is formatted in the way the SVG XML will be reading + //Namely, a point and the way to traverse to that point var pointString = ""; for(i = 0; i < pointArray.length; i++) { var x = pointArray[i].getX(); - //x = x - (x % 1); + //x = x - (x % 1); //Possible for simplifying var y = pointArray[i].getY(); //y = y - (x % 1); if(i === 0) { + //M is moveto, moving to a point without drawing pointString+= "M " + x + " " + y + " "; } else { + //L is lineto, moving to a point with drawing pointString+= "L " + x + " " + y + " "; } } if(pathClone.getClosed()) { + //Z implies a closed path, connecting the first and last points pointString += "z"; } svgPath.setAttribute("d",pointString); + //If the stroke doesn't have a color, there's no attribute for it if(pathClone.strokeColor != undefined) { + //Using rgb, each value between 0 and 1 var strokeRed = pathClone.strokeColor.red; var strokeGreen = pathClone.strokeColor.green; var strokeBlue = pathClone.strokeColor.blue; @@ -141,6 +150,7 @@ var ExportSVG = function() svgPath.setAttribute("stroke", strokeRGB); } + //If the fill doesn't have a color, there's no attribute for it if(pathClone.fillColor != undefined) { var fillRed = pathClone.fillColor.red; @@ -150,14 +160,17 @@ var ExportSVG = function() svgPath.setAttribute("fill", fillRGB); } svgPath.setAttribute("stroke-width",pathClone.strokeWidth); - svgObj.appendChild(svgPath); + svgObj.appendChild(svgPath); //appends path to svgObj return svgObj; }; function RGBConverter(deciColor) { + //since value is scaled from 0 to 1, must round the + //multiplication by 255 var decColor = Math.round(deciColor * 255); - var hexColor = decColor.toString(16); + var hexColor = decColor.toString(16); //to hex + //R, G, and B need to take up at 2 characters hexColor = hexColor.length > 1? hexColor : "0" + hexColor; return hexColor; }; @@ -167,6 +180,7 @@ var ExportSVG = function() var redVal = RGBConverter(red); var greenVal = RGBConverter(green); var blueVal = RGBConverter(blue); + //Returns hex for colors return "#" + redVal + greenVal + blueVal; } From 091170cb7c8badbb16a6223d5c2859cca789607a Mon Sep 17 00:00:00 2001 From: Jt Whissel Date: Mon, 17 Sep 2012 15:03:41 -0300 Subject: [PATCH 21/51] Update AUTHORS.md --- AUTHORS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 23eae2a7..5ec30511 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,3 +2,5 @@ - Juerg Lehni - Jonathan Puckey +- Jt WHissel +- Andrew Roles \ No newline at end of file From 2750b07189581c373d4cac4ef32b0f034af7e194 Mon Sep 17 00:00:00 2001 From: Jt Whissel Date: Mon, 17 Sep 2012 15:03:59 -0300 Subject: [PATCH 22/51] Update AUTHORS.md --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 5ec30511..2d94a5c7 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,5 +2,5 @@ - Juerg Lehni - Jonathan Puckey -- Jt WHissel +- Jt Whissel - Andrew Roles \ No newline at end of file From 6c1c6bc2d5e5d9085981ada7073be37ed9cccb85 Mon Sep 17 00:00:00 2001 From: skierons Date: Mon, 17 Sep 2012 19:34:46 -0400 Subject: [PATCH 23/51] Created an SVGRect.html to test exporting and modified SVGCircles.html for easier testing. --- examples/Tools/.SVGCircles.html.swp | Bin 0 -> 12288 bytes examples/Tools/.SVGRect.html.swp | Bin 0 -> 12288 bytes examples/Tools/SVGCircles.html | 33 ++++++++++++++++++++++------ examples/Tools/SVGRect.html | 32 +++++++++++++++++++++++++++ src/path/.Path.Constructors.js.swp | Bin 0 -> 16384 bytes 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 examples/Tools/.SVGCircles.html.swp create mode 100644 examples/Tools/.SVGRect.html.swp create mode 100644 examples/Tools/SVGRect.html create mode 100644 src/path/.Path.Constructors.js.swp diff --git a/examples/Tools/.SVGCircles.html.swp b/examples/Tools/.SVGCircles.html.swp new file mode 100644 index 0000000000000000000000000000000000000000..56100d522b699739475fdbbd8ad66a657478d5f1 GIT binary patch literal 12288 zcmeI2Pj4GV7>6g^0<<7{<1}4V;tG4$aT8inJ5uCS1wj>~xRDSS#_QMiCgYuDX4Xks z;J_!~!e7BB-~e|{aNrAYg$oBHZb)$AK>5wC?Ica56mg4Yl}Fypyz}lm&v^EbOs~H4 z+8us9yvA@n%b5Ohr{iwr3S--`vex}_#UL|L_8DO;UW@J;(k3brN14b-hr1@C z12N7dnW(FjMDNb+cA{f6gd;naXJz&M-hemocm^)AYmMdl3&CZ6>AAa)H^fJI1Kxl) z;0<^K-hemY4R{0Iz_~GCvjz45vv~r%3>K!~!(ZNjH{cC;1Kxl);0<^K-hemY4R{0I zfH!bX42V8suRO`vm8UQv{Quwm4d9Pw82cUk3cdm#f;Yhh@WVyMJ^}=8gO|W1@b?AA z{sMo3-@uRHd+;^52i^f2;CZkB82IUF#=ZsLfDgbM;C1jKxB?!arhmXM;Aik1_yT+m zJ_DbEPr%3EJ#Zi7U>Eej+h7&cKrz2_vSxl7-hemY4R{0IfH&X`cmw~-Kr?d3OxIa6 z>ZxP*kG@s?!*#aUj72&Th9~`2P~HYylS%H;dNV2;kgrz+BM*tb8x)yXCz-|V;^O-^ znfqAGgdK&N#%e-a>82LL%2o8ZYu4Kcg^s(bVpY~rNouRy>YNZY58y4H(mwAXRYlUk z7GW-pi5QpNMK8)$&o)L}>16=&G*D zUKMFyQsYE?y~=B=t6`&YV>*RLjCg238NM>FWIo3eaq~LdtfOcw_L6kSHwrazah{k9 z%LR`~TalzZb0$hhu}Y1S6iPL$n8{G(_E>FY10IE&kPb4XZDHE2+{v(MIk$=!oMLuM z>53`V*pQ^yQXfHX{f>HOlW<>z^4xQUCY0K+D6q=4=qI^3_N1}_!*p#nR;xW~E2;DvU+PH_?=2M_gG9<%^ZqEY zv{ZHNnO3`)MHuH=qr`1{C<%oW1w;|IBQnHI(TY$U@3skESk6@+1g zAKXS*#b~}lIDH;q$Cjc0DOEo))51>WkV(3S`N&pKm@p$E8}N~)K~YC+OjLA)xC`7v zZDJ*@A02ydMr8}S#$*K_S)0}9-8`AJg0@O6%-6cm0~zISQ%~+Sc9X{=p$*wqZU?m+ Z$lokqKh5b&?(*hVyZct>7P7jR-oLlv#(e+) literal 0 HcmV?d00001 diff --git a/examples/Tools/.SVGRect.html.swp b/examples/Tools/.SVGRect.html.swp new file mode 100644 index 0000000000000000000000000000000000000000..0e8ea1331f14726d24e8667d7e0c64bc6dbbb5b0 GIT binary patch literal 12288 zcmeI2J#W)M7{{+n1f)_?Ay(H6O{>ICTUDUu1wmR>9jZnot;B>J=aM*ae8zW4Ur+~z zegRlm5E2psAz0Y>0DJ)W2yBRjjS>E5r>&q!EfXSoto-8h-E(K(Prb)#d-dGb+PZPw zT3|RP82j{StD=i<))=e0LMeT5%26$E)N0vE`IIo`F4>!sN79Z5wnHc6k=2nl-*I}O z&!t@x!bj`Y>K*PXtF3zeX+u&w86X2^HZZ=qFh7^OW=fDDiU zGC&5%02vq!11cP2KQNVZUfDDiUGC&5%02v?yWMD)LI1R>L zpJ%L|!i4bufBiRrZlLWN># zKR;{ZlyXHNh0iTtw9<0W5`8t3*YyJ@GLmbfs0$X~2}PtTj%ueveEkxIkbrL+D{%<6 zUZ#^)9XD*!{VcsB(+OHWPlv(_R7OAU@i=kaVYqHj&*yR(a2%pL3?r&2rWbRW#iaQG zp4pyl_5)XWA~1SRmmlA4293#QKc3sanKK{oKv@m39aR1>``@QFhq(hfk%Is3ryyRi zdPN?sM-i-xzU0f1(@MwdKrcz1Vswhg<2O9yBYdT#ibR)}g)gEdW4i7;Zg*POH$C4! ztle&Vice=yt#1)VqN6u@yZtD_`l_m3A1MO4E=hHU+6{TpRD4Gzd&QG#(@1jUQS#K; z@nnyVgB%;DOw*8&TQn`p#s@_kDbYU4ci4b#BJU=le>GIYlfwr)F^2C2UF3AXXi7aP z+2&lCMmyro_&HoD?YO~0$<#Mhp7MEVxbwYWCzq)2apf3orNS(~-}eSZvn&DySJ@ie tz(jI2l%(G?dBbfxk>sk_SIz7V3|>gyAcf&uXli+*T)SIY!KnJJ^b>)_^o;-j literal 0 HcmV?d00001 diff --git a/examples/Tools/SVGCircles.html b/examples/Tools/SVGCircles.html index 1878f18a..9468bed8 100644 --- a/examples/Tools/SVGCircles.html +++ b/examples/Tools/SVGCircles.html @@ -2,7 +2,7 @@ - Circles + SVGCircles @@ -15,15 +15,34 @@ }; var path; - function onMouseDrag(event) { - // The radius is the distance between the position - // where the user clicked and the current position - // of the mouse. - var radius = (event.downPoint - event.point).length; - path = new Path.Circle(event.downPoint, radius); + function onMouseDown(event) + { + var radius = 100; + path = new Path.Circle(event.point, radius); + path.selected = true; var svg = new ExportSVG(); var svgout = svg.exportPath(path); console.log(svgout); + + //making A new circle at a certain point + leftPoint = new Point(44,107); + + var leftToTopHandle = new Point(0,55.22847); + var leftToTopHandle2 = new Point(0, -55.228); + + rightPoint = new Point(244,107); + + bottomPoint = new Point(144,207); + + topPoint = new Point(144,7); + + path2 = new Path(leftPoint); + path2.arcTo(topPoint, true); + + + + + path.removeOnDrag(); }; diff --git a/examples/Tools/SVGRect.html b/examples/Tools/SVGRect.html new file mode 100644 index 00000000..becba17d --- /dev/null +++ b/examples/Tools/SVGRect.html @@ -0,0 +1,32 @@ + + + + + SVGRect + + + + + + + + + diff --git a/src/path/.Path.Constructors.js.swp b/src/path/.Path.Constructors.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..f5c885e4cb553ac42c8aea2854fec711af57b665 GIT binary patch literal 16384 zcmeI2ZHOdC8OQrBFJ?TAAqi1DF?A;KW_I^_Ue?PU8`s-qbH-bCi^-B&8&7lMl-w1vXMea*f40uS8n0z@2h;M;FAj0V(sE9HCpQ`Gf zo_)F9J2q&v2Yxf%)%DcNQ%^nhR87}Qr%ueWBj%`q&n<@W^5<(+x@=DyM$Pu4h;Fv| z)TTZ@H+QHywM{m|9xI*P!#|I-=3>+dp*%it3D4)`QE4i195!Jlq6jGusKz%mHI zJU9(b0TbK+t_PRiX&65OUjQe;UEogeey|t(^Bsoq8}Jf12hM`iU_bctKAbmz--2hr zIpBd=@BpZQz2MT@4dXfRb?{a2W$-2N1h^j@1NVS^;4eAk1wRAl!5Odw#=t)C+D(S> z3ius313m_B1be`%Z!?TR@GbB;&;u*rL*RYj-QXWL7{-g>7vRU> zNg%)^xD{N!9(@JB1W$vr;BjDqNiYQVgG)Gwxd6TbT)@FB7zane5l{wy#dux@7r|5D z5#WMPfun%N`!=xICzoSGY}pblbROeuoOyhO)o__Fmr5fHUxoXOBv0TwUZgWs>3T!1 z3I3?n30y8^l;DKmQCE0ujo$d^v8c_d5_gr^f?E-9FnS$CXALZ2b=Vp;pr=|y*=5uG zrW6%^*K0t?_JxPnO9tg0;&xN9m%0%wH^io7T_LmN1LWzt=rgs5orrjctvI+^ zSGEcH;?R(RpWX<*a=IhbUQ$YqF3g8**ALO4afTOJxJ+M=I?LsxE_tiNp(v>?Q*}8n zoK`y;VRgK6<97-LDr?)!kslNavKd=vb$JuT?mTDQ09mZ+jn!!6=VgQFJ|1ga=5?o( z40YEJ*sxTm+2*oCQcU&@kEt#3^A)ENwN=|mYFtUJ$`rCanOCPiDpP6rkS`ff6XVy& zTcXt^ZHBTf$-^<$?0R^hHDIQOWj9c>dHw|N*^!ht9EIK~@d zbuK$Yb6ieo3!T;eLb(O)wc(@MYKgcu(~=4dO;Sk6S;J?ZPtJaK%`BPYX%kBl--;8z zzpQR;W%|jLt>>EjfwFos337%T7FVg|T&||p%XR)94mIL|`c}*3R{1d9DXUs3^@2?v zx=KqJI+v5N4su`sXOU($UEde|mBns$ta87%iKd+fr1PvdUdu zQB=wIO^QY;6_iCQK1<7otm%sm`Av&qwUUO!)bfJ$tA!XYh@1#MtJYtj!X7G--a%Ug zuGs`ex)G`cY^aF;K648c5Tt{)`I31ULGZ!|n_semz#3sCMmLAzy9F}F0f{p5n1?A7 z21e!6H&TWzNXr}$k(HDN%N?k36OnW+y5NB-NrddhU$$I5RYDloJbFpVN@Sc>VCSP) z;PY}SgpY_QUn#IdtPHcHaWEZk5i3)E4U@`>96KD7;Z726(R45<(n1-NuFIsC4-wws z)$e8AFp*A=?su@*IQ1??`xL$lX&bXA<}iXb_d;&68s}{0#MJQzYsazrVE8b~tidD8 zal^Qnb`%9;#iGmGo@4r=Rb(GzI&IPS&|J$4y7m%ZHEq8m+cf0|t7_%R+Xc*%GKOcm z%SDULP$7_?)`F}mC3S;!si7^LAo5$n3fg#movNhn=%@0X_Qfzsu3HrL_#Ufm5Q7Cb z(3{X{dC5wN4M>Y)@tmxlz;334spQmMm@_JvYdbJ=(gJ=F3PcR^t*T$4AA#XdTg#TJ zg`L9qKvfS=8!21$+F9;6?BPcn+Kc zXTfQ32lxZ__UFO(!8gEXz)3I(hQX`Y+g|`b1wQ~^1a&YAj)2S9-#-t24$gokm;q&Q zJNP~J_0NK*Km?}2o#4HI_WZA5FaK-sD{v9K0GV_*L~I1j!C7QjcqQDA_Vu)n_mz6+iJK9~jvz~7*=AA;|JC&6cd2NppSkWN1h zvQMUgOaqw){x3Dq>rpt{qcDmht{oqkQ5b1HOh-?l3jfssk17NqyIkT-;Ufm&c?$2b zMmhzv({&>!a98sVy9c4nF(#~r(+w+ZOkb4?1--3^%bj-?bd0T|qCDb{2x~i4PEDq; zBTpfcgM6j?@bh8jbvrU74skm?thNBTTwJ6sZ&CTbEL}Pl$Wa}`hr1^Lh$JyZ$HF_Yqj80b4$#OqJ zvF*L7yoo;K*6&R`seZ8AsdIsYG-Y|JwejiA;KTCf5BsBuGZ7jIltmKWf{fBqq71d z&<8%MY#hcg8Ph76wF%pA@L04bWe3tKJ)F8HWzgvpS6x)a^*4mnhYiP#8_o}QdN_Yo zz6PFU7z${H9H+`d>SSTJTuRNshG0h?Mds8FMKuQI9<>FwOvm6$;O=M(3AM$p5|8_a zkIA3p)q@@TN9~2w<8gL?+?T8j{&aK;7bTx>!{| zpSGiQ-l)NCtIZq2_slE%q<+R&HMHUkR-gE&kOn69OdA~&N*M4X|I%Mpg#`l z|4=Iy_2DP>bE)>}b9FLPH4!#B)4^t1{`;^^uj6cQUY|#=&gZ7PoHTAH9iGs$`zroJ z9CW_Y84kL-Kv|tuvOaK+rILv-=#rWPN+$N1whV;czX3{Qu~h&7 literal 0 HcmV?d00001 From 449db5de07ecfaadeaa8e1bb2ac51c0dab819a28 Mon Sep 17 00:00:00 2001 From: jaroles Date: Mon, 17 Sep 2012 20:36:37 -0300 Subject: [PATCH 24/51] Added Jacob, Justin, Scott, and Andrew --- AUTHORS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 2d94a5c7..6c907bd9 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -3,4 +3,8 @@ - Juerg Lehni - Jonathan Puckey - Jt Whissel -- Andrew Roles \ No newline at end of file +- Andrew Roles +- Jacob Lites +- Justin Ridgewell +- Andrew Wagenheim +- Scott Kieronski \ No newline at end of file From ce7e0cd349d2ff40c1f07a605d65cd47a2b41a59 Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Tue, 18 Sep 2012 21:08:04 -0400 Subject: [PATCH 25/51] Added comments to ImportSVG.js --- src/svg/ImportSVG.js | 128 ++++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 39 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 7653034a..fb5ed6df 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -1,33 +1,62 @@ +/* +* Paper.js +* +* This file is part of Paper.js, a JavaScript Vector Graphics Library, +* based on Scriptographer.org and designed to be largely API compatible. +* http://paperjs.org/ +* http://scriptographer.org/ +* +* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +* http://lehni.org/ & http://jonathanpuckey.com/ +* +* Distributed under the MIT license. See LICENSE file for details. +* +* All rights reserved. +* +* +* +* This class and all methods therein designed by Stetson-Team-Alpha +*/ + /** - * Imports svg into items with groups - * Stetson Alpha - Paper.js + * @name ImportSVG + * + * @class The ImportSVG object represents an object created using the SVG Canvas * that will be converted into a Paper.js object. The SVG object is imported * into Paper.js by converting it into items within groups. * */ -var ImportSVG = this.ImportSVG = Base.extend({ +var ImportSVG = this.ImportSVG = Base.extend(/** @Lends ImportSVG# */{ + /** - * Takes the svg dom obj and parses the data - * to create a layer with groups (if needed) with - * items inside. Should support nested groups. + * Creates a Paper.js object using data parsed from the selected SVG + * Document Object Model (DOM). The SVG object is imported, than a layer + * is created (with groups for the items if needed). * - * takes in a svg object (xml dom) - * returns Paper.js Layer + * Supports nested groups + * + * @param {SVG DOM} svg An SVG DOM object with parameters + * @return {Layer} A Paper.js layer */ + importSVG: function(svg) { - var layer = new Layer(); - groups = this.importGroup(svg); - layer.addChild(groups); + var layer = new Layer(); + groups = this.importGroup(svg); + layer.addChild(groups); - return layer; + return layer; }, - + /** - * Creates a Paper.js Group by parsing - * a specific svg g node + * Creates a Paper.js group by parsing a specific GNode of the imported + * SVG DOM + * + * @name ImportSVG#importGroup + * @function + * @param {XML DOM} svg A node passed in by the imported SVG + * @return {Group} group A Paper.js group + * * - * takes in a svg object (xml dom) - * returns Paper.js Group */ importGroup: function(svg) { @@ -47,11 +76,13 @@ var ImportSVG = this.ImportSVG = Base.extend({ /** * Creates a Paper.js Path by parsing - * a specific svg node (rect, path, circle, polygon, etc) - * and creating the right path object based on the svg type. + * a specific SVG node (rectangle, path, circle, polygon, etc.) + * and creating the right Path object based on the SVG type. * - * takes in a svg object (xml dom) - * returns Paper.js Item + * @name ImportSVG#importPath + * @function + * @param {XML DOM} svg An SVG object + * @return {Item} item A Paper.js item */ importPath: function(svg) { @@ -79,10 +110,13 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * Creates a Path.Circle Paper.js item + * Creates a Path.Circle item in Paper.js using an imported Circle from + * SVG * - * takes a svg circle node (xml dom) - * returns Paper.js Path.Circle item + * @name ImportSVG#importCircle + * @function + * @param {XML DOM} svgCircle An SVG circle node + * @return {Path.Circle} circle A Path.Circle item for Paper.js */ _importCircle: function(svgCircle) { @@ -96,10 +130,12 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * Creates a Path.Oval Paper.js item + * Creates a Path.Oval item in Paper.js using an imported Oval from SVG * - * takes a svg ellipse node (xml dom) - * returns Paper.js Path.Oval item + * @name ImportSVG#importOval + * @function + * @param {XML DOM} svgOval An SVG ellipse node + * @return {Path.Oval} oval A Path.Oval item for Paper.js */ _importOval: function(svgOval) { @@ -120,13 +156,23 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * Creates a "rectangle" Paper.js item + * Creates a Path.Rectangle item from an imported SVG rectangle * - * takes a svg rect node (xml dom) - * returns either a - * - Path.Rectangle item - * - Path.RoundRectangle item (if the rectangle has rounded corners) + * @name ImportSVG#importRectangle + * @function + * @param {XML DOM} svgRectangle An SVG rectangle node + * @return {Path.Rectangle} rectangle A Path.Rectangle item for Paper.js */ + /** + * Creates a Path.RoundRectangle item from an imported SVG rectangle + * with rounded corners + * + * @name ImportSVG#importRectangle + * @function + * @param {XML DOM} svgRectangle An SVG rectangle node with rounded + * corners + * @return {Path.RoundRectangle} rectangle A Path.Rectangle item for + * Paper.js _importRectangle: function(svgRectangle) { var x = svgRectangle.x.baseVal.value || 0; @@ -151,10 +197,12 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * Creates a Path.Line Paper.js item + * Creates a Path.Line item in Paper.js from an imported SVG line * - * takes a svg line node (xml dom) - * returns a Path.Line item + * @name ImportSVG#importLine + * @function + * @param {XML DOM} svgLine An SVG line node + * @return {Path.Line} line A Path.Line item for Paper.js */ _importLine: function(svgLine) { @@ -171,10 +219,12 @@ var ImportSVG = this.ImportSVG = Base.extend({ }, /** - * Creates a PointText Paper.js item + * Creates a PointText item in Paper.js from an imported SVG text node * - * takes a svg text node (xml dom) - * returns a PointText item + * @name ImportSVG#importText + * @function + * @param {XML DOM} svgText An SVG text node + * @return {Path.Text} text A PointText item for Paper.js */ _importText: function(svgText) { @@ -195,4 +245,4 @@ var ImportSVG = this.ImportSVG = Base.extend({ text.content = textContent; return text; } -}); \ No newline at end of file +}); From 555d179978f83e3c4c1311da2ab86260ef2db00f Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Tue, 18 Sep 2012 21:11:01 -0400 Subject: [PATCH 26/51] Added comments to ImportSVG.js --- src/svg/ImportSVG.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index fb5ed6df..013ca639 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -20,8 +20,10 @@ /** * @name ImportSVG - * - * @class The ImportSVG object represents an object created using the SVG Canvas * that will be converted into a Paper.js object. The SVG object is imported * into Paper.js by converting it into items within groups. + * @class The ImportSVG object represents an object created using the SVG + * Canvas that will be converted into a Paper.js object. + * The SVG object is imported into Paper.js by converting it into items + * within groups. * */ From ed6007004aa941cdc2b206ab72cbb70e95e2910b Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Tue, 18 Sep 2012 22:12:28 -0300 Subject: [PATCH 27/51] Update src/svg/ImportSVG.js --- src/svg/ImportSVG.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 013ca639..506ac90f 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -175,6 +175,7 @@ var ImportSVG = this.ImportSVG = Base.extend(/** @Lends ImportSVG# */{ * corners * @return {Path.RoundRectangle} rectangle A Path.Rectangle item for * Paper.js + */ _importRectangle: function(svgRectangle) { var x = svgRectangle.x.baseVal.value || 0; From 5f550a9f8a3f731d76f6c69b4b482f3d42fc843b Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Tue, 18 Sep 2012 22:35:48 -0400 Subject: [PATCH 28/51] Added ImportSVG.js Stub --- test/tests/ImportSVG.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/tests/ImportSVG.js diff --git a/test/tests/ImportSVG.js b/test/tests/ImportSVG.js new file mode 100644 index 00000000..e9b5cf71 --- /dev/null +++ b/test/tests/ImportSVG.js @@ -0,0 +1,21 @@ +/* +* Paper.js +* +* This file is part of Paper.js, a JavaScript Vector Graphics Library, +* based on Scriptographer.org and designed to be largely API compatible. +* http://paperjs.org/ +* http://scriptographer.org/ +* +* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +* http://lehni.org/ & http://jonathanpuckey.com/ +* +* Distributed under the MIT license. See LICENSE file for details. +* +* All rights reserved. +*/ + +module('ImportSVG'); + +/** +*TODO: Create SVGs utilizing ImportSVG methods +*/ From c2de6fbd05fb6ac8a5b89cd1c26769f403bb3842 Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Tue, 18 Sep 2012 23:42:50 -0300 Subject: [PATCH 29/51] Update test/tests/ImportSVG.js --- test/tests/ImportSVG.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tests/ImportSVG.js b/test/tests/ImportSVG.js index e9b5cf71..a964224d 100644 --- a/test/tests/ImportSVG.js +++ b/test/tests/ImportSVG.js @@ -18,4 +18,5 @@ module('ImportSVG'); /** *TODO: Create SVGs utilizing ImportSVG methods +* WILL ADD MORE AFTER LEARNING SVG */ From 3ca96b28509811de7f4783f2f3126a7331f6d9a4 Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Wed, 19 Sep 2012 16:31:49 -0300 Subject: [PATCH 30/51] Update AUTHORS.md --- AUTHORS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 6c907bd9..488ef858 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -7,4 +7,5 @@ - Jacob Lites - Justin Ridgewell - Andrew Wagenheim -- Scott Kieronski \ No newline at end of file +- Scott Kieronski +- Lily the Puppy \ No newline at end of file From bd83a434ff30eb30b84a7e485326eab4b8c69cff Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Wed, 19 Sep 2012 16:41:22 -0300 Subject: [PATCH 31/51] Update src/svg/ImportSVG.js --- src/svg/ImportSVG.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 506ac90f..981f231c 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -16,6 +16,7 @@ * * * This class and all methods therein designed by Stetson-Team-Alpha +* @author Stetson Team Alpha */ /** From 205586bbbdb2065d1b0a41b408fc2bebf4fa1032 Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Wed, 19 Sep 2012 16:42:00 -0300 Subject: [PATCH 32/51] Update src/svg/ImportSVG.js --- src/svg/ImportSVG.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 981f231c..a0d497a9 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -16,7 +16,7 @@ * * * This class and all methods therein designed by Stetson-Team-Alpha -* @author Stetson Team Alpha +* @author Stetson-Team-Alpha */ /** From c6840a0dbdbbd50377fbf6f4ad199c9a74846863 Mon Sep 17 00:00:00 2001 From: AWagenheim Date: Thu, 20 Sep 2012 21:54:23 -0400 Subject: [PATCH 33/51] Tinkering with Import.svg tests --- dist/docs/resources/js/paper.js | 7842 ----------------------------- dist/paper.js | 8237 ------------------------------- test/tests/ImportSVG.js | 18 +- 3 files changed, 14 insertions(+), 16083 deletions(-) diff --git a/dist/docs/resources/js/paper.js b/dist/docs/resources/js/paper.js index e963d27f..e69de29b 100644 --- a/dist/docs/resources/js/paper.js +++ b/dist/docs/resources/js/paper.js @@ -1,7842 +0,0 @@ -/*! - * Paper.js v0.22 - * - * This file is part of Paper.js, a JavaScript Vector Graphics Library, - * based on Scriptographer.org and designed to be largely API compatible. - * http://paperjs.org/ - * http://scriptographer.org/ - * - * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey - * http://lehni.org/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - * - * Date: Thu Nov 10 18:30:18 2011 +0100 - * - *** - * - * Bootstrap.js JavaScript Framework. - * http://bootstrapjs.org/ - * - * Copyright (c) 2006 - 2011 Juerg Lehni - * http://lehni.org/ - * - * Distributed under the MIT license. - * - *** - * - * Parse-js - * - * A JavaScript tokenizer / parser / generator, originally written in Lisp. - * Copyright (c) Marijn Haverbeke - * http://marijn.haverbeke.nl/parse-js/ - * - * Ported by to JavaScript by Mihai Bazon - * Copyright (c) 2010, Mihai Bazon - * http://mihai.bazon.net/blog/ - * - * Modifications and adaptions to browser (c) 2011, Juerg Lehni - * http://lehni.org/ - * - * Distributed under the BSD license. - */ - -var paper = new function() { - -var Base = new function() { - var fix = !this.__proto__, - hidden = /^(statics|generics|preserve|enumerable|prototype|__proto__|toString|valueOf)$/, - proto = Object.prototype, - has = fix - ? function(name) { - return name !== '__proto__' && this.hasOwnProperty(name); - } - : proto.hasOwnProperty, - toString = proto.toString, - proto = Array.prototype, - isArray = Array.isArray = Array.isArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }, - slice = proto.slice, - forEach = proto.forEach = proto.forEach || function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - iter.call(bind, this[i], i, this); - }, - forIn = function(iter, bind) { - for (var i in this) - if (this.hasOwnProperty(i)) - iter.call(bind, this[i], i, this); - }, - _define = Object.defineProperty, - _describe = Object.getOwnPropertyDescriptor; - - function define(obj, name, desc) { - if (_define) { - try { - delete obj[name]; - return _define(obj, name, desc); - } catch (e) {} - } - if ((desc.get || desc.set) && obj.__defineGetter__) { - desc.get && obj.__defineGetter__(name, desc.get); - desc.set && obj.__defineSetter__(name, desc.set); - } else { - obj[name] = desc.value; - } - return obj; - } - - function describe(obj, name) { - if (_describe) { - try { - return _describe(obj, name); - } catch (e) {} - } - var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); - return get - ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, - configurable: true } - : has.call(obj, name) - ? { value: obj[name], enumerable: true, configurable: true, - writable: true } - : null; - } - - function inject(dest, src, enumerable, base, preserve, generics) { - var beans, bean; - - function field(name, val, dontCheck, generics) { - var val = val || (val = describe(src, name)) - && (val.get ? val : val.value), - func = typeof val === 'function', - res = val, - prev = preserve || func - ? (val && val.get ? name in dest : dest[name]) : null; - if (generics && func && (!preserve || !generics[name])) { - generics[name] = function(bind) { - return bind && dest[name].apply(bind, - slice.call(arguments, 1)); - } - } - if ((dontCheck || val !== undefined && has.call(src, name)) - && (!preserve || !prev)) { - if (func) { - if (prev && /\bthis\.base\b/.test(val)) { - var fromBase = base && base[name] == prev; - res = function() { - var tmp = describe(this, 'base'); - define(this, 'base', { value: fromBase - ? base[name] : prev, configurable: true }); - try { - return val.apply(this, arguments); - } finally { - tmp ? define(this, 'base', tmp) - : delete this.base; - } - }; - res.toString = function() { - return val.toString(); - } - res.valueOf = function() { - return val.valueOf(); - } - } - if (beans && val.length == 0 - && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) - beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); - } - if (!res || func || !res.get && !res.set) - res = { value: res, writable: true }; - if ((describe(dest, name) - || { configurable: true }).configurable) { - res.configurable = true; - res.enumerable = enumerable; - } - define(dest, name, res); - } - } - if (src) { - beans = []; - for (var name in src) - if (has.call(src, name) && !hidden.test(name)) - field(name, null, true, generics); - field('toString'); - field('valueOf'); - for (var i = 0, l = beans && beans.length; i < l; i++) - try { - var bean = beans[i], part = bean[1]; - field(bean[0], { - get: dest['get' + part] || dest['is' + part], - set: dest['set' + part] - }, true); - } catch (e) {} - } - return dest; - } - - function extend(obj) { - var ctor = function(dont) { - if (fix) define(this, '__proto__', { value: obj }); - if (this.initialize && dont !== ctor.dont) - return this.initialize.apply(this, arguments); - } - ctor.prototype = obj; - ctor.toString = function() { - return (this.prototype.initialize || function() {}).toString(); - } - return ctor; - } - - function iterator(iter) { - return !iter - ? function(val) { return val } - : typeof iter !== 'function' - ? function(val) { return val == iter } - : iter; - } - - function each(obj, iter, bind, asArray) { - try { - if (obj) - (asArray || asArray === undefined && isArray(obj) - ? forEach : forIn).call(obj, iterator(iter), - bind = bind || obj); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - } - - function clone(obj) { - return each(obj, function(val, i) { - this[i] = val; - }, new obj.constructor()); - } - - return inject(function() {}, { - inject: function(src) { - if (src) { - var proto = this.prototype, - base = proto.__proto__ && proto.__proto__.constructor, - statics = src.statics == true ? src : src.statics; - if (statics != src) - inject(proto, src, src.enumerable, base && base.prototype, - src.preserve, src.generics && this); - inject(this, statics, true, base, src.preserve); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src) { - var proto = new this(this.dont), - ctor = extend(proto); - define(proto, 'constructor', - { value: ctor, writable: true, configurable: true }); - ctor.dont = {}; - inject(ctor, this, true); - return arguments.length ? this.inject.apply(ctor, arguments) : ctor; - } - }, true).inject({ - has: has, - each: each, - - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) - inject(this, arguments[i]); - return this; - }, - - extend: function() { - var res = new (extend(this)); - return res.inject.apply(res, arguments); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - clone: function() { - return clone(this); - }, - - statics: { - each: each, - clone: clone, - define: define, - describe: describe, - iterator: iterator, - - has: function(obj, name) { - return has.call(obj, name); - }, - - type: function(obj) { - return (obj || obj === 0) && (obj._type || typeof obj) || null; - }, - - check: function(obj) { - return !!(obj || obj === 0); - }, - - pick: function() { - for (var i = 0, l = arguments.length; i < l; i++) - if (arguments[i] !== undefined) - return arguments[i]; - return null; - }, - - stop: {} - } - }); -} - -this.Base = Base.inject({ - generics: true, - - clone: function() { - return new this.constructor(this); - }, - - toString: function() { - return '{ ' + Base.each(this, function(value, key) { - if (key.charAt(0) != '_') { - var type = typeof value; - this.push(key + ': ' + (type === 'number' - ? Base.formatNumber(value) - : type === 'string' ? "'" + value + "'" : value)); - } - }, []).join(', ') + ' }'; - }, - - statics: { - read: function(list, start, length) { - var start = start || 0, - length = length || list.length - start; - var obj = list[start]; - if (obj instanceof this - || this.prototype._readNull && obj == null && length <= 1) - return obj; - obj = new this(this.dont); - return obj.initialize.apply(obj, start > 0 || length < list.length - ? Array.prototype.slice.call(list, start, start + length) - : list) || obj; - }, - - readAll: function(list, start) { - var res = [], entry; - for (var i = start || 0, l = list.length; i < l; i++) { - res.push(Array.isArray(entry = list[i]) - ? this.read(entry, 0) - : this.read(list, i, 1)); - } - return res; - }, - - splice: function(list, items, index, remove) { - var amount = items && items.length, - append = index === undefined; - index = append ? list.length : index; - for (var i = 0; i < amount; i++) - items[i]._index = index + i; - if (append) { - list.push.apply(list, items); - return []; - } else { - var args = [index, remove]; - if (items) - args.push.apply(args, items); - var removed = list.splice.apply(list, args); - for (var i = 0, l = removed.length; i < l; i++) - delete removed[i]._index; - for (var i = index + amount, l = list.length; i < l; i++) - list[i]._index = i; - return removed; - } - }, - - merge: function() { - return Base.each(arguments, function(hash) { - Base.each(hash, function(value, key) { - this[key] = value; - }, this); - }, new Base(), true); - }, - - capitalize: function(str) { - return str.replace(/\b[a-z]/g, function(match) { - return match.toUpperCase(); - }); - }, - - camelize: function(str) { - return str.replace(/-(\w)/g, function(all, chr) { - return chr.toUpperCase(); - }); - }, - - hyphenate: function(str) { - return str.replace(/[a-z][A-Z0-9]|[0-9][a-zA-Z]|[A-Z]{2}[a-z]/g, - function(match) { - return match.charAt(0) + '-' + match.substring(1); - } - ).toLowerCase(); - }, - - formatNumber: function(num) { - return (Math.round(num * 100000) / 100000).toString(); - } - } -}); - -var PaperScope = this.PaperScope = Base.extend({ - - initialize: function(script) { - paper = this; - this.view = null; - this.views = []; - this.project = null; - this.projects = []; - this.tool = null; - this.tools = []; - this._id = script && (script.getAttribute('id') || script.src) - || ('paperscope-' + (PaperScope._id++)); - if (script) - script.setAttribute('id', this._id); - PaperScope._scopes[this._id] = this; - }, - - version: 0.22, - - evaluate: function(code) { - var res = PaperScript.evaluate(code, this); - View.updateFocus(); - return res; - }, - - install: function(scope) { - var that = this; - Base.each(['project', 'view', 'tool'], function(key) { - Base.define(scope, key, { - configurable: true, - writable: true, - get: function() { - return that[key]; - } - }); - }); - for (var key in this) { - if (!/^(version|_id|load)/.test(key) && !(key in scope)) - scope[key] = this[key]; - } - }, - - setup: function(canvas) { - paper = this; - this.project = new Project(); - if (canvas) - this.view = new View(canvas); - }, - - clear: function() { - for (var i = this.projects.length - 1; i >= 0; i--) - this.projects[i].remove(); - for (var i = this.views.length - 1; i >= 0; i--) - this.views[i].remove(); - for (var i = this.tools.length - 1; i >= 0; i--) - this.tools[i].remove(); - }, - - remove: function() { - this.clear(); - delete PaperScope._scopes[this._id]; - }, - - _needsRedraw: function() { - if (!this._redrawNotified) { - for (var i = this.views.length - 1; i >= 0; i--) - this.views[i]._redrawNeeded = true; - this._redrawNotified = true; - } - }, - - statics: { - _scopes: {}, - _id: 0, - - get: function(id) { - if (typeof id === 'object') - id = id.getAttribute('id'); - return this._scopes[id] || null; - }, - - each: function(iter) { - Base.each(this._scopes, iter); - } - } -}); - -var PaperScopeItem = Base.extend({ - - initialize: function(activate) { - this._scope = paper; - this._index = this._scope[this._list].push(this) - 1; - if (activate || !this._scope[this._reference]) - this.activate(); - }, - - activate: function() { - if (!this._scope) - return false; - this._scope[this._reference] = this; - return true; - }, - - remove: function() { - if (this._index == null) - return false; - Base.splice(this._scope[this._list], null, this._index, 1); - if (this._scope[this._reference] == this) - this._scope[this._reference] = null; - this._scope = null; - return true; - } -}); - -var Point = this.Point = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 !== undefined) { - this.x = arg0; - this.y = arg1; - } else if (arg0 !== undefined) { - if (arg0 == null) { - this.x = this.y = 0; - } else if (arg0.x !== undefined) { - this.x = arg0.x; - this.y = arg0.y; - } else if (arg0.width !== undefined) { - this.x = arg0.width; - this.y = arg0.height; - } else if (Array.isArray(arg0)) { - this.x = arg0[0]; - this.y = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (arg0.angle !== undefined) { - this.x = arg0.length; - this.y = 0; - this.setAngle(arg0.angle); - } else if (typeof arg0 === 'number') { - this.x = this.y = arg0; - } else { - this.x = this.y = 0; - } - } else { - this.x = this.y = 0; - } - }, - - set: function(x, y) { - this.x = x; - this.y = y; - return this; - }, - - clone: function() { - return Point.create(this.x, this.y); - }, - - toString: function() { - var format = Base.formatNumber; - return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }'; - }, - - add: function(point) { - point = Point.read(arguments); - return Point.create(this.x + point.x, this.y + point.y); - }, - - subtract: function(point) { - point = Point.read(arguments); - return Point.create(this.x - point.x, this.y - point.y); - }, - - multiply: function(point) { - point = Point.read(arguments); - return Point.create(this.x * point.x, this.y * point.y); - }, - - divide: function(point) { - point = Point.read(arguments); - return Point.create(this.x / point.x, this.y / point.y); - }, - - modulo: function(point) { - point = Point.read(arguments); - return Point.create(this.x % point.x, this.y % point.y); - }, - - negate: function() { - return Point.create(-this.x, -this.y); - }, - - transform: function(matrix) { - return matrix ? matrix._transformPoint(this) : this; - }, - - getDistance: function(point, squared) { - point = Point.read(arguments); - var x = point.x - this.x, - y = point.y - this.y, - d = x * x + y * y; - return squared ? d : Math.sqrt(d); - }, - - getLength: function() { - var l = this.x * this.x + this.y * this.y; - return arguments[0] ? l : Math.sqrt(l); - }, - - setLength: function(length) { - if (this.isZero()) { - var angle = this._angle || 0; - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } else { - var scale = length / this.getLength(); - if (scale == 0) - this.getAngle(); - this.set( - this.x * scale, - this.y * scale - ); - } - return this; - }, - - normalize: function(length) { - if (length === undefined) - length = 1; - var current = this.getLength(), - scale = current != 0 ? length / current : 0, - point = Point.create(this.x * scale, this.y * scale); - point._angle = this._angle; - return point; - }, - - getAngle: function() { - return this.getAngleInRadians(arguments[0]) * 180 / Math.PI; - }, - - setAngle: function(angle) { - angle = this._angle = angle * Math.PI / 180; - if (!this.isZero()) { - var length = this.getLength(); - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } - return this; - }, - - getAngleInRadians: function() { - if (arguments[0] === undefined) { - if (this._angle == null) - this._angle = Math.atan2(this.y, this.x); - return this._angle; - } else { - var point = Point.read(arguments), - div = this.getLength() * point.getLength(); - if (div == 0) { - return NaN; - } else { - return Math.acos(this.dot(point) / div); - } - } - }, - - getAngleInDegrees: function() { - return this.getAngle(arguments[0]); - }, - - getQuadrant: function() { - return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; - }, - - getDirectedAngle: function(point) { - point = Point.read(arguments); - return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; - }, - - rotate: function(angle, center) { - angle = angle * Math.PI / 180; - var point = center ? this.subtract(center) : this, - s = Math.sin(angle), - c = Math.cos(angle); - point = Point.create( - point.x * c - point.y * s, - point.y * c + point.x * s - ); - return center ? point.add(center) : point; - }, - - equals: function(point) { - point = Point.read(arguments); - return this.x == point.x && this.y == point.y; - }, - - isInside: function(rect) { - return rect.contains(this); - }, - - isClose: function(point, tolerance) { - return this.getDistance(point) < tolerance; - }, - - isColinear: function(point) { - return this.cross(point) < Numerical.TOLERANCE; - }, - - isOrthogonal: function(point) { - return this.dot(point) < Numerical.TOLERANCE; - }, - - isZero: function() { - return this.x == 0 && this.y == 0; - }, - - isNaN: function() { - return isNaN(this.x) || isNaN(this.y); - }, - - dot: function(point) { - point = Point.read(arguments); - return this.x * point.x + this.y * point.y; - }, - - cross: function(point) { - point = Point.read(arguments); - return this.x * point.y - this.y * point.x; - }, - - project: function(point) { - point = Point.read(arguments); - if (point.isZero()) { - return Point.create(0, 0); - } else { - var scale = this.dot(point) / point.dot(point); - return Point.create( - point.x * scale, - point.y * scale - ); - } - }, - - statics: { - create: function(x, y) { - var point = new Point(Point.dont); - point.x = x; - point.y = y; - return point; - }, - - min: function(point1, point2) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - return Point.create( - Math.min(point1.x, point2.x), - Math.min(point1.y, point2.y) - ); - }, - - max: function(point1, point2) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - return Point.create( - Math.max(point1.x, point2.x), - Math.max(point1.y, point2.y) - ); - }, - - random: function() { - return Point.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Point.create(op(this.x), op(this.y)); - }; - }, {}); -}); - -var LinkedPoint = Point.extend({ - set: function(x, y, dontNotify) { - this._x = x; - this._y = y; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner[this._setter](this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, x, y, dontLink) { - if (dontLink) - return Point.create(x, y); - var point = new LinkedPoint(LinkedPoint.dont); - point._x = x; - point._y = y; - point._owner = owner; - point._setter = setter; - return point; - } - } -}); - -var Size = this.Size = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 !== undefined) { - this.width = arg0; - this.height = arg1; - } else if (arg0 !== undefined) { - if (arg0 == null) { - this.width = this.height = 0; - } else if (arg0.width !== undefined) { - this.width = arg0.width; - this.height = arg0.height; - } else if (arg0.x !== undefined) { - this.width = arg0.x; - this.height = arg0.y; - } else if (Array.isArray(arg0)) { - this.width = arg0[0]; - this.height = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (typeof arg0 === 'number') { - this.width = this.height = arg0; - } else { - this.width = this.height = 0; - } - } else { - this.width = this.height = 0; - } - }, - - toString: function() { - var format = Base.formatNumber; - return '{ width: ' + format(this.width) - + ', height: ' + format(this.height) + ' }'; - }, - - set: function(width, height) { - this.width = width; - this.height = height; - return this; - }, - - clone: function() { - return Size.create(this.width, this.height); - }, - - add: function(size) { - size = Size.read(arguments); - return Size.create(this.width + size.width, this.height + size.height); - }, - - subtract: function(size) { - size = Size.read(arguments); - return Size.create(this.width - size.width, this.height - size.height); - }, - - multiply: function(size) { - size = Size.read(arguments); - return Size.create(this.width * size.width, this.height * size.height); - }, - - divide: function(size) { - size = Size.read(arguments); - return Size.create(this.width / size.width, this.height / size.height); - }, - - modulo: function(size) { - size = Size.read(arguments); - return Size.create(this.width % size.width, this.height % size.height); - }, - - negate: function() { - return Size.create(-this.width, -this.height); - }, - - equals: function(size) { - size = Size.read(arguments); - return this.width == size.width && this.height == size.height; - }, - - isZero: function() { - return this.width == 0 && this.height == 0; - }, - - isNaN: function() { - return isNaN(this.width) || isNaN(this.height); - }, - - statics: { - create: function(width, height) { - return new Size(Size.dont).set(width, height); - }, - - min: function(size1, size2) { - return Size.create( - Math.min(size1.width, size2.width), - Math.min(size1.height, size2.height)); - }, - - max: function(size1, size2) { - return Size.create( - Math.max(size1.width, size2.width), - Math.max(size1.height, size2.height)); - }, - - random: function() { - return Size.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Size.create(op(this.width), op(this.height)); - }; - }, {}); -}); - -var LinkedSize = Size.extend({ - set: function(width, height, dontNotify) { - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getWidth: function() { - return this._width; - }, - - setWidth: function(width) { - this._width = width; - this._owner[this._setter](this); - }, - - getHeight: function() { - return this._height; - }, - - setHeight: function(height) { - this._height = height; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, width, height, dontLink) { - if (dontLink) - return Size.create(width, height); - var size = new LinkedSize(LinkedSize.dont); - size._width = width; - size._height = height; - size._owner = owner; - size._setter = setter; - return size; - } - } -}); - -var Rectangle = this.Rectangle = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3) { - if (arguments.length == 4) { - this.x = arg0; - this.y = arg1; - this.width = arg2; - this.height = arg3; - } else if (arguments.length == 2) { - if (arg1 && arg1.x !== undefined) { - var point1 = Point.read(arguments, 0, 1); - var point2 = Point.read(arguments, 1, 1); - this.x = point1.x; - this.y = point1.y; - this.width = point2.x - point1.x; - this.height = point2.y - point1.y; - if (this.width < 0) { - this.x = point2.x; - this.width = -this.width; - } - if (this.height < 0) { - this.y = point2.y; - this.height = -this.height; - } - } else { - var point = Point.read(arguments, 0, 1); - var size = Size.read(arguments, 1, 1); - this.x = point.x; - this.y = point.y; - this.width = size.width; - this.height = size.height; - } - } else if (arg0) { - this.x = arg0.x || 0; - this.y = arg0.y || 0; - this.width = arg0.width || 0; - this.height = arg0.height || 0; - } else { - this.x = this.y = this.width = this.height = 0; - } - }, - - set: function(x, y, width, height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - return this; - }, - - getPoint: function() { - return LinkedPoint.create(this, 'setPoint', this.x, this.y, - arguments[0]); - }, - - setPoint: function(point) { - point = Point.read(arguments); - this.x = point.x; - this.y = point.y; - return this; - }, - - getSize: function() { - return LinkedSize.create(this, 'setSize', this.width, this.height, - arguments[0]); - }, - - setSize: function(size) { - size = Size.read(arguments); - this.width = size.width; - this.height = size.height; - return this; - }, - - getLeft: function() { - return this.x; - }, - - setLeft: function(left) { - this.width -= left - this.x; - this.x = left; - return this; - }, - - getTop: function() { - return this.y; - }, - - setTop: function(top) { - this.height -= top - this.y; - this.y = top; - return this; - }, - - getRight: function() { - return this.x + this.width; - }, - - setRight: function(right) { - this.width = right - this.x; - return this; - }, - - getBottom: function() { - return this.y + this.height; - }, - - setBottom: function(bottom) { - this.height = bottom - this.y; - return this; - }, - - getCenterX: function() { - return this.x + this.width * 0.5; - }, - - setCenterX: function(x) { - this.x = x - this.width * 0.5; - return this; - }, - - getCenterY: function() { - return this.y + this.height * 0.5; - }, - - setCenterY: function(y) { - this.y = y - this.height * 0.5; - return this; - }, - - getCenter: function() { - return LinkedPoint.create(this, 'setCenter', - this.getCenterX(), this.getCenterY(), arguments[0]); - }, - - setCenter: function(point) { - point = Point.read(arguments); - return this.setCenterX(point.x).setCenterY(point.y); - }, - - equals: function(rect) { - rect = Rectangle.read(arguments); - return this.x == rect.x && this.y == rect.y - && this.width == rect.width && this.height == rect.height; - }, - - isEmpty: function() { - return this.width == 0 || this.height == 0; - }, - - toString: function() { - var format = Base.formatNumber; - return '{ x: ' + format(this.x) - + ', y: ' + format(this.y) - + ', width: ' + format(this.width) - + ', height: ' + format(this.height) - + ' }'; - }, - - contains: function(arg) { - return arg && arg.width !== undefined - || (Array.isArray(arg) ? arg : arguments).length == 4 - ? this._containsRectangle(Rectangle.read(arguments)) - : this._containsPoint(Point.read(arguments)); - }, - - _containsPoint: function(point) { - var x = point.x, - y = point.y; - return x >= this.x && y >= this.y - && x <= this.x + this.width - && y <= this.y + this.height; - }, - - _containsRectangle: function(rect) { - var x = rect.x, - y = rect.y; - return x >= this.x && y >= this.y - && x + rect.width <= this.x + this.width - && y + rect.height <= this.y + this.height; - }, - - intersects: function(rect) { - rect = Rectangle.read(arguments); - return rect.x + rect.width > this.x - && rect.y + rect.height > this.y - && rect.x < this.x + this.width - && rect.y < this.y + this.height; - }, - - intersect: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.max(this.x, rect.x), - y1 = Math.max(this.y, rect.y), - x2 = Math.min(this.x + this.width, rect.x + rect.width), - y2 = Math.min(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - unite: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.min(this.x, rect.x), - y1 = Math.min(this.y, rect.y), - x2 = Math.max(this.x + this.width, rect.x + rect.width), - y2 = Math.max(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - include: function(point) { - point = Point.read(arguments); - var x1 = Math.min(this.x, point.x), - y1 = Math.min(this.y, point.y), - x2 = Math.max(this.x + this.width, point.x), - y2 = Math.max(this.y + this.height, point.y); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - expand: function(hor, ver) { - if (ver === undefined) - ver = hor; - return Rectangle.create(this.x - hor / 2, this.y - ver / 2, - this.width + hor, this.height + ver); - }, - - scale: function(hor, ver) { - return this.expand(this.width * hor - this.width, - this.height * (ver === undefined ? hor : ver) - this.height); - }, - - statics: { - create: function(x, y, width, height) { - return new Rectangle(Rectangle.dont).set(x, y, width, height); - } - } -}, new function() { - return Base.each([ - ['Top', 'Left'], ['Top', 'Right'], - ['Bottom', 'Left'], ['Bottom', 'Right'], - ['Left', 'Center'], ['Top', 'Center'], - ['Right', 'Center'], ['Bottom', 'Center'] - ], - function(parts, index) { - var part = parts.join(''); - var xFirst = /^[RL]/.test(part); - if (index >= 4) - parts[1] += xFirst ? 'Y' : 'X'; - var x = parts[xFirst ? 0 : 1], - y = parts[xFirst ? 1 : 0], - getX = 'get' + x, - getY = 'get' + y, - setX = 'set' + x, - setY = 'set' + y, - get = 'get' + part, - set = 'set' + part; - this[get] = function() { - return LinkedPoint.create(this, set, - this[getX](), this[getY](), arguments[0]); - }; - this[set] = function(point) { - point = Point.read(arguments); - return this[setX](point.x)[setY](point.y); - }; - }, {}); -}); - -var LinkedRectangle = Rectangle.extend({ - set: function(x, y, width, height, dontNotify) { - this._x = x; - this._y = y; - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - statics: { - create: function(owner, setter, x, y, width, height) { - var rect = new LinkedRectangle(LinkedRectangle.dont).set( - x, y, width, height, true); - rect._owner = owner; - rect._setter = setter; - return rect; - } - } -}, new function() { - var proto = Rectangle.prototype; - - return Base.each(['x', 'y', 'width', 'height'], function(key) { - var part = Base.capitalize(key); - var internal = '_' + key; - this['get' + part] = function() { - return this[internal]; - }; - - this['set' + part] = function(value) { - this[internal] = value; - if (!this._dontNotify) - this._owner[this._setter](this); - }; - }, Base.each(['Point', 'Size', 'Center', - 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', - 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - function(key) { - var name = 'set' + key; - this[name] = function(value) { - this._dontNotify = true; - proto[name].apply(this, arguments); - delete this._dontNotify; - this._owner[this._setter](this); - return this; - }; - }, {}) - ); -}); - -var Matrix = this.Matrix = Base.extend({ - initialize: function(arg) { - var count = arguments.length, - ok = true; - if (count == 6) { - this.set.apply(this, arguments); - } else if (count == 1) { - if (arg instanceof Matrix) { - this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty); - } else if (Array.isArray(arg)) { - this.set.apply(this, arg); - } else { - ok = false; - } - } else if (count == 0) { - this._a = this._d = 1; - this._c = this._b = this._tx = this._ty = 0; - } else { - ok = false; - } - if (!ok) - throw new Error('Unsupported matrix parameters'); - }, - - clone: function() { - return Matrix.create(this._a, this._c, this._b, this._d, - this._tx, this._ty); - }, - - set: function(a, c, b, d, tx, ty) { - this._a = a; - this._c = c; - this._b = b; - this._d = d; - this._tx = tx; - this._ty = ty; - return this; - }, - - scale: function( hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = Point.read(arguments, 1); - ver = hor; - } else { - center = Point.read(arguments, 2); - } - if (center) - this.translate(center); - this._a *= hor; - this._c *= hor; - this._b *= ver; - this._d *= ver; - if (center) - this.translate(center.negate()); - return this; - }, - - translate: function(point) { - point = Point.read(arguments); - var x = point.x, y = point.y; - this._tx += x * this._a + y * this._b; - this._ty += x * this._c + y * this._d; - return this; - }, - - rotate: function(angle, center) { - return this.concatenate( - Matrix.getRotateInstance.apply(Matrix, arguments)); - }, - - shear: function( hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = Point.read(arguments, 1); - ver = hor; - } else { - center = Point.read(arguments, 2); - } - if (center) - this.translate(center); - var a = this._a, - c = this._c; - this._a += ver * this._b; - this._c += ver * this._d; - this._b += hor * a; - this._d += hor * c; - if (center) - this.translate(center.negate()); - return this; - }, - - toString: function() { - var format = Base.formatNumber; - return '[[' + [format(this._a), format(this._b), - format(this._tx)].join(', ') + '], [' - + [format(this._c), format(this._d), - format(this._ty)].join(', ') + ']]'; - }, - - getValues: function() { - return [ this._a, this._c, this._b, this._d, this._tx, this._ty ]; - }, - - concatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d; - this._a = mx._a * a + mx._c * b; - this._b = mx._b * a + mx._d * b; - this._tx += mx._tx * a + mx._ty * b; - this._c = mx._a * c + mx._c * d; - this._d = mx._b * c + mx._d * d; - this._ty += mx._tx * c + mx._ty * d; - return this; - }, - - preConcatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - tx = this._tx, - ty = this._ty; - this._a = mx._a * a + mx._b * c; - this._c = mx._c * a + mx._d * c; - this._b = mx._a * b + mx._b * d; - this._d = mx._c * b + mx._d * d; - this._tx = mx._a * tx + mx._b * ty + mx._tx; - this._ty = mx._c * tx + mx._d * ty + mx._ty; - return this; - }, - - transform: function( src, srcOff, dst, dstOff, numPts) { - return arguments.length < 5 - ? this._transformPoint(Point.read(arguments)) - : this._transformCoordinates(src, srcOff, dst, dstOff, numPts); - }, - - _transformPoint: function(point, dest, dontNotify) { - var x = point.x, - y = point.y; - if (!dest) - dest = new Point(Point.dont); - return dest.set( - x * this._a + y * this._b + this._tx, - x * this._c + y * this._d + this._ty, - dontNotify - ); - }, - - _transformCoordinates: function(src, srcOff, dst, dstOff, numPts) { - var i = srcOff, j = dstOff, - srcEnd = srcOff + 2 * numPts; - while (i < srcEnd) { - var x = src[i++]; - var y = src[i++]; - dst[j++] = x * this._a + y * this._b + this._tx; - dst[j++] = x * this._c + y * this._d + this._ty; - } - return dst; - }, - - _transformCorners: function(rect) { - var x1 = rect.x, - y1 = rect.y, - x2 = x1 + rect.width, - y2 = y1 + rect.height, - coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; - return this._transformCoordinates(coords, 0, coords, 0, 4); - }, - - _transformBounds: function(bounds) { - var coords = this._transformCorners(bounds), - min = coords.slice(0, 2), - max = coords.slice(0); - for (var i = 2; i < 8; i++) { - var val = coords[i], - j = i & 1; - if (val < min[j]) - min[j] = val; - else if (val > max[j]) - max[j] = val; - } - return Rectangle.create(min[0], min[1], - max[0] - min[0], max[1] - min[1]); - }, - - inverseTransform: function(point) { - return this._inverseTransform(Point.read(arguments)); - }, - - _getDeterminant: function() { - var det = this._a * this._d - this._b * this._c; - return isFinite(det) && Math.abs(det) > Numerical.EPSILON - && isFinite(this._tx) && isFinite(this._ty) - ? det : null; - }, - - _inverseTransform: function(point, dest, dontNotify) { - var det = this._getDeterminant(); - if (!det) - return null; - var x = point.x - this._tx, - y = point.y - this._ty; - if (!dest) - dest = new Point(Point.dont); - return dest.set( - (x * this._d - y * this._b) / det, - (y * this._a - x * this._c) / det, - dontNotify - ); - }, - - getTranslation: function() { - return new Point(this._tx, this._ty); - }, - - getScaling: function() { - var hor = Math.sqrt(this._a * this._a + this._c * this._c), - ver = Math.sqrt(this._b * this._b + this._d * this._d); - return new Point(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); - }, - - getRotation: function() { - var angle1 = -Math.atan2(this._b, this._d), - angle2 = Math.atan2(this._c, this._a); - return Math.abs(angle1 - angle2) < Numerical.TOLERANCE - ? angle1 * 180 / Math.PI : undefined; - }, - - isIdentity: function() { - return this._a == 1 && this._c == 0 && this._b == 0 && this._d == 1 - && this._tx == 0 && this._ty == 0; - }, - - isInvertible: function() { - return !!this._getDeterminant(); - }, - - isSingular: function() { - return !this._getDeterminant(); - }, - - createInverse: function() { - var det = this._getDeterminant(); - return det && Matrix.create( - this._d / det, - -this._c / det, - -this._b / det, - this._a / det, - (this._b * this._ty - this._d * this._tx) / det, - (this._c * this._tx - this._a * this._ty) / det); - }, - - createShiftless: function() { - return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); - }, - - setToScale: function(hor, ver) { - return this.set(hor, 0, 0, ver, 0, 0); - }, - - setToTranslation: function(delta) { - delta = Point.read(arguments); - return this.set(1, 0, 0, 1, delta.x, delta.y); - }, - - setToShear: function(hor, ver) { - return this.set(1, ver, hor, 1, 0, 0); - }, - - setToRotation: function(angle, center) { - center = Point.read(arguments, 1); - angle = angle * Math.PI / 180; - var x = center.x, - y = center.y, - cos = Math.cos(angle), - sin = Math.sin(angle); - return this.set(cos, sin, -sin, cos, - x - x * cos + y * sin, - y - x * sin - y * cos); - }, - - applyToContext: function(ctx, reset) { - ctx[reset ? 'setTransform' : 'transform']( - this._a, this._c, this._b, this._d, this._tx, this._ty); - return this; - }, - - statics: { - create: function(a, c, b, d, tx, ty) { - return new Matrix(Matrix.dont).set(a, c, b, d, tx, ty); - }, - - getScaleInstance: function(hor, ver) { - var mx = new Matrix(); - return mx.setToScale.apply(mx, arguments); - }, - - getTranslateInstance: function(delta) { - var mx = new Matrix(); - return mx.setToTranslation.apply(mx, arguments); - }, - - getShearInstance: function(hor, ver, center) { - var mx = new Matrix(); - return mx.setToShear.apply(mx, arguments); - }, - - getRotateInstance: function(angle, center) { - var mx = new Matrix(); - return mx.setToRotation.apply(mx, arguments); - } - } -}, new function() { - return Base.each({ - scaleX: '_a', - scaleY: '_d', - translateX: '_tx', - translateY: '_ty', - shearX: '_b', - shearY: '_c' - }, function(prop, name) { - name = Base.capitalize(name); - this['get' + name] = function() { - return this[prop]; - }; - this['set' + name] = function(value) { - this[prop] = value; - }; - }, {}); -}); - -var Line = this.Line = Base.extend({ - initialize: function(point1, point2, infinite) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - if (arguments.length == 3) { - this.point = point1; - this.vector = point2.subtract(point1); - this.infinite = infinite; - } else { - this.point = point1; - this.vector = point2; - this.infinite = true; - } - }, - - intersect: function(line) { - var cross = this.vector.cross(line.vector); - if (Math.abs(cross) <= Numerical.EPSILON) - return null; - var v = line.point.subtract(this.point), - t1 = v.cross(line.vector) / cross, - t2 = v.cross(this.vector) / cross; - return (this.infinite || 0 <= t1 && t1 <= 1) - && (line.infinite || 0 <= t2 && t2 <= 1) - ? this.point.add(this.vector.multiply(t1)) : null; - }, - - getSide: function(point) { - var v1 = this.vector, - v2 = point.subtract(this.point), - ccw = v2.cross(v1); - if (ccw == 0) { - ccw = v2.dot(v1); - if (ccw > 0) { - ccw = v2.subtract(v1).dot(v1); - if (ccw < 0) - ccw = 0; - } - } - return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; - }, - - getDistance: function(point) { - var m = this.vector.y / this.vector.x, - b = this.point.y - (m * this.point.x); - var dist = Math.abs(point.y - (m * point.x) - b) / Math.sqrt(m * m + 1); - return this.infinite ? dist : Math.min(dist, - point.getDistance(this.point), - point.getDistance(this.point.add(this.vector))); - } -}); - -var Project = this.Project = PaperScopeItem.extend({ - _list: 'projects', - _reference: 'project', - - initialize: function() { - this.base(true); - this._currentStyle = new PathStyle(); - this._selectedItems = {}; - this._selectedItemCount = 0; - this.layers = []; - this.symbols = []; - this.activeLayer = new Layer(); - }, - - _needsRedraw: function() { - if (this._scope) - this._scope._needsRedraw(); - }, - - getCurrentStyle: function() { - return this._currentStyle; - }, - - setCurrentStyle: function(style) { - this._currentStyle.initialize(style); - }, - - getIndex: function() { - return this._index; - }, - - getSelectedItems: function() { - var items = []; - Base.each(this._selectedItems, function(item) { - items.push(item); - }); - return items; - }, - - _updateSelection: function(item) { - if (item._selected) { - this._selectedItemCount++; - this._selectedItems[item.getId()] = item; - } else { - this._selectedItemCount--; - delete this._selectedItems[item.getId()]; - } - }, - - selectAll: function() { - for (var i = 0, l = this.layers.length; i < l; i++) - this.layers[i].setSelected(true); - }, - - deselectAll: function() { - for (var i in this._selectedItems) - this._selectedItems[i].setSelected(false); - }, - - hitTest: function(point, options) { - options = HitResult.getOptions(point, options); - point = options.point; - for (var i = this.layers.length - 1; i >= 0; i--) { - var res = this.layers[i].hitTest(point, options); - if (res) return res; - } - return null; - }, - - draw: function(ctx) { - ctx.save(); - var param = { offset: new Point(0, 0) }; - for (var i = 0, l = this.layers.length; i < l; i++) - Item.draw(this.layers[i], ctx, param); - ctx.restore(); - - if (this._selectedItemCount > 0) { - ctx.save(); - ctx.strokeWidth = 1; - ctx.strokeStyle = ctx.fillStyle = '#009dec'; - param = { selection: true }; - Base.each(this._selectedItems, function(item) { - item.draw(ctx, param); - }); - ctx.restore(); - } - } -}); - -var Symbol = this.Symbol = Base.extend({ - initialize: function(item) { - this.project = paper.project; - this.project.symbols.push(this); - this.setDefinition(item); - this._instances = {}; - }, - - _changed: function(flags) { - Base.each(this._instances, function(item) { - item._changed(flags); - }); - }, - - getDefinition: function() { - return this._definition; - }, - - setDefinition: function(item) { - if (item._parentSymbol) - item = item.clone(); - if (this._definition) - delete this._definition._parentSymbol; - this._definition = item; - item.remove(); - item.setPosition(new Point()); - item._parentSymbol = this; - this._changed(Change.GEOMETRY); - }, - - place: function(position) { - return new PlacedSymbol(this, position); - }, - - clone: function() { - return new Symbol(this._definition.clone()); - } -}); - -var ChangeFlag = { - APPEARANCE: 1, - HIERARCHY: 2, - GEOMETRY: 4, - STROKE: 8, - STYLE: 16, - ATTRIBUTE: 32, - CONTENT: 64, - PIXELS: 128, - CLIPPING: 256 -}; - -var Change = { - HIERARCHY: ChangeFlag.HIERARCHY | ChangeFlag.APPEARANCE, - GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, - STROKE: ChangeFlag.STROKE | ChangeFlag.STYLE | ChangeFlag.APPEARANCE, - STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE, - ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE, - CONTENT: ChangeFlag.CONTENT | ChangeFlag.APPEARANCE, - PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE -}; - -var Item = this.Item = Base.extend({ - initialize: function() { - this._id = ++Item._id; - if (!this._project) - paper.project.activeLayer.addChild(this); - this._style = PathStyle.create(this); - this.setStyle(this._project.getCurrentStyle()); - }, - - _changed: function(flags) { - if (flags & ChangeFlag.GEOMETRY) { - delete this._bounds; - delete this._position; - } - if (flags & ChangeFlag.APPEARANCE) { - this._project._needsRedraw(); - } - if (this._parentSymbol) - this._parentSymbol._changed(flags); - if (this._project._changes) { - var entry = this._project._changesById[this._id]; - if (entry) { - entry.flags |= flags; - } else { - entry = { item: this, flags: flags }; - this._project._changesById[this._id] = entry; - this._project._changes.push(entry); - } - } - }, - - getId: function() { - return this._id; - }, - - getName: function() { - return this._name; - }, - - setName: function(name) { - - if (this._name) - this._removeFromNamed(); - this._name = name || undefined; - if (name) { - var children = this._parent._children, - namedChildren = this._parent._namedChildren; - (namedChildren[name] = namedChildren[name] || []).push(this); - children[name] = this; - } - this._changed(ChangeFlag.ATTRIBUTE); - }, - - getPosition: function() { - var pos = this._position - || (this._position = this.getBounds().getCenter()); - return LinkedPoint.create(this, 'setPosition', pos._x, pos._y); - }, - - setPosition: function(point) { - this.translate(Point.read(arguments).subtract(this.getPosition())); - }, - - getStyle: function() { - return this._style; - }, - - setStyle: function(style) { - this._style.initialize(style); - }, - - statics: { - _id: 0 - } -}, new function() { - return Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], - function(name) { - var part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - if (value != this[name]) { - this[name] = value; - this._changed(name === '_locked' - ? ChangeFlag.ATTRIBUTE : Change.ATTRIBUTE); - } - }; - }, {}); -}, { - - _locked: false, - - _visible: true, - - _blendMode: 'normal', - - _opacity: 1, - - _guide: false, - - isSelected: function() { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - if (this._children[i].isSelected()) - return true; - } - return this._selected; - }, - - setSelected: function(selected) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - this._children[i].setSelected(selected); - } - } else if ((selected = !!selected) != this._selected) { - this._selected = selected; - this._project._updateSelection(this); - this._changed(Change.ATTRIBUTE); - } - }, - - _selected: false, - - isFullySelected: function() { - if (this._children && this._selected) { - for (var i = 0, l = this._children.length; i < l; i++) - if (!this._children[i].isFullySelected()) - return false; - return true; - } - return this._selected; - }, - - setFullySelected: function(selected) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - this._children[i].setFullySelected(selected); - } - } - this.setSelected(selected); - }, - - isClipMask: function() { - return this._clipMask; - }, - - setClipMask: function(clipMask) { - if (this._clipMask != (clipMask = !!clipMask)) { - this._clipMask = clipMask; - if (clipMask) { - this.setFillColor(null); - this.setStrokeColor(null); - } - this._changed(Change.ATTRIBUTE); - if (this._parent) - this._parent._changed(ChangeFlag.CLIPPING); - } - }, - - _clipMask: false, - - getProject: function() { - return this._project; - }, - - _setProject: function(project) { - if (this._project != project) { - this._project = project; - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - this._children[i]._setProject(project); - } - } - } - }, - - getLayer: function() { - var parent = this; - while (parent = parent._parent) { - if (parent instanceof Layer) - return parent; - } - return null; - }, - - getParent: function() { - return this._parent; - }, - - getChildren: function() { - return this._children; - }, - - setChildren: function(items) { - this.removeChildren(); - this.addChildren(items); - }, - - getFirstChild: function() { - return this._children && this._children[0] || null; - }, - - getLastChild: function() { - return this._children && this._children[this._children.length - 1] - || null; - }, - - getNextSibling: function() { - return this._parent && this._parent._children[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent && this._parent._children[this._index - 1] || null; - }, - - getIndex: function() { - return this._index; - }, - - clone: function() { - return this._clone(new this.constructor()); - }, - - _clone: function(copy) { - copy.setStyle(this._style); - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - copy.addChild(this._children[i].clone()); - } - var keys = ['_locked', '_visible', '_blendMode', '_opacity', - '_clipMask', '_guide']; - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - if (this.hasOwnProperty(key)) - copy[key] = this[key]; - } - copy.setSelected(this._selected); - if (this._name) - copy.setName(this._name); - return copy; - }, - - copyTo: function(itemOrProject) { - var copy = this.clone(); - if (itemOrProject.layers) { - itemOrProject.activeLayer.addChild(copy); - } else { - itemOrProject.addChild(copy); - } - return copy; - }, - - rasterize: function(resolution) { - var bounds = this.getStrokeBounds(), - scale = (resolution || 72) / 72, - canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), - ctx = canvas.getContext('2d'), - matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); - matrix.applyToContext(ctx); - this.draw(ctx, {}); - var raster = new Raster(canvas); - raster.setBounds(bounds); - return raster; - }, - - hitTest: function(point, options, matrix) { - options = HitResult.getOptions(point, options); - point = options.point; - if (!this._children && !this.getRoughBounds(matrix) - .expand(options.tolerance)._containsPoint(point)) - return null; - if ((options.center || options.bounds) && - !(this instanceof Layer && !this._parent)) { - var bounds = this.getBounds(), - that = this, - points = ['TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - res; - function checkBounds(type, part) { - var pt = bounds['get' + part]().transform(matrix); - if (point.getDistance(pt) < options.tolerance) - return new HitResult(type, that, - { name: Base.hyphenate(part), point: pt }); - } - if (options.center && (res = checkBounds('center', 'Center'))) - return res; - if (options.bounds) { - for (var i = 0; i < 8; i++) - if (res = checkBounds('bounds', points[i])) - return res; - } - } - - return this._children || !(options.guides && !this._guide - || options.selected && !this._selected) - ? this._hitTest(point, options, matrix) : null; - }, - - _hitTest: function(point, options, matrix) { - if (this._children) { - for (var i = this._children.length - 1; i >= 0; i--) { - var res = this._children[i].hitTest(point, options, matrix); - if (res) return res; - } - } - }, - - addChild: function(item) { - return this.insertChild(undefined, item); - }, - - insertChild: function(index, item) { - if (this._children) { - item._remove(false, true); - Base.splice(this._children, [item], index, 0); - item._parent = this; - item._setProject(this._project); - if (item._name) - item.setName(item._name); - this._changed(Change.HIERARCHY); - return true; - } - return false; - }, - - addChildren: function(items) { - for (var i = 0, l = items && items.length; i < l; i++) - this.insertChild(undefined, items[i]); - }, - - insertChildren: function(index, items) { - for (var i = 0, l = items && items.length; i < l; i++) { - if (this.insertChild(index, items[i])) - index++; - } - }, - - insertAbove: function(item) { - return item._parent && item._parent.insertChild( - item._index + 1, this); - }, - - insertBelow: function(item) { - return item._parent && item._parent.insertChild( - item._index - 1, this); - }, - - appendTop: function(item) { - return this.addChild(item); - }, - - appendBottom: function(item) { - return this.insertChild(0, item); - }, - - moveAbove: function(item) { - return this.insertAbove(item); - }, - - moveBelow: function(item) { - return this.insertBelow(item); - }, - - _removeFromNamed: function() { - var children = this._parent._children, - namedChildren = this._parent._namedChildren, - name = this._name, - namedArray = namedChildren[name], - index = namedArray ? namedArray.indexOf(this) : -1; - if (index == -1) - return; - if (children[name] == this) - delete children[name]; - namedArray.splice(index, 1); - if (namedArray.length) { - children[name] = namedArray[namedArray.length - 1]; - } else { - delete namedChildren[name]; - } - }, - - _remove: function(deselect, notify) { - if (this._parent) { - if (deselect) - this.setSelected(false); - if (this._name) - this._removeFromNamed(); - Base.splice(this._parent._children, null, this._index, 1); - if (notify) - this._parent._changed(Change.HIERARCHY); - this._parent = null; - return true; - } - return false; - }, - - remove: function() { - return this._remove(true, true); - }, - - removeChildren: function(from, to) { - if (!this._children) - return null; - from = from || 0; - to = Base.pick(to, this._children.length); - var removed = this._children.splice(from, to - from); - for (var i = removed.length - 1; i >= 0; i--) - removed[i]._remove(true, false); - if (removed.length > 0) - this._changed(Change.HIERARCHY); - return removed; - }, - - reverseChildren: function() { - if (this._children) { - this._children.reverse(); - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i]._index = i; - this._changed(Change.HIERARCHY); - } - }, - - isEditable: function() { - var item = this; - while (item) { - if (!item._visible || item._locked) - return false; - item = item._parent; - } - return true; - }, - - _getOrder: function(item) { - function getList(item) { - var list = []; - do { - list.unshift(item); - } while (item = item._parent) - return list; - } - var list1 = getList(this), - list2 = getList(item); - for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { - if (list1[i] != list2[i]) { - return list1[i]._index < list2[i]._index ? 1 : -1; - } - } - return 0; - }, - - hasChildren: function() { - return this._children && this._children.length > 0; - }, - - isAbove: function(item) { - return this._getOrder(item) == -1; - }, - - isBelow: function(item) { - return this._getOrder(item) == 1; - }, - - isParent: function(item) { - return this._parent == item; - }, - - isChild: function(item) { - return item && item._parent == this; - }, - - isDescendant: function(item) { - var parent = this; - while (parent = parent._parent) { - if (parent == item) - return true; - } - return false; - }, - - isAncestor: function(item) { - return item ? item.isDescendant(this) : false; - }, - - isGroupedWith: function(item) { - var parent = this._parent; - while (parent) { - if (parent._parent - && (parent instanceof Group || parent instanceof CompoundPath) - && item.isDescendant(parent)) - return true; - parent = parent._parent; - } - return false; - }, - - _getBounds: function(getter, cacheName, args) { - var children = this._children; - if (!children || children.length == 0) - return new Rectangle(); - var x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - if (child._visible) { - var rect = child[getter](args[0]); - x1 = Math.min(rect.x, x1); - y1 = Math.min(rect.y, y1); - x2 = Math.max(rect.x + rect.width, x2); - y2 = Math.max(rect.y + rect.height, y2); - } - } - var bounds = Rectangle.create(x1, y1, x2 - x1, y2 - y1); - return getter == 'getBounds' ? this._createBounds(bounds) : bounds; - }, - - _createBounds: function(rect) { - return LinkedRectangle.create(this, 'setBounds', - rect.x, rect.y, rect.width, rect.height); - }, - - getBounds: function() { - return this._getBounds('getBounds', '_bounds', arguments); - }, - - setBounds: function(rect) { - rect = Rectangle.read(arguments); - var bounds = this.getBounds(), - matrix = new Matrix(), - center = rect.getCenter(); - matrix.translate(center); - if (rect.width != bounds.width || rect.height != bounds.height) { - matrix.scale( - bounds.width != 0 ? rect.width / bounds.width : 1, - bounds.height != 0 ? rect.height / bounds.height : 1); - } - center = bounds.getCenter(); - matrix.translate(-center.x, -center.y); - this.transform(matrix); - }, - - getStrokeBounds: function() { - return this._getBounds('getStrokeBounds', '_strokeBounds', arguments); - }, - - getHandleBounds: function() { - return this._getBounds('getHandleBounds', '_handleBounds', arguments); - }, - - getRoughBounds: function() { - return this._getBounds('getRoughBounds', '_roughBounds', arguments); - }, - - scale: function(hor, ver , center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = ver; - ver = hor; - } - return this.transform(new Matrix().scale(hor, ver, - center || this.getPosition())); - }, - - translate: function(delta) { - var mx = new Matrix(); - return this.transform(mx.translate.apply(mx, arguments)); - }, - - rotate: function(angle, center) { - return this.transform(new Matrix().rotate(angle, - center || this.getPosition())); - }, - - shear: function(hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = ver; - ver = hor; - } - return this.transform(new Matrix().shear(hor, ver, - center || this.getPosition())); - }, - - transform: function(matrix, flags) { - var bounds = this._bounds, - position = this._position, - children = this._children; - if (this._transform) { - this._transform(matrix, flags); - this._changed(Change.GEOMETRY); - } - if (bounds && matrix.getRotation() % 90 === 0) { - this._bounds = this._createBounds( - matrix._transformBounds(bounds)); - this._position = this._bounds.getCenter(); - } else if (position) { - this._position = matrix._transformPoint(position, position, true); - } - for (var i = 0, l = children && children.length; i < l; i++) - children[i].transform(matrix, flags); - return this; - }, - - fitBounds: function(rectangle, fill) { - rectangle = Rectangle.read(arguments); - var bounds = this.getBounds(), - itemRatio = bounds.height / bounds.width, - rectRatio = rectangle.height / rectangle.width, - scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) - ? rectangle.width / bounds.width - : rectangle.height / bounds.height, - delta = rectangle.getCenter().subtract(bounds.getCenter()), - newBounds = new Rectangle(new Point(), - new Size(bounds.width * scale, bounds.height * scale)); - newBounds.setCenter(rectangle.getCenter()); - this.setBounds(newBounds); - }, - - toString: function() { - return (this.constructor._name || 'Item') + (this._name - ? " '" + this._name + "'" - : ' @' + this._id); - }, - - statics: { - drawSelectedBounds: function(bounds, ctx, matrix) { - var coords = matrix._transformCorners(bounds); - ctx.beginPath(); - for (var i = 0; i < 8; i++) - ctx[i == 0 ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); - ctx.closePath(); - ctx.stroke(); - for (var i = 0; i < 8; i++) { - ctx.beginPath(); - ctx.rect(coords[i] - 2, coords[++i] - 2, 4, 4); - ctx.fill(); - } - }, - - draw: function(item, ctx, param) { - if (!item._visible || item._opacity == 0) - return; - - var tempCanvas, parentCtx; - if (item._blendMode !== 'normal' - || item._opacity < 1 - && !(item._segments && (!item.getFillColor() - || !item.getStrokeColor()))) { - var bounds = item.getStrokeBounds() || item.getBounds(); - if (!bounds.width || !bounds.height) - return; - - var itemOffset = bounds.getTopLeft().floor(), - size = bounds.getSize().ceil().add(new Size(1, 1)); - tempCanvas = CanvasProvider.getCanvas(size); - - parentCtx = ctx; - - ctx = tempCanvas.getContext('2d'); - ctx.save(); - - ctx.translate(-itemOffset.x, -itemOffset.y); - } - var savedOffset; - if (itemOffset) { - savedOffset = param.offset; - param.offset = itemOffset; - } - item.draw(ctx, param); - if (itemOffset) - param.offset = savedOffset; - - if (tempCanvas) { - - ctx.restore(); - - if (item._blendMode !== 'normal') { - var pixelOffset = itemOffset.subtract(param.offset); - BlendMode.process(item._blendMode, ctx, parentCtx, - item._opacity, pixelOffset); - } else { - parentCtx.save(); - parentCtx.globalAlpha = item._opacity; - parentCtx.drawImage(tempCanvas, - itemOffset.x, itemOffset.y); - parentCtx.restore(); - } - - CanvasProvider.returnCanvas(tempCanvas); - } - } - } -}, new function() { - - var sets = { - down: {}, drag: {}, up: {}, move: {} - }; - - function removeAll(set) { - for (var id in set) { - var item = set[id]; - item.remove(); - for (var type in sets) { - var other = sets[type]; - if (other != set && other[item.getId()]) - delete other[item.getId()]; - } - } - } - - function installHandler(name) { - var handler = 'onMouse' + Base.capitalize(name); - var func = paper.tool[handler]; - if (!func || !func._installed) { - var hash = {}; - hash[handler] = function(event) { - if (name === 'up') - sets.drag = {}; - removeAll(sets[name]); - sets[name] = {}; - if (this.base) - this.base(event); - }; - paper.tool.inject(hash); - paper.tool[handler]._installed = true; - } - } - - return Base.each(['down', 'drag', 'up', 'move'], function(name) { - this['removeOn' + Base.capitalize(name)] = function() { - var hash = {}; - hash[name] = true; - return this.removeOn(hash); - }; - }, { - removeOn: function(obj) { - for (var name in obj) { - if (obj[name]) { - sets[name][this.getId()] = this; - if (name === 'drag') - installHandler('up'); - installHandler(name); - } - } - return this; - } - }); -}); - -var Group = this.Group = Item.extend({ - initialize: function(items) { - this.base(); - this._children = []; - this._namedChildren = {}; - this.addChildren(!items || !Array.isArray(items) - || typeof items[0] !== 'object' ? arguments : items); - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & (ChangeFlag.HIERARCHY | ChangeFlag.CLIPPING)) { - delete this._clipItem; - } - }, - - _getClipItem: function() { - if (this._clipItem !== undefined) - return this._clipItem; - for (var i = 0, l = this._children.length; i < l; i++) { - var child = this._children[i]; - if (child._clipMask) - return this._clipItem = child; - } - return this._clipItem = null; - }, - - isClipped: function() { - return !!this._getClipItem(); - }, - - setClipped: function(clipped) { - var child = this.getFirstChild(); - if (child) - child.setClipMask(clipped); - return this; - }, - - draw: function(ctx, param) { - var clipItem = this._getClipItem(); - if (clipItem) - Item.draw(clipItem, ctx, param); - for (var i = 0, l = this._children.length; i < l; i++) { - var item = this._children[i]; - if (item != clipItem) - Item.draw(item, ctx, param); - } - } -}); - -var Layer = this.Layer = Group.extend({ - initialize: function(items) { - this._project = paper.project; - this._index = this._project.layers.push(this) - 1; - this.base.apply(this, arguments); - this.activate(); - }, - - _remove: function(deselect, notify) { - if (this._parent) - return this.base(deselect, notify); - if (this._index != null) { - if (deselect) - this.setSelected(false); - Base.splice(this._project.layers, null, this._index, 1); - this._project._needsRedraw(); - return true; - } - return false; - }, - - getNextSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index - 1] || null; - }, - - activate: function() { - this._project.activeLayer = this; - } -}, new function () { - function insert(above) { - return function(item) { - if (item instanceof Layer && !item._parent - && this._remove(false, true)) { - Base.splice(item._project.layers, [this], - item._index + (above ? 1 : -1), 0); - this._setProject(item._project); - return true; - } - return this.base(item); - }; - } - - return { - insertAbove: insert(true), - - insertBelow: insert(false) - }; -}); - -var PlacedItem = this.PlacedItem = Item.extend({ - - _transform: function(matrix, flags) { - this._matrix.preConcatenate(matrix); - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & ChangeFlag.GEOMETRY) { - delete this._strokeBounds; - delete this._handleBounds; - delete this._roughBounds; - } - }, - - getMatrix: function() { - return this._matrix; - }, - - setMatrix: function(matrix) { - this._matrix = matrix.clone(); - this._changed(Change.GEOMETRY); - }, - - getBounds: function() { - var useCache = arguments[0] === undefined; - if (useCache && this._bounds) - return this._bounds; - var bounds = this.getStrokeBounds(arguments[0]); - if (useCache) - bounds = this._bounds = this._createBounds(bounds); - return bounds; - }, - - _getBounds: function(getter, cacheName, args) { - var matrix = args[0], - useCache = matrix === undefined; - if (useCache && this[cacheName]) - return this[cacheName]; - matrix = matrix ? matrix.clone().concatenate(this._matrix) - : this._matrix; - var bounds = this._calculateBounds(getter, matrix); - if (useCache) - this[cacheName] = bounds; - return bounds; - } -}); - -var Raster = this.Raster = PlacedItem.extend({ - initialize: function(object) { - this.base(); - if (object.getContext) { - this.setCanvas(object); - } else { - if (typeof object === 'string') - object = document.getElementById(object); - this.setImage(object); - } - this._matrix = new Matrix(); - }, - - clone: function() { - var image = this._image; - if (!image) { - image = CanvasProvider.getCanvas(this._size); - image.getContext('2d').drawImage(this._canvas, 0, 0); - } - var copy = new Raster(image); - copy._matrix = this._matrix.clone(); - return this._clone(copy); - }, - - getSize: function() { - return this._size; - }, - - setSize: function() { - var size = Size.read(arguments), - image = this.getImage(); - this.setCanvas(CanvasProvider.getCanvas(size)); - this.getContext(true).drawImage(image, 0, 0, size.width, size.height); - }, - - getWidth: function() { - return this._size.width; - }, - - getHeight: function() { - return this._size.height; - }, - - getPpi: function() { - var matrix = this._matrix, - orig = new Point(0, 0).transform(matrix), - u = new Point(1, 0).transform(matrix).subtract(orig), - v = new Point(0, 1).transform(matrix).subtract(orig); - return new Size( - 72 / u.getLength(), - 72 / v.getLength() - ); - }, - - getContext: function() { - if (!this._context) - this._context = this.getCanvas().getContext('2d'); - if (arguments[0]) - this._changed(Change.PIXELS); - return this._context; - }, - - setContext: function(context) { - this._context = context; - }, - - getCanvas: function() { - if (!this._canvas) { - this._canvas = CanvasProvider.getCanvas(this._size); - if (this._image) - this.getContext(true).drawImage(this._image, 0, 0); - } - return this._canvas; - }, - - setCanvas: function(canvas) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._canvas = canvas; - this._size = new Size(canvas.width, canvas.height); - this._image = null; - this._context = null; - this._changed(Change.GEOMETRY); - }, - - getImage: function() { - return this._image || this.getCanvas(); - }, - - setImage: function(image) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._image = image; - this._size = new Size(image.naturalWidth, image.naturalHeight); - this._canvas = null; - this._context = null; - this._changed(Change.GEOMETRY); - }, - - getSubImage: function(rect) { - rect = Rectangle.read(arguments); - var canvas = CanvasProvider.getCanvas(rect.getSize()); - canvas.getContext('2d').drawImage(this.getCanvas(), rect.x, rect.y, - canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); - return canvas; - }, - - drawImage: function(image, point) { - point = Point.read(arguments, 1); - this.getContext(true).drawImage(image, point.x, point.y); - }, - - getAverageColor: function(object) { - if (!object) - object = this.getBounds(); - var bounds, path; - if (object instanceof PathItem) { - path = object; - bounds = object.getBounds(); - } else if (object.width) { - bounds = new Rectangle(object); - } else if (object.x) { - bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1); - } - var sampleSize = 32, - width = Math.min(bounds.width, sampleSize), - height = Math.min(bounds.height, sampleSize); - var ctx = Raster._sampleContext; - if (!ctx) { - ctx = Raster._sampleContext = CanvasProvider.getCanvas( - new Size(sampleSize)).getContext('2d'); - } else { - ctx.clearRect(0, 0, sampleSize, sampleSize); - } - ctx.save(); - ctx.scale(width / bounds.width, height / bounds.height); - ctx.translate(-bounds.x, -bounds.y); - if (path) - path.draw(ctx, { clip: true }); - this._matrix.applyToContext(ctx); - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - ctx.restore(); - var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), - Math.ceil(height)).data, - channels = [0, 0, 0], - total = 0; - for (var i = 0, l = pixels.length; i < l; i += 4) { - var alpha = pixels[i + 3]; - total += alpha; - alpha /= 255; - channels[0] += pixels[i] * alpha; - channels[1] += pixels[i + 1] * alpha; - channels[2] += pixels[i + 2] * alpha; - } - for (var i = 0; i < 3; i++) - channels[i] /= total; - return total ? Color.read(channels) : null; - }, - - getPixel: function(point) { - point = Point.read(arguments); - var pixels = this.getContext().getImageData(point.x, point.y, 1, 1).data, - channels = new Array(4); - for (var i = 0; i < 4; i++) - channels[i] = pixels[i] / 255; - return RgbColor.read(channels); - }, - - setPixel: function(point, color) { - var hasPoint = arguments.length == 2; - point = Point.read(arguments, 0, hasPoint ? 1 : 2); - color = Color.read(arguments, hasPoint ? 1 : 2); - var ctx = this.getContext(true), - imageData = ctx.createImageData(1, 1), - alpha = color.getAlpha(); - imageData.data[0] = color.getRed() * 255; - imageData.data[1] = color.getGreen() * 255; - imageData.data[2] = color.getBlue() * 255; - imageData.data[3] = alpha != null ? alpha * 255 : 255; - ctx.putImageData(imageData, point.x, point.y); - }, - - createData: function(size) { - size = Size.read(arguments); - return this.getContext().createImageData(size.width, size.height); - }, - - getData: function(rect) { - rect = Rectangle.read(arguments); - if (rect.isEmpty()) - rect = new Rectangle(this.getSize()); - return this.getContext().getImageData(rect.x, rect.y, - rect.width, rect.height); - }, - - setData: function(data, point) { - point = Point.read(arguments, 1); - this.getContext(true).putImageData(data, point.x, point.y); - }, - - _calculateBounds: function(getter, matrix) { - return matrix._transformBounds( - new Rectangle(this._size).setCenter(0, 0)); - }, - - getHandleBounds: function() { - return this.getStrokeBounds(arguments[0]); - }, - - getRoughBounds: function() { - return this.getStrokeBounds(arguments[0]); - }, - - draw: function(ctx, param) { - if (param.selection) { - var bounds = new Rectangle(this._size).setCenter(0, 0); - Item.drawSelectedBounds(bounds, ctx, this._matrix); - } else { - ctx.save(); - this._matrix.applyToContext(ctx); - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - ctx.restore(); - } - } -}); - -var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend({ - initialize: function(symbol, matrixOrOffset) { - this.base(); - this.setSymbol(symbol instanceof Symbol ? symbol : new Symbol(symbol)); - this._matrix = matrixOrOffset !== undefined - ? matrixOrOffset instanceof Matrix - ? matrixOrOffset - : new Matrix().translate(Point.read(arguments, 1)) - : new Matrix(); - }, - - getSymbol: function() { - return this._symbol; - }, - - setSymbol: function(symbol) { - if (this._symbol) - delete this._symbol._instances[this._id]; - this._symbol = symbol; - symbol._instances[this._id] = this; - }, - - clone: function() { - return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone())); - }, - - _calculateBounds: function(getter, matrix) { - return this.symbol._definition[getter](matrix); - }, - - draw: function(ctx, param) { - if (param.selection) { - Item.drawSelectedBounds(this.symbol._definition.getStrokeBounds(), - ctx, this._matrix); - } else { - ctx.save(); - this._matrix.applyToContext(ctx); - Item.draw(this.symbol.getDefinition(), ctx, param); - ctx.restore(); - } - } - -}); - -HitResult = Base.extend({ - initialize: function(type, item, values) { - this.type = type; - this.item = item; - if (values) { - Base.each(values, function(value, key) { - this[key] = value; - }, this); - } - }, - - statics: { - getOptions: function(point, options) { - return options && options._merged ? options : Base.merge({ - point: Point.read(arguments, 0, 1), - type: null, - tolerance: 2, - fill: !options, - stroke: !options, - segments: !options, - handles: false, - ends: false, - center: false, - bounds: false, - guides: false, - selected: false, - _merged: true - }, options); - } - } -}); - -var Segment = this.Segment = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5) { - var count = arguments.length, - createPoint = SegmentPoint.create, - point, handleIn, handleOut; - if (count == 0) { - } else if (count == 1) { - if (arg0.point) { - point = arg0.point; - handleIn = arg0.handleIn; - handleOut = arg0.handleOut; - } else { - point = arg0; - } - } else if (count < 6) { - if (count == 2 && arg1.x === undefined) { - point = [ arg0, arg1 ]; - } else { - point = arg0; - handleIn = arg1; - handleOut = arg2; - } - } else if (count == 6) { - point = [ arg0, arg1 ]; - handleIn = [ arg2, arg3 ]; - handleOut = [ arg4, arg5 ]; - } - createPoint(this, '_point', point); - createPoint(this, '_handleIn', handleIn); - createPoint(this, '_handleOut', handleOut); - }, - - _changed: function(point) { - if (!this._path) - return; - var curve = this._path._curves && this.getCurve(), other; - if (curve) { - curve._changed(); - if (other = (curve[point == this._point - || point == this._handleIn && curve._segment1 == this - ? 'getPrevious' : 'getNext']())) { - other._changed(); - } - } - this._path._changed(Change.GEOMETRY); - }, - - getPoint: function() { - return this._point; - }, - - setPoint: function(point) { - point = Point.read(arguments); - this._point.set(point.x, point.y); - }, - - getHandleIn: function() { - return this._handleIn; - }, - - setHandleIn: function(point) { - point = Point.read(arguments); - this._handleIn.set(point.x, point.y); - }, - - getHandleOut: function() { - return this._handleOut; - }, - - setHandleOut: function(point) { - point = Point.read(arguments); - this._handleOut.set(point.x, point.y); - }, - - _isSelected: function(point) { - var state = this._selectionState; - return point == this._point ? !!(state & SelectionState.POINT) - : point == this._handleIn ? !!(state & SelectionState.HANDLE_IN) - : point == this._handleOut ? !!(state & SelectionState.HANDLE_OUT) - : false; - }, - - _setSelected: function(point, selected) { - var path = this._path, - selected = !!selected, - state = this._selectionState || 0, - selection = [ - !!(state & SelectionState.POINT), - !!(state & SelectionState.HANDLE_IN), - !!(state & SelectionState.HANDLE_OUT) - ]; - if (point == this._point) { - if (selected) { - selection[1] = selection[2] = false; - } else { - var previous = this.getPrevious(), - next = this.getNext(); - selection[1] = previous && (previous._point.isSelected() - || previous._handleOut.isSelected()); - selection[2] = next && (next._point.isSelected() - || next._handleIn.isSelected()); - } - selection[0] = selected; - } else { - var index = point == this._handleIn ? 1 : 2; - if (selection[index] != selected) { - if (selected) - selection[0] = false; - selection[index] = selected; - path._changed(Change.ATTRIBUTE); - } - } - this._selectionState = (selection[0] ? SelectionState.POINT : 0) - | (selection[1] ? SelectionState.HANDLE_IN : 0) - | (selection[2] ? SelectionState.HANDLE_OUT : 0); - if (path && state != this._selectionState) - path._updateSelection(this, state, this._selectionState); - }, - - isSelected: function() { - return this._isSelected(this._point); - }, - - setSelected: function(selected) { - this._setSelected(this._point, selected); - }, - - getIndex: function() { - return this._index !== undefined ? this._index : null; - }, - - getPath: function() { - return this._path || null; - }, - - getCurve: function() { - if (this._path) { - var index = this._index; - if (!this._path._closed && index == this._path._segments.length - 1) - index--; - return this._path.getCurves()[index] || null; - } - return null; - }, - - getNext: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index + 1] - || this._path._closed && segments[0]) || null; - }, - - getPrevious: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index - 1] - || this._path._closed && segments[segments.length - 1]) || null; - }, - - reverse: function() { - return new Segment(this._point, this._handleOut, this._handleIn); - }, - - remove: function() { - return this._path ? !!this._path.removeSegment(this._index) : false; - }, - - toString: function() { - var parts = [ 'point: ' + this._point ]; - if (!this._handleIn.isZero()) - parts.push('handleIn: ' + this._handleIn); - if (!this._handleOut.isZero()) - parts.push('handleOut: ' + this._handleOut); - return '{ ' + parts.join(', ') + ' }'; - }, - - _transformCoordinates: function(matrix, coords, change) { - var point = this._point, - handleIn = !change || !this._handleIn.isZero() - ? this._handleIn : null, - handleOut = !change || !this._handleOut.isZero() - ? this._handleOut : null, - x = point._x, - y = point._y, - i = 2; - coords[0] = x; - coords[1] = y; - if (handleIn) { - coords[i++] = handleIn._x + x; - coords[i++] = handleIn._y + y; - } - if (handleOut) { - coords[i++] = handleOut._x + x; - coords[i++] = handleOut._y + y; - } - if (!matrix) - return; - matrix._transformCoordinates(coords, 0, coords, 0, i / 2); - x = coords[0]; - y = coords[1]; - if (change) { - point._x = x; - point._y = y; - i = 2; - if (handleIn) { - handleIn._x = coords[i++] - x; - handleIn._y = coords[i++] - y; - } - if (handleOut) { - handleOut._x = coords[i++] - x; - handleOut._y = coords[i++] - y; - } - } else { - if (!handleIn) { - coords[i++] = x; - coords[i++] = y; - } - if (!handleOut) { - coords[i++] = x; - coords[i++] = y; - } - } - } -}); - -var SegmentPoint = Point.extend({ - set: function(x, y) { - this._x = x; - this._y = y; - this._owner._changed(this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner._changed(this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner._changed(this); - }, - - isZero: function() { - return this._x == 0 && this._y == 0; - }, - - setSelected: function(selected) { - this._owner._setSelected(this, selected); - }, - - isSelected: function() { - return this._owner._isSelected(this); - }, - - statics: { - create: function(segment, key, pt) { - var point = new SegmentPoint(SegmentPoint.dont), - x, y, selected; - if (!pt) { - x = y = 0; - } else if ((x = pt[0]) !== undefined) { - y = pt[1]; - } else { - if ((x = pt.x) === undefined) { - pt = Point.read(arguments, 2, 1); - x = pt.x; - } - y = pt.y; - selected = pt.selected; - } - point._x = x; - point._y = y; - point._owner = segment; - segment[key] = point; - if (selected) - point.setSelected(true); - return point; - } - } -}); - -var SelectionState = { - HANDLE_IN: 1, - HANDLE_OUT: 2, - POINT: 4 -}; - -var Curve = this.Curve = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { - var count = arguments.length; - if (count == 0) { - this._segment1 = new Segment(); - this._segment2 = new Segment(); - } else if (count == 1) { - this._segment1 = new Segment(arg0.segment1); - this._segment2 = new Segment(arg0.segment2); - } else if (count == 2) { - this._segment1 = new Segment(arg0); - this._segment2 = new Segment(arg1); - } else if (count == 4) { - this._segment1 = new Segment(arg0, null, arg1); - this._segment2 = new Segment(arg3, arg2, null); - } else if (count == 8) { - var p1 = Point.create(arg0, arg1), - p2 = Point.create(arg6, arg7); - this._segment1 = new Segment(p1, null, - Point.create(arg2, arg3).subtract(p1)); - this._segment2 = new Segment(p2, - Point.create(arg4, arg5).subtract(p2), null); - } - }, - - _changed: function() { - delete this._length; - }, - - getPoint1: function() { - return this._segment1._point; - }, - - setPoint1: function(point) { - point = Point.read(arguments); - this._segment1._point.set(point.x, point.y); - }, - - getPoint2: function() { - return this._segment2._point; - }, - - setPoint2: function(point) { - point = Point.read(arguments); - this._segment2._point.set(point.x, point.y); - }, - - getHandle1: function() { - return this._segment1._handleOut; - }, - - setHandle1: function(point) { - point = Point.read(arguments); - this._segment1._handleOut.set(point.x, point.y); - }, - - getHandle2: function() { - return this._segment2._handleIn; - }, - - setHandle2: function(point) { - point = Point.read(arguments); - this._segment2._handleIn.set(point.x, point.y); - }, - - getSegment1: function() { - return this._segment1; - }, - - getSegment2: function() { - return this._segment2; - }, - - getPath: function() { - return this._path; - }, - - getIndex: function() { - return this._segment1._index; - }, - - getNext: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index + 1] - || this._path._closed && curves[0]) || null; - }, - - getPrevious: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index - 1] - || this._path._closed && curves[curves.length - 1]) || null; - }, - - isSelected: function() { - return this.getHandle1().isSelected() && this.getHandle2().isSelected(); - }, - - setSelected: function(selected) { - this.getHandle1().setSelected(selected); - this.getHandle2().setSelected(selected); - }, - - getValues: function(matrix) { - return Curve.getValues(this._segment1, this._segment2, matrix); - }, - - getPoints: function(matrix) { - var coords = this.getValues(matrix), - points = []; - for (var i = 0; i < 8; i += 2) - points.push(Point.create(coords[i], coords[i + 1])); - return points; - }, - - getLength: function() { - var from = arguments[0], - to = arguments[1]; - fullLength = arguments.length == 0 || from == 0 && to == 1; - if (fullLength && this._length != null) - return this._length; - var length = Curve.getLength(this.getValues(), from, to); - if (fullLength) - this._length = length; - return length; - }, - - getPart: function(from, to) { - return new Curve(Curve.getPart(this.getValues(), from, to)); - }, - - isLinear: function() { - return this._segment1._handleOut.isZero() - && this._segment2._handleIn.isZero(); - }, - - getParameterAt: function(offset, start) { - return Curve.getParameterAt(this.getValues(), offset, - start !== undefined ? start : offset < 0 ? 1 : 0); - }, - - getPoint: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 0); - }, - - getTangent: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 1); - }, - - getNormal: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 2); - }, - - getParameter: function(point) { - point = Point.read(point); - return Curve.getParameter(this.getValues(), point.x, point.y); - }, - - getCrossings: function(point, matrix, roots) { - var vals = this.getValues(matrix), - num = Curve.solveCubic(vals, 1, point.y, roots), - crossings = 0; - for (var i = 0; i < num; i++) { - var t = roots[i]; - if (t >= 0 && t < 1 && Curve.evaluate(vals, t, 0).x > point.x) { - if (t < Numerical.TOLERANCE && Curve.evaluate( - this.getPrevious().getValues(matrix), 1, 1).y - * Curve.evaluate(vals, t, 1).y >= 0) - continue; - crossings++; - } - } - return crossings; - }, - - reverse: function() { - return new Curve(this._segment2.reverse(), this._segment1.reverse()); - }, - - clone: function() { - return new Curve(this._segment1, this._segment2); - }, - - toString: function() { - var parts = [ 'point1: ' + this._segment1._point ]; - if (!this._segment1._handleOut.isZero()) - parts.push('handle1: ' + this._segment1._handleOut); - if (!this._segment2._handleIn.isZero()) - parts.push('handle2: ' + this._segment2._handleIn); - parts.push('point2: ' + this._segment2._point); - return '{ ' + parts.join(', ') + ' }'; - }, - - statics: { - create: function(path, segment1, segment2) { - var curve = new Curve(Curve.dont); - curve._path = path; - curve._segment1 = segment1; - curve._segment2 = segment2; - return curve; - }, - - getValues: function(segment1, segment2, matrix) { - var p1 = segment1._point, - h1 = segment1._handleOut, - h2 = segment2._handleIn, - p2 = segment2._point, - coords = [ - p1._x, p1._y, - p1._x + h1._x, p1._y + h1._y, - p2._x + h2._x, p2._y + h2._y, - p2._x, p2._y - ]; - return matrix - ? matrix._transformCoordinates(coords, 0, coords, 0, 4) - : coords; - }, - - evaluate: function(v, t, type) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - x, y; - - if (type == 0 && (t == 0 || t == 1)) { - x = t == 0 ? p1x : p2x; - y = t == 0 ? p1y : p2y; - } else { - var tMin = Numerical.TOLERANCE; - if (t < tMin && c1x == p1x && c1y == p1y) - t = tMin; - else if (t > 1 - tMin && c2x == p2x && c2y == p2y) - t = 1 - tMin; - var cx = 3 * (c1x - p1x), - bx = 3 * (c2x - c1x) - cx, - ax = p2x - p1x - cx - bx, - - cy = 3 * (c1y - p1y), - by = 3 * (c2y - c1y) - cy, - ay = p2y - p1y - cy - by; - - switch (type) { - case 0: - x = ((ax * t + bx) * t + cx) * t + p1x; - y = ((ay * t + by) * t + cy) * t + p1y; - break; - case 1: - case 2: - x = (3 * ax * t + 2 * bx) * t + cx; - y = (3 * ay * t + 2 * by) * t + cy; - break; - } - } - return type == 2 ? new Point(y, -x) : new Point(x, y); - }, - - subdivide: function(v, t) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7]; - if (t === undefined) - t = 0.5; - var u = 1 - t, - p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y, - p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y, - p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y, - p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y, - p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y, - p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y; - return [ - [p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], - [p8x, p8y, p7x, p7y, p5x, p5y, p2x, p2y] - ]; - }, - - solveCubic: function (v, coord, val, roots) { - var p1 = v[coord], - c1 = v[coord + 2], - c2 = v[coord + 4], - p2 = v[coord + 6], - c = 3 * (c1 - p1), - b = 3 * (c2 - c1) - c, - a = p2 - p1 - c - b; - return Numerical.solveCubic(a, b, c, p1 - val, roots, - Numerical.TOLERANCE); - }, - - getParameter: function(v, x, y) { - var txs = [], - tys = [], - sx = Curve.solveCubic(v, 0, x, txs), - sy = Curve.solveCubic(v, 1, y, tys), - tx, ty; - for (var cx = 0; sx == -1 || cx < sx;) { - if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) { - for (var cy = 0; sy == -1 || cy < sy;) { - if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) { - if (sx == -1) tx = ty; - else if (sy == -1) ty = tx; - if (Math.abs(tx - ty) < Numerical.TOLERANCE) - return (tx + ty) * 0.5; - } - } - if (sx == -1) - break; - } - } - return null; - }, - - getPart: function(v, from, to) { - if (from > 0) - v = Curve.subdivide(v, from)[1]; - if (to < 1) - v = Curve.subdivide(v, (to - from) / (1 - from))[0]; - return v; - }, - - isFlatEnough: function(v) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - - a = p1y - p2y, - b = p2x - p1x, - c = p1x * p2y - p2x * p1y, - v1 = a * c1x + b * c1y + c, - v2 = a * c2x + b * c2y + c; - return Math.abs((v1 * v1 + v2 * v2) / (a * (a * a + b * b))) < 0.005; - } - } -}, new function() { - - function getLengthIntegrand(v) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - - ax = 9 * (c1x - c2x) + 3 * (p2x - p1x), - bx = 6 * (p1x + c2x) - 12 * c1x, - cx = 3 * (c1x - p1x), - - ay = 9 * (c1y - c2y) + 3 * (p2y - p1y), - by = 6 * (p1y + c2y) - 12 * c1y, - cy = 3 * (c1y - p1y); - - return function(t) { - var dx = (ax * t + bx) * t + cx, - dy = (ay * t + by) * t + cy; - return Math.sqrt(dx * dx + dy * dy); - }; - } - - function getIterations(a, b) { - return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); - } - - return { - statics: true, - - getLength: function(v, a, b) { - if (a === undefined) - a = 0; - if (b === undefined) - b = 1; - if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) { - var dx = v[6] - v[0], - dy = v[7] - v[1]; - return (b - a) * Math.sqrt(dx * dx + dy * dy); - } - var ds = getLengthIntegrand(v); - return Numerical.integrate(ds, a, b, getIterations(a, b)); - }, - - getParameterAt: function(v, offset, start) { - if (offset == 0) - return start; - var forward = offset > 0, - a = forward ? start : 0, - b = forward ? 1 : start, - offset = Math.abs(offset), - ds = getLengthIntegrand(v), - rangeLength = Numerical.integrate(ds, a, b, - getIterations(a, b)); - if (offset >= rangeLength) - return forward ? b : a; - var guess = offset / rangeLength, - length = 0; - function f(t) { - var count = getIterations(start, t); - length += start < t - ? Numerical.integrate(ds, start, t, count) - : -Numerical.integrate(ds, t, start, count); - start = t; - return length - offset; - } - return Numerical.findRoot(f, ds, - forward ? a + guess : b - guess, - a, b, 16, Numerical.TOLERANCE); - } - }; -}, new function() { - - var maxDepth = 32, - epsilon = Math.pow(2, -maxDepth - 1); - - var zCubic = [ - [1.0, 0.6, 0.3, 0.1], - [0.4, 0.6, 0.6, 0.4], - [0.1, 0.3, 0.6, 1.0] - ]; - - var xAxis = new Line(new Point(0, 0), new Point(1, 0)); - - function toBezierForm(v, point) { - var n = 3, - degree = 5, - c = [], - d = [], - cd = [], - w = []; - for(var i = 0; i <= n; i++) { - c[i] = v[i].subtract(point); - if (i < n) - d[i] = v[i + 1].subtract(v[i]).multiply(n); - } - - for (var row = 0; row < n; row++) { - cd[row] = []; - for (var column = 0; column <= n; column++) - cd[row][column] = d[row].dot(c[column]); - } - - for (var i = 0; i <= degree; i++) - w[i] = new Point(i / degree, 0); - - for (k = 0; k <= degree; k++) { - var lb = Math.max(0, k - n + 1), - ub = Math.min(k, n); - for (var i = lb; i <= ub; i++) { - var j = k - i; - w[k].y += cd[j][i] * zCubic[j][i]; - } - } - - return w; - } - - function findRoots(w, depth) { - switch (countCrossings(w)) { - case 0: - return []; - case 1: - if (depth >= maxDepth) - return [0.5 * (w[0].x + w[5].x)]; - if (isFlatEnough(w)) { - var line = new Line(w[0], w[5], true); - return [ line.vector.getLength(true) <= Numerical.EPSILON - ? line.point.x - : xAxis.intersect(line).x ]; - } - } - - var p = [[]], - left = [], - right = []; - for (var j = 0; j <= 5; j++) - p[0][j] = new Point(w[j]); - - for (var i = 1; i <= 5; i++) { - p[i] = []; - for (var j = 0 ; j <= 5 - i; j++) - p[i][j] = p[i - 1][j].add(p[i - 1][j + 1]).multiply(0.5); - } - for (var j = 0; j <= 5; j++) { - left[j] = p[j][0]; - right[j] = p[5 - j][j]; - } - - return findRoots(left, depth + 1).concat(findRoots(right, depth + 1)); - } - - function countCrossings(v) { - var crossings = 0, - prevSign = null; - for (var i = 0, l = v.length; i < l; i++) { - var sign = v[i].y < 0 ? -1 : 1; - if (prevSign != null && sign != prevSign) - crossings++; - prevSign = sign; - } - return crossings; - } - - function isFlatEnough(v) { - - var n = v.length - 1, - a = v[0].y - v[n].y, - b = v[n].x - v[0].x, - c = v[0].x * v[n].y - v[n].x * v[0].y, - maxAbove = 0, - maxBelow = 0; - for (var i = 1; i < n; i++) { - var val = a * v[i].x + b * v[i].y + c, - dist = val * val; - if (val < 0 && dist > maxBelow) { - maxBelow = dist; - } else if (dist > maxAbove) { - maxAbove = dist; - } - } - return Math.abs((maxAbove + maxBelow) / (2 * a * (a * a + b * b))) - < epsilon; - } - - return { - getNearestLocation: function(point, matrix) { - var w = toBezierForm(this.getPoints(matrix), point); - var roots = findRoots(w, 0).concat([0, 1]); - var minDist = Infinity, - minT, - minPoint; - for (var i = 0; i < roots.length; i++) { - var pt = this.getPoint(roots[i]), - dist = point.getDistance(pt, true); - if (dist < minDist) { - minDist = dist; - minT = roots[i]; - minPoint = pt; - } - } - return new CurveLocation(this, minT, minPoint, Math.sqrt(minDist)); - }, - - getNearestPoint: function(point, matrix) { - return this.getNearestLocation(point, matrix).getPoint(); - } - }; -}); - -CurveLocation = Base.extend({ - initialize: function(curve, parameter, point, distance) { - this._curve = curve; - this._parameter = parameter; - this._point = point; - this._distance = distance; - }, - - getSegment: function() { - if (!this._segment) { - var curve = this._curve, - parameter = this.getParameter(); - if (parameter == 0) { - this._segment = curve._segment1; - } else if (parameter == 1) { - this._segment = curve._segment2; - } else if (parameter == null) { - return null; - } else { - this._segment = curve.getLength(0, parameter) - < curve.getLength(parameter, 1) - ? curve._segment1 - : curve._segment2; - } - } - return this._segment; - }, - - getCurve: function() { - return this._curve; - }, - - getPath: function() { - return this._curve && this._curve._path; - }, - - getIndex: function() { - return this._curve && this._curve.getIndex(); - }, - - getOffset: function() { - var path = this._curve && this._curve._path; - return path && path._getOffset(this); - }, - - getCurveOffset: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getLength(0, parameter); - }, - - getParameter: function() { - if (this._parameter == null && this._curve && this._point) - this._parameter = this._curve.getParameterAt(this._point); - return this._parameter; - }, - - getPoint: function() { - if (!this._point && this._curve && this._parameter != null) - this._point = this._curve.getPoint(this._parameter); - return this._point; - }, - - getTangent: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getTangent(parameter); - }, - - getNormal: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getNormal(parameter); - }, - - getDistance: function() { - return this._distance; - }, - - toString: function() { - var parts = [], - point = this.getPoint(); - if (point) - parts.push('point: ' + point); - var index = this.getIndex(); - if (index != null) - parts.push('index: ' + index); - var parameter = this.getParameter(); - if (parameter != null) - parts.push('parameter: ' + Base.formatNumber(parameter)); - if (this._distance != null) - parts.push('distance: ' + Base.formatNumber(this._distance)); - return '{ ' + parts.join(', ') + ' }'; - } -}); - -var PathItem = this.PathItem = Item.extend({ - -}); - -var Path = this.Path = PathItem.extend({ - initialize: function(segments) { - this.base(); - this._closed = false; - this._selectedSegmentState = 0; - this.setSegments(!segments || !Array.isArray(segments) - || typeof segments[0] !== 'object' ? arguments : segments); - }, - - clone: function() { - var copy = this._clone(new Path(this._segments)); - copy._closed = this._closed; - if (this._clockwise !== undefined) - copy._clockwise = this._clockwise; - return copy; - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & ChangeFlag.GEOMETRY) { - delete this._strokeBounds; - delete this._handleBounds; - delete this._roughBounds; - delete this._length; - delete this._clockwise; - } else if (flags & ChangeFlag.STROKE) { - delete this._strokeBounds; - } - }, - - getSegments: function() { - return this._segments; - }, - - setSegments: function(segments) { - if (!this._segments) { - this._segments = []; - } else { - this._selectedSegmentState = 0; - this._segments.length = 0; - if (this._curves) - delete this._curves; - } - this._add(Segment.readAll(segments)); - }, - - getFirstSegment: function() { - return this._segments[0]; - }, - - getLastSegment: function() { - return this._segments[this._segments.length - 1]; - }, - - getCurves: function() { - if (!this._curves) { - var segments = this._segments, - length = segments.length; - if (!this._closed && length > 0) - length--; - this._curves = new Array(length); - for (var i = 0; i < length; i++) - this._curves[i] = Curve.create(this, segments[i], - segments[i + 1] || segments[0]); - } - return this._curves; - }, - - getFirstCurve: function() { - return this.getCurves()[0]; - }, - - getLastCurve: function() { - var curves = this.getCurves(); - return curves[curves.length - 1]; - }, - - getClosed: function() { - return this._closed; - }, - - setClosed: function(closed) { - if (this._closed != (closed = !!closed)) { - this._closed = closed; - if (this._curves) { - var length = this._segments.length, - i; - if (!closed && length > 0) - length--; - this._curves.length = length; - if (closed) - this._curves[i = length - 1] = Curve.create(this, - this._segments[i], this._segments[0]); - } - this._changed(Change.GEOMETRY); - } - }, - - _transform: function(matrix, flags) { - if (!matrix.isIdentity()) { - var coords = new Array(6); - for (var i = 0, l = this._segments.length; i < l; i++) { - this._segments[i]._transformCoordinates(matrix, coords, true); - } - var fillColor = this.getFillColor(), - strokeColor = this.getStrokeColor(); - if (fillColor && fillColor.transform) - fillColor.transform(matrix); - if (strokeColor && strokeColor.transform) - strokeColor.transform(matrix); - } - }, - - _add: function(segs, index) { - var segments = this._segments, - curves = this._curves, - amount = segs.length, - append = index == null, - index = append ? segments.length : index, - fullySelected = this.isFullySelected(); - for (var i = 0; i < amount; i++) { - var segment = segs[i]; - if (segment._path) { - segment = segs[i] = new Segment(segment); - } - segment._path = this; - segment._index = index + i; - if (fullySelected) - segment._selectionState = SelectionState.POINT; - if (segment._selectionState) - this._updateSelection(segment, 0, segment._selectionState); - } - if (append) { - segments.push.apply(segments, segs); - } else { - segments.splice.apply(segments, [index, 0].concat(segs)); - for (var i = index + amount, l = segments.length; i < l; i++) { - segments[i]._index = i; - } - } - if (curves && --index >= 0) { - curves.splice(index, 0, Curve.create(this, segments[index], - segments[index + 1])); - var curve = curves[index + amount]; - if (curve) { - curve._segment1 = segments[index + amount]; - } - } - this._changed(Change.GEOMETRY); - return segs; - }, - - add: function(segment1 ) { - return arguments.length > 1 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments)) - : this._add([ Segment.read(arguments) ])[0]; - }, - - insert: function(index, segment1 ) { - return arguments.length > 2 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments, 1), index) - : this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegment: function(segment) { - return this._add([ Segment.read(arguments) ])[0]; - }, - - insertSegment: function(index, segment) { - return this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegments: function(segments) { - return this._add(Segment.readAll(segments)); - }, - - insertSegments: function(index, segments) { - return this._add(Segment.readAll(segments), index); - }, - - removeSegment: function(index) { - var segments = this.removeSegments(index, index + 1); - return segments[0] || null; - }, - - removeSegments: function(from, to) { - from = from || 0; - to = Base.pick(to, this._segments.length); - var segments = this._segments, - curves = this._curves, - last = to >= segments.length, - removed = segments.splice(from, to - from), - amount = removed.length; - if (!amount) - return removed; - for (var i = 0; i < amount; i++) { - var segment = removed[i]; - if (segment._selectionState) - this._updateSelection(segment, segment._selectionState, 0); - removed._index = removed._path = undefined; - } - for (var i = from, l = segments.length; i < l; i++) - segments[i]._index = i; - if (curves) { - curves.splice(from, amount); - var curve; - if (curve = curves[from - 1]) - curve._segment2 = segments[from]; - if (curve = curves[from]) - curve._segment1 = segments[from]; - if (last && this._closed && (curve = curves[curves.length - 1])) - curve._segment2 = segments[0]; - } - this._changed(Change.GEOMETRY); - return removed; - }, - - isFullySelected: function() { - return this._selected && this._selectedSegmentState - == this._segments.length * SelectionState.POINT; - }, - - setFullySelected: function(selected) { - var length = this._segments.length; - this._selectedSegmentState = selected - ? length * SelectionState.POINT : 0; - for (var i = 0; i < length; i++) - this._segments[i]._selectionState = selected - ? SelectionState.POINT : 0; - this.setSelected(selected); - }, - - _updateSelection: function(segment, oldState, newState) { - segment._selectionState = newState; - var total = this._selectedSegmentState += newState - oldState; - if (total > 0) - this.setSelected(true); - }, - - flatten: function(maxDistance) { - var flattener = new PathFlattener(this), - pos = 0, - step = flattener.length / Math.ceil(flattener.length / maxDistance), - end = flattener.length + (this._closed ? -step : step) / 2; - var segments = []; - while (pos <= end) { - segments.push(new Segment(flattener.evaluate(pos, 0))); - pos += step; - } - this.setSegments(segments); - }, - - simplify: function(tolerance) { - if (this._segments.length > 2) { - var fitter = new PathFitter(this, tolerance || 2.5); - this.setSegments(fitter.fit()); - } - }, - - isClockwise: function() { - if (this._clockwise !== undefined) - return this._clockwise; - var sum = 0, - xPre, yPre; - function edge(x, y) { - if (xPre !== undefined) - sum += (xPre - x) * (y + yPre); - xPre = x; - yPre = y; - } - for (var i = 0, l = this._segments.length; i < l; i++) { - var seg1 = this._segments[i], - seg2 = this._segments[i + 1 < l ? i + 1 : 0], - point1 = seg1._point, - handle1 = seg1._handleOut, - handle2 = seg2._handleIn, - point2 = seg2._point; - edge(point1._x, point1._y); - edge(point1._x + handle1._x, point1._y + handle1._y); - edge(point2._x + handle2._x, point2._y + handle2._y); - edge(point2._x, point2._y); - } - return sum > 0; - }, - - setClockwise: function(clockwise) { - if (this.isClockwise() != (clockwise = !!clockwise)) { - this.reverse(); - this._clockwise = clockwise; - } - }, - - reverse: function() { - this._segments.reverse(); - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - var handleIn = segment._handleIn; - segment._handleIn = segment._handleOut; - segment._handleOut = handleIn; - } - if (this._clockwise !== undefined) - this._clockwise = !this._clockwise; - }, - - join: function(path) { - if (path) { - var segments = path._segments, - last1 = this.getLastSegment(), - last2 = path.getLastSegment(); - if (last1._point.equals(last2._point)) - path.reverse(); - var first2 = path.getFirstSegment(); - if (last1._point.equals(first2._point)) { - last1.setHandleOut(first2._handleOut); - this._add(segments.slice(1)); - } else { - var first1 = this.getFirstSegment(); - if (first1._point.equals(first2._point)) - path.reverse(); - last2 = path.getLastSegment(); - if (first1._point.equals(last2._point)) { - first1.setHandleIn(last2._handleIn); - this._add(segments.slice(0, segments.length - 1), 0); - } else { - this._add(segments.slice(0)); - } - } - path.remove(); - var first1 = this.getFirstSegment(); - last1 = this.getLastSegment(); - if (last1._point.equals(first1._point)) { - first1.setHandleIn(last1._handleIn); - last1.remove(); - this.setClosed(true); - } - this._changed(Change.GEOMETRY); - return true; - } - return false; - }, - - getLength: function() { - if (this._length == null) { - var curves = this.getCurves(); - this._length = 0; - for (var i = 0, l = curves.length; i < l; i++) - this._length += curves[i].getLength(); - } - return this._length; - }, - - _getOffset: function(location) { - var index = location && location.getIndex(); - if (index != null) { - var curves = this.getCurves(), - offset = 0; - for (var i = 0; i < index; i++) - offset += curves[i].getLength(); - var curve = curves[index]; - return offset + curve.getLength(0, location.getParameter()); - } - return null; - }, - - getLocation: function(point) { - var curves = this.getCurves(); - for (var i = 0, l = curves.length; i < l; i++) { - var curve = curves[i]; - var t = curve.getParameter(point); - if (t != null) - return new CurveLocation(curve, t); - } - return null; - }, - - getLocationAt: function(offset, isParameter) { - var curves = this.getCurves(), - length = 0; - if (isParameter) { - var index = ~~offset; - return new CurveLocation(curves[index], offset - index); - } - for (var i = 0, l = curves.length; i < l; i++) { - var start = length, - curve = curves[i]; - length += curve.getLength(); - if (length >= offset) { - return new CurveLocation(curve, - curve.getParameterAt(offset - start)); - } - } - if (offset <= this.getLength()) - return new CurveLocation(curves[curves.length - 1], 1); - return null; - }, - - getPointAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getPoint(); - }, - - getTangentAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getTangent(); - }, - - getNormalAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getNormal(); - }, - - getNearestLocation: function(point, matrix) { - var curves = this.getCurves(), - minDist = Infinity, - minLoc = null; - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getNearestLocation(point, matrix); - if (loc._distance < minDist) { - minDist = loc._distance; - minLoc = loc; - } - } - return minLoc; - }, - - getNearestPoint: function(point, matrix) { - return this.getNearestLocation(point, matrix).getPoint(); - }, - - contains: function(point, matrix) { - point = Point.read(arguments); - if (!this._closed || !this.getRoughBounds(matrix)._containsPoint(point)) - return false; - var curves = this.getCurves(), - crossings = 0, - roots = []; - for (var i = 0, l = curves.length; i < l; i++) - crossings += curves[i].getCrossings(point, matrix, roots); - return (crossings & 1) == 1; - }, - - _hitTest: function(point, options, matrix) { - var tolerance = options.tolerance || 0, - radius = (options.stroke ? this.getStrokeWidth() / 2 : 0) + tolerance, - loc, - res; - var coords = [], - that = this; - function checkSegment(segment, ends) { - segment._transformCoordinates(matrix, coords); - for (var j = ends || options.segments ? 0 : 2, - m = !ends && options.handles ? 6 : 2; j < m; j += 2) { - if (point.getDistance(coords[j], coords[j + 1]) < tolerance) - return new HitResult(j == 0 ? 'segment' - : 'handle-' + (j == 2 ? 'in' : 'out'), - that, { segment: segment }); - } - } - if (options.ends && !options.segments && !this._closed) { - if (res = checkSegment(this.getFirstSegment(), true) - || checkSegment(this.getLastSegment(), true)) - return res; - } else if (options.segments || options.handles) { - for (var i = 0, l = this._segments.length; i < l; i++) { - if (res = checkSegment(this._segments[i])) - return res; - } - } - if (options.stroke && radius > 0) - loc = this.getNearestLocation(point, matrix); - if (!(loc && loc._distance <= radius) && options.fill - && this.getFillColor() && this.contains(point, matrix)) - return new HitResult('fill', this); - if (!loc && options.stroke && radius > 0) - loc = this.getNearestLocation(point, matrix); - if (loc && loc._distance <= radius) - return options.stroke - ? new HitResult('stroke', this, { location: loc }) - : new HitResult('fill', this); - } - -}, new function() { - - function drawHandles(ctx, segments) { - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i], - point = segment._point, - state = segment._selectionState, - selected = state & SelectionState.POINT; - if (selected || (state & SelectionState.HANDLE_IN)) - drawHandle(ctx, point, segment._handleIn); - if (selected || (state & SelectionState.HANDLE_OUT)) - drawHandle(ctx, point, segment._handleOut); - ctx.save(); - ctx.beginPath(); - ctx.rect(point._x - 2, point._y - 2, 4, 4); - ctx.fill(); - if (!selected) { - ctx.beginPath(); - ctx.rect(point._x - 1, point._y - 1, 2, 2); - ctx.fillStyle = '#ffffff'; - ctx.fill(); - } - ctx.restore(); - } - } - - function drawHandle(ctx, point, handle) { - if (!handle.isZero()) { - var handleX = point._x + handle._x, - handleY = point._y + handle._y; - ctx.beginPath(); - ctx.moveTo(point._x, point._y); - ctx.lineTo(handleX, handleY); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(handleX, handleY, 1.75, 0, Math.PI * 2, true); - ctx.fill(); - } - } - - function drawSegments(ctx, path) { - var segments = path._segments, - length = segments.length, - handleOut, outX, outY; - - function drawSegment(i) { - var segment = segments[i], - point = segment._point, - x = point._x, - y = point._y, - handleIn = segment._handleIn; - if (!handleOut) { - ctx.moveTo(x, y); - } else { - if (handleIn.isZero() && handleOut.isZero()) { - ctx.lineTo(x, y); - } else { - ctx.bezierCurveTo(outX, outY, - handleIn._x + x, handleIn._y + y, x, y); - } - } - handleOut = segment._handleOut; - outX = handleOut._x + x; - outY = handleOut._y + y; - } - - for (var i = 0; i < length; i++) - drawSegment(i); - if (path._closed && length > 1) - drawSegment(0); - } - - function drawDashes(ctx, path, dashArray, dashOffset) { - var flattener = new PathFlattener(path), - from = dashOffset, to, - i = 0; - while (from < flattener.length) { - to = from + dashArray[(i++) % dashArray.length]; - flattener.drawPart(ctx, from, to); - from = to + dashArray[(i++) % dashArray.length]; - } - } - - return { - draw: function(ctx, param) { - if (!param.compound) - ctx.beginPath(); - - var fillColor = this.getFillColor(), - strokeColor = this.getStrokeColor(), - dashArray = this.getDashArray() || [], - hasDash = !!dashArray.length; - - if (param.compound || param.selection || this._clipMask || fillColor - || strokeColor && !hasDash) { - drawSegments(ctx, this); - } - - if (param.selection) { - ctx.stroke(); - drawHandles(ctx, this._segments); - } else if (this._clipMask) { - ctx.clip(); - } else if (!param.compound && (fillColor || strokeColor)) { - ctx.save(); - this._setStyles(ctx); - if (!fillColor || !strokeColor) - ctx.globalAlpha = this._opacity; - if (fillColor) { - ctx.fillStyle = fillColor.getCanvasStyle(ctx); - ctx.fill(); - } - if (strokeColor) { - ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); - if (hasDash) { - ctx.beginPath(); - drawDashes(ctx, this, dashArray, this.getDashOffset()); - } - ctx.stroke(); - } - ctx.restore(); - } - } - }; -}, new function() { - - function getFirstControlPoints(rhs) { - var n = rhs.length, - x = [], - tmp = [], - b = 2; - x[0] = rhs[0] / b; - for (var i = 1; i < n; i++) { - tmp[i] = 1 / b; - b = (i < n - 1 ? 4 : 2) - tmp[i]; - x[i] = (rhs[i] - x[i - 1]) / b; - } - for (var i = 1; i < n; i++) { - x[n - i - 1] -= tmp[n - i] * x[n - i]; - } - return x; - }; - - var styles = { - getStrokeWidth: 'lineWidth', - getStrokeJoin: 'lineJoin', - getStrokeCap: 'lineCap', - getMiterLimit: 'miterLimit' - }; - - return { - _setStyles: function(ctx) { - for (var i in styles) { - var style = this._style[i](); - if (style) - ctx[styles[i]] = style; - } - }, - - smooth: function() { - var segments = this._segments, - size = segments.length, - n = size, - overlap; - - if (size <= 2) - return; - - if (this._closed) { - overlap = Math.min(size, 4); - n += Math.min(size, overlap) * 2; - } else { - overlap = 0; - } - var knots = []; - for (var i = 0; i < size; i++) - knots[i + overlap] = segments[i]._point; - if (this._closed) { - for (var i = 0; i < overlap; i++) { - knots[i] = segments[i + size - overlap]._point; - knots[i + size + overlap] = segments[i]._point; - } - } else { - n--; - } - var rhs = []; - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._x + 2 * knots[i + 1]._x; - rhs[0] = knots[0]._x + 2 * knots[1]._x; - rhs[n - 1] = 3 * knots[n - 1]._x; - var x = getFirstControlPoints(rhs); - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._y + 2 * knots[i + 1]._y; - rhs[0] = knots[0]._y + 2 * knots[1]._y; - rhs[n - 1] = 3 * knots[n - 1]._y; - var y = getFirstControlPoints(rhs); - - if (this._closed) { - for (var i = 0, j = size; i < overlap; i++, j++) { - var f1 = (i / overlap); - var f2 = 1 - f1; - x[j] = x[i] * f1 + x[j] * f2; - y[j] = y[i] * f1 + y[j] * f2; - var ie = i + overlap, je = j + overlap; - x[je] = x[ie] * f2 + x[je] * f1; - y[je] = y[ie] * f2 + y[je] * f1; - } - n--; - } - var handleIn = null; - for (var i = overlap; i <= n - overlap; i++) { - var segment = segments[i - overlap]; - if (handleIn) - segment.setHandleIn(handleIn.subtract(segment._point)); - if (i < n) { - segment.setHandleOut( - new Point(x[i], y[i]).subtract(segment._point)); - if (i < n - 1) - handleIn = new Point( - 2 * knots[i + 1]._x - x[i + 1], - 2 * knots[i + 1]._y - y[i + 1]); - else - handleIn = new Point( - (knots[n]._x + x[n - 1]) / 2, - (knots[n]._y + y[n - 1]) / 2); - } - } - if (this._closed && handleIn) { - var segment = this._segments[0]; - segment.setHandleIn(handleIn.subtract(segment._point)); - } - } - }; -}, new function() { - function getCurrentSegment(that) { - var segments = that._segments; - if (segments.length == 0) - throw new Error('Use a moveTo() command first'); - return segments[segments.length - 1]; - } - - return { - moveTo: function(point) { - if (!this._segments.length) - this._add([ new Segment(Point.read(arguments)) ]); - }, - - moveBy: function(point) { - throw new Error('moveBy() is unsupported on Path items.'); - }, - - lineTo: function(point) { - this._add([ new Segment(Point.read(arguments)) ]); - }, - - cubicCurveTo: function(handle1, handle2, to) { - handle1 = Point.read(arguments, 0, 1); - handle2 = Point.read(arguments, 1, 1); - to = Point.read(arguments, 2, 1); - var current = getCurrentSegment(this); - current.setHandleOut(handle1.subtract(current._point)); - this._add([ new Segment(to, handle2.subtract(to)) ]); - }, - - quadraticCurveTo: function(handle, to) { - handle = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - var current = getCurrentSegment(this)._point; - this.cubicCurveTo( - handle.add(current.subtract(handle).multiply(1/3)), - handle.add(to.subtract(handle).multiply(1/3)), - to - ); - }, - - curveTo: function(through, to, parameter) { - through = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - var t = Base.pick(parameter, 0.5), - t1 = 1 - t, - current = getCurrentSegment(this)._point, - handle = through.subtract(current.multiply(t1 * t1)) - .subtract(to.multiply(t * t)).divide(2 * t * t1); - if (handle.isNaN()) - throw new Error( - 'Cannot put a curve through points with parameter = ' + t); - this.quadraticCurveTo(handle, to); - }, - - arcTo: function(to, clockwise ) { - var current = getCurrentSegment(this), - from = current._point, - through; - if (clockwise === undefined) - clockwise = true; - if (typeof clockwise === 'boolean') { - to = Point.read(arguments, 0, 1); - var middle = from.add(to).divide(2), - through = middle.add(middle.subtract(from).rotate( - clockwise ? -90 : 90)); - } else { - through = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - } - var l1 = new Line(from.add(through).divide(2), - through.subtract(from).rotate(90)), - l2 = new Line(through.add(to).divide(2), - to.subtract(through).rotate(90)), - center = l1.intersect(l2), - line = new Line(from, to, true), - throughSide = line.getSide(through); - if (!center) { - if (!throughSide) - return this.lineTo(to); - throw new Error("Cannot put an arc through the given points: " - + [from, through, to]); - } - var vector = from.subtract(center), - radius = vector.getLength(), - extent = vector.getDirectedAngle(to.subtract(center)), - centerSide = line.getSide(center); - if (centerSide == 0) { - extent = throughSide * Math.abs(extent); - } else if (throughSide == centerSide) { - extent -= 360 * (extent < 0 ? -1 : 1); - } - var ext = Math.abs(extent), - count = ext >= 360 ? 4 : Math.ceil(ext / 90), - inc = extent / count, - half = inc * Math.PI / 360, - z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), - segments = []; - for (var i = 0; i <= count; i++) { - var pt = i < count ? center.add(vector) : to; - var out = i < count ? vector.rotate(90).multiply(z) : null; - if (i == 0) { - current.setHandleOut(out); - } else { - segments.push( - new Segment(pt, vector.rotate(-90).multiply(z), out)); - } - vector = vector.rotate(inc); - } - this._add(segments); - }, - - lineBy: function(vector) { - vector = Point.read(arguments); - var current = getCurrentSegment(this); - this.lineTo(current._point.add(vector)); - }, - - curveBy: function(throughVector, toVector, parameter) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.curveTo(current.add(throughVector), current.add(toVector), - parameter); - }, - - arcBy: function(throughVector, toVector) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.arcBy(current.add(throughVector), current.add(toVector)); - }, - - closePath: function() { - this.setClosed(true); - } - }; -}, new function() { - - function getBounds(that, matrix, strokePadding) { - var segments = that._segments, - first = segments[0]; - if (!first) - return null; - var coords = new Array(6), - prevCoords = new Array(6); - if (matrix && matrix.isIdentity()) - matrix = null; - first._transformCoordinates(matrix, prevCoords, false); - var min = prevCoords.slice(0, 2), - max = min.slice(0), - tMin = Numerical.TOLERANCE, - tMax = 1 - tMin; - function processSegment(segment) { - segment._transformCoordinates(matrix, coords, false); - - for (var i = 0; i < 2; i++) { - var v0 = prevCoords[i], - v1 = prevCoords[i + 4], - v2 = coords[i + 2], - v3 = coords[i]; - - function add(value, t) { - var padding = 0; - if (value == null) { - var u = 1 - t; - value = u * u * u * v0 - + 3 * u * u * t * v1 - + 3 * u * t * t * v2 - + t * t * t * v3; - padding = strokePadding ? strokePadding[i] : 0; - } - var left = value - padding, - right = value + padding; - if (left < min[i]) - min[i] = left; - if (right > max[i]) - max[i] = right; - - } - add(v3, null); - - var a = 3 * (v1 - v2) - v0 + v3, - b = 2 * (v0 + v2) - 4 * v1, - c = v1 - v0; - - if (a == 0) { - if (b == 0) - continue; - var t = -c / b; - if (tMin < t && t < tMax) - add(null, t); - continue; - } - - var q = b * b - 4 * a * c; - if (q < 0) - continue; - var sqrt = Math.sqrt(q), - f = -0.5 / a, - t1 = (b - sqrt) * f, - t2 = (b + sqrt) * f; - if (tMin < t1 && t1 < tMax) - add(null, t1); - if (tMin < t2 && t2 < tMax) - add(null, t2); - } - var tmp = prevCoords; - prevCoords = coords; - coords = tmp; - } - for (var i = 1, l = segments.length; i < l; i++) - processSegment(segments[i]); - if (that._closed) - processSegment(first); - return Rectangle.create(min[0], min[1], - max[0] - min[0], max[1] - min[1]); - } - - function getPenPadding(radius, matrix) { - if (!matrix) - return [radius, radius]; - var mx = matrix.createShiftless(), - hor = mx.transform(new Point(radius, 0)), - ver = mx.transform(new Point(0, radius)), - phi = hor.getAngleInRadians(), - a = hor.getLength(), - b = ver.getLength(); - var tx = - Math.atan(b * Math.tan(phi)), - ty = + Math.atan(b / Math.tan(phi)), - x = a * Math.cos(tx) * Math.cos(phi) - - b * Math.sin(tx) * Math.sin(phi), - y = b * Math.sin(ty) * Math.cos(phi) - + a * Math.cos(ty) * Math.sin(phi); - return [Math.abs(x), Math.abs(y)]; - } - - return { - getBounds: function() { - var useCache = arguments[0] === undefined; - if (useCache && this._bounds) - return this._bounds; - var bounds = this._createBounds(getBounds(this, arguments[0])); - if (useCache) - this._bounds = bounds; - return bounds; - }, - - getStrokeBounds: function() { - if (!this._style._strokeColor || !this._style._strokeWidth) - return this.getBounds.apply(this, arguments); - var useCache = arguments[0] === undefined; - if (useCache && this._strokeBounds) - return this._strokeBounds; - var matrix = arguments[0], - width = this.getStrokeWidth(), - radius = width / 2, - padding = getPenPadding(radius, matrix), - join = this.getStrokeJoin(), - cap = this.getStrokeCap(), - miter = this.getMiterLimit() * width / 2, - segments = this._segments, - length = segments.length, - bounds = getBounds(this, matrix, getPenPadding(radius)); - var joinBounds = new Rectangle(new Size(padding).multiply(2)); - - function add(point) { - bounds = bounds.include(matrix - ? matrix.transform(point) : point); - } - - function addBevelJoin(curve, t) { - var point = curve.getPoint(t), - normal = curve.getNormal(t).normalize(radius); - add(point.add(normal)); - add(point.subtract(normal)); - } - - function addJoin(segment, join) { - if (join === 'round' || !segment._handleIn.isZero() - && !segment._handleOut.isZero()) { - bounds = bounds.unite(joinBounds.setCenter(matrix - ? matrix.transform(segment._point) : segment._point)); - } else if (join == 'bevel') { - var curve = segment.getCurve(); - addBevelJoin(curve, 0); - addBevelJoin(curve.getPrevious(), 1); - } else if (join == 'miter') { - var curve2 = segment.getCurve(), - curve1 = curve2.getPrevious(), - point = curve2.getPoint(0), - normal1 = curve1.getNormal(1).normalize(radius), - normal2 = curve2.getNormal(0).normalize(radius), - line1 = new Line(point.subtract(normal1), - new Point(-normal1.y, normal1.x)), - line2 = new Line(point.subtract(normal2), - new Point(-normal2.y, normal2.x)), - corner = line1.intersect(line2); - if (!corner || point.getDistance(corner) > miter) { - addJoin(segment, 'bevel'); - } else { - add(corner); - } - } - } - - function addCap(segment, cap, t) { - switch (cap) { - case 'round': - return addJoin(segment, cap); - case 'butt': - case 'square': - var curve = segment.getCurve(), - point = curve.getPoint(t), - normal = curve.getNormal(t).normalize(radius); - if (cap === 'square') - point = point.add(normal.y, -normal.x); - add(point.add(normal)); - add(point.subtract(normal)); - break; - } - } - - for (var i = 1, l = length - (this._closed ? 0 : 1); i < l; i++) { - addJoin(segments[i], join); - } - if (this._closed) { - addJoin(segments[0], join); - } else { - addCap(segments[0], cap, 0); - addCap(segments[length - 1], cap, 1); - } - if (useCache) - this._strokeBounds = bounds; - return bounds; - }, - - getHandleBounds: function() { - var matrix = arguments[0], - useCache = matrix === undefined; - if (useCache && this._handleBounds) - return this._handleBounds; - var coords = new Array(6), - stroke = arguments[1] / 2 || 0, - join = arguments[2] / 2 || 0, - open = !this._closed, - x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - segment._transformCoordinates(matrix, coords, false); - for (var j = 0; j < 6; j += 2) { - var padding = j == 0 ? join : stroke, - x = coords[j], - y = coords[j + 1], - xn = x - padding, - xx = x + padding, - yn = y - padding, - yx = y + padding; - if (xn < x1) x1 = xn; - if (xx > x2) x2 = xx; - if (yn < y1) y1 = yn; - if (yx > y2) y2 = yx; - } - } - var bounds = Rectangle.create(x1, y1, x2 - x1, y2 - y1); - if (useCache) - this._handleBounds = bounds; - return bounds; - }, - - getRoughBounds: function() { - var useCache = arguments[0] === undefined; - if (useCache && this._roughBounds) - return this._roughBounds; - var bounds = this.getHandleBounds(arguments[0], this.strokeWidth, - this.getStrokeJoin() == 'miter' - ? this.strokeWidth * this.getMiterLimit() - : this.strokeWidth); - if (useCache) - this._roughBounds = bounds; - return bounds; - } - }; -}); - -Path.inject({ statics: new function() { - var kappa = 2 / 3 * (Math.sqrt(2) - 1); - - var ovalSegments = [ - new Segment([0, 0.5], [0, kappa ], [0, -kappa]), - new Segment([0.5, 0], [-kappa, 0], [kappa, 0 ]), - new Segment([1, 0.5], [0, -kappa], [0, kappa ]), - new Segment([0.5, 1], [kappa, 0 ], [-kappa, 0]) - ]; - - return { - Line: function() { - var step = Math.floor(arguments.length / 2); - return new Path( - Segment.read(arguments, 0, step), - Segment.read(arguments, step, step) - ); - }, - - Rectangle: function(rect) { - rect = Rectangle.read(arguments); - var left = rect.x, - top = rect.y - right = left + rect.width, - bottom = top + rect.height, - path = new Path(); - path._add([ - new Segment(Point.create(left, bottom)), - new Segment(Point.create(left, top)), - new Segment(Point.create(right, top)), - new Segment(Point.create(right, bottom)) - ]); - path._closed = true; - return path; - }, - - RoundRectangle: function(rect, size) { - if (arguments.length == 2) { - rect = Rectangle.read(arguments, 0, 1); - size = Size.read(arguments, 1, 1); - } else if (arguments.length == 6) { - rect = Rectangle.read(arguments, 0, 4); - size = Size.read(arguments, 4, 2); - } - size = Size.min(size, rect.getSize(true).divide(2)); - var path = new Path(), - uSize = size.multiply(kappa * 2), - bl = rect.getBottomLeft(true), - tl = rect.getTopLeft(true), - tr = rect.getTopRight(true), - br = rect.getBottomRight(true); - path._add([ - new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]), - new Segment(bl.subtract(0, size.height), [0, uSize.height], null), - - new Segment(tl.add(0, size.height), null, [0, -uSize.height]), - new Segment(tl.add(size.width, 0), [-uSize.width, 0], null), - - new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]), - new Segment(tr.add(0, size.height), [0, -uSize.height], null), - - new Segment(br.subtract(0, size.height), null, [0, uSize.height]), - new Segment(br.subtract(size.width, 0), [uSize.width, 0], null) - ]); - path._closed = true; - return path; - }, - - Oval: function(rect) { - rect = Rectangle.read(arguments); - var path = new Path(), - point = rect.getPoint(true), - size = rect.getSize(true), - segments = new Array(4); - for (var i = 0; i < 4; i++) { - var segment = ovalSegments[i]; - segments[i] = new Segment( - segment._point.multiply(size).add(point), - segment._handleIn.multiply(size), - segment._handleOut.multiply(size) - ); - } - path._add(segments); - path._closed = true; - return path; - }, - - Circle: function(center, radius) { - if (arguments.length == 3) { - center = Point.read(arguments, 0, 2); - radius = arguments[2]; - } else { - center = Point.read(arguments, 0, 1); - } - return Path.Oval(new Rectangle(center.subtract(radius), - Size.create(radius * 2, radius * 2))); - }, - - Arc: function(from, through, to) { - var path = new Path(); - path.moveTo(from); - path.arcTo(through, to); - return path; - }, - - RegularPolygon: function(center, numSides, radius) { - center = Point.read(arguments, 0, 1); - var path = new Path(), - step = 360 / numSides, - three = !(numSides % 3), - vector = new Point(0, three ? -radius : radius), - offset = three ? -1 : 0.5, - segments = new Array(numSides); - for (var i = 0; i < numSides; i++) { - segments[i] = new Segment(center.add( - vector.rotate((i + offset) * step))); - } - path._add(segments); - path._closed = true; - return path; - }, - - Star: function(center, numPoints, radius1, radius2) { - center = Point.read(arguments, 0, 1); - numPoints *= 2; - var path = new Path(), - step = 360 / numPoints, - vector = new Point(0, -1), - segments = new Array(numPoints); - for (var i = 0; i < numPoints; i++) { - segments[i] = new Segment(center.add( - vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); - } - path._add(segments); - path._closed = true; - return path; - } - }; -}}); - -var CompoundPath = this.CompoundPath = PathItem.extend({ - initialize: function(paths) { - this.base(); - this._children = []; - this._namedChildren = {}; - var items = !paths || !Array.isArray(paths) - || typeof paths[0] !== 'object' ? arguments : paths; - this.addChildren(items); - }, - - insertChild: function(index, item) { - this.base(index, item); - if (item._clockwise === undefined) - item.setClockwise(item._index == 0); - }, - - simplify: function() { - if (this._children.length == 1) { - var child = this._children[0]; - child.insertAbove(this); - this.remove(); - return child; - } - return this; - }, - - smooth: function() { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].smooth(); - }, - - draw: function(ctx, param) { - var l = this._children.length; - if (l == 0) { - return; - } - var firstChild = this._children[0]; - ctx.beginPath(); - param.compound = true; - for (var i = 0; i < l; i++) - Item.draw(this._children[i], ctx, param); - firstChild._setStyles(ctx); - var fillColor = firstChild.getFillColor(), - strokeColor = firstChild.getStrokeColor(); - if (fillColor) { - ctx.fillStyle = fillColor.getCanvasStyle(ctx); - ctx.fill(); - } - if (strokeColor) { - ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); - ctx.stroke(); - } - param.compound = false; - } -}, new function() { - function getCurrentPath(that) { - if (!that._children.length) - throw new Error('Use a moveTo() command first'); - return that._children[that._children.length - 1]; - } - - var fields = { - moveTo: function(point) { - var path = new Path(); - this.addChild(path); - path.moveTo.apply(path, arguments); - }, - - moveBy: function(point) { - this.moveTo(getCurrentPath(this).getLastSegment()._point.add( - Point.read(arguments))); - }, - - closePath: function() { - getCurrentPath(this).setClosed(true); - } - }; - - Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', - 'arcTo', 'lineBy', 'curveBy', 'arcBy'], function(key) { - fields[key] = function() { - var path = getCurrentPath(this); - path[key].apply(path, arguments); - }; - }); - - return fields; -}); - -var PathFlattener = Base.extend({ - initialize: function(path) { - this.curves = []; - this.parts = []; - this.length = 0; - this.index = 0; - - var segments = path._segments, - segment1 = segments[0], - segment2, - that = this; - - function addCurve(segment1, segment2) { - var curve = Curve.getValues(segment1, segment2); - that.curves.push(curve); - that._computeParts(curve, segment1._index, 0, 1); - } - - for (var i = 1, l = segments.length; i < l; i++) { - segment2 = segments[i]; - addCurve(segment1, segment2); - segment1 = segment2; - } - if (path._closed) - addCurve(segment2, segments[0]); - }, - - _computeParts: function(curve, index, minT, maxT) { - if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough(curve)) { - var curves = Curve.subdivide(curve); - var halfT = (minT + maxT) / 2; - this._computeParts(curves[0], index, minT, halfT); - this._computeParts(curves[1], index, halfT, maxT); - } else { - var x = curve[6] - curve[0], - y = curve[7] - curve[1], - dist = Math.sqrt(x * x + y * y); - if (dist > Numerical.TOLERANCE) { - this.length += dist; - this.parts.push({ - offset: this.length, - value: maxT, - index: index - }); - } - } - }, - - getParameterAt: function(offset) { - var i, j = this.index; - for (;;) { - i = j; - if (j == 0 || this.parts[--j].offset < offset) - break; - } - for (var l = this.parts.length; i < l; i++) { - var part = this.parts[i]; - if (part.offset >= offset) { - this.index = i; - var prev = this.parts[i - 1]; - var prevVal = prev && prev.index == part.index ? prev.value : 0, - prevLen = prev ? prev.offset : 0; - return { - value: prevVal + (part.value - prevVal) - * (offset - prevLen) / (part.offset - prevLen), - index: part.index - }; - } - } - var part = this.parts[this.parts.length - 1]; - return { - value: 1, - index: part.index - }; - }, - - evaluate: function(offset, type) { - var param = this.getParameterAt(offset); - return Curve.evaluate(this.curves[param.index], param.value, type); - }, - - drawPart: function(ctx, from, to) { - from = this.getParameterAt(from); - to = this.getParameterAt(to); - for (var i = from.index; i <= to.index; i++) { - var curve = Curve.getPart(this.curves[i], - i == from.index ? from.value : 0, - i == to.index ? to.value : 1); - if (i == from.index) - ctx.moveTo(curve[0], curve[1]); - ctx.bezierCurveTo.apply(ctx, curve.slice(2)); - } - } -}); - -var PathFitter = Base.extend({ - initialize: function(path, error) { - this.points = []; - var segments = path._segments, - prev; - for (var i = 0, l = segments.length; i < l; i++) { - var point = segments[i].point.clone(); - if (!prev || !prev.equals(point)) { - this.points.push(point); - prev = point; - } - } - this.error = error; - }, - - fit: function() { - this.segments = [new Segment(this.points[0])]; - this.fitCubic(0, this.points.length - 1, - this.points[1].subtract(this.points[0]).normalize(), - this.points[this.points.length - 2].subtract( - this.points[this.points.length - 1]).normalize()); - return this.segments; - }, - - fitCubic: function(first, last, tan1, tan2) { - if (last - first == 1) { - var pt1 = this.points[first], - pt2 = this.points[last], - dist = pt1.getDistance(pt2) / 3; - this.addCurve([pt1, pt1.add(tan1.normalize(dist)), - pt2.add(tan2.normalize(dist)), pt2]); - return; - } - var uPrime = this.chordLengthParameterize(first, last), - maxError = Math.max(this.error, this.error * this.error), - error, - split; - for (var i = 0; i <= 4; i++) { - var curve = this.generateBezier(first, last, uPrime, tan1, tan2); - var max = this.findMaxError(first, last, curve, uPrime); - if (max.error < this.error) { - this.addCurve(curve); - return; - } - split = max.index; - if (max.error >= maxError) - break; - this.reparameterize(first, last, uPrime, curve); - maxError = max.error; - } - var V1 = this.points[split - 1].subtract(this.points[split]), - V2 = this.points[split].subtract(this.points[split + 1]), - tanCenter = V1.add(V2).divide(2).normalize(); - this.fitCubic(first, split, tan1, tanCenter); - this.fitCubic(split, last, tanCenter.negate(), tan2); - }, - - addCurve: function(curve) { - var prev = this.segments[this.segments.length - 1]; - prev.setHandleOut(curve[1].subtract(curve[0])); - this.segments.push( - new Segment(curve[3], curve[2].subtract(curve[3]))); - }, - - generateBezier: function(first, last, uPrime, tan1, tan2) { - var epsilon = Numerical.EPSILON, - pt1 = this.points[first], - pt2 = this.points[last], - C = [[0, 0], [0, 0]], - X = [0, 0]; - - for (var i = 0, l = last - first + 1; i < l; i++) { - var u = uPrime[i], - t = 1 - u, - b = 3 * u * t, - b0 = t * t * t, - b1 = b * t, - b2 = b * u, - b3 = u * u * u, - a1 = tan1.normalize(b1), - a2 = tan2.normalize(b2), - tmp = this.points[first + i] - .subtract(pt1.multiply(b0 + b1)) - .subtract(pt2.multiply(b2 + b3)); - C[0][0] += a1.dot(a1); - C[0][1] += a1.dot(a2); - C[1][0] = C[0][1]; - C[1][1] += a2.dot(a2); - X[0] += a1.dot(tmp); - X[1] += a2.dot(tmp); - } - - var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], - alpha1, alpha2; - if (Math.abs(detC0C1) > epsilon) { - var detC0X = C[0][0] * X[1] - C[1][0] * X[0], - detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; - alpha1 = detXC1 / detC0C1; - alpha2 = detC0X / detC0C1; - } else { - var c0 = C[0][0] + C[0][1], - c1 = C[1][0] + C[1][1]; - if (Math.abs(c0) > epsilon) { - alpha1 = alpha2 = X[0] / c0; - } else if (Math.abs(c0) > epsilon) { - alpha1 = alpha2 = X[1] / c1; - } else { - alpha1 = alpha2 = 0.; - } - } - - var segLength = pt2.getDistance(pt1); - epsilon *= segLength; - if (alpha1 < epsilon || alpha2 < epsilon) { - alpha1 = alpha2 = segLength / 3; - } - - return [pt1, pt1.add(tan1.normalize(alpha1)), - pt2.add(tan2.normalize(alpha2)), pt2]; - }, - - reparameterize: function(first, last, u, curve) { - for (var i = first; i <= last; i++) { - u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); - } - }, - - findRoot: function(curve, point, u) { - var curve1 = [], - curve2 = []; - for (var i = 0; i <= 2; i++) { - curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); - } - for (var i = 0; i <= 1; i++) { - curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); - } - var pt = this.evaluate(3, curve, u), - pt1 = this.evaluate(2, curve1, u), - pt2 = this.evaluate(1, curve2, u), - diff = pt.subtract(point), - df = pt1.dot(pt1) + diff.dot(pt2); - if (Math.abs(df) < Numerical.TOLERANCE) - return u; - return u - diff.dot(pt1) / df; - }, - - evaluate: function(degree, curve, t) { - var tmp = curve.slice(); - for (var i = 1; i <= degree; i++) { - for (var j = 0; j <= degree - i; j++) { - tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); - } - } - return tmp[0]; - }, - - chordLengthParameterize: function(first, last) { - var u = [0]; - for (var i = first + 1; i <= last; i++) { - u[i - first] = u[i - first - 1] - + this.points[i].getDistance(this.points[i - 1]); - } - for (var i = 1, m = last - first; i <= m; i++) { - u[i] /= u[m]; - } - return u; - }, - - findMaxError: function(first, last, curve, u) { - var index = Math.floor((last - first + 1) / 2), - maxDist = 0; - for (var i = first + 1; i < last; i++) { - var P = this.evaluate(3, curve, u[i - first]); - var v = P.subtract(this.points[i]); - var dist = v.x * v.x + v.y * v.y; - if (dist >= maxDist) { - maxDist = dist; - index = i; - } - } - return { - error: maxDist, - index: index - }; - } -}); - -var TextItem = this.TextItem = Item.extend({ - initialize: function() { - this.base(); - this._content = ''; - this._characterStyle = CharacterStyle.create(this); - this.setCharacterStyle(this._project.getCurrentStyle()); - this._paragraphStyle = ParagraphStyle.create(this); - this.setParagraphStyle(); - }, - - _clone: function(copy) { - copy._content = this._content; - copy.setCharacterStyle(this._characterStyle); - copy.setParagraphStyle(this._paragraphStyle); - return this.base(copy); - }, - - getContent: function() { - return this._content; - }, - - setContent: function(content) { - this._changed(Change.CONTENT); - this._content = '' + content; - }, - - getCharacterStyle: function() { - return this._characterStyle; - }, - - setCharacterStyle: function(style) { - this._characterStyle.initialize(style); - }, - - getParagraphStyle: function() { - return this._paragraphStyle; - }, - - setParagraphStyle: function(style) { - this._paragraphStyle.initialize(style); - } -}); - -var PointText = this.PointText = TextItem.extend({ - initialize: function(point) { - this.base(); - this._point = Point.read(arguments).clone(); - this._matrix = new Matrix().translate(this._point); - }, - - clone: function() { - var copy = this._clone(new PointText(this._point)); - copy._matrix.initialize(this._matrix); - return copy; - }, - - getPoint: function() { - return LinkedPoint.create(this, 'setPoint', - this._point.x, this._point.y); - }, - - setPoint: function(point) { - this.translate(Point.read(arguments).subtract(this._point)); - }, - - getPosition: function() { - return this.getPoint(); - }, - - setPosition: function(point) { - this.setPoint.apply(this, arguments); - }, - - _transform: function(matrix, flags) { - this._matrix.preConcatenate(matrix); - matrix._transformPoint(this._point, this._point); - }, - - draw: function(ctx) { - if (!this._content) - return; - ctx.save(); - ctx.font = this.getFontSize() + 'pt ' + this.getFont(); - ctx.textAlign = this.getJustification(); - this._matrix.applyToContext(ctx); - - var fillColor = this.getFillColor(); - var strokeColor = this.getStrokeColor(); - if (!fillColor || !strokeColor) - ctx.globalAlpha = this._opacity; - if (fillColor) { - ctx.fillStyle = fillColor.getCanvasStyle(ctx); - ctx.fillText(this._content, 0, 0); - } - if (strokeColor) { - ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); - ctx.strokeText(this._content, 0, 0); - } - ctx.restore(); - } -}); - -var Style = Item.extend({ - initialize: function(style) { - var clone = style instanceof Style; - return Base.each(this._defaults, function(value, key) { - value = style && style[key] || value; - this[key] = value && clone && value.clone - ? value.clone() : value; - }, this); - }, - - statics: { - create: function(item) { - var style = new this(this.dont); - style._item = item; - return style; - }, - - extend: function(src) { - var styleKey = src._style, - flags = src._flags || {}; - src._owner.inject(Base.each(src._defaults, function(value, key) { - var isColor = !!key.match(/Color$/), - part = Base.capitalize(key), - set = 'set' + part, - get = 'get' + part; - src[set] = function(value) { - var children = this._item && this._item._children; - value = isColor ? Color.read(arguments) : value; - if (children) { - for (var i = 0, l = children.length; i < l; i++) - children[i][styleKey][set](value); - } else { - var old = this['_' + key]; - if (old != value && !(old && old.equals - && old.equals(value))) { - this['_' + key] = value; - if (isColor) { - if (old) - old._removeOwner(this._item); - if (value) - value._addOwner(this._item); - } - if (this._item) - this._item._changed(flags[key] || Change.STYLE); - } - } - return this; - }; - src[get] = function() { - var children = this._item && this._item._children, - style; - if (!children) - return this['_' + key]; - for (var i = 0, l = children.length; i < l; i++) { - var childStyle = children[i][styleKey][get](); - if (!style) { - style = childStyle; - } else if (style != childStyle && !(style - && style.equals && style.equals(childStyle))) { - return undefined; - } - } - return style; - }; - this[set] = function(value) { - this[styleKey][set](value); - return this; - }; - this[get] = function() { - return this[styleKey][get](); - }; - }, {})); - return this.base(src); - } - } -}); - -var PathStyle = this.PathStyle = Style.extend({ - _defaults: { - fillColor: undefined, - strokeColor: undefined, - strokeWidth: 1, - strokeCap: 'butt', - strokeJoin: 'miter', - miterLimit: 10, - dashOffset: 0, - dashArray: [] - }, - _flags: { - strokeWidth: Change.STROKE, - strokeCap: Change.STROKE, - strokeJoin: Change.STROKE, - miterLimit: Change.STROKE - }, - _owner: Item, - _style: '_style' - -}); - -var ParagraphStyle = this.ParagraphStyle = Style.extend({ - _defaults: { - justification: 'left' - }, - _owner: TextItem, - _style: '_paragraphStyle' - -}); - -var CharacterStyle = this.CharacterStyle = PathStyle.extend({ - _defaults: Base.merge(PathStyle.prototype._defaults, { - fillColor: 'black', - fontSize: 10, - font: 'sans-serif' - }), - _owner: TextItem, - _style: '_characterStyle' - -}); - -var Color = this.Color = Base.extend(new function() { - - var components = { - gray: ['gray'], - rgb: ['red', 'green', 'blue'], - hsb: ['hue', 'saturation', 'brightness'], - hsl: ['hue', 'saturation', 'lightness'] - }; - - var colorCache = {}, - colorContext; - - function nameToRgbColor(name) { - var color = colorCache[name]; - if (color) - return color.clone(); - if (!colorContext) { - var canvas = CanvasProvider.getCanvas(Size.create(1, 1)); - colorContext = canvas.getContext('2d'); - colorContext.globalCompositeOperation = 'copy'; - } - colorContext.fillStyle = 'rgba(0,0,0,0)'; - colorContext.fillStyle = name; - colorContext.fillRect(0, 0, 1, 1); - var data = colorContext.getImageData(0, 0, 1, 1).data, - rgb = [data[0] / 255, data[1] / 255, data[2] / 255]; - return (colorCache[name] = RgbColor.read(rgb)).clone(); - } - - function hexToRgbColor(string) { - var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - if (hex.length >= 4) { - var rgb = new Array(3); - for (var i = 0; i < 3; i++) { - var channel = hex[i + 1]; - rgb[i] = parseInt(channel.length == 1 - ? channel + channel : channel, 16) / 255; - } - return RgbColor.read(rgb); - } - } - - var hsbIndices = [ - [0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2] - ]; - - var converters = { - 'rgb-hsb': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - h = delta == 0 ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - s = max == 0 ? 0 : delta / max, - v = max; - return new HsbColor(h, s, v, color._alpha); - }, - - 'hsb-rgb': function(color) { - var h = (color._hue / 60) % 6, - s = color._saturation, - b = color._brightness, - i = Math.floor(h), - f = h - i, - i = hsbIndices[i], - v = [ - b, - b * (1 - s), - b * (1 - s * f), - b * (1 - s * (1 - f)) - ]; - return new RgbColor(v[i[0]], v[i[1]], v[i[2]], color._alpha); - }, - - 'rgb-hsl': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - achromatic = delta == 0, - h = achromatic ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - l = (max + min) / 2, - s = achromatic ? 0 : l < 0.5 - ? delta / (max + min) - : delta / (2 - max - min); - return new HslColor(h, s, l, color._alpha); - }, - - 'hsl-rgb': function(color) { - var s = color._saturation, - h = color._hue / 360, - l = color._lightness, - t1, t2, c; - if (s == 0) - return new RgbColor(l, l, l, color._alpha); - var t3s = [ h + 1 / 3, h, h - 1 / 3 ], - t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, - t1 = 2 * l - t2, - c = []; - for (var i = 0; i < 3; i++) { - var t3 = t3s[i]; - if (t3 < 0) t3 += 1; - if (t3 > 1) t3 -= 1; - c[i] = 6 * t3 < 1 - ? t1 + (t2 - t1) * 6 * t3 - : 2 * t3 < 1 - ? t2 - : 3 * t3 < 2 - ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 - : t1; - } - return new RgbColor(c[0], c[1], c[2], color._alpha); - }, - - 'rgb-gray': function(color) { - return new GrayColor(1 - (color._red * 0.2989 + color._green * 0.587 - + color._blue * 0.114), color._alpha); - }, - - 'gray-rgb': function(color) { - var comp = 1 - color._gray; - return new RgbColor(comp, comp, comp, color._alpha); - }, - - 'gray-hsb': function(color) { - return new HsbColor(0, 0, 1 - color._gray, color._alpha); - }, - - 'gray-hsl': function(color) { - return new HslColor(0, 0, 1 - color._gray, color._alpha); - } - }; - - var fields = { - _readNull: true, - - initialize: function(arg) { - var isArray = Array.isArray(arg), - type = this._colorType; - if (typeof arg === 'object' && !isArray) { - if (!type) { - return arg.red !== undefined - ? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha) - : arg.gray !== undefined - ? new GrayColor(arg.gray, arg.alpha) - : arg.lightness !== undefined - ? new HslColor(arg.hue, arg.saturation, arg.lightness, - arg.alpha) - : arg.hue !== undefined - ? new HsbColor(arg.hue, arg.saturation, arg.brightness, - arg.alpha) - : new RgbColor(); - } else { - return Color.read(arguments).convert(type); - } - } else if (typeof arg === 'string') { - var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i) - ? hexToRgbColor(arg) - : nameToRgbColor(arg); - return type - ? rgbColor.convert(type) - : rgbColor; - } else { - var components = isArray ? arg - : Array.prototype.slice.call(arguments); - if (!type) { - if (components.length >= 3) - return new RgbColor(components); - return new GrayColor(components); - } else { - Base.each(this._components, - function(name, i) { - var value = components[i]; - this['_' + name] = value !== undefined - ? value : null; - }, - this); - } - } - }, - - clone: function() { - var ctor = this.constructor, - copy = new ctor(ctor.dont), - components = this._components; - for (var i = 0, l = components.length; i < l; i++) { - var key = '_' + components[i]; - copy[key] = this[key]; - } - return copy; - }, - - convert: function(type) { - var converter; - return this._colorType == type - ? this.clone() - : (converter = converters[this._colorType + '-' + type]) - ? converter(this) - : converters['rgb-' + type]( - converters[this._colorType + '-rgb'](this)); - }, - - statics: { - extend: function(src) { - src.beans = true; - if (src._colorType) { - var comps = components[src._colorType]; - src._components = comps.concat(['alpha']); - Base.each(comps, function(name) { - var isHue = name === 'hue', - part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - this[name] = isHue - ? ((value % 360) + 360) % 360 - : Math.min(Math.max(value, 0), 1); - this._changed(); - return this; - }; - }, src); - } - return this.base(src); - } - } - }; - - Base.each(components, function(comps, type) { - Base.each(comps, function(component) { - var part = Base.capitalize(component); - fields['get' + part] = function() { - return this.convert(type)[component]; - }; - fields['set' + part] = function(value) { - var color = this.convert(type); - color[component] = value; - color = color.convert(this._colorType); - for (var i = 0, l = this._components.length; i < l; i++) { - var key = this._components[i]; - this[key] = color[key]; - } - }; - }); - }); - - return fields; -}, { - - _changed: function() { - this._cssString = null; - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) - this._owners[i]._changed(Change.STYLE); - }, - - _addOwner: function(item) { - if (!this._owners) - this._owners = []; - this._owners.push(item); - }, - - _removeOwner: function(item) { - var index = this._owners ? this._owners.indexOf(item) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (this._owners.length == 0) - delete this._owners; - } - }, - - getType: function() { - return this._colorType; - }, - - getComponents: function() { - var length = this._components.length; - var comps = new Array(length); - for (var i = 0; i < length; i++) - comps[i] = this['_' + this._components[i]]; - return comps; - }, - - getAlpha: function() { - return this._alpha != null ? this._alpha : 1; - }, - - setAlpha: function(alpha) { - this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); - this._changed(); - return this; - }, - - hasAlpha: function() { - return this._alpha != null; - }, - - equals: function(color) { - if (color && color._colorType === this._colorType) { - for (var i = 0, l = this._components.length; i < l; i++) { - var component = '_' + this._components[i]; - if (this[component] !== color[component]) - return false; - } - return true; - } - return false; - }, - - toString: function() { - var parts = [], - format = Base.formatNumber; - for (var i = 0, l = this._components.length; i < l; i++) { - var component = this._components[i], - value = this['_' + component]; - if (component === 'alpha' && value == null) - value = 1; - parts.push(component + ': ' + format(value)); - } - return '{ ' + parts.join(', ') + ' }'; - }, - - toCssString: function() { - if (!this._cssString) { - var color = this.convert('rgb'), - alpha = color.getAlpha(), - components = [ - Math.round(color._red * 255), - Math.round(color._green * 255), - Math.round(color._blue * 255), - alpha != null ? alpha : 1 - ]; - this._cssString = 'rgba(' + components.join(', ') + ')'; - } - return this._cssString; - }, - - getCanvasStyle: function() { - return this.toCssString(); - } - -}); - -var GrayColor = this.GrayColor = Color.extend({ - - _colorType: 'gray' -}); - -var RgbColor = this.RgbColor = this.RGBColor = Color.extend({ - - _colorType: 'rgb' -}); - -var HsbColor = this.HsbColor = this.HSBColor = Color.extend({ - - _colorType: 'hsb' -}); - -var HslColor = this.HslColor = this.HSLColor = Color.extend({ - - _colorType: 'hsl' -}); - -var GradientColor = this.GradientColor = Color.extend({ - - initialize: function(gradient, origin, destination, hilite) { - this.gradient = gradient || new Gradient(); - this.setOrigin(origin); - this.setDestination(destination); - if (hilite) - this.setHilite(hilite); - }, - - clone: function() { - return new GradientColor(this.gradient, this._origin, this._destination, - this._hilite); - }, - - getOrigin: function() { - return this._origin; - }, - - setOrigin: function(origin) { - origin = Point.read(arguments).clone(); - this._origin = origin; - if (this._destination) - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getDestination: function() { - return this._destination; - }, - - setDestination: function(destination) { - destination = Point.read(arguments).clone(); - this._destination = destination; - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getHilite: function() { - return this._hilite; - }, - - setHilite: function(hilite) { - hilite = Point.read(arguments).clone(); - var vector = hilite.subtract(this._origin); - if (vector.getLength() > this._radius) { - this._hilite = this._origin.add( - vector.normalize(this._radius - 0.1)); - } else { - this._hilite = hilite; - } - this._changed(); - return this; - }, - - getCanvasStyle: function(ctx) { - var gradient; - if (this.gradient.type === 'linear') { - gradient = ctx.createLinearGradient(this._origin.x, this._origin.y, - this._destination.x, this._destination.y); - } else { - var origin = this._hilite || this._origin; - gradient = ctx.createRadialGradient(origin.x, origin.y, - 0, this._origin.x, this._origin.y, this._radius); - } - for (var i = 0, l = this.gradient._stops.length; i < l; i++) { - var stop = this.gradient._stops[i]; - gradient.addColorStop(stop._rampPoint, stop._color.toCssString()); - } - return gradient; - }, - - equals: function(color) { - return color == this || color && color._colorType === this._colorType - && this.gradient.equals(color.gradient) - && this._origin.equals(color._origin) - && this._destination.equals(color._destination); - }, - - transform: function(matrix) { - matrix._transformPoint(this._origin, this._origin, true); - matrix._transformPoint(this._destination, this._destination, true); - if (this._hilite) - matrix._transformPoint(this._hilite, this._hilite, true); - this._radius = this._destination.getDistance(this._origin); - } -}); - -var Gradient = this.Gradient = Base.extend({ - initialize: function(stops, type) { - this.setStops(stops || ['white', 'black']); - this.type = type || 'linear'; - }, - - clone: function() { - var stops = []; - for (var i = 0, l = this._stops.length; i < l; i++) - stops[i] = this._stops[i].clone(); - return new Gradient(stops, this.type); - }, - - getStops: function() { - return this._stops; - }, - - setStops: function(stops) { - if (stops.length < 2) - throw new Error( - 'Gradient stop list needs to contain at least two stops.'); - this._stops = GradientStop.readAll(stops); - for (var i = 0, l = this._stops.length; i < l; i++) { - var stop = this._stops[i]; - if (stop._defaultRamp) - stop.setRampPoint(i / (l - 1)); - } - }, - - equals: function(gradient) { - if (gradient.type != this.type) - return false; - if (this._stops.length == gradient._stops.length) { - for (var i = 0, l = this._stops.length; i < l; i++) { - if (!this._stops[i].equals(gradient._stops[i])) - return false; - } - return true; - } - return false; - } -}); - -var GradientStop = this.GradientStop = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 === undefined && Array.isArray(arg0)) { - this.setColor(arg0[0]); - this.setRampPoint(arg0[1]); - } else if (arg0.color) { - this.setColor(arg0.color); - this.setRampPoint(arg0.rampPoint); - } else { - this.setColor(arg0); - this.setRampPoint(arg1); - } - }, - - clone: function() { - return new GradientStop(this._color.clone(), this._rampPoint); - }, - - getRampPoint: function() { - return this._rampPoint; - }, - - setRampPoint: function(rampPoint) { - this._defaultRamp = rampPoint == null; - this._rampPoint = rampPoint || 0; - }, - - getColor: function() { - return this._color; - }, - - setColor: function(color) { - this._color = Color.read(arguments); - }, - - equals: function(stop) { - return stop == this || stop instanceof GradientStop - && this._color.equals(stop._color) - && this._rampPoint == stop._rampPoint; - } -}); - -var DomElement = { - getBounds: function(el, viewport) { - var rect = el.getBoundingClientRect(), - doc = el.ownerDocument, - body = doc.body, - docEl = doc.documentElement, - x = rect.left - (docEl.clientLeft || body.clientLeft || 0), - y = rect.top - (docEl.clientTop || body.clientTop || 0); - if (!viewport) { - var win = DomElement.getViewport(doc); - x += win.pageXOffset || docEl.scrollLeft || body.scrollLeft; - y += win.pageYOffset || docEl.scrollTop || body.scrollTop; - } - return new Rectangle(x, y, rect.width, rect.height); - }, - - getOffset: function(el, viewport) { - return this.getBounds(el, viewport).getPoint(); - }, - - getSize: function(el) { - return this.getBounds(el, true).getSize(); - }, - - isInvisible: function(el) { - return this.getSize(el).equals([0, 0]); - }, - - isVisible: function(el) { - return !this.isInvisible(el) && this.getViewportBounds(el).intersects( - this.getBounds(el, true)); - }, - - getViewport: function(doc) { - return doc.defaultView || doc.parentWindow; - }, - - getViewportBounds: function(el) { - var doc = el.ownerDocument, - view = this.getViewport(doc), - body = doc.getElementsByTagName( - doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; - return Rectangle.create(0, 0, - view.innerWidth || body.clientWidth, - view.innerHeight || body.clientHeight - ); - }, - - getComputedStyle: function(el, name) { - if (el.currentStyle) - return el.currentStyle[Base.camelize(name)]; - var style = this.getViewport(el.ownerDocument) - .getComputedStyle(el, null); - return style ? style.getPropertyValue(Base.hyphenate(name)) : null; - } -}; - -var DomEvent = { - add: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.addEventListener) { - el.addEventListener(type, func, false); - } else if (el.attachEvent) { - el.attachEvent('on' + type, func.bound = function() { - func.call(el, window.event); - }); - } - } - }, - - remove: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.removeEventListener) { - el.removeEventListener(type, func, false); - } else if (el.detachEvent) { - el.detachEvent('on' + type, func.bound); - } - } - }, - - getPoint: function(event) { - var pos = event.targetTouches - ? event.targetTouches.length - ? event.targetTouches[0] - : event.changedTouches[0] - : event; - return Point.create( - pos.pageX || pos.clientX + document.documentElement.scrollLeft, - pos.pageY || pos.clientY + document.documentElement.scrollTop - ); - }, - - getTarget: function(event) { - return event.target || event.srcElement; - }, - - getOffset: function(event, target) { - return DomEvent.getPoint(event).subtract(DomElement.getOffset( - target || DomEvent.getTarget(event))); - }, - - preventDefault: function(event) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - }, - - stopPropagation: function(event) { - if (event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - }, - - stop: function(event) { - DomEvent.stopPropagation(event); - DomEvent.preventDefault(event); - } -}; - -DomEvent.requestAnimationFrame = new function() { - var part = 'equestAnimationFrame', - request = window['r' + part] || window['webkitR' + part] - || window['mozR' + part] || window['oR' + part] - || window['msR' + part]; - if (request) { - request(function(time) { - if (time == undefined) - request = null; - }); - } - - var callbacks = [], - focused = true, - timer; - - DomEvent.add(window, { - focus: function() { - focused = true; - }, - blur: function() { - focused = false; - } - }); - - return function(callback, element) { - if (request) - return request(callback, element); - callbacks.push([callback, element]); - if (timer) - return; - timer = window.setInterval(function() { - for (var i = callbacks.length - 1; i >= 0; i--) { - var entry = callbacks[i], - func = entry[0], - el = entry[1]; - if (!el || (PaperScript.getAttribute(el, 'keepalive') == 'true' - || focused) && DomElement.isVisible(el)) { - callbacks.splice(i, 1); - func(Date.now()); - } - } - }, 1000 / 60); - }; -}; - -var View = this.View = PaperScopeItem.extend({ - _list: 'views', - _reference: 'view', - - initialize: function(canvas) { - this.base(); - var size; - - if (typeof canvas === 'string') - canvas = document.getElementById(canvas); - if (canvas instanceof HTMLCanvasElement) { - this._canvas = canvas; - if (PaperScript.hasAttribute(canvas, 'resize')) { - var offset = DomElement.getOffset(canvas, true), - that = this; - size = DomElement.getViewportBounds(canvas) - .getSize().subtract(offset); - canvas.width = size.width; - canvas.height = size.height; - DomEvent.add(window, { - resize: function(event) { - if (!DomElement.isInvisible(canvas)) - offset = DomElement.getOffset(canvas, true); - that.setViewSize(DomElement.getViewportBounds(canvas) - .getSize().subtract(offset)); - } - }); - } else { - size = DomElement.isInvisible(canvas) - ? Size.create(parseInt(canvas.getAttribute('width')), - parseInt(canvas.getAttribute('height'))) - : DomElement.getSize(canvas); - } - if (PaperScript.hasAttribute(canvas, 'stats')) { - this._stats = new Stats(); - var element = this._stats.domElement, - style = element.style, - offset = DomElement.getOffset(canvas); - style.position = 'absolute'; - style.left = offset.x + 'px'; - style.top = offset.y + 'px'; - document.body.appendChild(element); - } - } else { - size = Size.read(arguments, 1); - if (size.isZero()) - size = new Size(1024, 768); - this._canvas = CanvasProvider.getCanvas(size); - } - this._id = this._canvas.getAttribute('id'); - if (this._id == null) - this._canvas.setAttribute('id', this._id = 'canvas-' + View._id++); - - View._views[this._id] = this; - this._viewSize = LinkedSize.create(this, 'setViewSize', - size.width, size.height); - this._context = this._canvas.getContext('2d'); - this._matrix = new Matrix(); - this._zoom = 1; - - this._events = this._createEvents(); - DomEvent.add(this._canvas, this._events); - if (!View._focused) - View._focused = this; - - this._scope._redrawNotified = false; - }, - - remove: function() { - if (!this.base()) - return false; - if (View._focused == this) - View._focused = null; - delete View._views[this._id]; - DomEvent.remove(this._canvas, this._events); - this._canvas = this._events = this._onFrame = null; - return true; - }, - - _redraw: function() { - this._redrawNeeded = true; - if (this._onFrameCallback) { - this._onFrameCallback(0, true); - } else { - this.draw(); - } - }, - - _transform: function(matrix, flags) { - this._matrix.preConcatenate(matrix); - this._bounds = null; - this._inverse = null; - this._redraw(); - }, - - getCanvas: function() { - return this._canvas; - }, - - getViewSize: function() { - return this._viewSize; - }, - - setViewSize: function(size) { - size = Size.read(arguments); - var delta = size.subtract(this._viewSize); - if (delta.isZero()) - return; - this._canvas.width = size.width; - this._canvas.height = size.height; - this._viewSize.set(size.width, size.height, true); - this._bounds = null; - this._redrawNeeded = true; - if (this.onResize) { - this.onResize({ - size: size, - delta: delta - }); - } - this._redraw(); - }, - - getBounds: function() { - if (!this._bounds) - this._bounds = this._getInverse()._transformBounds( - new Rectangle(new Point(), this._viewSize)); - return this._bounds; - }, - - getSize: function() { - return this.getBounds().getSize(); - }, - - getCenter: function() { - return this.getBounds().getCenter(); - }, - - setCenter: function(center) { - this.scrollBy(Point.read(arguments).subtract(this.getCenter())); - }, - - getZoom: function() { - return this._zoom; - }, - - setZoom: function(zoom) { - this._transform(new Matrix().scale(zoom / this._zoom, this.getCenter())); - this._zoom = zoom; - }, - - isVisible: function() { - return DomElement.isVisible(this._canvas); - }, - - scrollBy: function(point) { - this._transform(new Matrix().translate(Point.read(arguments).negate())); - }, - - draw: function(checkRedraw) { - if (checkRedraw && !this._redrawNeeded) - return false; - if (this._stats) - this._stats.update(); - var ctx = this._context, - size = this._viewSize; - ctx.clearRect(0, 0, size._width + 1, size._height + 1); - - ctx.save(); - this._matrix.applyToContext(ctx); - this._scope.project.draw(ctx); - ctx.restore(); - if (this._redrawNeeded) { - this._redrawNeeded = false; - this._scope._redrawNotified = false; - } - return true; - }, - - projectToView: function(point) { - return this._matrix._transformPoint(Point.read(arguments)); - }, - - viewToProject: function(point) { - return this._getInverse()._transformPoint(Point.read(arguments)); - }, - - _getInverse: function() { - if (!this._inverse) - this._inverse = this._matrix.createInverse(); - return this._inverse; - }, - - getOnFrame: function() { - return this._onFrame; - }, - - setOnFrame: function(onFrame) { - this._onFrame = onFrame; - if (!onFrame) { - delete this._onFrameCallback; - return; - } - var that = this, - requested = false, - before, - time = 0, - count = 0; - this._onFrameCallback = function(param, dontRequest) { - requested = false; - if (!that._onFrame) - return; - paper = that._scope; - requested = true; - if (!dontRequest) { - DomEvent.requestAnimationFrame(that._onFrameCallback, - that._canvas); - } - var now = Date.now() / 1000, - delta = before ? now - before : 0; - that._onFrame(Base.merge({ - delta: delta, - time: time += delta, - count: count++ - })); - before = now; - that.draw(true); - }; - if (!requested) - this._onFrameCallback(); - }, - - onResize: null -}, { - statics: { - _views: {}, - _id: 0 - } -}, new function() { - var tool, - timer, - curPoint, - tempFocus, - dragging = false; - - function viewToProject(view, event) { - return view.viewToProject(DomEvent.getOffset(event, view._canvas)); - } - - function updateFocus() { - if (!View._focused || !View._focused.isVisible()) { - PaperScope.each(function(scope) { - for (var i = 0, l = scope.views.length; i < l; i++) { - var view = scope.views[i]; - if (view.isVisible()) { - View._focused = tempFocus = view; - throw Base.stop; - } - } - }); - } - } - - function mousemove(event) { - var view; - if (!dragging) { - view = View._views[DomEvent.getTarget(event).getAttribute('id')]; - if (view) { - View._focused = tempFocus = view; - } else if (tempFocus && tempFocus == View._focused) { - View._focused = null; - updateFocus(); - } - } - if (!(view = view || View._focused) || !(tool = view._scope.tool)) - return; - var point = event && viewToProject(view, event); - var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove); - if (dragging && !onlyMove) { - curPoint = point || curPoint; - if (curPoint && tool.onHandleEvent('mousedrag', curPoint, event)) { - view.draw(true); - DomEvent.stop(event); - } - } else if ((!dragging || onlyMove) - && tool.onHandleEvent('mousemove', point, event)) { - view.draw(true); - DomEvent.stop(event); - } - } - - function mouseup(event) { - var view = View._focused; - if (!view || !dragging) - return; - dragging = false; - curPoint = null; - if (tool) { - if (timer != null) - timer = clearInterval(timer); - if (tool.onHandleEvent('mouseup', viewToProject(view, event), event)) { - view.draw(true); - DomEvent.stop(event); - } - } - } - - function selectstart(event) { - if (dragging) - DomEvent.stop(event); - } - - DomEvent.add(document, { - mousemove: mousemove, - mouseup: mouseup, - touchmove: mousemove, - touchend: mouseup, - selectstart: selectstart, - scroll: updateFocus - }); - - DomEvent.add(window, { - load: updateFocus - }); - - return { - _createEvents: function() { - var view = this; - - function mousedown(event) { - View._focused = view; - if (!(tool = view._scope.tool)) - return; - curPoint = viewToProject(view, event); - if (tool.onHandleEvent('mousedown', curPoint, event)) - view.draw(true); - if (tool.eventInterval != null) - timer = setInterval(mousemove, tool.eventInterval); - dragging = true; - } - - return { - mousedown: mousedown, - touchstart: mousedown, - selectstart: selectstart - }; - }, - - statics: { - - updateFocus: updateFocus - } - }; -}); - -var Event = this.Event = Base.extend({ - initialize: function(event) { - this.event = event; - }, - - preventDefault: function() { - DomEvent.preventDefault(this.event); - }, - - stopPropagation: function() { - DomEvent.stopPropagation(this.event); - }, - - stop: function() { - DomEvent.stop(this.event); - }, - - getModifiers: function() { - return Key.modifiers; - } -}); - -var KeyEvent = this.KeyEvent = Event.extend(new function() { - return { - initialize: function(down, key, character, event) { - this.base(event); - this.type = down ? 'keydown' : 'keyup'; - this.key = key; - this.character = character; - }, - - toString: function() { - return '{ type: ' + this.type - + ', key: ' + this.key - + ', character: ' + this.character - + ', modifiers: ' + this.getModifiers() - + ' }'; - } - }; -}); - -var Key = this.Key = new function() { - - var keys = { - 8: 'backspace', - 13: 'enter', - 16: 'shift', - 17: 'control', - 18: 'option', - 19: 'pause', - 20: 'caps-lock', - 27: 'escape', - 32: 'space', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 46: 'delete', - 91: 'command', - 93: 'command', - 224: 'command' - }, - - modifiers = Base.merge({ - shift: false, - control: false, - option: false, - command: false, - capsLock: false - }), - - charCodeMap = {}, - keyMap = {}, - downCode; - - function handleKey(down, keyCode, charCode, event) { - var character = String.fromCharCode(charCode), - key = keys[keyCode] || character.toLowerCase(), - handler = down ? 'onKeyDown' : 'onKeyUp', - view = View._focused, - scope = view && view.isVisible() && view._scope, - tool = scope && scope.tool; - keyMap[key] = down; - if (tool && tool[handler]) { - var keyEvent = new KeyEvent(down, key, character, event); - if (tool[handler](keyEvent) === false) - keyEvent.preventDefault(); - if (view) - view.draw(true); - } - } - - DomEvent.add(document, { - keydown: function(event) { - var code = event.which || event.keyCode; - var key = keys[code], name; - if (key) { - if ((name = Base.camelize(key)) in modifiers) - modifiers[name] = true; - charCodeMap[code] = 0; - handleKey(true, code, null, event); - } else { - downCode = code; - } - }, - - keypress: function(event) { - if (downCode != null) { - var code = event.which || event.keyCode; - charCodeMap[downCode] = code; - handleKey(true, downCode, code, event); - downCode = null; - } - }, - - keyup: function(event) { - var code = event.which || event.keyCode, - key = keys[code], name; - if (key && (name = Base.camelize(key)) in modifiers) - modifiers[name] = false; - if (charCodeMap[code] != null) { - handleKey(false, code, charCodeMap[code], event); - delete charCodeMap[code]; - } - } - }); - - return { - modifiers: modifiers, - - isDown: function(key) { - return !!keyMap[key]; - } - }; -}; - -var ToolEvent = this.ToolEvent = Event.extend({ - initialize: function(tool, type, event) { - this.tool = tool; - this.type = type; - this.event = event; - }, - - _choosePoint: function(point, toolPoint) { - return point ? point : toolPoint ? toolPoint.clone() : null; - }, - - getPoint: function() { - return this._choosePoint(this._point, this.tool._point); - }, - - setPoint: function(point) { - this._point = point; - }, - - getLastPoint: function() { - return this._choosePoint(this._lastPoint, this.tool._lastPoint); - }, - - setLastPoint: function(lastPoint) { - this._lastPoint = lastPoint; - }, - - getDownPoint: function() { - return this._choosePoint(this._downPoint, this.tool._downPoint); - }, - - setDownPoint: function(downPoint) { - this._downPoint = downPoint; - }, - - getMiddlePoint: function() { - if (!this._middlePoint && this.tool._lastPoint) { - return this.tool._point.add(this.tool._lastPoint).divide(2); - } - return this.middlePoint; - }, - - setMiddlePoint: function(middlePoint) { - this._middlePoint = middlePoint; - }, - - getDelta: function() { - return !this._delta && this.tool._lastPoint - ? this.tool._point.subtract(this.tool._lastPoint) - : this._delta; - }, - - setDelta: function(delta) { - this._delta = delta; - }, - - getCount: function() { - return /^mouse(down|up)$/.test(this.type) - ? this.tool._downCount - : this.tool._count; - }, - - setCount: function(count) { - this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] - = count; - }, - - getItem: function() { - if (!this._item) { - var result = this.tool._scope.project.hitTest(this.getPoint()); - if (result) { - var item = result.item, - parent = item._parent; - while ((parent instanceof Group && !(parent instanceof Layer)) - || parent instanceof CompoundPath) { - item = parent; - parent = parent._parent; - } - this._item = item; - } - } - return this._item; - }, - setItem: function(item) { - this._item = item; - }, - - toString: function() { - return '{ type: ' + this.type - + ', point: ' + this.getPoint() - + ', count: ' + this.getCount() - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Tool = this.Tool = PaperScopeItem.extend({ - _list: 'tools', - _reference: 'tool', - - initialize: function() { - this.base(); - this._firstMove = true; - this._count = 0; - this._downCount = 0; - }, - - eventInterval: null, - - getMinDistance: function() { - return this._minDistance; - }, - - setMinDistance: function(minDistance) { - this._minDistance = minDistance; - if (this._minDistance != null && this._maxDistance != null - && this._minDistance > this._maxDistance) { - this._maxDistance = this._minDistance; - } - }, - - getMaxDistance: function() { - return this._maxDistance; - }, - - setMaxDistance: function(maxDistance) { - this._maxDistance = maxDistance; - if (this._minDistance != null && this._maxDistance != null - && this._maxDistance < this._minDistance) { - this._minDistance = maxDistance; - } - }, - - getFixedDistance: function() { - return this._minDistance == this._maxDistance - ? this._minDistance : null; - }, - - setFixedDistance: function(distance) { - this._minDistance = distance; - this._maxDistance = distance; - }, - - updateEvent: function(type, pt, minDistance, maxDistance, start, - needsChange, matchMaxDistance) { - if (!start) { - if (minDistance != null || maxDistance != null) { - var minDist = minDistance != null ? minDistance : 0; - var vector = pt.subtract(this._point); - var distance = vector.getLength(); - if (distance < minDist) - return false; - var maxDist = maxDistance != null ? maxDistance : 0; - if (maxDist != 0) { - if (distance > maxDist) { - pt = this._point.add(vector.normalize(maxDist)); - } else if (matchMaxDistance) { - return false; - } - } - } - if (needsChange && pt.equals(this._point)) - return false; - } - this._lastPoint = start && type == 'mousemove' ? pt : this._point; - this._point = pt; - switch (type) { - case 'mousedown': - this._lastPoint = this._downPoint; - this._downPoint = this._point; - this._downCount++; - break; - case 'mouseup': - this._lastPoint = this._downPoint; - break; - } - this._count = start ? 0 : this._count + 1; - return true; - }, - - onHandleEvent: function(type, pt, event) { - paper = this._scope; - var called = false; - switch (type) { - case 'mousedown': - this.updateEvent(type, pt, null, null, true, false, false); - if (this.onMouseDown) { - this.onMouseDown(new ToolEvent(this, type, event)); - called = true; - } - break; - case 'mousedrag': - var needsChange = false, - matchMaxDistance = false; - while (this.updateEvent(type, pt, this.minDistance, - this.maxDistance, false, needsChange, matchMaxDistance)) { - if (this.onMouseDrag) { - this.onMouseDrag(new ToolEvent(this, type, event)); - called = true; - } - needsChange = true; - matchMaxDistance = true; - } - break; - case 'mouseup': - if ((this._point.x != pt.x || this._point.y != pt.y) - && this.updateEvent('mousedrag', pt, this.minDistance, - this.maxDistance, false, false, false)) { - if (this.onMouseDrag) { - this.onMouseDrag(new ToolEvent(this, type, event)); - called = true; - } - } - this.updateEvent(type, pt, null, this.maxDistance, false, - false, false); - if (this.onMouseUp) { - this.onMouseUp(new ToolEvent(this, type, event)); - called = true; - } - this.updateEvent(type, pt, null, null, true, false, false); - this._firstMove = true; - break; - case 'mousemove': - while (this.updateEvent(type, pt, this.minDistance, - this.maxDistance, this._firstMove, true, false)) { - if (this.onMouseMove) { - this.onMouseMove(new ToolEvent(this, type, event)); - called = true; - } - this._firstMove = false; - } - break; - } - return called; - } -}); - -var CanvasProvider = { - canvases: [], - getCanvas: function(size) { - if (this.canvases.length) { - var canvas = this.canvases.pop(); - if ((canvas.width != size.width) - || (canvas.height != size.height)) { - canvas.width = size.width; - canvas.height = size.height; - } else { - canvas.getContext('2d').clearRect(0, 0, - size.width + 1, size.height + 1); - } - return canvas; - } else { - var canvas = document.createElement('canvas'); - canvas.width = size.width; - canvas.height = size.height; - return canvas; - } - }, - - returnCanvas: function(canvas) { - this.canvases.push(canvas); - } -}; - -var Numerical = new function() { - - var abscissas = [ - [ 0.5773502691896257645091488], - [0,0.7745966692414833770358531], - [ 0.3399810435848562648026658,0.8611363115940525752239465], - [0,0.5384693101056830910363144,0.9061798459386639927976269], - [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], - [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], - [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], - [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], - [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], - [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], - [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], - [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], - [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], - [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], - [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] - ]; - - var weights = [ - [1], - [0.8888888888888888888888889,0.5555555555555555555555556], - [0.6521451548625461426269361,0.3478548451374538573730639], - [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], - [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], - [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], - [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], - [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], - [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], - [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], - [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], - [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], - [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], - [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], - [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] - ]; - - var abs = Math.abs, - sqrt = Math.sqrt, - cos = Math.cos, - PI = Math.PI; - - return { - TOLERANCE: 10e-6, - EPSILON: 10e-12, - - integrate: function(f, a, b, n) { - var x = abscissas[n - 2], - w = weights[n - 2], - A = 0.5 * (b - a), - B = A + a, - i = 0, - m = (n + 1) >> 1, - sum = n & 1 ? w[i++] * f(B) : 0; - while (i < m) { - var Ax = A * x[i]; - sum += w[i++] * (f(B + Ax) + f(B - Ax)); - } - return A * sum; - }, - - findRoot: function(f, df, x, a, b, n, tolerance) { - for (var i = 0; i < n; i++) { - var fx = f(x), - dx = fx / df(x); - if (abs(dx) < tolerance) - return x; - var nx = x - dx; - if (fx > 0) { - b = x; - x = nx <= a ? 0.5 * (a + b) : nx; - } else { - a = x; - x = nx >= b ? 0.5 * (a + b) : nx; - } - } - }, - - solveQuadratic: function(a, b, c, roots, tolerance) { - if (abs(a) < tolerance) { - if (abs(b) >= tolerance) { - roots[0] = -c / b; - return 1; - } - if (abs(c) < tolerance) - return -1; - return 0; - } - var q = b * b - 4 * a * c; - if (q < 0) - return 0; - q = sqrt(q); - if (b < 0) - q = -q; - q = (b + q) * -0.5; - var n = 0; - if (abs(q) >= tolerance) - roots[n++] = c / q; - if (abs(a) >= tolerance) - roots[n++] = q / a; - return n; - }, - - solveCubic: function(a, b, c, d, roots, tolerance) { - if (abs(a) < tolerance) - return Numerical.solveQuadratic(b, c, d, roots, tolerance); - b /= a; - c /= a; - d /= a; - var Q = (b * b - 3 * c) / 9, - R = (2 * b * b * b - 9 * b * c + 27 * d) / 54, - Q3 = Q * Q * Q, - R2 = R * R; - b /= 3; - if (R2 < Q3) { - var theta = Math.acos(R / sqrt(Q3)), - q = -2 * sqrt(Q); - roots[0] = q * cos(theta / 3) - b; - roots[1] = q * cos((theta + 2 * PI) / 3) - b; - roots[2] = q * cos((theta - 2 * PI) / 3) - b; - return 3; - } else { - var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3); - if (R < 0) A = -A; - var B = (abs(A) < tolerance) ? 0 : Q / A; - roots[0] = (A + B) - b; - return 1; - } - return 0; - } - }; -}; - -var BlendMode = { - process: function(blendMode, srcContext, dstContext, alpha, offset) { - var srcCanvas = srcContext.canvas, - dstData = dstContext.getImageData(offset.x, offset.y, - srcCanvas.width, srcCanvas.height), - dst = dstData.data, - src = srcContext.getImageData(0, 0, - srcCanvas.width, srcCanvas.height).data, - min = Math.min, - max = Math.max, - abs = Math.abs, - sr, sg, sb, sa, - br, bg, bb, ba, - dr, dg, db; - - function getLum(r, g, b) { - return 0.2989 * r + 0.587 * g + 0.114 * b; - } - - function setLum(r, g, b, l) { - var d = l - getLum(r, g, b); - dr = r + d; - dg = g + d; - db = b + d; - var l = getLum(dr, dg, db), - mn = min(dr, dg, db), - mx = max(dr, dg, db); - if (mn < 0) { - var lmn = l - mn; - dr = l + (dr - l) * l / lmn; - dg = l + (dg - l) * l / lmn; - db = l + (db - l) * l / lmn; - } - if (mx > 255) { - var ln = 255 - l, mxl = mx - l; - dr = l + (dr - l) * ln / mxl; - dg = l + (dg - l) * ln / mxl; - db = l + (db - l) * ln / mxl; - } - } - - function getSat(r, g, b) { - return max(r, g, b) - min(r, g, b); - } - - function setSat(r, g, b, s) { - var col = [r, g, b], - mx = max(r, g, b), - mn = min(r, g, b), - md; - mn = mn == r ? 0 : mn == g ? 1 : 2; - mx = mx == r ? 0 : mx == g ? 1 : 2; - md = min(mn, mx) == 0 ? max(mn, mx) == 1 ? 2 : 1 : 0; - if (col[mx] > col[mn]) { - col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); - col[mx] = s; - } else { - col[md] = col[mx] = 0; - } - col[mn] = 0; - dr = col[0]; - dg = col[1]; - db = col[2]; - } - - var modes = { - multiply: function() { - dr = br * sr / 255; - dg = bg * sg / 255; - db = bb * sb / 255; - }, - - screen: function() { - dr = 255 - (255 - br) * (255 - sr) / 255; - dg = 255 - (255 - bg) * (255 - sg) / 255; - db = 255 - (255 - bb) * (255 - sb) / 255; - }, - - overlay: function() { - dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; - dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; - db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; - }, - - 'soft-light': function() { - var t = sr * br / 255; - dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; - t = sg * bg / 255; - dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; - t = sb * bb / 255; - db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; - }, - - 'hard-light': function() { - dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; - dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; - db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; - }, - - 'color-dodge': function() { - dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr)); - dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg)); - db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb)); - }, - - 'color-burn': function() { - dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0); - dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0); - db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0); - }, - - darken: function() { - dr = br < sr ? br : sr; - dg = bg < sg ? bg : sg; - db = bb < sb ? bb : sb; - }, - - lighten: function() { - dr = br > sr ? br : sr; - dg = bg > sg ? bg : sg; - db = bb > sb ? bb : sb; - }, - - difference: function() { - dr = br - sr; - if (dr < 0) - dr = -dr; - dg = bg - sg; - if (dg < 0) - dg = -dg; - db = bb - sb; - if (db < 0) - db = -db; - }, - - exclusion: function() { - dr = br + sr * (255 - br - br) / 255; - dg = bg + sg * (255 - bg - bg) / 255; - db = bb + sb * (255 - bb - bb) / 255; - }, - - hue: function() { - setSat(sr, sg, sb, getSat(br, bg, bb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - saturation: function() { - setSat(br, bg, bb, getSat(sr, sg, sb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - luminosity: function() { - setLum(br, bg, bb, getLum(sr, sg, sb)); - }, - - color: function() { - setLum(sr, sg, sb, getLum(br, bg, bb)); - }, - - add: function() { - dr = min(br + sr, 255); - dg = min(bg + sg, 255); - db = min(bb + sb, 255); - }, - - subtract: function() { - dr = max(br - sr, 0); - dg = max(bg - sg, 0); - db = max(bb - sb, 0); - }, - - average: function() { - dr = (br + sr) / 2; - dg = (bg + sg) / 2; - db = (bb + sb) / 2; - }, - - negation: function() { - dr = 255 - abs(255 - sr - br); - dg = 255 - abs(255 - sg - bg); - db = 255 - abs(255 - sb - bb); - } - }; - - var process = modes[blendMode]; - if (!process) - return; - - for (var i = 0, l = dst.length; i < l; i += 4) { - sr = src[i]; - br = dst[i]; - sg = src[i + 1]; - bg = dst[i + 1]; - sb = src[i + 2]; - bb = dst[i + 2]; - sa = src[i + 3]; - ba = dst[i + 3]; - process(); - var a1 = sa * alpha / 255, - a2 = 1 - a1; - dst[i] = a1 * dr + a2 * br; - dst[i + 1] = a1 * dg + a2 * bg; - dst[i + 2] = a1 * db + a2 * bb; - dst[i + 3] = sa * alpha + a2 * ba; - } - dstContext.putImageData(dstData, offset.x, offset.y); - } -}; - -var PaperScript = this.PaperScript = new function() { -var parse_js=new function(){function W(a,b,c){var d=[];for(var e=0;e0,g=j(function(){return h(a[0]?k(["case",z(a[0])+":"]):"default:")},.5)+(f?e+j(function(){return u(a[1]).join(e)}):"");!c&&f&&d0?h(a):a}).join(e)},block:w,"var":function(a){return"var "+l(W(a,x))+";"},"const":function(a){return"const "+l(W(a,x))+";"},"try":function(a,b,c){var d=["try",w(a)];b&&d.push("catch","("+b[0]+")",w(b[1])),c&&d.push("finally",w(c));return k(d)},"throw":function(a){return k(["throw",z(a)])+";"},"new":function(a,b){b=b.length>0?"("+l(W(b,z))+")":"";return k(["new",m(a,"seq","binary","conditional","assign",function(a){var b=N(),c={};try{b.with_walkers({call:function(){throw c},"function":function(){return this}},function(){b.walk(a)})}catch(d){if(d===c)return!0;throw d}})+b])},"switch":function(a,b){return k(["switch","("+z(a)+")",v(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+g(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+g(a));return b+";"},conditional:function(a,b,c){return k([m(a,"assign","seq","conditional"),"?",m(b,"seq"),":",m(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return k([z(b),a,m(c,"seq")])},dot:function(a){var b=z(a),c=1;a[0]=="num"?/\./.test(a[1])||(b+="."):o(a)&&(b="("+b+")");while(cB[b[1]])d="("+d+")";if(L(c[0],["assign","conditional","seq"])||c[0]=="binary"&&B[a]>=B[c[1]]&&(c[1]!=a||!L(a,["&&","||","*"])))e="("+e+")";return k([d,a,e])},"unary-prefix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-prefix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return a+(p(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-postfix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=z(a);o(a)&&(c="("+c+")");return c+"["+z(b)+"]"},object:function(a){return a.length==0?"{}":"{"+e+j(function(){return W(a,function(a){if(a.length==3)return h(t(a[0],a[1][2],a[1][3],a[2]));var d=a[0],e=z(a[1]);b.quote_keys?d=Q(d):(typeof d=="number"||!c&&+d+""==d)&&parseFloat(d)>=0?d=q(+d):V(d)||(d=Q(d));return h(k(c&&b.space_colon?[d,":",e]:[d+":",e]))}).join(","+e)})+e+h("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){return a.length==0?"[]":k(["[",l(W(a,function(a){return!c&&a[0]=="atom"&&a[1]=="undefined"?"":m(a,"seq")})),"]"])},stat:function(a){return z(a).replace(/;*\s*$/,";")},seq:function(){return l(W(J(arguments),z))},label:function(a,b){return k([g(a),":",z(b)])},"with":function(a,b){return k(["with","("+z(a)+")",z(b)])},atom:function(a){return g(a)}},y=[];return z(a)}function Q(a){var b=0,c=0;a=a.replace(/[\\\b\f\n\r\t\x22\x27]/g,function(a){switch(a){case"\\":return"\\\\";case"\b":return"\\b";case"\f":return"\\f";case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";case'"':++b;return'"';case"'":++c;return"'"}return a});return b>c?"'"+a.replace(/\x27/g,"\\'")+"'":'"'+a.replace(/\x22/g,'\\"')+'"'}function O(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function N(){function g(a,b){var c={},e;for(e in a)M(a,e)&&(c[e]=d[e],d[e]=a[e]);var f=b();for(e in c)M(c,e)&&(c[e]?d[e]=c[e]:delete d[e]);return f}function f(a){if(a==null)return null;try{e.push(a);var b=a[0],f=d[b];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=c[b];return f.apply(a,a.slice(1))}finally{e.pop()}}function b(a){var b=[this[0]];a!=null&&b.push(W(a,f));return b}function a(a){return[this[0],W(a,function(a){var b=[a[0]];a.length>1&&(b[1]=f(a[1]));return b})]}var c={string:function(a){return[this[0],a]},num:function(a){return[this[0],a]},name:function(a){return[this[0],a]},toplevel:function(a){return[this[0],W(a,f)]},block:b,splice:b,"var":a,"const":a,"try":function(a,b,c){return[this[0],W(a,f),b!=null?[b[0],W(b[1],f)]:null,c!=null?W(c,f):null]},"throw":function(a){return[this[0],f(a)]},"new":function(a,b){return[this[0],f(a),W(b,f)]},"switch":function(a,b){return[this[0],f(a),W(b,function(a){return[a[0]?f(a[0]):null,W(a[1],f)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],f(a),f(b),f(c)]},assign:function(a,b,c){return[this[0],a,f(b),f(c)]},dot:function(a){return[this[0],f(a)].concat(J(arguments,1))},call:function(a,b){return[this[0],f(a),W(b,f)]},"function":function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},defun:function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},"if":function(a,b,c){return[this[0],f(a),f(b),f(c)]},"for":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"for-in":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"while":function(a,b){return[this[0],f(a),f(b)]},"do":function(a,b){return[this[0],f(a),f(b)]},"return":function(a){return[this[0],f(a)]},binary:function(a,b,c){return[this[0],a,f(b),f(c)]},"unary-prefix":function(a,b){return[this[0],a,f(b)]},"unary-postfix":function(a,b){return[this[0],a,f(b)]},sub:function(a,b){return[this[0],f(a),f(b)]},object:function(a){return[this[0],W(a,function(a){return a.length==2?[a[0],f(a[1])]:[a[0],f(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],W(a,f)]},stat:function(a){return[this[0],f(a)]},seq:function(){return[this[0]].concat(W(J(arguments),f))},label:function(a,b){return[this[0],a,f(b)]},"with":function(a,b){return[this[0],f(a),f(b)]},atom:function(a){return[this[0],a]}},d={},e=[];return{walk:f,with_walkers:g,parent:function(){return e[e.length-2]},stack:function(){return e}}}function M(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function L(a,b){for(var c=b.length;--c>=0;)if(b[c]===a)return!0;return!1}function K(a){return a.split("")}function J(a,b){return Array.prototype.slice.call(a,b||0)}function I(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function G(a){var b=J(arguments,1);return function(){return a.apply(this,b.concat(J(arguments)))}}function F(a,b,c){function bk(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){var b=bg(a),c=d.token.value;if(e("operator")&&M(A,c)){if(bh(b)){g();return p("assign",A[c],b,bi(a))}i("Invalid assignment")}return b}function bh(a){if(!b)return!0;switch(a[0]){case"dot":case"sub":case"new":case"call":return!0;case"name":return a[1]!="this"}}function bg(a){var b=bf(a);if(e("operator","?")){g();var c=bj(!1);m(":");return p("conditional",b,c,bj(!1,a))}return b}function bf(a){return be(Y(!0),0,a)}function be(a,b,c){var f=e("operator")?d.token.value:null;f&&f=="in"&&c&&(f=null);var h=f!=null?B[f]:null;if(h!=null&&h>b){g();var i=be(Y(!0),h,c);return be(p("binary",f,a,i),b,c)}return a}function bd(a,b,c){(b=="++"||b=="--")&&!bh(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bc(a,b){if(e("punc",".")){g();return bc(p("dot",a,bb()),b)}if(e("punc","[")){g();return bc(p("sub",a,H(bj,G(m,"]"))),b)}if(b&&e("punc","(")){g();return bc(p("call",a,Z(")")),!0)}return b&&e("operator")&&M(z,d.token.value)?H(G(bd,"unary-postfix",d.token.value,a),g):a}function bb(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return H(d.token.value,g);default:k()}}function ba(){switch(d.token.type){case"num":case"string":return H(d.token.value,g)}return bb()}function _(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=ba();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bj(!1)])):c.push([bb(),P(!1),h])}g();return p("object",c)}function $(){return p("array",Z("]",!b,!0))}function Z(a,b,c){var d=!0,f=[];while(!e("punc",a)){d?d=!1:m(",");if(b&&e("punc",a))break;e("punc",",")&&c?f.push(["atom","undefined"]):f.push(bj(!1))}g();return f}function X(){var a=Y(!1),b;e("punc","(")?(g(),b=Z(")")):b=[];return bc(p("new",a,b),!0)}function W(){return p("const",U())}function V(a){return p("var",U(a))}function U(a){var b=[];for(;;){e("name")||k();var c=d.token.value;g(),e("operator","=")?(g(),b.push([c,bj(!1,a)])):b.push([c]);if(!e("punc",","))break;g()}return b}function T(){var a=R(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,R()]}e("keyword","finally")&&(g(),c=R()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function R(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(t());g();return a}function Q(){var a=q(),b=t(),c;e("keyword","else")&&(g(),c=t());return p("if",a,b,c)}function O(a){var b=a[0]=="var"?p("name",a[1][0]):a;g();var c=bj();m(")");return p("for-in",a,b,c,bk(t))}function N(a){m(";");var b=e("punc",";")?null:bj();m(";");var c=e("punc",")")?null:bj();m(")");return p("for",a,b,c,bk(t))}function K(){m("(");var a=null;if(!e("punc",";")){a=e("keyword","var")?(g(),V(!0)):bj(!0,!0);if(e("operator","in"))return O(a)}return N(a)}function I(a){var b;n()||(b=e("name")?d.token.value:null),b!=null?(g(),L(b,d.labels)||i("Label "+b+" without matching loop or statement")):d.in_loop==0&&i(a+" not inside a loop or switch"),o();return p(a,b)}function F(){return p("stat",H(bj,o))}function w(a){d.labels.push(a);var c=d.token,e=t();b&&!M(C,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function s(a){return c?function(){var b=d.token,c=a.apply(this,arguments);c[0]=r(c[0],b,h());return c}:a}function r(a,b,c){return a instanceof E?a:new E(a,b,c)}function q(){m("(");var a=bj();m(")");return a}function p(){return J(arguments)}function o(){e("punc",";")?g():n()||k()}function n(){return!b&&(d.token.nlb||e("eof")||e("punc","}"))}function m(a){return l("punc",a)}function l(a,b){if(e(a,b))return g();j(d.token,"Unexpected token "+d.token.type+", expected "+a)}function k(a){a==null&&(a=d.token),j(a,"Unexpected token: "+a.type+" ("+a.value+")")}function j(a,b){i(b,a.line,a.col)}function i(a,b,c,e){var f=d.input.context();u(a,b!=null?b:f.tokline,c!=null?c:f.tokcol,e!=null?e:f.tokpos)}function h(){return d.prev}function g(){d.prev=d.token,d.peeked?(d.token=d.peeked,d.peeked=null):d.token=d.input();return d.token}function f(){return d.peeked||(d.peeked=d.input())}function e(a,b){return v(d.token,a,b)}var d={input:typeof a=="string"?x(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var t=s(function(){e("operator","/")&&(d.peeked=null,d.token=d.input(!0));switch(d.token.type){case"num":case"string":case"regexp":case"operator":case"atom":return F();case"name":return v(f(),"punc",":")?w(H(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",R());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(H(d.token.value,g)){case"break":return I("break");case"continue":return I("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",H(q,o),a)}(bk(t));case"for":return K();case"function":return P(!0);case"if":return Q();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:H(bj,o));case"switch":return p("switch",q(),S());case"throw":return p("throw",H(bj,o));case"try":return T();case"var":return H(V,o);case"const":return H(W,o);case"while":return p("while",q(),bk(t));case"with":return p("with",q(),t());default:k()}}}),P=s(function(a){var b=e("name")?H(d.token.value,g):null;a&&!b&&k(),m("(");return p(a?"defun":"function",b,function(a,b){while(!e("punc",")"))a?a=!1:m(","),e("name")||k(),b.push(d.token.value),g();g();return b}(!0,[]),function(){++d.in_function;var a=d.in_loop;d.in_loop=0;var b=R();--d.in_function,d.in_loop=a;return b}())}),S=G(bk,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bj(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(t()));g();return a}),Y=s(function(a){if(e("operator","new")){g();return X()}if(e("operator")&&M(y,d.token.value))return bd("unary-prefix",H(d.token.value,g),Y(a));if(e("punc")){switch(d.token.value){case"(":g();return bc(H(bj,G(m,")")),a);case"[":g();return bc($(),a);case"{":g();return bc(_(),a)}k()}if(e("keyword","function")){g();return bc(P(!1),a)}if(M(D,d.token.type)){var b=d.token.type=="regexp"?p("regexp",d.token.value[0],d.token.value[1]):p(d.token.type,d.token.value);return bc(H(b,g),a)}k()}),bj=s(function(a,b){arguments.length==0&&(a=!0);var c=bi(b);if(a&&e("punc",",")){g();return p("seq",c,bj(!0,b))}return c});return p("toplevel",function(a){while(!e("eof"))a.push(t());return a}([]))}function E(a,b,c){this.name=a,this.start=b,this.end=c}function x(b){function P(a){if(a)return I();y(),v();var b=g();if(!b)return x("eof");if(o(b))return C();if(b=='"'||b=="'")return F();if(M(l,b))return x("punc",h());if(b==".")return L();if(b=="/")return K();if(M(e,b))return J();if(b=="\\"||q(b))return N();B("Unexpected character '"+b+"'")}function O(a,b){try{return b()}catch(c){if(c===w)B(a);else throw c}}function N(){var b=A(r);return M(a,b)?M(i,b)?x("operator",b):M(d,b)?x("atom",b):x("keyword",b):x("name",b)}function L(){h();return o(g())?C("."):x("punc",".")}function K(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(G()),f.regex_allowed=a;return P();case"*":f.comments_before.push(H()),f.regex_allowed=a;return P()}return f.regex_allowed?I():J("/")}function J(a){function b(a){if(!g())return a;var c=a+g();if(M(i,c)){h();return b(c)}return a}return x("operator",b(a||h()))}function I(){return O("Unterminated regular expression",function(){var a=!1,b="",c,d=!1;while(c=h(!0))if(a)b+="\\"+c,a=!1;else if(c=="[")d=!0,b+=c;else if(c=="]"&&d)d=!1,b+=c;else{if(c=="/"&&!d)break;c=="\\"?a=!0:b+=c}var e=A(function(a){return M(m,a)});return x("regexp",[b,e])})}function H(){h();return O("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=x("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function G(){h();var a=t("\n"),b;a==-1?(b=f.text.substr(f.pos),f.pos=f.text.length):(b=f.text.substring(f.pos,a),f.pos=a);return x("comment1",b,!0)}function F(){return O("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=D();else if(c==a)break;b+=c}return x("string",b)})}function E(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&B("Invalid hex-character pattern in string"),b=b<<4|c}return b}function D(){var a=h(!0);switch(a){case"n":return"\n";case"r":return"\r";case"t":return"\t";case"b":return"\b";case"v":return" ";case"f":return"\f";case"0":return"";case"x":return String.fromCharCode(E(2));case"u":return String.fromCharCode(E(4));case"\n":return"";default:return a}}function C(a){var b=!1,c=!1,d=!1,e=a==".",f=A(function(f,g){if(f=="x"||f=="X")return d?!1:d=!0;if(!d&&(f=="E"||f=="e"))return b?!1:b=c=!0;if(f=="-")return c||g==0&&!a?!0:!1;if(f=="+")return c;c=!1;if(f==".")return!e&&!d?e=!0:!1;return p(f)});a&&(f=a+f);var g=s(f);if(!isNaN(g))return x("num",g);B("Invalid syntax: "+f)}function B(a){u(a,f.tokline,f.tokcol,f.tokpos)}function A(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(M(j,g()))h()}function x(a,b,d){f.regex_allowed=a=="operator"&&!M(z,b)||a=="keyword"&&M(c,b)||a=="punc"&&M(k,b);var e={type:a,value:b,line:f.tokline,col:f.tokcol,pos:f.tokpos,nlb:f.newline_before};d||(e.comments_before=f.comments_before,f.comments_before=[]),f.newline_before=!1;return e}function v(){f.tokline=f.line,f.tokcol=f.col,f.tokpos=f.pos}function t(a,b){var c=f.text.indexOf(a,f.pos);if(b&&c==-1)throw w;return c}function n(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw w;b=="\n"?(f.newline_before=!0,++f.line,f.col=0):++f.col;return b}function g(){return f.text.charAt(f.pos)}var f={text:b.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,""),pos:0,tokpos:0,line:0,tokline:0,col:0,tokcol:0,newline_before:!1,regex_allowed:!1,comments_before:[]};P.context=function(a){a&&(f=a);return f};return P}function v(a,b,c){return a.type==b&&(c==null||a.value==c)}function u(a,b,c,d){throw new t(a,b,c,d)}function t(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d}function s(a){if(f.test(a))return parseInt(a.substr(2),16);if(g.test(a))return parseInt(a.substr(1),8);if(h.test(a))return parseFloat(a)}function r(a){return q(a)||o(a)}function q(a){return a=="$"||a=="_"||n(a)}function p(a){return o(a)||n(a)}function o(a){a=a.charCodeAt(0);return a>=48&&a<=57}function n(a){a=a.charCodeAt(0);return a>=65&&a<=90||a>=97&&a<=122}var a=I(["break","case","catch","const","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","throw","try","typeof","var","void","while","with"]),b=I(["abstract","boolean","byte","char","class","debugger","double","enum","export","extends","final","float","goto","implements","import","int","interface","long","native","package","private","protected","public","short","static","super","synchronized","throws","transient","volatile"]),c=I(["return","new","delete","throw","else","case"]),d=I(["false","null","true","undefined"]),e=I(K("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=I(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","|=","^=","&=","&&","||"]),j=I(K(" \n\r\t")),k=I(K("[{}(,.;:")),l=I(K("[]{}(),;:")),m=I(K("gmsiy"));t.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"};var w={},y=I(["typeof","void","delete","--","++","!","~","-","+"]),z=I(["--","++"]),A=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),B=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),C=I(["for","do","while","switch"]),D=I(["atom","num","string","regexp","name"]);E.prototype.toString=function(){return this.name};var P=I(["name","array","object","string","dot","sub","call","regexp"]),R=I(["if","while","do","for","for-in","with"]);return{parse:F,gen_code:S,tokenizer:x,ast_walker:N}} - - // Math Operators - - var operators = { - '+': 'add', - '-': 'subtract', - '*': 'multiply', - '/': 'divide', - '%': 'modulo', - '==': 'equals', - '!=': 'equals' - }; - - function $eval(left, operator, right) { - var handler = operators[operator]; - if (left && left[handler]) { - var res = left[handler](right); - return operator == '!=' ? !res : res; - } - switch (operator) { - case '+': return left + right; - case '-': return left - right; - case '*': return left * right; - case '/': return left / right; - case '%': return left % right; - case '==': return left == right; - case '!=': return left != right; - default: - throw new Error('Implement Operator: ' + operator); - } - }; - - // Sign Operators - - var signOperators = { - '-': 'negate' - }; - - function $sign(operator, value) { - var handler = signOperators[operator]; - if (value && value[handler]) { - return value[handler](); - } - switch (operator) { - case '+': return +value; - case '-': return -value; - default: - throw new Error('Implement Sign Operator: ' + operator); - } - } - - // AST Helpers - - function isDynamic(exp) { - var type = exp[0]; - return type != 'num' && type != 'string'; - } - - function handleOperator(operator, left, right) { - // Only replace operators with calls to $operator if the left hand side - // is potentially an object. - if (operators[operator] && isDynamic(left)) { - // Replace with call to $operator(left, operator, right): - return ['call', ['name', '$eval'], - [left, ['string', operator], right]]; - } - } - - /** - * Compiles PaperScript code into JavaScript code. - * - * @name PaperScript.compile - * @function - * @param {String} code The PaperScript code. - * @return {String} The compiled PaperScript as JavaScript code. - */ - function compile(code) { - // Use parse-js to translate the code into a AST structure which is then - // walked and parsed for operators to overload. The resulting AST is - // translated back to code and evaluated. - var ast = parse_js.parse(code), - walker = parse_js.ast_walker(), - walk = walker.walk; - - ast = walker.with_walkers({ - 'binary': function(operator, left, right) { - // Handle simple mathematical operators here: - return handleOperator(operator, left = walk(left), - right = walk(right)) - // Always return something since we're walking left and - || [this[0], operator, left, right]; - }, - - 'assign': function(operator, left, right) { - var res = handleOperator(operator, left = walk(left), - right = walk(right)); - if (res) - return [this[0], true, left, res]; - return [this[0], operator, left, right]; - }, - - 'unary-prefix': function(operator, exp) { - if (signOperators[operator] && isDynamic(exp)) { - return ['call', ['name', '$sign'], - [['string', operator], walk(exp)]]; - } - } - }, function() { - return walk(ast); - }); - - return parse_js.gen_code(ast, { - beautify: true - }); - } - - function evaluate(code, scope) { - paper = scope; - var view = scope.view, - tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) - && new Tool(), - res; - with (scope) { - (function() { - var onEditOptions, onSelect, onDeselect, onReselect, onMouseDown, - onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp, - onFrame, onResize, - handlers = [ 'onEditOptions', 'onSelect', 'onDeselect', - 'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag', - 'onMouseMove', 'onKeyDown', 'onKeyUp']; - res = eval(compile(code)); - if (tool) { - Base.each(handlers, function(key) { - tool[key] = eval(key); - }); - } - if (view) { - view.onResize = onResize; - view.setOnFrame(onFrame); - view.draw(); - } - }).call(scope); - } - return res; - } - - function request(url, scope) { - var xhr = new (window.ActiveXObject || XMLHttpRequest)( - 'Microsoft.XMLHTTP'); - xhr.open('GET', url, true); - if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain'); - } - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - return evaluate(xhr.responseText, scope); - } - }; - return xhr.send(null); - } - - function load() { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, l = scripts.length; i < l; i++) { - var script = scripts[i]; - if (/^text\/(?:x-|)paperscript$/.test(script.type) - && !script.getAttribute('data-paper-loaded')) { - var scope = new PaperScope(script); - scope.setup(PaperScript.getAttribute(script, 'canvas')); - if (script.src) { - request(script.src, scope); - } else { - evaluate(script.innerHTML, scope); - } - script.setAttribute('data-paper-loaded', true); - } - } - } - - DomEvent.add(window, { load: load }); - - function handleAttribute(name) { - name += 'Attribute'; - return function(el, attr) { - return el[name](attr) || el[name]('data-paper-' + attr); - }; - } - - return { - compile: compile, - evaluate: evaluate, - load: load, - getAttribute: handleAttribute('get'), - hasAttribute: handleAttribute('has') - }; - -}; - -this.load = PaperScript.load; - -Base.each(this, function(val, key) { - if (val && val.prototype instanceof Base) { - val._name = key; - } -}); - -this.enumerable = true; -return new (PaperScope.inject(this)); -}; \ No newline at end of file diff --git a/dist/paper.js b/dist/paper.js index e459b4a4..e69de29b 100644 --- a/dist/paper.js +++ b/dist/paper.js @@ -1,8237 +0,0 @@ -/*! - * Paper.js v0.22 - * - * This file is part of Paper.js, a JavaScript Vector Graphics Library, - * based on Scriptographer.org and designed to be largely API compatible. - * http://paperjs.org/ - * http://scriptographer.org/ - * - * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey - * http://lehni.org/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - * - * Date: Wed Apr 25 20:47:53 2012 +0200 - * - *** - * - * Bootstrap.js JavaScript Framework. - * http://bootstrapjs.org/ - * - * Copyright (c) 2006 - 2011 Juerg Lehni - * http://lehni.org/ - * - * Distributed under the MIT license. - * - *** - * - * Parse-js - * - * A JavaScript tokenizer / parser / generator, originally written in Lisp. - * Copyright (c) Marijn Haverbeke - * http://marijn.haverbeke.nl/parse-js/ - * - * Ported by to JavaScript by Mihai Bazon - * Copyright (c) 2010, Mihai Bazon - * http://mihai.bazon.net/blog/ - * - * Modifications and adaptions to browser (c) 2011, Juerg Lehni - * http://lehni.org/ - * - * Distributed under the BSD license. - */ - -var paper = new function() { - -var Base = new function() { - var fix = !this.__proto__, - hidden = /^(statics|generics|preserve|enumerable|prototype|__proto__|toString|valueOf)$/, - proto = Object.prototype, - has = fix - ? function(name) { - return name !== '__proto__' && this.hasOwnProperty(name); - } - : proto.hasOwnProperty, - toString = proto.toString, - proto = Array.prototype, - isArray = Array.isArray = Array.isArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }, - slice = proto.slice, - forEach = proto.forEach || function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - iter.call(bind, this[i], i, this); - }, - forIn = function(iter, bind) { - for (var i in this) - if (this.hasOwnProperty(i)) - iter.call(bind, this[i], i, this); - }, - _define = Object.defineProperty, - _describe = Object.getOwnPropertyDescriptor; - - function define(obj, name, desc) { - if (_define) { - try { - delete obj[name]; - return _define(obj, name, desc); - } catch (e) {} - } - if ((desc.get || desc.set) && obj.__defineGetter__) { - desc.get && obj.__defineGetter__(name, desc.get); - desc.set && obj.__defineSetter__(name, desc.set); - } else { - obj[name] = desc.value; - } - return obj; - } - - function describe(obj, name) { - if (_describe) { - try { - return _describe(obj, name); - } catch (e) {} - } - var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); - return get - ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, - configurable: true } - : has.call(obj, name) - ? { value: obj[name], enumerable: true, configurable: true, - writable: true } - : null; - } - - function inject(dest, src, enumerable, base, preserve, generics) { - var beans, bean; - - function field(name, val, dontCheck, generics) { - var val = val || (val = describe(src, name)) - && (val.get ? val : val.value), - func = typeof val === 'function', - res = val, - prev = preserve || func - ? (val && val.get ? name in dest : dest[name]) : null; - if (generics && func && (!preserve || !generics[name])) { - generics[name] = function(bind) { - return bind && dest[name].apply(bind, - slice.call(arguments, 1)); - } - } - if ((dontCheck || val !== undefined && has.call(src, name)) - && (!preserve || !prev)) { - if (func) { - if (prev && /\bthis\.base\b/.test(val)) { - var fromBase = base && base[name] == prev; - res = function() { - var tmp = describe(this, 'base'); - define(this, 'base', { value: fromBase - ? base[name] : prev, configurable: true }); - try { - return val.apply(this, arguments); - } finally { - tmp ? define(this, 'base', tmp) - : delete this.base; - } - }; - res.toString = function() { - return val.toString(); - } - res.valueOf = function() { - return val.valueOf(); - } - } - if (beans && val.length == 0 - && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) - beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); - } - if (!res || func || !res.get) - res = { value: res, writable: true }; - if ((describe(dest, name) - || { configurable: true }).configurable) { - res.configurable = true; - res.enumerable = enumerable; - } - define(dest, name, res); - } - } - if (src) { - beans = []; - for (var name in src) - if (has.call(src, name) && !hidden.test(name)) - field(name, null, true, generics); - field('toString'); - field('valueOf'); - for (var i = 0, l = beans && beans.length; i < l; i++) - try { - var bean = beans[i], part = bean[1]; - field(bean[0], { - get: dest['get' + part] || dest['is' + part], - set: dest['set' + part] - }, true); - } catch (e) {} - } - return dest; - } - - function extend(obj) { - var ctor = function(dont) { - if (fix) define(this, '__proto__', { value: obj }); - if (this.initialize && dont !== ctor.dont) - return this.initialize.apply(this, arguments); - } - ctor.prototype = obj; - ctor.toString = function() { - return (this.prototype.initialize || function() {}).toString(); - } - return ctor; - } - - function iterator(iter) { - return !iter - ? function(val) { return val } - : typeof iter !== 'function' - ? function(val) { return val == iter } - : iter; - } - - function each(obj, iter, bind, asArray) { - try { - if (obj) - (asArray || asArray === undefined && isArray(obj) - ? forEach : forIn).call(obj, iterator(iter), - bind = bind || obj); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - } - - function clone(obj) { - return each(obj, function(val, i) { - this[i] = val; - }, new obj.constructor()); - } - - return inject(function() {}, { - inject: function(src) { - if (src) { - var proto = this.prototype, - base = proto.__proto__ && proto.__proto__.constructor, - statics = src.statics == true ? src : src.statics; - if (statics != src) - inject(proto, src, src.enumerable, base && base.prototype, - src.preserve, src.generics && this); - inject(this, statics, true, base, src.preserve); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src) { - var proto = new this(this.dont), - ctor = extend(proto); - define(proto, 'constructor', - { value: ctor, writable: true, configurable: true }); - ctor.dont = {}; - inject(ctor, this, true); - return arguments.length ? this.inject.apply(ctor, arguments) : ctor; - } - }, true).inject({ - has: has, - each: each, - - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) - inject(this, arguments[i]); - return this; - }, - - extend: function() { - var res = new (extend(this)); - return res.inject.apply(res, arguments); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - clone: function() { - return clone(this); - }, - - statics: { - each: each, - clone: clone, - define: define, - describe: describe, - iterator: iterator, - - has: function(obj, name) { - return has.call(obj, name); - }, - - type: function(obj) { - return (obj || obj === 0) && (obj._type || typeof obj) || null; - }, - - check: function(obj) { - return !!(obj || obj === 0); - }, - - pick: function() { - for (var i = 0, l = arguments.length; i < l; i++) - if (arguments[i] !== undefined) - return arguments[i]; - return null; - }, - - stop: {} - } - }); -} - -this.Base = Base.inject({ - generics: true, - - clone: function() { - return new this.constructor(this); - }, - - toString: function() { - return '{ ' + Base.each(this, function(value, key) { - if (key.charAt(0) != '_') { - var type = typeof value; - this.push(key + ': ' + (type === 'number' - ? Base.formatNumber(value) - : type === 'string' ? "'" + value + "'" : value)); - } - }, []).join(', ') + ' }'; - }, - - statics: { - read: function(list, start, length) { - var start = start || 0, - length = length || list.length - start; - var obj = list[start]; - if (obj instanceof this - || this.prototype._readNull && obj == null && length <= 1) - return obj; - obj = new this(this.dont); - return obj.initialize.apply(obj, start > 0 || length < list.length - ? Array.prototype.slice.call(list, start, start + length) - : list) || obj; - }, - - readAll: function(list, start) { - var res = [], entry; - for (var i = start || 0, l = list.length; i < l; i++) { - res.push(Array.isArray(entry = list[i]) - ? this.read(entry, 0) - : this.read(list, i, 1)); - } - return res; - }, - - splice: function(list, items, index, remove) { - var amount = items && items.length, - append = index === undefined; - index = append ? list.length : index; - for (var i = 0; i < amount; i++) - items[i]._index = index + i; - if (append) { - list.push.apply(list, items); - return []; - } else { - var args = [index, remove]; - if (items) - args.push.apply(args, items); - var removed = list.splice.apply(list, args); - for (var i = 0, l = removed.length; i < l; i++) - delete removed[i]._index; - for (var i = index + amount, l = list.length; i < l; i++) - list[i]._index = i; - return removed; - } - }, - - merge: function() { - return Base.each(arguments, function(hash) { - Base.each(hash, function(value, key) { - this[key] = value; - }, this); - }, new Base(), true); - }, - - capitalize: function(str) { - return str.replace(/\b[a-z]/g, function(match) { - return match.toUpperCase(); - }); - }, - - camelize: function(str) { - return str.replace(/-(\w)/g, function(all, chr) { - return chr.toUpperCase(); - }); - }, - - hyphenate: function(str) { - return str.replace(/[a-z][A-Z0-9]|[0-9][a-zA-Z]|[A-Z]{2}[a-z]/g, - function(match) { - return match.charAt(0) + '-' + match.substring(1); - } - ).toLowerCase(); - }, - - formatNumber: function(num) { - return (Math.round(num * 100000) / 100000).toString(); - } - } -}); - -var PaperScope = this.PaperScope = Base.extend({ - - initialize: function(script) { - paper = this; - this.project = null; - this.projects = []; - this.tools = []; - this._id = script && (script.getAttribute('id') || script.src) - || ('paperscope-' + (PaperScope._id++)); - if (script) - script.setAttribute('id', this._id); - PaperScope._scopes[this._id] = this; - }, - - version: 0.22, - - getView: function() { - return this.project.view; - }, - - getTool: function() { - if (!this._tool) - this._tool = new Tool(); - return this._tool; - }, - - evaluate: function(code) { - var res = PaperScript.evaluate(code, this); - View.updateFocus(); - return res; - }, - - install: function(scope) { - var that = this; - Base.each(['project', 'view', 'tool'], function(key) { - Base.define(scope, key, { - configurable: true, - writable: true, - get: function() { - return that[key]; - } - }); - }); - for (var key in this) { - if (!/^(version|_id|load)/.test(key) && !(key in scope)) - scope[key] = this[key]; - } - }, - - setup: function(canvas) { - paper = this; - this.project = new Project(canvas); - }, - - clear: function() { - for (var i = this.projects.length - 1; i >= 0; i--) - this.projects[i].remove(); - for (var i = this.tools.length - 1; i >= 0; i--) - this.tools[i].remove(); - }, - - remove: function() { - this.clear(); - delete PaperScope._scopes[this._id]; - }, - - statics: { - _scopes: {}, - _id: 0, - - get: function(id) { - if (typeof id === 'object') - id = id.getAttribute('id'); - return this._scopes[id] || null; - } - } -}); - -var PaperScopeItem = Base.extend({ - - initialize: function(activate) { - this._scope = paper; - this._index = this._scope[this._list].push(this) - 1; - if (activate || !this._scope[this._reference]) - this.activate(); - }, - - activate: function() { - if (!this._scope) - return false; - this._scope[this._reference] = this; - return true; - }, - - remove: function() { - if (this._index == null) - return false; - Base.splice(this._scope[this._list], null, this._index, 1); - if (this._scope[this._reference] == this) - this._scope[this._reference] = null; - this._scope = null; - return true; - } -}); - -var Callback = { - attach: function(type, func) { - if (typeof type !== 'string') { - return Base.each(type, function(value, key) { - this.attach(key, value); - }, this); - } - var entry = this._eventTypes[type]; - if (!entry) - return this; - var handlers = this._handlers = this._handlers || {}; - handlers = handlers[type] = handlers[type] || []; - if (handlers.indexOf(func) == -1) { - handlers.push(func); - if (entry.install && handlers.length == 1) - entry.install.call(this, type); - } - return this; - }, - - detach: function(type, func) { - if (typeof type !== 'string') { - return Base.each(type, function(value, key) { - this.detach(key, value); - }, this); - } - var entry = this._eventTypes[type], - handlers = this._handlers && this._handlers[type], - index; - if (entry && handlers) { - if (!func || (index = handlers.indexOf(func)) != -1 - && handlers.length == 1) { - if (entry.uninstall) - entry.uninstall.call(this, type); - delete this._handlers[type]; - } else if (index != -1) { - handlers.splice(index, 1); - } - } - return this; - }, - - fire: function(type, event) { - var handlers = this._handlers && this._handlers[type]; - if (!handlers) - return false; - Base.each(handlers, function(func) { - if (func.call(this, event) === false && event && event.stop) - event.stop(); - }, this); - return true; - }, - - responds: function(type) { - return !!(this._handlers && this._handlers[type]); - }, - - statics: { - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) { - var src = arguments[i], - events = src._events; - if (events) { - var types = {}; - Base.each(events, function(entry, key) { - var isString = typeof entry === 'string', - name = isString ? entry : key, - part = Base.capitalize(name), - type = name.substring(2).toLowerCase(); - types[type] = isString ? {} : entry; - name = '_' + name; - src['get' + part] = function() { - return this[name]; - }; - src['set' + part] = function(func) { - if (func) { - this.attach(type, func); - } else if (this[name]) { - this.detach(type, this[name]); - } - this[name] = func; - }; - }); - src._eventTypes = types; - } - this.base(src); - } - return this; - } - } -}; - -var Point = this.Point = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 !== undefined) { - this.x = arg0; - this.y = arg1; - } else if (arg0 !== undefined) { - if (arg0 == null) { - this.x = this.y = 0; - } else if (arg0.x !== undefined) { - this.x = arg0.x; - this.y = arg0.y; - } else if (arg0.width !== undefined) { - this.x = arg0.width; - this.y = arg0.height; - } else if (Array.isArray(arg0)) { - this.x = arg0[0]; - this.y = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (arg0.angle !== undefined) { - this.x = arg0.length; - this.y = 0; - this.setAngle(arg0.angle); - } else if (typeof arg0 === 'number') { - this.x = this.y = arg0; - } else { - this.x = this.y = 0; - } - } else { - this.x = this.y = 0; - } - }, - - set: function(x, y) { - this.x = x; - this.y = y; - return this; - }, - - clone: function() { - return Point.create(this.x, this.y); - }, - - toString: function() { - var format = Base.formatNumber; - return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }'; - }, - - add: function(point) { - point = Point.read(arguments); - return Point.create(this.x + point.x, this.y + point.y); - }, - - subtract: function(point) { - point = Point.read(arguments); - return Point.create(this.x - point.x, this.y - point.y); - }, - - multiply: function(point) { - point = Point.read(arguments); - return Point.create(this.x * point.x, this.y * point.y); - }, - - divide: function(point) { - point = Point.read(arguments); - return Point.create(this.x / point.x, this.y / point.y); - }, - - modulo: function(point) { - point = Point.read(arguments); - return Point.create(this.x % point.x, this.y % point.y); - }, - - negate: function() { - return Point.create(-this.x, -this.y); - }, - - transform: function(matrix) { - return matrix ? matrix._transformPoint(this) : this; - }, - - getDistance: function(point, squared) { - point = Point.read(arguments); - var x = point.x - this.x, - y = point.y - this.y, - d = x * x + y * y; - return squared ? d : Math.sqrt(d); - }, - - getLength: function() { - var l = this.x * this.x + this.y * this.y; - return arguments[0] ? l : Math.sqrt(l); - }, - - setLength: function(length) { - if (this.isZero()) { - var angle = this._angle || 0; - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } else { - var scale = length / this.getLength(); - if (scale == 0) - this.getAngle(); - this.set( - this.x * scale, - this.y * scale - ); - } - return this; - }, - - normalize: function(length) { - if (length === undefined) - length = 1; - var current = this.getLength(), - scale = current != 0 ? length / current : 0, - point = Point.create(this.x * scale, this.y * scale); - point._angle = this._angle; - return point; - }, - - getAngle: function() { - return this.getAngleInRadians(arguments[0]) * 180 / Math.PI; - }, - - setAngle: function(angle) { - angle = this._angle = angle * Math.PI / 180; - if (!this.isZero()) { - var length = this.getLength(); - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } - return this; - }, - - getAngleInRadians: function() { - if (arguments[0] === undefined) { - if (this._angle == null) - this._angle = Math.atan2(this.y, this.x); - return this._angle; - } else { - var point = Point.read(arguments), - div = this.getLength() * point.getLength(); - if (div == 0) { - return NaN; - } else { - return Math.acos(this.dot(point) / div); - } - } - }, - - getAngleInDegrees: function() { - return this.getAngle(arguments[0]); - }, - - getQuadrant: function() { - return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; - }, - - getDirectedAngle: function(point) { - point = Point.read(arguments); - return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; - }, - - rotate: function(angle, center) { - angle = angle * Math.PI / 180; - var point = center ? this.subtract(center) : this, - s = Math.sin(angle), - c = Math.cos(angle); - point = Point.create( - point.x * c - point.y * s, - point.y * c + point.x * s - ); - return center ? point.add(center) : point; - }, - - equals: function(point) { - point = Point.read(arguments); - return this.x == point.x && this.y == point.y; - }, - - isInside: function(rect) { - return rect.contains(this); - }, - - isClose: function(point, tolerance) { - return this.getDistance(point) < tolerance; - }, - - isColinear: function(point) { - return this.cross(point) < Numerical.TOLERANCE; - }, - - isOrthogonal: function(point) { - return this.dot(point) < Numerical.TOLERANCE; - }, - - isZero: function() { - return this.x == 0 && this.y == 0; - }, - - isNaN: function() { - return isNaN(this.x) || isNaN(this.y); - }, - - dot: function(point) { - point = Point.read(arguments); - return this.x * point.x + this.y * point.y; - }, - - cross: function(point) { - point = Point.read(arguments); - return this.x * point.y - this.y * point.x; - }, - - project: function(point) { - point = Point.read(arguments); - if (point.isZero()) { - return Point.create(0, 0); - } else { - var scale = this.dot(point) / point.dot(point); - return Point.create( - point.x * scale, - point.y * scale - ); - } - }, - - statics: { - create: function(x, y) { - var point = new Point(Point.dont); - point.x = x; - point.y = y; - return point; - }, - - min: function(point1, point2) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - return Point.create( - Math.min(point1.x, point2.x), - Math.min(point1.y, point2.y) - ); - }, - - max: function(point1, point2) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - return Point.create( - Math.max(point1.x, point2.x), - Math.max(point1.y, point2.y) - ); - }, - - random: function() { - return Point.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Point.create(op(this.x), op(this.y)); - }; - }, {}); -}); - -var LinkedPoint = Point.extend({ - set: function(x, y, dontNotify) { - this._x = x; - this._y = y; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner[this._setter](this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, x, y, dontLink) { - if (dontLink) - return Point.create(x, y); - var point = new LinkedPoint(LinkedPoint.dont); - point._x = x; - point._y = y; - point._owner = owner; - point._setter = setter; - return point; - } - } -}); - -var Size = this.Size = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 !== undefined) { - this.width = arg0; - this.height = arg1; - } else if (arg0 !== undefined) { - if (arg0 == null) { - this.width = this.height = 0; - } else if (arg0.width !== undefined) { - this.width = arg0.width; - this.height = arg0.height; - } else if (arg0.x !== undefined) { - this.width = arg0.x; - this.height = arg0.y; - } else if (Array.isArray(arg0)) { - this.width = arg0[0]; - this.height = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (typeof arg0 === 'number') { - this.width = this.height = arg0; - } else { - this.width = this.height = 0; - } - } else { - this.width = this.height = 0; - } - }, - - toString: function() { - var format = Base.formatNumber; - return '{ width: ' + format(this.width) - + ', height: ' + format(this.height) + ' }'; - }, - - set: function(width, height) { - this.width = width; - this.height = height; - return this; - }, - - clone: function() { - return Size.create(this.width, this.height); - }, - - add: function(size) { - size = Size.read(arguments); - return Size.create(this.width + size.width, this.height + size.height); - }, - - subtract: function(size) { - size = Size.read(arguments); - return Size.create(this.width - size.width, this.height - size.height); - }, - - multiply: function(size) { - size = Size.read(arguments); - return Size.create(this.width * size.width, this.height * size.height); - }, - - divide: function(size) { - size = Size.read(arguments); - return Size.create(this.width / size.width, this.height / size.height); - }, - - modulo: function(size) { - size = Size.read(arguments); - return Size.create(this.width % size.width, this.height % size.height); - }, - - negate: function() { - return Size.create(-this.width, -this.height); - }, - - equals: function(size) { - size = Size.read(arguments); - return this.width == size.width && this.height == size.height; - }, - - isZero: function() { - return this.width == 0 && this.height == 0; - }, - - isNaN: function() { - return isNaN(this.width) || isNaN(this.height); - }, - - statics: { - create: function(width, height) { - return new Size(Size.dont).set(width, height); - }, - - min: function(size1, size2) { - return Size.create( - Math.min(size1.width, size2.width), - Math.min(size1.height, size2.height)); - }, - - max: function(size1, size2) { - return Size.create( - Math.max(size1.width, size2.width), - Math.max(size1.height, size2.height)); - }, - - random: function() { - return Size.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Size.create(op(this.width), op(this.height)); - }; - }, {}); -}); - -var LinkedSize = Size.extend({ - set: function(width, height, dontNotify) { - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getWidth: function() { - return this._width; - }, - - setWidth: function(width) { - this._width = width; - this._owner[this._setter](this); - }, - - getHeight: function() { - return this._height; - }, - - setHeight: function(height) { - this._height = height; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, width, height, dontLink) { - if (dontLink) - return Size.create(width, height); - var size = new LinkedSize(LinkedSize.dont); - size._width = width; - size._height = height; - size._owner = owner; - size._setter = setter; - return size; - } - } -}); - -var Rectangle = this.Rectangle = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3) { - if (arguments.length == 4) { - this.x = arg0; - this.y = arg1; - this.width = arg2; - this.height = arg3; - } else if (arguments.length == 2) { - if (arg1 && arg1.x !== undefined) { - var point1 = Point.read(arguments, 0, 1); - var point2 = Point.read(arguments, 1, 1); - this.x = point1.x; - this.y = point1.y; - this.width = point2.x - point1.x; - this.height = point2.y - point1.y; - if (this.width < 0) { - this.x = point2.x; - this.width = -this.width; - } - if (this.height < 0) { - this.y = point2.y; - this.height = -this.height; - } - } else { - var point = Point.read(arguments, 0, 1); - var size = Size.read(arguments, 1, 1); - this.x = point.x; - this.y = point.y; - this.width = size.width; - this.height = size.height; - } - } else if (arg0) { - this.x = arg0.x || 0; - this.y = arg0.y || 0; - this.width = arg0.width || 0; - this.height = arg0.height || 0; - } else { - this.x = this.y = this.width = this.height = 0; - } - }, - - set: function(x, y, width, height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - return this; - }, - - getPoint: function() { - return LinkedPoint.create(this, 'setPoint', this.x, this.y, - arguments[0]); - }, - - setPoint: function(point) { - point = Point.read(arguments); - this.x = point.x; - this.y = point.y; - return this; - }, - - getSize: function() { - return LinkedSize.create(this, 'setSize', this.width, this.height, - arguments[0]); - }, - - setSize: function(size) { - size = Size.read(arguments); - this.width = size.width; - this.height = size.height; - return this; - }, - - getLeft: function() { - return this.x; - }, - - setLeft: function(left) { - this.width -= left - this.x; - this.x = left; - return this; - }, - - getTop: function() { - return this.y; - }, - - setTop: function(top) { - this.height -= top - this.y; - this.y = top; - return this; - }, - - getRight: function() { - return this.x + this.width; - }, - - setRight: function(right) { - this.width = right - this.x; - return this; - }, - - getBottom: function() { - return this.y + this.height; - }, - - setBottom: function(bottom) { - this.height = bottom - this.y; - return this; - }, - - getCenterX: function() { - return this.x + this.width * 0.5; - }, - - setCenterX: function(x) { - this.x = x - this.width * 0.5; - return this; - }, - - getCenterY: function() { - return this.y + this.height * 0.5; - }, - - setCenterY: function(y) { - this.y = y - this.height * 0.5; - return this; - }, - - getCenter: function() { - return LinkedPoint.create(this, 'setCenter', - this.getCenterX(), this.getCenterY(), arguments[0]); - }, - - setCenter: function(point) { - point = Point.read(arguments); - return this.setCenterX(point.x).setCenterY(point.y); - }, - - equals: function(rect) { - rect = Rectangle.read(arguments); - return this.x == rect.x && this.y == rect.y - && this.width == rect.width && this.height == rect.height; - }, - - isEmpty: function() { - return this.width == 0 || this.height == 0; - }, - - toString: function() { - var format = Base.formatNumber; - return '{ x: ' + format(this.x) - + ', y: ' + format(this.y) - + ', width: ' + format(this.width) - + ', height: ' + format(this.height) - + ' }'; - }, - - contains: function(arg) { - return arg && arg.width !== undefined - || (Array.isArray(arg) ? arg : arguments).length == 4 - ? this._containsRectangle(Rectangle.read(arguments)) - : this._containsPoint(Point.read(arguments)); - }, - - _containsPoint: function(point) { - var x = point.x, - y = point.y; - return x >= this.x && y >= this.y - && x <= this.x + this.width - && y <= this.y + this.height; - }, - - _containsRectangle: function(rect) { - var x = rect.x, - y = rect.y; - return x >= this.x && y >= this.y - && x + rect.width <= this.x + this.width - && y + rect.height <= this.y + this.height; - }, - - intersects: function(rect) { - rect = Rectangle.read(arguments); - return rect.x + rect.width > this.x - && rect.y + rect.height > this.y - && rect.x < this.x + this.width - && rect.y < this.y + this.height; - }, - - intersect: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.max(this.x, rect.x), - y1 = Math.max(this.y, rect.y), - x2 = Math.min(this.x + this.width, rect.x + rect.width), - y2 = Math.min(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - unite: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.min(this.x, rect.x), - y1 = Math.min(this.y, rect.y), - x2 = Math.max(this.x + this.width, rect.x + rect.width), - y2 = Math.max(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - include: function(point) { - point = Point.read(arguments); - var x1 = Math.min(this.x, point.x), - y1 = Math.min(this.y, point.y), - x2 = Math.max(this.x + this.width, point.x), - y2 = Math.max(this.y + this.height, point.y); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - expand: function(hor, ver) { - if (ver === undefined) - ver = hor; - return Rectangle.create(this.x - hor / 2, this.y - ver / 2, - this.width + hor, this.height + ver); - }, - - scale: function(hor, ver) { - return this.expand(this.width * hor - this.width, - this.height * (ver === undefined ? hor : ver) - this.height); - }, - - statics: { - create: function(x, y, width, height) { - return new Rectangle(Rectangle.dont).set(x, y, width, height); - } - } -}, new function() { - return Base.each([ - ['Top', 'Left'], ['Top', 'Right'], - ['Bottom', 'Left'], ['Bottom', 'Right'], - ['Left', 'Center'], ['Top', 'Center'], - ['Right', 'Center'], ['Bottom', 'Center'] - ], - function(parts, index) { - var part = parts.join(''); - var xFirst = /^[RL]/.test(part); - if (index >= 4) - parts[1] += xFirst ? 'Y' : 'X'; - var x = parts[xFirst ? 0 : 1], - y = parts[xFirst ? 1 : 0], - getX = 'get' + x, - getY = 'get' + y, - setX = 'set' + x, - setY = 'set' + y, - get = 'get' + part, - set = 'set' + part; - this[get] = function() { - return LinkedPoint.create(this, set, - this[getX](), this[getY](), arguments[0]); - }; - this[set] = function(point) { - point = Point.read(arguments); - return this[setX](point.x)[setY](point.y); - }; - }, {}); -}); - -var LinkedRectangle = Rectangle.extend({ - set: function(x, y, width, height, dontNotify) { - this._x = x; - this._y = y; - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - statics: { - create: function(owner, setter, x, y, width, height) { - var rect = new LinkedRectangle(LinkedRectangle.dont).set( - x, y, width, height, true); - rect._owner = owner; - rect._setter = setter; - return rect; - } - } -}, new function() { - var proto = Rectangle.prototype; - - return Base.each(['x', 'y', 'width', 'height'], function(key) { - var part = Base.capitalize(key); - var internal = '_' + key; - this['get' + part] = function() { - return this[internal]; - }; - - this['set' + part] = function(value) { - this[internal] = value; - if (!this._dontNotify) - this._owner[this._setter](this); - }; - }, Base.each(['Point', 'Size', 'Center', - 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', - 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - function(key) { - var name = 'set' + key; - this[name] = function(value) { - this._dontNotify = true; - proto[name].apply(this, arguments); - delete this._dontNotify; - this._owner[this._setter](this); - return this; - }; - }, {}) - ); -}); - -var Matrix = this.Matrix = Base.extend({ - initialize: function(arg) { - var count = arguments.length, - ok = true; - if (count == 6) { - this.set.apply(this, arguments); - } else if (count == 1) { - if (arg instanceof Matrix) { - this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty); - } else if (Array.isArray(arg)) { - this.set.apply(this, arg); - } else { - ok = false; - } - } else if (count == 0) { - this.setIdentity(); - } else { - ok = false; - } - if (!ok) - throw new Error('Unsupported matrix parameters'); - }, - - clone: function() { - return Matrix.create(this._a, this._c, this._b, this._d, - this._tx, this._ty); - }, - - set: function(a, c, b, d, tx, ty) { - this._a = a; - this._c = c; - this._b = b; - this._d = d; - this._tx = tx; - this._ty = ty; - return this; - }, - - setIdentity: function() { - this._a = this._d = 1; - this._c = this._b = this._tx = this._ty = 0; - return this; - }, - - scale: function( hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = Point.read(arguments, 1); - ver = hor; - } else { - center = Point.read(arguments, 2); - } - if (center) - this.translate(center); - this._a *= hor; - this._c *= hor; - this._b *= ver; - this._d *= ver; - if (center) - this.translate(center.negate()); - return this; - }, - - translate: function(point) { - point = Point.read(arguments); - var x = point.x, y = point.y; - this._tx += x * this._a + y * this._b; - this._ty += x * this._c + y * this._d; - return this; - }, - - rotate: function(angle, center) { - return this.concatenate( - Matrix.getRotateInstance.apply(Matrix, arguments)); - }, - - shear: function( hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = Point.read(arguments, 1); - ver = hor; - } else { - center = Point.read(arguments, 2); - } - if (center) - this.translate(center); - var a = this._a, - c = this._c; - this._a += ver * this._b; - this._c += ver * this._d; - this._b += hor * a; - this._d += hor * c; - if (center) - this.translate(center.negate()); - return this; - }, - - toString: function() { - var format = Base.formatNumber; - return '[[' + [format(this._a), format(this._b), - format(this._tx)].join(', ') + '], [' - + [format(this._c), format(this._d), - format(this._ty)].join(', ') + ']]'; - }, - - getValues: function() { - return [ this._a, this._c, this._b, this._d, this._tx, this._ty ]; - }, - - concatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d; - this._a = mx._a * a + mx._c * b; - this._b = mx._b * a + mx._d * b; - this._c = mx._a * c + mx._c * d; - this._d = mx._b * c + mx._d * d; - this._tx += mx._tx * a + mx._ty * b; - this._ty += mx._tx * c + mx._ty * d; - return this; - }, - - preConcatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - tx = this._tx, - ty = this._ty; - this._a = mx._a * a + mx._b * c; - this._b = mx._a * b + mx._b * d; - this._c = mx._c * a + mx._d * c; - this._d = mx._c * b + mx._d * d; - this._tx = mx._a * tx + mx._b * ty + mx._tx; - this._ty = mx._c * tx + mx._d * ty + mx._ty; - return this; - }, - - transform: function( src, srcOff, dst, dstOff, numPts) { - return arguments.length < 5 - ? this._transformPoint(Point.read(arguments)) - : this._transformCoordinates(src, srcOff, dst, dstOff, numPts); - }, - - _transformPoint: function(point, dest, dontNotify) { - var x = point.x, - y = point.y; - if (!dest) - dest = new Point(Point.dont); - return dest.set( - x * this._a + y * this._b + this._tx, - x * this._c + y * this._d + this._ty, - dontNotify - ); - }, - - _transformCoordinates: function(src, srcOff, dst, dstOff, numPts) { - var i = srcOff, j = dstOff, - srcEnd = srcOff + 2 * numPts; - while (i < srcEnd) { - var x = src[i++]; - var y = src[i++]; - dst[j++] = x * this._a + y * this._b + this._tx; - dst[j++] = x * this._c + y * this._d + this._ty; - } - return dst; - }, - - _transformCorners: function(rect) { - var x1 = rect.x, - y1 = rect.y, - x2 = x1 + rect.width, - y2 = y1 + rect.height, - coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; - return this._transformCoordinates(coords, 0, coords, 0, 4); - }, - - _transformBounds: function(bounds, dest, dontNotify) { - var coords = this._transformCorners(bounds), - min = coords.slice(0, 2), - max = coords.slice(0); - for (var i = 2; i < 8; i++) { - var val = coords[i], - j = i & 1; - if (val < min[j]) - min[j] = val; - else if (val > max[j]) - max[j] = val; - } - if (!dest) - dest = new Rectangle(Rectangle.dont); - return dest.set(min[0], min[1], max[0] - min[0], max[1] - min[1], - dontNotify); - }, - - inverseTransform: function(point) { - return this._inverseTransform(Point.read(arguments)); - }, - - _getDeterminant: function() { - var det = this._a * this._d - this._b * this._c; - return isFinite(det) && Math.abs(det) > Numerical.EPSILON - && isFinite(this._tx) && isFinite(this._ty) - ? det : null; - }, - - _inverseTransform: function(point, dest, dontNotify) { - var det = this._getDeterminant(); - if (!det) - return null; - var x = point.x - this._tx, - y = point.y - this._ty; - if (!dest) - dest = new Point(Point.dont); - return dest.set( - (x * this._d - y * this._b) / det, - (y * this._a - x * this._c) / det, - dontNotify - ); - }, - - getTranslation: function() { - return Point.create(this._tx, this._ty); - }, - - getScaling: function() { - var hor = Math.sqrt(this._a * this._a + this._c * this._c), - ver = Math.sqrt(this._b * this._b + this._d * this._d); - return Point.create(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); - }, - - getRotation: function() { - var angle1 = -Math.atan2(this._b, this._d), - angle2 = Math.atan2(this._c, this._a); - return Math.abs(angle1 - angle2) < Numerical.TOLERANCE - ? angle1 * 180 / Math.PI : undefined; - }, - - equals: function(mx) { - return this._a == mx._a && this._b == mx._b && this._c == mx._c - && this._d == mx._d && this._tx == mx._tx && this._ty == mx._ty; - }, - - isIdentity: function() { - return this._a == 1 && this._c == 0 && this._b == 0 && this._d == 1 - && this._tx == 0 && this._ty == 0; - }, - - isInvertible: function() { - return !!this._getDeterminant(); - }, - - isSingular: function() { - return !this._getDeterminant(); - }, - - createInverse: function() { - var det = this._getDeterminant(); - return det && Matrix.create( - this._d / det, - -this._c / det, - -this._b / det, - this._a / det, - (this._b * this._ty - this._d * this._tx) / det, - (this._c * this._tx - this._a * this._ty) / det); - }, - - createShiftless: function() { - return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); - }, - - setToScale: function(hor, ver) { - return this.set(hor, 0, 0, ver, 0, 0); - }, - - setToTranslation: function(delta) { - delta = Point.read(arguments); - return this.set(1, 0, 0, 1, delta.x, delta.y); - }, - - setToShear: function(hor, ver) { - return this.set(1, ver, hor, 1, 0, 0); - }, - - setToRotation: function(angle, center) { - center = Point.read(arguments, 1); - angle = angle * Math.PI / 180; - var x = center.x, - y = center.y, - cos = Math.cos(angle), - sin = Math.sin(angle); - return this.set(cos, sin, -sin, cos, - x - x * cos + y * sin, - y - x * sin - y * cos); - }, - - applyToContext: function(ctx, reset) { - ctx[reset ? 'setTransform' : 'transform']( - this._a, this._c, this._b, this._d, this._tx, this._ty); - return this; - }, - - statics: { - create: function(a, c, b, d, tx, ty) { - return new Matrix(Matrix.dont).set(a, c, b, d, tx, ty); - }, - - getScaleInstance: function(hor, ver) { - var mx = new Matrix(); - return mx.setToScale.apply(mx, arguments); - }, - - getTranslateInstance: function(delta) { - var mx = new Matrix(); - return mx.setToTranslation.apply(mx, arguments); - }, - - getShearInstance: function(hor, ver, center) { - var mx = new Matrix(); - return mx.setToShear.apply(mx, arguments); - }, - - getRotateInstance: function(angle, center) { - var mx = new Matrix(); - return mx.setToRotation.apply(mx, arguments); - } - } -}, new function() { - return Base.each({ - scaleX: '_a', - scaleY: '_d', - translateX: '_tx', - translateY: '_ty', - shearX: '_b', - shearY: '_c' - }, function(prop, name) { - name = Base.capitalize(name); - this['get' + name] = function() { - return this[prop]; - }; - this['set' + name] = function(value) { - this[prop] = value; - }; - }, {}); -}); - -var Line = this.Line = Base.extend({ - initialize: function(point1, point2, infinite) { - point1 = Point.read(arguments, 0, 1); - point2 = Point.read(arguments, 1, 1); - if (arguments.length == 3) { - this.point = point1; - this.vector = point2.subtract(point1); - this.infinite = infinite; - } else { - this.point = point1; - this.vector = point2; - this.infinite = true; - } - }, - - intersect: function(line) { - var cross = this.vector.cross(line.vector); - if (Math.abs(cross) <= Numerical.EPSILON) - return null; - var v = line.point.subtract(this.point), - t1 = v.cross(line.vector) / cross, - t2 = v.cross(this.vector) / cross; - return (this.infinite || 0 <= t1 && t1 <= 1) - && (line.infinite || 0 <= t2 && t2 <= 1) - ? this.point.add(this.vector.multiply(t1)) : null; - }, - - getSide: function(point) { - var v1 = this.vector, - v2 = point.subtract(this.point), - ccw = v2.cross(v1); - if (ccw == 0) { - ccw = v2.dot(v1); - if (ccw > 0) { - ccw = v2.subtract(v1).dot(v1); - if (ccw < 0) - ccw = 0; - } - } - return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; - }, - - getDistance: function(point) { - var m = this.vector.y / this.vector.x, - b = this.point.y - (m * this.point.x); - var dist = Math.abs(point.y - (m * point.x) - b) / Math.sqrt(m * m + 1); - return this.infinite ? dist : Math.min(dist, - point.getDistance(this.point), - point.getDistance(this.point.add(this.vector))); - } -}); - -var Project = this.Project = PaperScopeItem.extend({ - _list: 'projects', - _reference: 'project', - - initialize: function(view) { - this.base(true); - this._currentStyle = new PathStyle(); - this._selectedItems = {}; - this._selectedItemCount = 0; - this.layers = []; - this.symbols = []; - this.activeLayer = new Layer(); - if (view) - this.view = view instanceof View ? view : View.create(view); - }, - - _needsRedraw: function() { - if (this.view) - this.view._redrawNeeded = true; - }, - - remove: function() { - if (!this.base()) - return false; - if (this.view) - this.view.remove(); - return true; - }, - - getCurrentStyle: function() { - return this._currentStyle; - }, - - setCurrentStyle: function(style) { - this._currentStyle.initialize(style); - }, - - getIndex: function() { - return this._index; - }, - - getSelectedItems: function() { - var items = []; - Base.each(this._selectedItems, function(item) { - items.push(item); - }); - return items; - }, - - _updateSelection: function(item) { - if (item._selected) { - this._selectedItemCount++; - this._selectedItems[item._id] = item; - } else { - this._selectedItemCount--; - delete this._selectedItems[item._id]; - } - }, - - selectAll: function() { - for (var i = 0, l = this.layers.length; i < l; i++) - this.layers[i].setSelected(true); - }, - - deselectAll: function() { - for (var i in this._selectedItems) - this._selectedItems[i].setSelected(false); - }, - - hitTest: function(point, options) { - options = HitResult.getOptions(point, options); - point = options.point; - for (var i = this.layers.length - 1; i >= 0; i--) { - var res = this.layers[i].hitTest(point, options); - if (res) return res; - } - return null; - }, - - draw: function(ctx, matrix) { - ctx.save(); - if (!matrix.isIdentity()) - matrix.applyToContext(ctx); - var param = { offset: new Point(0, 0) }; - for (var i = 0, l = this.layers.length; i < l; i++) - Item.draw(this.layers[i], ctx, param); - ctx.restore(); - - if (this._selectedItemCount > 0) { - ctx.save(); - ctx.strokeWidth = 1; - ctx.strokeStyle = ctx.fillStyle = '#009dec'; - var matrices = {}; - function getGlobalMatrix(item, mx, cached) { - var cache = cached && matrices[item._id]; - if (cache) { - mx.concatenate(cache); - return mx; - } - if (item._parent) { - getGlobalMatrix(item._parent, mx, true); - if (!item._matrix.isIdentity()) - mx.concatenate(item._matrix); - } else { - mx.initialize(item._matrix); - } - if (cached) - matrices[item._id] = mx.clone(); - return mx; - } - for (var id in this._selectedItems) { - var item = this._selectedItems[id]; - item.drawSelected(ctx, getGlobalMatrix(item, matrix.clone())); - } - ctx.restore(); - } - } -}); - -var Symbol = this.Symbol = Base.extend({ - initialize: function(item) { - this.project = paper.project; - this.project.symbols.push(this); - this.setDefinition(item); - this._instances = {}; - }, - - _changed: function(flags) { - Base.each(this._instances, function(item) { - item._changed(flags); - }); - }, - - getDefinition: function() { - return this._definition; - }, - - setDefinition: function(item) { - if (item._parentSymbol) - item = item.clone(); - if (this._definition) - delete this._definition._parentSymbol; - this._definition = item; - item.remove(); - item.setPosition(new Point()); - item._parentSymbol = this; - this._changed(Change.GEOMETRY); - }, - - place: function(position) { - return new PlacedSymbol(this, position); - }, - - clone: function() { - return new Symbol(this._definition.clone()); - } -}); - -var ChangeFlag = { - APPEARANCE: 1, - HIERARCHY: 2, - GEOMETRY: 4, - STROKE: 8, - STYLE: 16, - ATTRIBUTE: 32, - CONTENT: 64, - PIXELS: 128, - CLIPPING: 256 -}; - -var Change = { - HIERARCHY: ChangeFlag.HIERARCHY | ChangeFlag.APPEARANCE, - GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, - STROKE: ChangeFlag.STROKE | ChangeFlag.STYLE | ChangeFlag.APPEARANCE, - STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE, - ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE, - CONTENT: ChangeFlag.CONTENT | ChangeFlag.APPEARANCE, - PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE -}; - -var Item = this.Item = Base.extend(Callback, { - _events: new function() { - - var mouseFlags = { - mousedown: { - mousedown: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mouseup: { - mouseup: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mousemove: { - mousedrag: 1, - mousemove: 1, - mouseenter: 1, - mouseleave: 1 - } - }; - - var mouseEvent = { - install: function(type) { - var counters = this._project.view._eventCounters; - if (counters) { - for (var key in mouseFlags) { - counters[key] = (counters[key] || 0) - + (mouseFlags[key][type] || 0); - } - } - }, - uninstall: function(type) { - var counters = this._project.view._eventCounters; - if (counters) { - for (var key in mouseFlags) - counters[key] -= mouseFlags[key][type] || 0; - } - } - }; - - var onFrameItems = []; - function onFrame(event) { - for (var i = 0, l = onFrameItems.length; i < l; i++) - onFrameItems[i].fire('frame', event); - } - - return Base.each(['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick', - 'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave'], - function(name) { - this[name] = mouseEvent; - }, { - onFrame: { - install: function() { - if (!onFrameItems.length) - this._project.view.attach('frame', onFrame); - onFrameItems.push(this); - }, - uninstall: function() { - onFrameItems.splice(onFrameItems.indexOf(this), 1); - if (!onFrameItems.length) - this._project.view.detach('frame', onFrame); - } - } - }); - }, - - initialize: function(pointOrMatrix) { - this._id = ++Item._id; - if (!this._project) - paper.project.activeLayer.addChild(this); - if (!this._style) - this._style = PathStyle.create(this); - this.setStyle(this._project.getCurrentStyle()); - this._matrix = pointOrMatrix !== undefined - ? pointOrMatrix instanceof Matrix - ? pointOrMatrix.clone() - : new Matrix().translate(Point.read(arguments, 0)) - : new Matrix(); - }, - - _changed: function(flags) { - if (flags & ChangeFlag.GEOMETRY) { - delete this._bounds; - delete this._position; - } - if (this._parent - && (flags & (ChangeFlag.GEOMETRY | ChangeFlag.STROKE))) { - this._parent._clearBoundsCache(); - } - if (flags & ChangeFlag.HIERARCHY) { - this._clearBoundsCache(); - } - if (flags & ChangeFlag.APPEARANCE) { - this._project._needsRedraw(); - } - if (this._parentSymbol) - this._parentSymbol._changed(flags); - if (this._project._changes) { - var entry = this._project._changesById[this._id]; - if (entry) { - entry.flags |= flags; - } else { - entry = { item: this, flags: flags }; - this._project._changesById[this._id] = entry; - this._project._changes.push(entry); - } - } - }, - - getId: function() { - return this._id; - }, - - getName: function() { - return this._name; - }, - - setName: function(name) { - - if (this._name) - this._removeFromNamed(); - this._name = name || undefined; - if (name && this._parent) { - var children = this._parent._children, - namedChildren = this._parent._namedChildren; - (namedChildren[name] = namedChildren[name] || []).push(this); - children[name] = this; - } - this._changed(ChangeFlag.ATTRIBUTE); - }, - - statics: { - _id: 0 - } -}, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], - function(name) { - var part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - if (value != this[name]) { - this[name] = value; - this._changed(name === '_locked' - ? ChangeFlag.ATTRIBUTE : Change.ATTRIBUTE); - } - }; -}, {}), { - - _locked: false, - - _visible: true, - - _blendMode: 'normal', - - _opacity: 1, - - _guide: false, - - isSelected: function() { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - if (this._children[i].isSelected()) - return true; - } - return this._selected; - }, - - setSelected: function(selected ) { - if (this._children && !arguments[1]) { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].setSelected(selected); - } else if ((selected = !!selected) != this._selected) { - this._selected = selected; - this._project._updateSelection(this); - this._changed(Change.ATTRIBUTE); - } - }, - - _selected: false, - - isFullySelected: function() { - if (this._children && this._selected) { - for (var i = 0, l = this._children.length; i < l; i++) - if (!this._children[i].isFullySelected()) - return false; - return true; - } - return this._selected; - }, - - setFullySelected: function(selected) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].setFullySelected(selected); - } - this.setSelected(selected, true); - }, - - isClipMask: function() { - return this._clipMask; - }, - - setClipMask: function(clipMask) { - if (this._clipMask != (clipMask = !!clipMask)) { - this._clipMask = clipMask; - if (clipMask) { - this.setFillColor(null); - this.setStrokeColor(null); - } - this._changed(Change.ATTRIBUTE); - if (this._parent) - this._parent._changed(ChangeFlag.CLIPPING); - } - }, - - _clipMask: false, - - getPosition: function() { - var pos = this._position - || (this._position = this.getBounds().getCenter(true)); - return arguments[0] ? pos - : LinkedPoint.create(this, 'setPosition', pos.x, pos.y); - }, - - setPosition: function(point) { - this.translate(Point.read(arguments).subtract(this.getPosition(true))); - }, - - getMatrix: function() { - return this._matrix; - }, - - setMatrix: function(matrix) { - this._matrix.initialize(matrix); - this._changed(Change.GEOMETRY); - } -}, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds'], -function(name) { - this['get' + Base.capitalize(name)] = function() { - var type = this._boundsType, - bounds = this._getCachedBounds( - typeof type == 'string' ? type : type && type[name] || name, - arguments[0]); - return name == 'bounds' ? LinkedRectangle.create(this, 'setBounds', - bounds.x, bounds.y, bounds.width, bounds.height) : bounds; - }; -}, { - _getCachedBounds: function(type, matrix, cacheItem) { - var cache = (!matrix || matrix.equals(this._matrix)) && type; - if (cacheItem && this._parent) { - var id = cacheItem._id, - ref = this._parent._boundsCache - = this._parent._boundsCache || { - ids: {}, - list: [] - }; - if (!ref.ids[id]) { - ref.list.push(cacheItem); - ref.ids[id] = cacheItem; - } - } - if (cache && this._bounds && this._bounds[cache]) - return this._bounds[cache]; - var identity = this._matrix.isIdentity(); - matrix = !matrix || matrix.isIdentity() - ? identity ? null : this._matrix - : identity ? matrix : matrix.clone().concatenate(this._matrix); - var bounds = this._getBounds(type, matrix, cache ? this : cacheItem); - if (cache) { - if (!this._bounds) - this._bounds = {}; - this._bounds[cache] = bounds.clone(); - } - return bounds; - }, - - _clearBoundsCache: function() { - if (this._boundsCache) { - for (var i = 0, list = this._boundsCache.list, l = list.length; - i < l; i++) { - var item = list[i]; - delete item._bounds; - if (item != this && item._boundsCache) - item._clearBoundsCache(); - } - delete this._boundsCache; - } - }, - - _getBounds: function(type, matrix, cacheItem) { - var children = this._children; - if (!children || children.length == 0) - return new Rectangle(); - var x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - if (child._visible) { - var rect = child._getCachedBounds(type, matrix, cacheItem); - x1 = Math.min(rect.x, x1); - y1 = Math.min(rect.y, y1); - x2 = Math.max(rect.x + rect.width, x2); - y2 = Math.max(rect.y + rect.height, y2); - } - } - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - setBounds: function(rect) { - rect = Rectangle.read(arguments); - var bounds = this.getBounds(), - matrix = new Matrix(), - center = rect.getCenter(); - matrix.translate(center); - if (rect.width != bounds.width || rect.height != bounds.height) { - matrix.scale( - bounds.width != 0 ? rect.width / bounds.width : 1, - bounds.height != 0 ? rect.height / bounds.height : 1); - } - center = bounds.getCenter(); - matrix.translate(-center.x, -center.y); - this.transform(matrix); - } - -}), { - getProject: function() { - return this._project; - }, - - _setProject: function(project) { - if (this._project != project) { - this._project = project; - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - this._children[i]._setProject(project); - } - } - } - }, - - getLayer: function() { - var parent = this; - while (parent = parent._parent) { - if (parent instanceof Layer) - return parent; - } - return null; - }, - - getParent: function() { - return this._parent; - }, - - getChildren: function() { - return this._children; - }, - - setChildren: function(items) { - this.removeChildren(); - this.addChildren(items); - }, - - getFirstChild: function() { - return this._children && this._children[0] || null; - }, - - getLastChild: function() { - return this._children && this._children[this._children.length - 1] - || null; - }, - - getNextSibling: function() { - return this._parent && this._parent._children[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent && this._parent._children[this._index - 1] || null; - }, - - getIndex: function() { - return this._index; - }, - - clone: function() { - return this._clone(new this.constructor()); - }, - - _clone: function(copy) { - copy.setStyle(this._style); - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - copy.addChild(this._children[i].clone()); - } - var keys = ['_locked', '_visible', '_blendMode', '_opacity', - '_clipMask', '_guide']; - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - if (this.hasOwnProperty(key)) - copy[key] = this[key]; - } - copy._matrix.initialize(this._matrix); - copy.setSelected(this._selected); - if (this._name) - copy.setName(this._name); - return copy; - }, - - copyTo: function(itemOrProject) { - var copy = this.clone(); - if (itemOrProject.layers) { - itemOrProject.activeLayer.addChild(copy); - } else { - itemOrProject.addChild(copy); - } - return copy; - }, - - rasterize: function(resolution) { - var bounds = this.getStrokeBounds(), - scale = (resolution || 72) / 72, - canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), - ctx = canvas.getContext('2d'), - matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); - matrix.applyToContext(ctx); - this.draw(ctx, {}); - var raster = new Raster(canvas); - raster.setBounds(bounds); - return raster; - }, - - hitTest: function(point, options) { - options = HitResult.getOptions(point, options); - point = options.point = this._matrix._inverseTransform(options.point); - if (!this._children && !this.getRoughBounds() - .expand(options.tolerance)._containsPoint(point)) - return null; - if ((options.center || options.bounds) && - !(this instanceof Layer && !this._parent)) { - var bounds = this.getBounds(), - that = this, - points = ['TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - res; - function checkBounds(type, part) { - var pt = bounds['get' + part](); - if (point.getDistance(pt) < options.tolerance) - return new HitResult(type, that, - { name: Base.hyphenate(part), point: pt }); - } - if (options.center && (res = checkBounds('center', 'Center'))) - return res; - if (options.bounds) { - for (var i = 0; i < 8; i++) - if (res = checkBounds('bounds', points[i])) - return res; - } - } - - return this._children || !(options.guides && !this._guide - || options.selected && !this._selected) - ? this._hitTest(point, options) : null; - }, - - _hitTest: function(point, options) { - if (this._children) { - for (var i = this._children.length - 1; i >= 0; i--) { - var res = this._children[i].hitTest(point, options); - if (res) return res; - } - } - }, - - addChild: function(item) { - return this.insertChild(undefined, item); - }, - - insertChild: function(index, item) { - if (this._children) { - item._remove(false, true); - Base.splice(this._children, [item], index, 0); - item._parent = this; - item._setProject(this._project); - if (item._name) - item.setName(item._name); - this._changed(Change.HIERARCHY); - return true; - } - return false; - }, - - addChildren: function(items) { - for (var i = 0, l = items && items.length; i < l; i++) - this.insertChild(undefined, items[i]); - }, - - insertChildren: function(index, items) { - for (var i = 0, l = items && items.length; i < l; i++) { - if (this.insertChild(index, items[i])) - index++; - } - }, - - insertAbove: function(item) { - var index = item._index; - if (item._parent == this._parent && index < this._index) - index++; - return item._parent.insertChild(index, this); - }, - - insertBelow: function(item) { - var index = item._index; - if (item._parent == this._parent && index > this._index) - index--; - return item._parent.insertChild(index, this); - }, - - appendTop: function(item) { - return this.addChild(item); - }, - - appendBottom: function(item) { - return this.insertChild(0, item); - }, - - moveAbove: function(item) { - return this.insertAbove(item); - }, - - moveBelow: function(item) { - return this.insertBelow(item); - }, - - _removeFromNamed: function() { - var children = this._parent._children, - namedChildren = this._parent._namedChildren, - name = this._name, - namedArray = namedChildren[name], - index = namedArray ? namedArray.indexOf(this) : -1; - if (index == -1) - return; - if (children[name] == this) - delete children[name]; - namedArray.splice(index, 1); - if (namedArray.length) { - children[name] = namedArray[namedArray.length - 1]; - } else { - delete namedChildren[name]; - } - }, - - _remove: function(deselect, notify) { - if (this._parent) { - if (deselect) - this.setSelected(false); - if (this._name) - this._removeFromNamed(); - if (this._index != null) - Base.splice(this._parent._children, null, this._index, 1); - if (notify) - this._parent._changed(Change.HIERARCHY); - this._parent = null; - return true; - } - return false; - }, - - remove: function() { - return this._remove(true, true); - }, - - removeChildren: function(from, to) { - if (!this._children) - return null; - from = from || 0; - to = Base.pick(to, this._children.length); - var removed = Base.splice(this._children, null, from, to - from); - for (var i = removed.length - 1; i >= 0; i--) - removed[i]._remove(true, false); - if (removed.length > 0) - this._changed(Change.HIERARCHY); - return removed; - }, - - reverseChildren: function() { - if (this._children) { - this._children.reverse(); - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i]._index = i; - this._changed(Change.HIERARCHY); - } - }, - - isEditable: function() { - var item = this; - while (item) { - if (!item._visible || item._locked) - return false; - item = item._parent; - } - return true; - }, - - _getOrder: function(item) { - function getList(item) { - var list = []; - do { - list.unshift(item); - } while (item = item._parent) - return list; - } - var list1 = getList(this), - list2 = getList(item); - for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { - if (list1[i] != list2[i]) { - return list1[i]._index < list2[i]._index ? 1 : -1; - } - } - return 0; - }, - - hasChildren: function() { - return this._children && this._children.length > 0; - }, - - isAbove: function(item) { - return this._getOrder(item) == -1; - }, - - isBelow: function(item) { - return this._getOrder(item) == 1; - }, - - isParent: function(item) { - return this._parent == item; - }, - - isChild: function(item) { - return item && item._parent == this; - }, - - isDescendant: function(item) { - var parent = this; - while (parent = parent._parent) { - if (parent == item) - return true; - } - return false; - }, - - isAncestor: function(item) { - return item ? item.isDescendant(this) : false; - }, - - isGroupedWith: function(item) { - var parent = this._parent; - while (parent) { - if (parent._parent - && (parent instanceof Group || parent instanceof CompoundPath) - && item.isDescendant(parent)) - return true; - parent = parent._parent; - } - return false; - }, - - scale: function(hor, ver , center, apply) { - if (arguments.length < 2 || typeof ver === 'object') { - apply = center; - center = ver; - ver = hor; - } - return this.transform(new Matrix().scale(hor, ver, - center || this.getPosition(true)), apply); - }, - - translate: function(delta, apply) { - var mx = new Matrix(); - return this.transform(mx.translate.apply(mx, arguments), apply); - }, - - rotate: function(angle, center, apply) { - return this.transform(new Matrix().rotate(angle, - center || this.getPosition(true)), apply); - }, - - shear: function(hor, ver, center, apply) { - if (arguments.length < 2 || typeof ver === 'object') { - apply = center; - center = ver; - ver = hor; - } - return this.transform(new Matrix().shear(hor, ver, - center || this.getPosition(true)), apply); - }, - - transform: function(matrix, apply) { - var bounds = this._bounds, - position = this._position; - this._matrix.preConcatenate(matrix); - if (this._transform) - this._transform(matrix); - if (apply) - this.apply(); - this._changed(Change.GEOMETRY); - if (bounds && matrix.getRotation() % 90 === 0) { - for (var key in bounds) { - var rect = bounds[key]; - matrix._transformBounds(rect, rect); - } - var type = this._boundsType, - rect = bounds[type && type.bounds || 'bounds']; - if (rect) - this._position = rect.getCenter(true); - this._bounds = bounds; - } else if (position) { - this._position = matrix._transformPoint(position, position); - } - return this; - }, - - apply: function() { - if (this._apply(this._matrix)) { - this._matrix.setIdentity(); - } - }, - - _apply: function(matrix) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - var child = this._children[i]; - child.transform(matrix); - child.apply(); - } - return true; - } - }, - - fitBounds: function(rectangle, fill) { - rectangle = Rectangle.read(arguments); - var bounds = this.getBounds(), - itemRatio = bounds.height / bounds.width, - rectRatio = rectangle.height / rectangle.width, - scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) - ? rectangle.width / bounds.width - : rectangle.height / bounds.height, - newBounds = new Rectangle(new Point(), - Size.create(bounds.width * scale, bounds.height * scale)); - newBounds.setCenter(rectangle.getCenter()); - this.setBounds(newBounds); - }, - - toString: function() { - return (this.constructor._name || 'Item') + (this._name - ? " '" + this._name + "'" - : ' @' + this._id); - }, - - _setStyles: function(ctx) { - var style = this._style, - width = style._strokeWidth, - join = style._strokeJoin, - cap = style._strokeCap, - limit = style._miterLimit, - fillColor = style._fillColor, - strokeColor = style._strokeColor; - if (width != null) ctx.lineWidth = width; - if (join) ctx.lineJoin = join; - if (cap) ctx.lineCap = cap; - if (limit) ctx.miterLimit = limit; - if (fillColor) ctx.fillStyle = fillColor.getCanvasStyle(ctx); - if (strokeColor) ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); - if (!fillColor || !strokeColor) - ctx.globalAlpha = this._opacity; - }, - - statics: { - drawSelectedBounds: function(bounds, ctx, matrix) { - var coords = matrix._transformCorners(bounds); - ctx.beginPath(); - for (var i = 0; i < 8; i++) - ctx[i == 0 ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); - ctx.closePath(); - ctx.stroke(); - for (var i = 0; i < 8; i++) { - ctx.beginPath(); - ctx.rect(coords[i] - 2, coords[++i] - 2, 4, 4); - ctx.fill(); - } - }, - - draw: function(item, ctx, param) { - if (!item._visible || item._opacity == 0) - return; - var tempCanvas, parentCtx, - itemOffset, prevOffset; - if (item._blendMode !== 'normal' || item._opacity < 1 - && !(item._segments - && (!item.getFillColor() || !item.getStrokeColor()))) { - var bounds = item.getStrokeBounds(); - if (!bounds.width || !bounds.height) - return; - prevOffset = param.offset; - parentCtx = ctx; - itemOffset = param.offset = bounds.getTopLeft().floor(); - tempCanvas = CanvasProvider.getCanvas( - bounds.getSize().ceil().add(Size.create(1, 1))); - ctx = tempCanvas.getContext('2d'); - } - if (!param.clipping) - ctx.save(); - if (tempCanvas) - ctx.translate(-itemOffset.x, -itemOffset.y); - item._matrix.applyToContext(ctx); - item.draw(ctx, param); - if (!param.clipping) - ctx.restore(); - if (tempCanvas) { - param.offset = prevOffset; - if (item._blendMode !== 'normal') { - BlendMode.process(item._blendMode, ctx, parentCtx, - item._opacity, itemOffset.subtract(prevOffset)); - } else { - parentCtx.save(); - parentCtx.globalAlpha = item._opacity; - parentCtx.drawImage(tempCanvas, itemOffset.x, itemOffset.y); - parentCtx.restore(); - } - CanvasProvider.returnCanvas(tempCanvas); - } - } - } -}, Base.each(['down', 'drag', 'up', 'move'], function(name) { - this['removeOn' + Base.capitalize(name)] = function() { - var hash = {}; - hash[name] = true; - return this.removeOn(hash); - }; -}, { - - removeOn: function(obj) { - for (var name in obj) { - if (obj[name]) { - var key = 'mouse' + name, - sets = Tool._removeSets = Tool._removeSets || {}; - sets[key] = sets[key] || {}; - sets[key][this._id] = this; - } - } - return this; - } -})); - -var Group = this.Group = Item.extend({ - initialize: function(items) { - this.base(); - this._children = []; - this._namedChildren = {}; - this.addChildren(!items || !Array.isArray(items) - || typeof items[0] !== 'object' ? arguments : items); - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & (ChangeFlag.HIERARCHY | ChangeFlag.CLIPPING)) { - delete this._clipItem; - } - }, - - _getClipItem: function() { - if (this._clipItem !== undefined) - return this._clipItem; - for (var i = 0, l = this._children.length; i < l; i++) { - var child = this._children[i]; - if (child._clipMask) - return this._clipItem = child; - } - return this._clipItem = null; - }, - - isClipped: function() { - return !!this._getClipItem(); - }, - - setClipped: function(clipped) { - var child = this.getFirstChild(); - if (child) - child.setClipMask(clipped); - return this; - }, - - draw: function(ctx, param) { - var clipItem = this._getClipItem(); - if (clipItem) { - param.clipping = true; - Item.draw(clipItem, ctx, param); - delete param.clipping; - } - for (var i = 0, l = this._children.length; i < l; i++) { - var item = this._children[i]; - if (item != clipItem) - Item.draw(item, ctx, param); - } - } -}); - -var Layer = this.Layer = Group.extend({ - initialize: function(items) { - this._project = paper.project; - this._index = this._project.layers.push(this) - 1; - this.base.apply(this, arguments); - this.activate(); - }, - - _remove: function(deselect, notify) { - if (this._parent) - return this.base(deselect, notify); - if (this._index != null) { - if (deselect) - this.setSelected(false); - Base.splice(this._project.layers, null, this._index, 1); - this._project._needsRedraw(); - return true; - } - return false; - }, - - getNextSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index - 1] || null; - }, - - activate: function() { - this._project.activeLayer = this; - } -}, new function () { - function insert(above) { - return function(item) { - if (item instanceof Layer && !item._parent - && this._remove(false, true)) { - Base.splice(item._project.layers, [this], - item._index + (above ? 1 : -1), 0); - this._setProject(item._project); - return true; - } - return this.base(item); - }; - } - - return { - insertAbove: insert(true), - - insertBelow: insert(false) - }; -}); - -var PlacedItem = this.PlacedItem = Item.extend({ - _boundsType: { bounds: 'strokeBounds' } -}); - -var Raster = this.Raster = PlacedItem.extend({ - _boundsType: 'bounds', - - initialize: function(object, pointOrMatrix) { - this.base(pointOrMatrix); - if (object.getContext) { - this.setCanvas(object); - } else { - if (typeof object === 'string') - object = document.getElementById(object); - this.setImage(object); - } - }, - - clone: function() { - var image = this._image; - if (!image) { - image = CanvasProvider.getCanvas(this._size); - image.getContext('2d').drawImage(this._canvas, 0, 0); - } - var copy = new Raster(image); - return this._clone(copy); - }, - - getSize: function() { - return this._size; - }, - - setSize: function() { - var size = Size.read(arguments), - image = this.getImage(); - this.setCanvas(CanvasProvider.getCanvas(size)); - this.getContext(true).drawImage(image, 0, 0, size.width, size.height); - }, - - getWidth: function() { - return this._size.width; - }, - - getHeight: function() { - return this._size.height; - }, - - getPpi: function() { - var matrix = this._matrix, - orig = new Point(0, 0).transform(matrix), - u = new Point(1, 0).transform(matrix).subtract(orig), - v = new Point(0, 1).transform(matrix).subtract(orig); - return Size.create( - 72 / u.getLength(), - 72 / v.getLength() - ); - }, - - getContext: function() { - if (!this._context) - this._context = this.getCanvas().getContext('2d'); - if (arguments[0]) - this._changed(Change.PIXELS); - return this._context; - }, - - setContext: function(context) { - this._context = context; - }, - - getCanvas: function() { - if (!this._canvas) { - this._canvas = CanvasProvider.getCanvas(this._size); - if (this._image) - this.getContext(true).drawImage(this._image, 0, 0); - } - return this._canvas; - }, - - setCanvas: function(canvas) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._canvas = canvas; - this._size = Size.create(canvas.width, canvas.height); - this._image = null; - this._context = null; - this._changed(Change.GEOMETRY | Change.PIXELS); - }, - - getImage: function() { - return this._image || this.getCanvas(); - }, - - setImage: function(image) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._image = image; - this._size = Size.create(image.naturalWidth, image.naturalHeight); - this._canvas = null; - this._context = null; - this._changed(Change.GEOMETRY); - }, - - getSubImage: function(rect) { - rect = Rectangle.read(arguments); - var canvas = CanvasProvider.getCanvas(rect.getSize()); - canvas.getContext('2d').drawImage(this.getCanvas(), rect.x, rect.y, - canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); - return canvas; - }, - - drawImage: function(image, point) { - point = Point.read(arguments, 1); - this.getContext(true).drawImage(image, point.x, point.y); - }, - - getAverageColor: function(object) { - var bounds, path; - if (!object) { - bounds = this.getBounds(); - } else if (object instanceof PathItem) { - path = object; - bounds = object.getBounds(); - } else if (object.width) { - bounds = new Rectangle(object); - } else if (object.x) { - bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1); - } - var sampleSize = 32, - width = Math.min(bounds.width, sampleSize), - height = Math.min(bounds.height, sampleSize); - var ctx = Raster._sampleContext; - if (!ctx) { - ctx = Raster._sampleContext = CanvasProvider.getCanvas( - new Size(sampleSize)).getContext('2d'); - } else { - ctx.clearRect(0, 0, sampleSize, sampleSize); - } - ctx.save(); - ctx.scale(width / bounds.width, height / bounds.height); - ctx.translate(-bounds.x, -bounds.y); - if (path) - path.draw(ctx, { clip: true }); - this._matrix.applyToContext(ctx); - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - ctx.restore(); - var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), - Math.ceil(height)).data, - channels = [0, 0, 0], - total = 0; - for (var i = 0, l = pixels.length; i < l; i += 4) { - var alpha = pixels[i + 3]; - total += alpha; - alpha /= 255; - channels[0] += pixels[i] * alpha; - channels[1] += pixels[i + 1] * alpha; - channels[2] += pixels[i + 2] * alpha; - } - for (var i = 0; i < 3; i++) - channels[i] /= total; - return total ? Color.read(channels) : null; - }, - - getPixel: function(point) { - point = Point.read(arguments); - var pixels = this.getContext().getImageData(point.x, point.y, 1, 1).data, - channels = new Array(4); - for (var i = 0; i < 4; i++) - channels[i] = pixels[i] / 255; - return RgbColor.read(channels); - }, - - setPixel: function(point, color) { - var hasPoint = arguments.length == 2; - point = Point.read(arguments, 0, hasPoint ? 1 : 2); - color = Color.read(arguments, hasPoint ? 1 : 2); - var ctx = this.getContext(true), - imageData = ctx.createImageData(1, 1), - alpha = color.getAlpha(); - imageData.data[0] = color.getRed() * 255; - imageData.data[1] = color.getGreen() * 255; - imageData.data[2] = color.getBlue() * 255; - imageData.data[3] = alpha != null ? alpha * 255 : 255; - ctx.putImageData(imageData, point.x, point.y); - }, - - createData: function(size) { - size = Size.read(arguments); - return this.getContext().createImageData(size.width, size.height); - }, - - getData: function(rect) { - rect = Rectangle.read(arguments); - if (rect.isEmpty()) - rect = new Rectangle(this.getSize()); - return this.getContext().getImageData(rect.x, rect.y, - rect.width, rect.height); - }, - - setData: function(data, point) { - point = Point.read(arguments, 1); - this.getContext(true).putImageData(data, point.x, point.y); - }, - - _getBounds: function(type, matrix) { - var rect = new Rectangle(this._size).setCenter(0, 0); - return matrix ? matrix._transformBounds(rect) : rect; - }, - - _hitTest: function(point, options) { - if (point.isInside(this._getBounds())) { - var that = this; - return new HitResult('pixel', that, { - offset: point.add(that._size.divide(2)).round(), - getColor: function() { - return that.getPixel(this.offset); - } - }); - } - }, - - draw: function(ctx, param) { - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - }, - - drawSelected: function(ctx, matrix) { - Item.drawSelectedBounds(new Rectangle(this._size).setCenter(0, 0), ctx, - matrix); - } -}); - -var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend({ - initialize: function(symbol, pointOrMatrix) { - this.base(pointOrMatrix); - this.setSymbol(symbol instanceof Symbol ? symbol : new Symbol(symbol)); - }, - - getSymbol: function() { - return this._symbol; - }, - - setSymbol: function(symbol) { - if (this._symbol) - delete this._symbol._instances[this._id]; - this._symbol = symbol; - symbol._instances[this._id] = this; - }, - - clone: function() { - return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone())); - }, - - _getBounds: function(type, matrix) { - return this.symbol._definition._getCachedBounds(type, matrix); - }, - - draw: function(ctx, param) { - Item.draw(this.symbol._definition, ctx, param); - }, - - drawSelected: function(ctx, matrix) { - Item.drawSelectedBounds(this.symbol._definition.getBounds(), ctx, - matrix); - } - -}); - -HitResult = Base.extend({ - initialize: function(type, item, values) { - this.type = type; - this.item = item; - if (values) - this.inject(values); - }, - - statics: { - getOptions: function(point, options) { - return options && options._merged ? options : Base.merge({ - point: Point.read(arguments, 0, 1), - type: null, - tolerance: 2, - fill: !options, - stroke: !options, - segments: !options, - handles: false, - ends: false, - center: false, - bounds: false, - guides: false, - selected: false, - _merged: true - }, options); - } - } -}); - -var Segment = this.Segment = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5) { - var count = arguments.length, - createPoint = SegmentPoint.create, - point, handleIn, handleOut; - if (count == 0) { - } else if (count == 1) { - if (arg0.point) { - point = arg0.point; - handleIn = arg0.handleIn; - handleOut = arg0.handleOut; - } else { - point = arg0; - } - } else if (count < 6) { - if (count == 2 && arg1.x === undefined) { - point = [ arg0, arg1 ]; - } else { - point = arg0; - handleIn = arg1; - handleOut = arg2; - } - } else if (count == 6) { - point = [ arg0, arg1 ]; - handleIn = [ arg2, arg3 ]; - handleOut = [ arg4, arg5 ]; - } - createPoint(this, '_point', point); - createPoint(this, '_handleIn', handleIn); - createPoint(this, '_handleOut', handleOut); - }, - - _changed: function(point) { - if (!this._path) - return; - var curve = this._path._curves && this.getCurve(), other; - if (curve) { - curve._changed(); - if (other = (curve[point == this._point - || point == this._handleIn && curve._segment1 == this - ? 'getPrevious' : 'getNext']())) { - other._changed(); - } - } - this._path._changed(Change.GEOMETRY); - }, - - getPoint: function() { - return this._point; - }, - - setPoint: function(point) { - point = Point.read(arguments); - this._point.set(point.x, point.y); - }, - - getHandleIn: function() { - return this._handleIn; - }, - - setHandleIn: function(point) { - point = Point.read(arguments); - this._handleIn.set(point.x, point.y); - }, - - getHandleOut: function() { - return this._handleOut; - }, - - setHandleOut: function(point) { - point = Point.read(arguments); - this._handleOut.set(point.x, point.y); - }, - - _isSelected: function(point) { - var state = this._selectionState; - return point == this._point ? !!(state & SelectionState.POINT) - : point == this._handleIn ? !!(state & SelectionState.HANDLE_IN) - : point == this._handleOut ? !!(state & SelectionState.HANDLE_OUT) - : false; - }, - - _setSelected: function(point, selected) { - var path = this._path, - selected = !!selected, - state = this._selectionState || 0, - selection = [ - !!(state & SelectionState.POINT), - !!(state & SelectionState.HANDLE_IN), - !!(state & SelectionState.HANDLE_OUT) - ]; - if (point == this._point) { - if (selected) { - selection[1] = selection[2] = false; - } else { - var previous = this.getPrevious(), - next = this.getNext(); - selection[1] = previous && (previous._point.isSelected() - || previous._handleOut.isSelected()); - selection[2] = next && (next._point.isSelected() - || next._handleIn.isSelected()); - } - selection[0] = selected; - } else { - var index = point == this._handleIn ? 1 : 2; - if (selection[index] != selected) { - if (selected) - selection[0] = false; - selection[index] = selected; - path._changed(Change.ATTRIBUTE); - } - } - this._selectionState = (selection[0] ? SelectionState.POINT : 0) - | (selection[1] ? SelectionState.HANDLE_IN : 0) - | (selection[2] ? SelectionState.HANDLE_OUT : 0); - if (path && state != this._selectionState) - path._updateSelection(this, state, this._selectionState); - }, - - isSelected: function() { - return this._isSelected(this._point); - }, - - setSelected: function(selected) { - this._setSelected(this._point, selected); - }, - - getIndex: function() { - return this._index !== undefined ? this._index : null; - }, - - getPath: function() { - return this._path || null; - }, - - getCurve: function() { - if (this._path) { - var index = this._index; - if (!this._path._closed && index == this._path._segments.length - 1) - index--; - return this._path.getCurves()[index] || null; - } - return null; - }, - - getNext: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index + 1] - || this._path._closed && segments[0]) || null; - }, - - getPrevious: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index - 1] - || this._path._closed && segments[segments.length - 1]) || null; - }, - - reverse: function() { - return new Segment(this._point, this._handleOut, this._handleIn); - }, - - remove: function() { - return this._path ? !!this._path.removeSegment(this._index) : false; - }, - - clone: function() { - return new Segment(this._point, this._handleIn, this._handleOut); - }, - - equals: function(segment) { - return segment == this || segment - && this._point.equals(segment._point) - && this._handleIn.equals(segment._handleIn) - && this._handleOut.equals(segment._handleOut); - }, - - toString: function() { - var parts = [ 'point: ' + this._point ]; - if (!this._handleIn.isZero()) - parts.push('handleIn: ' + this._handleIn); - if (!this._handleOut.isZero()) - parts.push('handleOut: ' + this._handleOut); - return '{ ' + parts.join(', ') + ' }'; - }, - - _transformCoordinates: function(matrix, coords, change) { - var point = this._point, - handleIn = !change || !this._handleIn.isZero() - ? this._handleIn : null, - handleOut = !change || !this._handleOut.isZero() - ? this._handleOut : null, - x = point._x, - y = point._y, - i = 2; - coords[0] = x; - coords[1] = y; - if (handleIn) { - coords[i++] = handleIn._x + x; - coords[i++] = handleIn._y + y; - } - if (handleOut) { - coords[i++] = handleOut._x + x; - coords[i++] = handleOut._y + y; - } - if (!matrix) - return; - matrix._transformCoordinates(coords, 0, coords, 0, i / 2); - x = coords[0]; - y = coords[1]; - if (change) { - point._x = x; - point._y = y; - i = 2; - if (handleIn) { - handleIn._x = coords[i++] - x; - handleIn._y = coords[i++] - y; - } - if (handleOut) { - handleOut._x = coords[i++] - x; - handleOut._y = coords[i++] - y; - } - } else { - if (!handleIn) { - coords[i++] = x; - coords[i++] = y; - } - if (!handleOut) { - coords[i++] = x; - coords[i++] = y; - } - } - } -}); - -var SegmentPoint = Point.extend({ - set: function(x, y) { - this._x = x; - this._y = y; - this._owner._changed(this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner._changed(this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner._changed(this); - }, - - isZero: function() { - return this._x == 0 && this._y == 0; - }, - - setSelected: function(selected) { - this._owner._setSelected(this, selected); - }, - - isSelected: function() { - return this._owner._isSelected(this); - }, - - statics: { - create: function(segment, key, pt) { - var point = new SegmentPoint(SegmentPoint.dont), - x, y, selected; - if (!pt) { - x = y = 0; - } else if ((x = pt[0]) !== undefined) { - y = pt[1]; - } else { - if ((x = pt.x) === undefined) { - pt = Point.read(arguments, 2, 1); - x = pt.x; - } - y = pt.y; - selected = pt.selected; - } - point._x = x; - point._y = y; - point._owner = segment; - segment[key] = point; - if (selected) - point.setSelected(true); - return point; - } - } -}); - -var SelectionState = { - HANDLE_IN: 1, - HANDLE_OUT: 2, - POINT: 4 -}; - -var Curve = this.Curve = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { - var count = arguments.length; - if (count == 0) { - this._segment1 = new Segment(); - this._segment2 = new Segment(); - } else if (count == 1) { - this._segment1 = new Segment(arg0.segment1); - this._segment2 = new Segment(arg0.segment2); - } else if (count == 2) { - this._segment1 = new Segment(arg0); - this._segment2 = new Segment(arg1); - } else if (count == 4) { - this._segment1 = new Segment(arg0, null, arg1); - this._segment2 = new Segment(arg3, arg2, null); - } else if (count == 8) { - var p1 = Point.create(arg0, arg1), - p2 = Point.create(arg6, arg7); - this._segment1 = new Segment(p1, null, - Point.create(arg2, arg3).subtract(p1)); - this._segment2 = new Segment(p2, - Point.create(arg4, arg5).subtract(p2), null); - } - }, - - _changed: function() { - delete this._length; - }, - - getPoint1: function() { - return this._segment1._point; - }, - - setPoint1: function(point) { - point = Point.read(arguments); - this._segment1._point.set(point.x, point.y); - }, - - getPoint2: function() { - return this._segment2._point; - }, - - setPoint2: function(point) { - point = Point.read(arguments); - this._segment2._point.set(point.x, point.y); - }, - - getHandle1: function() { - return this._segment1._handleOut; - }, - - setHandle1: function(point) { - point = Point.read(arguments); - this._segment1._handleOut.set(point.x, point.y); - }, - - getHandle2: function() { - return this._segment2._handleIn; - }, - - setHandle2: function(point) { - point = Point.read(arguments); - this._segment2._handleIn.set(point.x, point.y); - }, - - getSegment1: function() { - return this._segment1; - }, - - getSegment2: function() { - return this._segment2; - }, - - getPath: function() { - return this._path; - }, - - getIndex: function() { - return this._segment1._index; - }, - - getNext: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index + 1] - || this._path._closed && curves[0]) || null; - }, - - getPrevious: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index - 1] - || this._path._closed && curves[curves.length - 1]) || null; - }, - - isSelected: function() { - return this.getHandle1().isSelected() && this.getHandle2().isSelected(); - }, - - setSelected: function(selected) { - this.getHandle1().setSelected(selected); - this.getHandle2().setSelected(selected); - }, - - getValues: function() { - return Curve.getValues(this._segment1, this._segment2); - }, - - getPoints: function() { - var coords = this.getValues(), - points = []; - for (var i = 0; i < 8; i += 2) - points.push(Point.create(coords[i], coords[i + 1])); - return points; - }, - - getLength: function() { - var from = arguments[0], - to = arguments[1]; - fullLength = arguments.length == 0 || from == 0 && to == 1; - if (fullLength && this._length != null) - return this._length; - var length = Curve.getLength(this.getValues(), from, to); - if (fullLength) - this._length = length; - return length; - }, - - getPart: function(from, to) { - return new Curve(Curve.getPart(this.getValues(), from, to)); - }, - - isLinear: function() { - return this._segment1._handleOut.isZero() - && this._segment2._handleIn.isZero(); - }, - - getParameterAt: function(offset, start) { - return Curve.getParameterAt(this.getValues(), offset, - start !== undefined ? start : offset < 0 ? 1 : 0); - }, - - getPoint: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 0); - }, - - getTangent: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 1); - }, - - getNormal: function(parameter) { - return Curve.evaluate(this.getValues(), parameter, 2); - }, - - getParameter: function(point) { - point = Point.read(point); - return Curve.getParameter(this.getValues(), point.x, point.y); - }, - - getCrossings: function(point, roots) { - var vals = this.getValues(), - num = Curve.solveCubic(vals, 1, point.y, roots), - crossings = 0; - for (var i = 0; i < num; i++) { - var t = roots[i]; - if (t >= 0 && t < 1 && Curve.evaluate(vals, t, 0).x > point.x) { - if (t < Numerical.TOLERANCE && Curve.evaluate( - this.getPrevious().getValues(), 1, 1).y - * Curve.evaluate(vals, t, 1).y >= 0) - continue; - crossings++; - } - } - return crossings; - }, - - reverse: function() { - return new Curve(this._segment2.reverse(), this._segment1.reverse()); - }, - - clone: function() { - return new Curve(this._segment1, this._segment2); - }, - - toString: function() { - var parts = [ 'point1: ' + this._segment1._point ]; - if (!this._segment1._handleOut.isZero()) - parts.push('handle1: ' + this._segment1._handleOut); - if (!this._segment2._handleIn.isZero()) - parts.push('handle2: ' + this._segment2._handleIn); - parts.push('point2: ' + this._segment2._point); - return '{ ' + parts.join(', ') + ' }'; - }, - - statics: { - create: function(path, segment1, segment2) { - var curve = new Curve(Curve.dont); - curve._path = path; - curve._segment1 = segment1; - curve._segment2 = segment2; - return curve; - }, - - getValues: function(segment1, segment2) { - var p1 = segment1._point, - h1 = segment1._handleOut, - h2 = segment2._handleIn, - p2 = segment2._point; - return [ - p1._x, p1._y, - p1._x + h1._x, p1._y + h1._y, - p2._x + h2._x, p2._y + h2._y, - p2._x, p2._y - ]; - }, - - evaluate: function(v, t, type) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - x, y; - - if (type == 0 && (t == 0 || t == 1)) { - x = t == 0 ? p1x : p2x; - y = t == 0 ? p1y : p2y; - } else { - var tMin = Numerical.TOLERANCE; - if (t < tMin && c1x == p1x && c1y == p1y) - t = tMin; - else if (t > 1 - tMin && c2x == p2x && c2y == p2y) - t = 1 - tMin; - var cx = 3 * (c1x - p1x), - bx = 3 * (c2x - c1x) - cx, - ax = p2x - p1x - cx - bx, - - cy = 3 * (c1y - p1y), - by = 3 * (c2y - c1y) - cy, - ay = p2y - p1y - cy - by; - - switch (type) { - case 0: - x = ((ax * t + bx) * t + cx) * t + p1x; - y = ((ay * t + by) * t + cy) * t + p1y; - break; - case 1: - case 2: - x = (3 * ax * t + 2 * bx) * t + cx; - y = (3 * ay * t + 2 * by) * t + cy; - break; - } - } - return type == 2 ? new Point(y, -x) : new Point(x, y); - }, - - subdivide: function(v, t) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7]; - if (t === undefined) - t = 0.5; - var u = 1 - t, - p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y, - p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y, - p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y, - p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y, - p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y, - p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y; - return [ - [p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], - [p8x, p8y, p7x, p7y, p5x, p5y, p2x, p2y] - ]; - }, - - solveCubic: function (v, coord, val, roots) { - var p1 = v[coord], - c1 = v[coord + 2], - c2 = v[coord + 4], - p2 = v[coord + 6], - c = 3 * (c1 - p1), - b = 3 * (c2 - c1) - c, - a = p2 - p1 - c - b; - return Numerical.solveCubic(a, b, c, p1 - val, roots, - Numerical.TOLERANCE); - }, - - getParameter: function(v, x, y) { - var txs = [], - tys = [], - sx = Curve.solveCubic(v, 0, x, txs), - sy = Curve.solveCubic(v, 1, y, tys), - tx, ty; - for (var cx = 0; sx == -1 || cx < sx;) { - if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) { - for (var cy = 0; sy == -1 || cy < sy;) { - if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) { - if (sx == -1) tx = ty; - else if (sy == -1) ty = tx; - if (Math.abs(tx - ty) < Numerical.TOLERANCE) - return (tx + ty) * 0.5; - } - } - if (sx == -1) - break; - } - } - return null; - }, - - getPart: function(v, from, to) { - if (from > 0) - v = Curve.subdivide(v, from)[1]; - if (to < 1) - v = Curve.subdivide(v, (to - from) / (1 - from))[0]; - return v; - }, - - isFlatEnough: function(v) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - ux = 3 * c1x - 2 * p1x - p2x, - uy = 3 * c1y - 2 * p1y - p2y, - vx = 3 * c2x - 2 * p2x - p1x, - vy = 3 * c2y - 2 * p2y - p1y; - return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy) < 1; - } - } -}, new function() { - - function getLengthIntegrand(v) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - - ax = 9 * (c1x - c2x) + 3 * (p2x - p1x), - bx = 6 * (p1x + c2x) - 12 * c1x, - cx = 3 * (c1x - p1x), - - ay = 9 * (c1y - c2y) + 3 * (p2y - p1y), - by = 6 * (p1y + c2y) - 12 * c1y, - cy = 3 * (c1y - p1y); - - return function(t) { - var dx = (ax * t + bx) * t + cx, - dy = (ay * t + by) * t + cy; - return Math.sqrt(dx * dx + dy * dy); - }; - } - - function getIterations(a, b) { - return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); - } - - return { - statics: true, - - getLength: function(v, a, b) { - if (a === undefined) - a = 0; - if (b === undefined) - b = 1; - if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) { - var dx = v[6] - v[0], - dy = v[7] - v[1]; - return (b - a) * Math.sqrt(dx * dx + dy * dy); - } - var ds = getLengthIntegrand(v); - return Numerical.integrate(ds, a, b, getIterations(a, b)); - }, - - getParameterAt: function(v, offset, start) { - if (offset == 0) - return start; - var forward = offset > 0, - a = forward ? start : 0, - b = forward ? 1 : start, - offset = Math.abs(offset), - ds = getLengthIntegrand(v), - rangeLength = Numerical.integrate(ds, a, b, - getIterations(a, b)); - if (offset >= rangeLength) - return forward ? b : a; - var guess = offset / rangeLength, - length = 0; - function f(t) { - var count = getIterations(start, t); - length += start < t - ? Numerical.integrate(ds, start, t, count) - : -Numerical.integrate(ds, t, start, count); - start = t; - return length - offset; - } - return Numerical.findRoot(f, ds, - forward ? a + guess : b - guess, - a, b, 16, Numerical.TOLERANCE); - } - }; -}, new function() { - - var maxDepth = 32, - epsilon = Math.pow(2, -maxDepth - 1); - - var zCubic = [ - [1.0, 0.6, 0.3, 0.1], - [0.4, 0.6, 0.6, 0.4], - [0.1, 0.3, 0.6, 1.0] - ]; - - var xAxis = new Line(new Point(0, 0), new Point(1, 0)); - - function toBezierForm(v, point) { - var n = 3, - degree = 5, - c = [], - d = [], - cd = [], - w = []; - for(var i = 0; i <= n; i++) { - c[i] = v[i].subtract(point); - if (i < n) - d[i] = v[i + 1].subtract(v[i]).multiply(n); - } - - for (var row = 0; row < n; row++) { - cd[row] = []; - for (var column = 0; column <= n; column++) - cd[row][column] = d[row].dot(c[column]); - } - - for (var i = 0; i <= degree; i++) - w[i] = new Point(i / degree, 0); - - for (k = 0; k <= degree; k++) { - var lb = Math.max(0, k - n + 1), - ub = Math.min(k, n); - for (var i = lb; i <= ub; i++) { - var j = k - i; - w[k].y += cd[j][i] * zCubic[j][i]; - } - } - - return w; - } - - function findRoots(w, depth) { - switch (countCrossings(w)) { - case 0: - return []; - case 1: - if (depth >= maxDepth) - return [0.5 * (w[0].x + w[5].x)]; - if (isFlatEnough(w)) { - var line = new Line(w[0], w[5], true); - return [ line.vector.getLength(true) <= Numerical.EPSILON - ? line.point.x - : xAxis.intersect(line).x ]; - } - } - - var p = [[]], - left = [], - right = []; - for (var j = 0; j <= 5; j++) - p[0][j] = new Point(w[j]); - - for (var i = 1; i <= 5; i++) { - p[i] = []; - for (var j = 0 ; j <= 5 - i; j++) - p[i][j] = p[i - 1][j].add(p[i - 1][j + 1]).multiply(0.5); - } - for (var j = 0; j <= 5; j++) { - left[j] = p[j][0]; - right[j] = p[5 - j][j]; - } - - return findRoots(left, depth + 1).concat(findRoots(right, depth + 1)); - } - - function countCrossings(v) { - var crossings = 0, - prevSign = null; - for (var i = 0, l = v.length; i < l; i++) { - var sign = v[i].y < 0 ? -1 : 1; - if (prevSign != null && sign != prevSign) - crossings++; - prevSign = sign; - } - return crossings; - } - - function isFlatEnough(v) { - - var n = v.length - 1, - a = v[0].y - v[n].y, - b = v[n].x - v[0].x, - c = v[0].x * v[n].y - v[n].x * v[0].y, - maxAbove = 0, - maxBelow = 0; - for (var i = 1; i < n; i++) { - var val = a * v[i].x + b * v[i].y + c, - dist = val * val; - if (val < 0 && dist > maxBelow) { - maxBelow = dist; - } else if (dist > maxAbove) { - maxAbove = dist; - } - } - return Math.abs((maxAbove + maxBelow) / (2 * a * (a * a + b * b))) - < epsilon; - } - - return { - getNearestLocation: function(point) { - var w = toBezierForm(this.getPoints(), point); - var roots = findRoots(w, 0).concat([0, 1]); - var minDist = Infinity, - minT, - minPoint; - for (var i = 0; i < roots.length; i++) { - var pt = this.getPoint(roots[i]), - dist = point.getDistance(pt, true); - if (dist < minDist) { - minDist = dist; - minT = roots[i]; - minPoint = pt; - } - } - return new CurveLocation(this, minT, minPoint, Math.sqrt(minDist)); - }, - - getNearestPoint: function(point) { - return this.getNearestLocation(point).getPoint(); - } - }; -}); - -CurveLocation = Base.extend({ - initialize: function(curve, parameter, point, distance) { - this._curve = curve; - this._parameter = parameter; - this._point = point; - this._distance = distance; - }, - - getSegment: function() { - if (!this._segment) { - var curve = this._curve, - parameter = this.getParameter(); - if (parameter == 0) { - this._segment = curve._segment1; - } else if (parameter == 1) { - this._segment = curve._segment2; - } else if (parameter == null) { - return null; - } else { - this._segment = curve.getLength(0, parameter) - < curve.getLength(parameter, 1) - ? curve._segment1 - : curve._segment2; - } - } - return this._segment; - }, - - getCurve: function() { - return this._curve; - }, - - getPath: function() { - return this._curve && this._curve._path; - }, - - getIndex: function() { - return this._curve && this._curve.getIndex(); - }, - - getOffset: function() { - var path = this._curve && this._curve._path; - return path && path._getOffset(this); - }, - - getCurveOffset: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getLength(0, parameter); - }, - - getParameter: function() { - if (this._parameter == null && this._curve && this._point) - this._parameter = this._curve.getParameterAt(this._point); - return this._parameter; - }, - - getPoint: function() { - if (!this._point && this._curve && this._parameter != null) - this._point = this._curve.getPoint(this._parameter); - return this._point; - }, - - getTangent: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getTangent(parameter); - }, - - getNormal: function() { - var parameter = this.getParameter(); - return parameter != null && this._curve - && this._curve.getNormal(parameter); - }, - - getDistance: function() { - return this._distance; - }, - - toString: function() { - var parts = [], - point = this.getPoint(); - if (point) - parts.push('point: ' + point); - var index = this.getIndex(); - if (index != null) - parts.push('index: ' + index); - var parameter = this.getParameter(); - if (parameter != null) - parts.push('parameter: ' + Base.formatNumber(parameter)); - if (this._distance != null) - parts.push('distance: ' + Base.formatNumber(this._distance)); - return '{ ' + parts.join(', ') + ' }'; - } -}); - -var PathItem = this.PathItem = Item.extend({ - -}); - -var Path = this.Path = PathItem.extend({ - initialize: function(segments) { - this.base(); - this._closed = false; - this._selectedSegmentState = 0; - this.setSegments(!segments || !Array.isArray(segments) - || typeof segments[0] !== 'object' ? arguments : segments); - }, - - clone: function() { - var copy = this._clone(new Path(this._segments)); - copy._closed = this._closed; - if (this._clockwise !== undefined) - copy._clockwise = this._clockwise; - return copy; - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & ChangeFlag.GEOMETRY) { - delete this._length; - delete this._clockwise; - if (this._curves != null) { - for (var i = 0, l = this._curves.length; i < l; i++) { - this._curves[i]._changed(Change.GEOMETRY); - } - } - } else if (flags & ChangeFlag.STROKE) { - delete this._bounds; - } - }, - - getSegments: function() { - return this._segments; - }, - - setSegments: function(segments) { - if (!this._segments) { - this._segments = []; - } else { - this._selectedSegmentState = 0; - this._segments.length = 0; - if (this._curves) - delete this._curves; - } - this._add(Segment.readAll(segments)); - }, - - getFirstSegment: function() { - return this._segments[0]; - }, - - getLastSegment: function() { - return this._segments[this._segments.length - 1]; - }, - - getCurves: function() { - if (!this._curves) { - var segments = this._segments, - length = segments.length; - if (!this._closed && length > 0) - length--; - this._curves = new Array(length); - for (var i = 0; i < length; i++) - this._curves[i] = Curve.create(this, segments[i], - segments[i + 1] || segments[0]); - } - return this._curves; - }, - - getFirstCurve: function() { - return this.getCurves()[0]; - }, - - getLastCurve: function() { - var curves = this.getCurves(); - return curves[curves.length - 1]; - }, - - getClosed: function() { - return this._closed; - }, - - setClosed: function(closed) { - if (this._closed != (closed = !!closed)) { - this._closed = closed; - if (this._curves) { - var length = this._segments.length, - i; - if (!closed && length > 0) - length--; - this._curves.length = length; - if (closed) - this._curves[i = length - 1] = Curve.create(this, - this._segments[i], this._segments[0]); - } - this._changed(Change.GEOMETRY); - } - }, - - transform: function(matrix) { - return this.base(matrix, true); - }, - - getMatrix: function() { - return null; - }, - - setMatrix: function(matrix) { - }, - - _apply: function(matrix) { - var coords = new Array(6); - for (var i = 0, l = this._segments.length; i < l; i++) { - this._segments[i]._transformCoordinates(matrix, coords, true); - } - var style = this._style, - fillColor = style._fillColor, - strokeColor = style._strokeColor; - if (fillColor && fillColor.transform) - fillColor.transform(matrix); - if (strokeColor && strokeColor.transform) - strokeColor.transform(matrix); - return true; - }, - - _add: function(segs, index) { - var segments = this._segments, - curves = this._curves, - amount = segs.length, - append = index == null, - index = append ? segments.length : index, - fullySelected = this.isFullySelected(); - for (var i = 0; i < amount; i++) { - var segment = segs[i]; - if (segment._path) { - segment = segs[i] = new Segment(segment); - } - segment._path = this; - segment._index = index + i; - if (fullySelected) - segment._selectionState = SelectionState.POINT; - if (segment._selectionState) - this._updateSelection(segment, 0, segment._selectionState); - } - if (append) { - segments.push.apply(segments, segs); - } else { - segments.splice.apply(segments, [index, 0].concat(segs)); - for (var i = index + amount, l = segments.length; i < l; i++) { - segments[i]._index = i; - } - } - if (curves && --index >= 0) { - curves.splice(index, 0, Curve.create(this, segments[index], - segments[index + 1])); - var curve = curves[index + amount]; - if (curve) { - curve._segment1 = segments[index + amount]; - } - } - this._changed(Change.GEOMETRY); - return segs; - }, - - add: function(segment1 ) { - return arguments.length > 1 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments)) - : this._add([ Segment.read(arguments) ])[0]; - }, - - insert: function(index, segment1 ) { - return arguments.length > 2 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments, 1), index) - : this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegment: function(segment) { - return this._add([ Segment.read(arguments) ])[0]; - }, - - insertSegment: function(index, segment) { - return this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegments: function(segments) { - return this._add(Segment.readAll(segments)); - }, - - insertSegments: function(index, segments) { - return this._add(Segment.readAll(segments), index); - }, - - removeSegment: function(index) { - var segments = this.removeSegments(index, index + 1); - return segments[0] || null; - }, - - removeSegments: function(from, to) { - from = from || 0; - to = Base.pick(to, this._segments.length); - var segments = this._segments, - curves = this._curves, - last = to >= segments.length, - removed = segments.splice(from, to - from), - amount = removed.length; - if (!amount) - return removed; - for (var i = 0; i < amount; i++) { - var segment = removed[i]; - if (segment._selectionState) - this._updateSelection(segment, segment._selectionState, 0); - removed._index = removed._path = undefined; - } - for (var i = from, l = segments.length; i < l; i++) - segments[i]._index = i; - if (curves) { - curves.splice(from, amount); - var curve; - if (curve = curves[from - 1]) - curve._segment2 = segments[from]; - if (curve = curves[from]) - curve._segment1 = segments[from]; - if (last && this._closed && (curve = curves[curves.length - 1])) - curve._segment2 = segments[0]; - } - this._changed(Change.GEOMETRY); - return removed; - }, - - isFullySelected: function() { - return this._selected && this._selectedSegmentState - == this._segments.length * SelectionState.POINT; - }, - - setFullySelected: function(selected) { - var length = this._segments.length; - this._selectedSegmentState = selected - ? length * SelectionState.POINT : 0; - for (var i = 0; i < length; i++) - this._segments[i]._selectionState = selected - ? SelectionState.POINT : 0; - this.setSelected(selected); - }, - - _updateSelection: function(segment, oldState, newState) { - segment._selectionState = newState; - var total = this._selectedSegmentState += newState - oldState; - if (total > 0) - this.setSelected(true); - }, - - flatten: function(maxDistance) { - var flattener = new PathFlattener(this), - pos = 0, - step = flattener.length / Math.ceil(flattener.length / maxDistance), - end = flattener.length + (this._closed ? -step : step) / 2; - var segments = []; - while (pos <= end) { - segments.push(new Segment(flattener.evaluate(pos, 0))); - pos += step; - } - this.setSegments(segments); - }, - - simplify: function(tolerance) { - if (this._segments.length > 2) { - var fitter = new PathFitter(this, tolerance || 2.5); - this.setSegments(fitter.fit()); - } - }, - - isClockwise: function() { - if (this._clockwise !== undefined) - return this._clockwise; - var sum = 0, - xPre, yPre; - function edge(x, y) { - if (xPre !== undefined) - sum += (xPre - x) * (y + yPre); - xPre = x; - yPre = y; - } - for (var i = 0, l = this._segments.length; i < l; i++) { - var seg1 = this._segments[i], - seg2 = this._segments[i + 1 < l ? i + 1 : 0], - point1 = seg1._point, - handle1 = seg1._handleOut, - handle2 = seg2._handleIn, - point2 = seg2._point; - edge(point1._x, point1._y); - edge(point1._x + handle1._x, point1._y + handle1._y); - edge(point2._x + handle2._x, point2._y + handle2._y); - edge(point2._x, point2._y); - } - return sum > 0; - }, - - setClockwise: function(clockwise) { - if (this.isClockwise() != (clockwise = !!clockwise)) { - this.reverse(); - this._clockwise = clockwise; - } - }, - - reverse: function() { - this._segments.reverse(); - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - var handleIn = segment._handleIn; - segment._handleIn = segment._handleOut; - segment._handleOut = handleIn; - segment._index = i; - } - if (this._clockwise !== undefined) - this._clockwise = !this._clockwise; - }, - - join: function(path) { - if (path) { - var segments = path._segments, - last1 = this.getLastSegment(), - last2 = path.getLastSegment(); - if (last1._point.equals(last2._point)) - path.reverse(); - var first2 = path.getFirstSegment(); - if (last1._point.equals(first2._point)) { - last1.setHandleOut(first2._handleOut); - this._add(segments.slice(1)); - } else { - var first1 = this.getFirstSegment(); - if (first1._point.equals(first2._point)) - path.reverse(); - last2 = path.getLastSegment(); - if (first1._point.equals(last2._point)) { - first1.setHandleIn(last2._handleIn); - this._add(segments.slice(0, segments.length - 1), 0); - } else { - this._add(segments.slice(0)); - } - } - path.remove(); - var first1 = this.getFirstSegment(); - last1 = this.getLastSegment(); - if (last1._point.equals(first1._point)) { - first1.setHandleIn(last1._handleIn); - last1.remove(); - this.setClosed(true); - } - this._changed(Change.GEOMETRY); - return true; - } - return false; - }, - - getLength: function() { - if (this._length == null) { - var curves = this.getCurves(); - this._length = 0; - for (var i = 0, l = curves.length; i < l; i++) - this._length += curves[i].getLength(); - } - return this._length; - }, - - _getOffset: function(location) { - var index = location && location.getIndex(); - if (index != null) { - var curves = this.getCurves(), - offset = 0; - for (var i = 0; i < index; i++) - offset += curves[i].getLength(); - var curve = curves[index]; - return offset + curve.getLength(0, location.getParameter()); - } - return null; - }, - - getLocation: function(point) { - var curves = this.getCurves(); - for (var i = 0, l = curves.length; i < l; i++) { - var curve = curves[i]; - var t = curve.getParameter(point); - if (t != null) - return new CurveLocation(curve, t); - } - return null; - }, - - getLocationAt: function(offset, isParameter) { - var curves = this.getCurves(), - length = 0; - if (isParameter) { - var index = ~~offset; - return new CurveLocation(curves[index], offset - index); - } - for (var i = 0, l = curves.length; i < l; i++) { - var start = length, - curve = curves[i]; - length += curve.getLength(); - if (length >= offset) { - return new CurveLocation(curve, - curve.getParameterAt(offset - start)); - } - } - if (offset <= this.getLength()) - return new CurveLocation(curves[curves.length - 1], 1); - return null; - }, - - getPointAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getPoint(); - }, - - getTangentAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getTangent(); - }, - - getNormalAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getNormal(); - }, - - getNearestLocation: function(point) { - var curves = this.getCurves(), - minDist = Infinity, - minLoc = null; - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getNearestLocation(point); - if (loc._distance < minDist) { - minDist = loc._distance; - minLoc = loc; - } - } - return minLoc; - }, - - getNearestPoint: function(point) { - return this.getNearestLocation(point).getPoint(); - }, - - contains: function(point) { - point = Point.read(arguments); - if (!this._closed || !this.getRoughBounds()._containsPoint(point)) - return false; - var curves = this.getCurves(), - crossings = 0, - roots = []; - for (var i = 0, l = curves.length; i < l; i++) - crossings += curves[i].getCrossings(point, roots); - return (crossings & 1) == 1; - }, - - _hitTest: function(point, options) { - var style = this._style, - tolerance = options.tolerance || 0, - radius = (options.stroke && style._strokeColor - ? style._strokeWidth / 2 : 0) + tolerance, - loc, - res; - var coords = [], - that = this; - function checkPoint(seg, pt, name) { - if (point.getDistance(pt) < tolerance) - return new HitResult(name, that, { segment: seg, point: pt }); - } - function checkSegment(seg, ends) { - var point = seg._point; - return (ends || options.segments) - && checkPoint(seg, point, 'segment') - || (!ends && options.handles) && ( - checkPoint(seg, point.add(seg._handleIn), 'handle-in') || - checkPoint(seg, point.add(seg._handleOut), 'handle-out')); - } - if (options.ends && !options.segments && !this._closed) { - if (res = checkSegment(this.getFirstSegment(), true) - || checkSegment(this.getLastSegment(), true)) - return res; - } else if (options.segments || options.handles) { - for (var i = 0, l = this._segments.length; i < l; i++) { - if (res = checkSegment(this._segments[i])) - return res; - } - } - if (options.stroke && radius > 0) - loc = this.getNearestLocation(point); - if (!(loc && loc._distance <= radius) && options.fill - && style._fillColor && this.contains(point)) - return new HitResult('fill', this); - if (!loc && options.stroke && radius > 0) - loc = this.getNearestLocation(point); - if (loc && loc._distance <= radius) - return options.stroke - ? new HitResult('stroke', this, { location: loc }) - : new HitResult('fill', this); - } - -}, new function() { - - function drawHandles(ctx, segments, matrix) { - var coords = new Array(6); - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i]; - segment._transformCoordinates(matrix, coords, false); - var state = segment._selectionState, - selected = state & SelectionState.POINT, - pX = coords[0], - pY = coords[1]; - - function drawHandle(index) { - var hX = coords[index], - hY = coords[index + 1]; - if (pX != hX || pY != hY) { - ctx.beginPath(); - ctx.moveTo(pX, pY); - ctx.lineTo(hX, hY); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(hX, hY, 1.75, 0, Math.PI * 2, true); - ctx.fill(); - } - } - - if (selected || (state & SelectionState.HANDLE_IN)) - drawHandle(2); - if (selected || (state & SelectionState.HANDLE_OUT)) - drawHandle(4); - ctx.save(); - ctx.beginPath(); - ctx.rect(pX - 2, pY - 2, 4, 4); - ctx.fill(); - if (!selected) { - ctx.beginPath(); - ctx.rect(pX - 1, pY - 1, 2, 2); - ctx.fillStyle = '#ffffff'; - ctx.fill(); - } - ctx.restore(); - } - } - - function drawSegments(ctx, path, matrix) { - var segments = path._segments, - length = segments.length, - coords = new Array(6), - first = true, - pX, pY, - inX, inY, - outX, outY; - - function drawSegment(i) { - var segment = segments[i]; - if (matrix) { - segment._transformCoordinates(matrix, coords, false); - pX = coords[0]; - pY = coords[1]; - } else { - var point = segment._point; - pX = point._x; - pY = point._y; - } - if (first) { - ctx.moveTo(pX, pY); - first = false; - } else { - if (matrix) { - inX = coords[2]; - inY = coords[3]; - } else { - var handle = segment._handleIn; - inX = pX + handle._x; - inY = pY + handle._y; - } - if (inX == pX && inY == pY && outX == pX && outY == pY) { - ctx.lineTo(pX, pY); - } else { - ctx.bezierCurveTo(outX, outY, inX, inY, pX, pY); - } - } - if (matrix) { - outX = coords[4]; - outY = coords[5]; - } else { - var handle = segment._handleOut; - outX = pX + handle._x; - outY = pY + handle._y; - } - } - - for (var i = 0; i < length; i++) - drawSegment(i); - if (path._closed && length > 1) - drawSegment(0); - } - - return { - draw: function(ctx, param) { - if (!param.compound) - ctx.beginPath(); - - var style = this._style, - fillColor = style._fillColor, - strokeColor = style._strokeColor, - dashArray = style._dashArray, - hasDash = strokeColor && dashArray && dashArray.length; - - if (param.compound || this._clipMask || fillColor - || strokeColor && !hasDash) { - drawSegments(ctx, this); - } - - if (this._closed) - ctx.closePath(); - - if (this._clipMask) { - ctx.clip(); - } else if (!param.compound && (fillColor || strokeColor)) { - ctx.save(); - this._setStyles(ctx); - if (fillColor) - ctx.fill(); - if (strokeColor) { - if (hasDash) { - ctx.beginPath(); - var flattener = new PathFlattener(this), - from = style._dashOffset, to, - i = 0; - while (from < flattener.length) { - to = from + dashArray[(i++) % dashArray.length]; - flattener.drawPart(ctx, from, to); - from = to + dashArray[(i++) % dashArray.length]; - } - } - ctx.stroke(); - } - ctx.restore(); - } - }, - - drawSelected: function(ctx, matrix) { - ctx.beginPath(); - drawSegments(ctx, this, matrix); - ctx.stroke(); - drawHandles(ctx, this._segments, matrix); - } - }; -}, new function() { - - function getFirstControlPoints(rhs) { - var n = rhs.length, - x = [], - tmp = [], - b = 2; - x[0] = rhs[0] / b; - for (var i = 1; i < n; i++) { - tmp[i] = 1 / b; - b = (i < n - 1 ? 4 : 2) - tmp[i]; - x[i] = (rhs[i] - x[i - 1]) / b; - } - for (var i = 1; i < n; i++) { - x[n - i - 1] -= tmp[n - i] * x[n - i]; - } - return x; - }; - - return { - smooth: function() { - var segments = this._segments, - size = segments.length, - n = size, - overlap; - - if (size <= 2) - return; - - if (this._closed) { - overlap = Math.min(size, 4); - n += Math.min(size, overlap) * 2; - } else { - overlap = 0; - } - var knots = []; - for (var i = 0; i < size; i++) - knots[i + overlap] = segments[i]._point; - if (this._closed) { - for (var i = 0; i < overlap; i++) { - knots[i] = segments[i + size - overlap]._point; - knots[i + size + overlap] = segments[i]._point; - } - } else { - n--; - } - var rhs = []; - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._x + 2 * knots[i + 1]._x; - rhs[0] = knots[0]._x + 2 * knots[1]._x; - rhs[n - 1] = 3 * knots[n - 1]._x; - var x = getFirstControlPoints(rhs); - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._y + 2 * knots[i + 1]._y; - rhs[0] = knots[0]._y + 2 * knots[1]._y; - rhs[n - 1] = 3 * knots[n - 1]._y; - var y = getFirstControlPoints(rhs); - - if (this._closed) { - for (var i = 0, j = size; i < overlap; i++, j++) { - var f1 = (i / overlap); - var f2 = 1 - f1; - x[j] = x[i] * f1 + x[j] * f2; - y[j] = y[i] * f1 + y[j] * f2; - var ie = i + overlap, je = j + overlap; - x[je] = x[ie] * f2 + x[je] * f1; - y[je] = y[ie] * f2 + y[je] * f1; - } - n--; - } - var handleIn = null; - for (var i = overlap; i <= n - overlap; i++) { - var segment = segments[i - overlap]; - if (handleIn) - segment.setHandleIn(handleIn.subtract(segment._point)); - if (i < n) { - segment.setHandleOut( - Point.create(x[i], y[i]).subtract(segment._point)); - if (i < n - 1) - handleIn = Point.create( - 2 * knots[i + 1]._x - x[i + 1], - 2 * knots[i + 1]._y - y[i + 1]); - else - handleIn = Point.create( - (knots[n]._x + x[n - 1]) / 2, - (knots[n]._y + y[n - 1]) / 2); - } - } - if (this._closed && handleIn) { - var segment = this._segments[0]; - segment.setHandleIn(handleIn.subtract(segment._point)); - } - } - }; -}, new function() { - function getCurrentSegment(that) { - var segments = that._segments; - if (segments.length == 0) - throw new Error('Use a moveTo() command first'); - return segments[segments.length - 1]; - } - - return { - moveTo: function(point) { - if (!this._segments.length) - this._add([ new Segment(Point.read(arguments)) ]); - }, - - moveBy: function(point) { - throw new Error('moveBy() is unsupported on Path items.'); - }, - - lineTo: function(point) { - this._add([ new Segment(Point.read(arguments)) ]); - }, - - cubicCurveTo: function(handle1, handle2, to) { - handle1 = Point.read(arguments, 0, 1); - handle2 = Point.read(arguments, 1, 1); - to = Point.read(arguments, 2, 1); - var current = getCurrentSegment(this); - current.setHandleOut(handle1.subtract(current._point)); - this._add([ new Segment(to, handle2.subtract(to)) ]); - }, - - quadraticCurveTo: function(handle, to) { - handle = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - var current = getCurrentSegment(this)._point; - this.cubicCurveTo( - handle.add(current.subtract(handle).multiply(1/3)), - handle.add(to.subtract(handle).multiply(1/3)), - to - ); - }, - - curveTo: function(through, to, parameter) { - through = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - var t = Base.pick(parameter, 0.5), - t1 = 1 - t, - current = getCurrentSegment(this)._point, - handle = through.subtract(current.multiply(t1 * t1)) - .subtract(to.multiply(t * t)).divide(2 * t * t1); - if (handle.isNaN()) - throw new Error( - 'Cannot put a curve through points with parameter = ' + t); - this.quadraticCurveTo(handle, to); - }, - - arcTo: function(to, clockwise ) { - var current = getCurrentSegment(this), - from = current._point, - through; - if (clockwise === undefined) - clockwise = true; - if (typeof clockwise === 'boolean') { - to = Point.read(arguments, 0, 1); - var middle = from.add(to).divide(2), - through = middle.add(middle.subtract(from).rotate( - clockwise ? -90 : 90)); - } else { - through = Point.read(arguments, 0, 1); - to = Point.read(arguments, 1, 1); - } - var l1 = new Line(from.add(through).divide(2), - through.subtract(from).rotate(90)), - l2 = new Line(through.add(to).divide(2), - to.subtract(through).rotate(90)), - center = l1.intersect(l2), - line = new Line(from, to, true), - throughSide = line.getSide(through); - if (!center) { - if (!throughSide) - return this.lineTo(to); - throw new Error("Cannot put an arc through the given points: " - + [from, through, to]); - } - var vector = from.subtract(center), - radius = vector.getLength(), - extent = vector.getDirectedAngle(to.subtract(center)), - centerSide = line.getSide(center); - if (centerSide == 0) { - extent = throughSide * Math.abs(extent); - } else if (throughSide == centerSide) { - extent -= 360 * (extent < 0 ? -1 : 1); - } - var ext = Math.abs(extent), - count = ext >= 360 ? 4 : Math.ceil(ext / 90), - inc = extent / count, - half = inc * Math.PI / 360, - z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), - segments = []; - for (var i = 0; i <= count; i++) { - var pt = i < count ? center.add(vector) : to; - var out = i < count ? vector.rotate(90).multiply(z) : null; - if (i == 0) { - current.setHandleOut(out); - } else { - segments.push( - new Segment(pt, vector.rotate(-90).multiply(z), out)); - } - vector = vector.rotate(inc); - } - this._add(segments); - }, - - lineBy: function(vector) { - vector = Point.read(arguments); - var current = getCurrentSegment(this); - this.lineTo(current._point.add(vector)); - }, - - curveBy: function(throughVector, toVector, parameter) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.curveTo(current.add(throughVector), current.add(toVector), - parameter); - }, - - arcBy: function(throughVector, toVector) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.arcBy(current.add(throughVector), current.add(toVector)); - }, - - closePath: function() { - this.setClosed(true); - } - }; -}, new function() { - function getBounds(matrix, strokePadding) { - var segments = this._segments, - first = segments[0]; - if (!first) - return null; - var coords = new Array(6), - prevCoords = new Array(6); - first._transformCoordinates(matrix, prevCoords, false); - var min = prevCoords.slice(0, 2), - max = min.slice(0), - tMin = Numerical.TOLERANCE, - tMax = 1 - tMin; - function processSegment(segment) { - segment._transformCoordinates(matrix, coords, false); - - for (var i = 0; i < 2; i++) { - var v0 = prevCoords[i], - v1 = prevCoords[i + 4], - v2 = coords[i + 2], - v3 = coords[i]; - - function add(value, t) { - var padding = 0; - if (value == null) { - var u = 1 - t; - value = u * u * u * v0 - + 3 * u * u * t * v1 - + 3 * u * t * t * v2 - + t * t * t * v3; - padding = strokePadding ? strokePadding[i] : 0; - } - var left = value - padding, - right = value + padding; - if (left < min[i]) - min[i] = left; - if (right > max[i]) - max[i] = right; - - } - add(v3, null); - - var a = 3 * (v1 - v2) - v0 + v3, - b = 2 * (v0 + v2) - 4 * v1, - c = v1 - v0; - - if (a == 0) { - if (b == 0) - continue; - var t = -c / b; - if (tMin < t && t < tMax) - add(null, t); - continue; - } - - var q = b * b - 4 * a * c; - if (q < 0) - continue; - var sqrt = Math.sqrt(q), - f = -0.5 / a, - t1 = (b - sqrt) * f, - t2 = (b + sqrt) * f; - if (tMin < t1 && t1 < tMax) - add(null, t1); - if (tMin < t2 && t2 < tMax) - add(null, t2); - } - var tmp = prevCoords; - prevCoords = coords; - coords = tmp; - } - for (var i = 1, l = segments.length; i < l; i++) - processSegment(segments[i]); - if (this._closed) - processSegment(first); - return Rectangle.create(min[0], min[1], - max[0] - min[0], max[1] - min[1]); - } - - function getPenPadding(radius, matrix) { - if (!matrix) - return [radius, radius]; - var mx = matrix.createShiftless(), - hor = mx.transform(Point.create(radius, 0)), - ver = mx.transform(Point.create(0, radius)), - phi = hor.getAngleInRadians(), - a = hor.getLength(), - b = ver.getLength(); - var sin = Math.sin(phi), - cos = Math.cos(phi), - tan = Math.tan(phi), - tx = -Math.atan(b * tan / a), - ty = Math.atan(b / (tan * a)); - return [Math.abs(a * Math.cos(tx) * cos - b * Math.sin(tx) * sin), - Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)]; - } - - function getStrokeBounds(matrix) { - var style = this._style; - if (!style._strokeColor || !style._strokeWidth) - return getBounds.call(this, matrix); - var width = style._strokeWidth, - radius = width / 2, - padding = getPenPadding(radius, matrix), - join = style._strokeJoin, - cap = style._strokeCap, - miter = style._miterLimit * width / 2, - segments = this._segments, - length = segments.length, - bounds = getBounds.call(this, matrix, padding); - var joinBounds = new Rectangle(new Size(padding).multiply(2)); - - function add(point) { - bounds = bounds.include(matrix - ? matrix._transformPoint(point, point) : point); - } - - function addBevelJoin(curve, t) { - var point = curve.getPoint(t), - normal = curve.getNormal(t).normalize(radius); - add(point.add(normal)); - add(point.subtract(normal)); - } - - function addJoin(segment, join) { - if (join === 'round' || !segment._handleIn.isZero() - && !segment._handleOut.isZero()) { - bounds = bounds.unite(joinBounds.setCenter(matrix - ? matrix._transformPoint(segment._point) : segment._point)); - } else if (join == 'bevel') { - var curve = segment.getCurve(); - addBevelJoin(curve, 0); - addBevelJoin(curve.getPrevious(), 1); - } else if (join == 'miter') { - var curve2 = segment.getCurve(), - curve1 = curve2.getPrevious(), - point = curve2.getPoint(0), - normal1 = curve1.getNormal(1).normalize(radius), - normal2 = curve2.getNormal(0).normalize(radius), - line1 = new Line(point.subtract(normal1), - Point.create(-normal1.y, normal1.x)), - line2 = new Line(point.subtract(normal2), - Point.create(-normal2.y, normal2.x)), - corner = line1.intersect(line2); - if (!corner || point.getDistance(corner) > miter) { - addJoin(segment, 'bevel'); - } else { - add(corner); - } - } - } - - function addCap(segment, cap, t) { - switch (cap) { - case 'round': - return addJoin(segment, cap); - case 'butt': - case 'square': - var curve = segment.getCurve(), - point = curve.getPoint(t), - normal = curve.getNormal(t).normalize(radius); - if (cap === 'square') - point = point.add(normal.rotate(t == 0 ? -90 : 90)); - add(point.add(normal)); - add(point.subtract(normal)); - break; - } - } - - for (var i = 1, l = length - (this._closed ? 0 : 1); i < l; i++) { - addJoin(segments[i], join); - } - if (this._closed) { - addJoin(segments[0], join); - } else { - addCap(segments[0], cap, 0); - addCap(segments[length - 1], cap, 1); - } - return bounds; - } - - function getHandleBounds(matrix, stroke, join) { - var coords = new Array(6), - x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - stroke = stroke / 2 || 0; - join = join / 2 || 0; - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - segment._transformCoordinates(matrix, coords, false); - for (var j = 0; j < 6; j += 2) { - var padding = j == 0 ? join : stroke, - x = coords[j], - y = coords[j + 1], - xn = x - padding, - xx = x + padding, - yn = y - padding, - yx = y + padding; - if (xn < x1) x1 = xn; - if (xx > x2) x2 = xx; - if (yn < y1) y1 = yn; - if (yx > y2) y2 = yx; - } - } - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - } - - function getRoughBounds(matrix) { - var style = this._style, - width = style._strokeWidth; - return getHandleBounds.call(this, matrix, width, - style._strokeJoin == 'miter' - ? width * style._miterLimit - : width); - } - - var get = { - bounds: getBounds, - strokeBounds: getStrokeBounds, - handleBounds: getHandleBounds, - roughBounds: getRoughBounds - }; - - return { - _getBounds: function(type, matrix) { - return get[type].call(this, matrix); - } - }; -}); - -Path.inject({ statics: new function() { - var kappa = 2 / 3 * (Math.sqrt(2) - 1); - - var ovalSegments = [ - new Segment([0, 0.5], [0, kappa ], [0, -kappa]), - new Segment([0.5, 0], [-kappa, 0], [kappa, 0 ]), - new Segment([1, 0.5], [0, -kappa], [0, kappa ]), - new Segment([0.5, 1], [kappa, 0 ], [-kappa, 0]) - ]; - - return { - Line: function() { - var step = Math.floor(arguments.length / 2); - return new Path( - Segment.read(arguments, 0, step), - Segment.read(arguments, step, step) - ); - }, - - Rectangle: function(rect) { - rect = Rectangle.read(arguments); - var left = rect.x, - top = rect.y, - right = left + rect.width, - bottom = top + rect.height, - path = new Path(); - path._add([ - new Segment(Point.create(left, bottom)), - new Segment(Point.create(left, top)), - new Segment(Point.create(right, top)), - new Segment(Point.create(right, bottom)) - ]); - path._closed = true; - return path; - }, - - RoundRectangle: function(rect, size) { - if (arguments.length == 2) { - rect = Rectangle.read(arguments, 0, 1); - size = Size.read(arguments, 1, 1); - } else if (arguments.length == 6) { - rect = Rectangle.read(arguments, 0, 4); - size = Size.read(arguments, 4, 2); - } - size = Size.min(size, rect.getSize(true).divide(2)); - var path = new Path(), - uSize = size.multiply(kappa * 2), - bl = rect.getBottomLeft(true), - tl = rect.getTopLeft(true), - tr = rect.getTopRight(true), - br = rect.getBottomRight(true); - path._add([ - new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]), - new Segment(bl.subtract(0, size.height), [0, uSize.height], null), - - new Segment(tl.add(0, size.height), null, [0, -uSize.height]), - new Segment(tl.add(size.width, 0), [-uSize.width, 0], null), - - new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]), - new Segment(tr.add(0, size.height), [0, -uSize.height], null), - - new Segment(br.subtract(0, size.height), null, [0, uSize.height]), - new Segment(br.subtract(size.width, 0), [uSize.width, 0], null) - ]); - path._closed = true; - return path; - }, - - Oval: function(rect) { - rect = Rectangle.read(arguments); - var path = new Path(), - point = rect.getPoint(true), - size = rect.getSize(true), - segments = new Array(4); - for (var i = 0; i < 4; i++) { - var segment = ovalSegments[i]; - segments[i] = new Segment( - segment._point.multiply(size).add(point), - segment._handleIn.multiply(size), - segment._handleOut.multiply(size) - ); - } - path._add(segments); - path._closed = true; - return path; - }, - - Circle: function(center, radius) { - if (arguments.length == 3) { - center = Point.read(arguments, 0, 2); - radius = arguments[2]; - } else { - center = Point.read(arguments, 0, 1); - } - return Path.Oval(new Rectangle(center.subtract(radius), - Size.create(radius * 2, radius * 2))); - }, - - Arc: function(from, through, to) { - var path = new Path(); - path.moveTo(from); - path.arcTo(through, to); - return path; - }, - - RegularPolygon: function(center, numSides, radius) { - center = Point.read(arguments, 0, 1); - var path = new Path(), - step = 360 / numSides, - three = !(numSides % 3), - vector = new Point(0, three ? -radius : radius), - offset = three ? -1 : 0.5, - segments = new Array(numSides); - for (var i = 0; i < numSides; i++) { - segments[i] = new Segment(center.add( - vector.rotate((i + offset) * step))); - } - path._add(segments); - path._closed = true; - return path; - }, - - Star: function(center, numPoints, radius1, radius2) { - center = Point.read(arguments, 0, 1); - numPoints *= 2; - var path = new Path(), - step = 360 / numPoints, - vector = new Point(0, -1), - segments = new Array(numPoints); - for (var i = 0; i < numPoints; i++) { - segments[i] = new Segment(center.add( - vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); - } - path._add(segments); - path._closed = true; - return path; - } - }; -}}); - -var CompoundPath = this.CompoundPath = PathItem.extend({ - initialize: function(paths) { - this.base(); - this._children = []; - this._namedChildren = {}; - var items = !paths || !Array.isArray(paths) - || typeof paths[0] !== 'object' ? arguments : paths; - this.addChildren(items); - }, - - insertChild: function(index, item) { - this.base(index, item); - if (item._clockwise === undefined) - item.setClockwise(item._index == 0); - }, - - simplify: function() { - if (this._children.length == 1) { - var child = this._children[0]; - child.insertAbove(this); - this.remove(); - return child; - } - return this; - }, - - smooth: function() { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].smooth(); - }, - - draw: function(ctx, param) { - var children = this._children; - if (children.length == 0) - return; - var firstChild = children[0], - style = firstChild._style; - ctx.beginPath(); - param.compound = true; - for (var i = 0, l = children.length; i < l; i++) - Item.draw(children[i], ctx, param); - firstChild._setStyles(ctx); - if (style._fillColor) - ctx.fill(); - if (style._strokeColor) - ctx.stroke(); - param.compound = false; - } -}, new function() { - function getCurrentPath(that) { - if (!that._children.length) - throw new Error('Use a moveTo() command first'); - return that._children[that._children.length - 1]; - } - - var fields = { - moveTo: function(point) { - var path = new Path(); - this.addChild(path); - path.moveTo.apply(path, arguments); - }, - - moveBy: function(point) { - this.moveTo(getCurrentPath(this).getLastSegment()._point.add( - Point.read(arguments))); - }, - - closePath: function() { - getCurrentPath(this).setClosed(true); - } - }; - - Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', - 'arcTo', 'lineBy', 'curveBy', 'arcBy'], function(key) { - fields[key] = function() { - var path = getCurrentPath(this); - path[key].apply(path, arguments); - }; - }); - - return fields; -}); - -var PathFlattener = Base.extend({ - initialize: function(path) { - this.curves = []; - this.parts = []; - this.length = 0; - this.index = 0; - - var segments = path._segments, - segment1 = segments[0], - segment2, - that = this; - - function addCurve(segment1, segment2) { - var curve = Curve.getValues(segment1, segment2); - that.curves.push(curve); - that._computeParts(curve, segment1._index, 0, 1); - } - - for (var i = 1, l = segments.length; i < l; i++) { - segment2 = segments[i]; - addCurve(segment1, segment2); - segment1 = segment2; - } - if (path._closed) - addCurve(segment2, segments[0]); - }, - - _computeParts: function(curve, index, minT, maxT) { - if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough(curve)) { - var curves = Curve.subdivide(curve); - var halfT = (minT + maxT) / 2; - this._computeParts(curves[0], index, minT, halfT); - this._computeParts(curves[1], index, halfT, maxT); - } else { - var x = curve[6] - curve[0], - y = curve[7] - curve[1], - dist = Math.sqrt(x * x + y * y); - if (dist > Numerical.TOLERANCE) { - this.length += dist; - this.parts.push({ - offset: this.length, - value: maxT, - index: index - }); - } - } - }, - - getParameterAt: function(offset) { - var i, j = this.index; - for (;;) { - i = j; - if (j == 0 || this.parts[--j].offset < offset) - break; - } - for (var l = this.parts.length; i < l; i++) { - var part = this.parts[i]; - if (part.offset >= offset) { - this.index = i; - var prev = this.parts[i - 1]; - var prevVal = prev && prev.index == part.index ? prev.value : 0, - prevLen = prev ? prev.offset : 0; - return { - value: prevVal + (part.value - prevVal) - * (offset - prevLen) / (part.offset - prevLen), - index: part.index - }; - } - } - var part = this.parts[this.parts.length - 1]; - return { - value: 1, - index: part.index - }; - }, - - evaluate: function(offset, type) { - var param = this.getParameterAt(offset); - return Curve.evaluate(this.curves[param.index], param.value, type); - }, - - drawPart: function(ctx, from, to) { - from = this.getParameterAt(from); - to = this.getParameterAt(to); - for (var i = from.index; i <= to.index; i++) { - var curve = Curve.getPart(this.curves[i], - i == from.index ? from.value : 0, - i == to.index ? to.value : 1); - if (i == from.index) - ctx.moveTo(curve[0], curve[1]); - ctx.bezierCurveTo.apply(ctx, curve.slice(2)); - } - } -}); - -var PathFitter = Base.extend({ - initialize: function(path, error) { - this.points = []; - var segments = path._segments, - prev; - for (var i = 0, l = segments.length; i < l; i++) { - var point = segments[i].point.clone(); - if (!prev || !prev.equals(point)) { - this.points.push(point); - prev = point; - } - } - this.error = error; - }, - - fit: function() { - this.segments = [new Segment(this.points[0])]; - this.fitCubic(0, this.points.length - 1, - this.points[1].subtract(this.points[0]).normalize(), - this.points[this.points.length - 2].subtract( - this.points[this.points.length - 1]).normalize()); - return this.segments; - }, - - fitCubic: function(first, last, tan1, tan2) { - if (last - first == 1) { - var pt1 = this.points[first], - pt2 = this.points[last], - dist = pt1.getDistance(pt2) / 3; - this.addCurve([pt1, pt1.add(tan1.normalize(dist)), - pt2.add(tan2.normalize(dist)), pt2]); - return; - } - var uPrime = this.chordLengthParameterize(first, last), - maxError = Math.max(this.error, this.error * this.error), - error, - split; - for (var i = 0; i <= 4; i++) { - var curve = this.generateBezier(first, last, uPrime, tan1, tan2); - var max = this.findMaxError(first, last, curve, uPrime); - if (max.error < this.error) { - this.addCurve(curve); - return; - } - split = max.index; - if (max.error >= maxError) - break; - this.reparameterize(first, last, uPrime, curve); - maxError = max.error; - } - var V1 = this.points[split - 1].subtract(this.points[split]), - V2 = this.points[split].subtract(this.points[split + 1]), - tanCenter = V1.add(V2).divide(2).normalize(); - this.fitCubic(first, split, tan1, tanCenter); - this.fitCubic(split, last, tanCenter.negate(), tan2); - }, - - addCurve: function(curve) { - var prev = this.segments[this.segments.length - 1]; - prev.setHandleOut(curve[1].subtract(curve[0])); - this.segments.push( - new Segment(curve[3], curve[2].subtract(curve[3]))); - }, - - generateBezier: function(first, last, uPrime, tan1, tan2) { - var epsilon = Numerical.EPSILON, - pt1 = this.points[first], - pt2 = this.points[last], - C = [[0, 0], [0, 0]], - X = [0, 0]; - - for (var i = 0, l = last - first + 1; i < l; i++) { - var u = uPrime[i], - t = 1 - u, - b = 3 * u * t, - b0 = t * t * t, - b1 = b * t, - b2 = b * u, - b3 = u * u * u, - a1 = tan1.normalize(b1), - a2 = tan2.normalize(b2), - tmp = this.points[first + i] - .subtract(pt1.multiply(b0 + b1)) - .subtract(pt2.multiply(b2 + b3)); - C[0][0] += a1.dot(a1); - C[0][1] += a1.dot(a2); - C[1][0] = C[0][1]; - C[1][1] += a2.dot(a2); - X[0] += a1.dot(tmp); - X[1] += a2.dot(tmp); - } - - var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], - alpha1, alpha2; - if (Math.abs(detC0C1) > epsilon) { - var detC0X = C[0][0] * X[1] - C[1][0] * X[0], - detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; - alpha1 = detXC1 / detC0C1; - alpha2 = detC0X / detC0C1; - } else { - var c0 = C[0][0] + C[0][1], - c1 = C[1][0] + C[1][1]; - if (Math.abs(c0) > epsilon) { - alpha1 = alpha2 = X[0] / c0; - } else if (Math.abs(c1) > epsilon) { - alpha1 = alpha2 = X[1] / c1; - } else { - alpha1 = alpha2 = 0.; - } - } - - var segLength = pt2.getDistance(pt1); - epsilon *= segLength; - if (alpha1 < epsilon || alpha2 < epsilon) { - alpha1 = alpha2 = segLength / 3; - } - - return [pt1, pt1.add(tan1.normalize(alpha1)), - pt2.add(tan2.normalize(alpha2)), pt2]; - }, - - reparameterize: function(first, last, u, curve) { - for (var i = first; i <= last; i++) { - u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); - } - }, - - findRoot: function(curve, point, u) { - var curve1 = [], - curve2 = []; - for (var i = 0; i <= 2; i++) { - curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); - } - for (var i = 0; i <= 1; i++) { - curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); - } - var pt = this.evaluate(3, curve, u), - pt1 = this.evaluate(2, curve1, u), - pt2 = this.evaluate(1, curve2, u), - diff = pt.subtract(point), - df = pt1.dot(pt1) + diff.dot(pt2); - if (Math.abs(df) < Numerical.TOLERANCE) - return u; - return u - diff.dot(pt1) / df; - }, - - evaluate: function(degree, curve, t) { - var tmp = curve.slice(); - for (var i = 1; i <= degree; i++) { - for (var j = 0; j <= degree - i; j++) { - tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); - } - } - return tmp[0]; - }, - - chordLengthParameterize: function(first, last) { - var u = [0]; - for (var i = first + 1; i <= last; i++) { - u[i - first] = u[i - first - 1] - + this.points[i].getDistance(this.points[i - 1]); - } - for (var i = 1, m = last - first; i <= m; i++) { - u[i] /= u[m]; - } - return u; - }, - - findMaxError: function(first, last, curve, u) { - var index = Math.floor((last - first + 1) / 2), - maxDist = 0; - for (var i = first + 1; i < last; i++) { - var P = this.evaluate(3, curve, u[i - first]); - var v = P.subtract(this.points[i]); - var dist = v.x * v.x + v.y * v.y; - if (dist >= maxDist) { - maxDist = dist; - index = i; - } - } - return { - error: maxDist, - index: index - }; - } -}); - -var TextItem = this.TextItem = Item.extend({ - _boundsType: 'bounds', - - initialize: function(pointOrMatrix) { - this._style = CharacterStyle.create(this); - this._paragraphStyle = ParagraphStyle.create(this); - this.base(pointOrMatrix); - this.setParagraphStyle(); - this._content = ''; - this._lines = []; - }, - - _clone: function(copy) { - copy.setContent(this._content); - copy.setParagraphStyle(this._paragraphStyle); - return this.base(copy); - }, - - getContent: function() { - return this._content; - }, - - setContent: function(content) { - this._content = '' + content; - this._lines = this._content.split(/\r\n|\n|\r/mg); - this._changed(Change.CONTENT); - }, - - getCharacterStyle: function() { - return this.getStyle(); - }, - - setCharacterStyle: function(style) { - this.setStyle(style); - } - -}); - -var PointText = this.PointText = TextItem.extend({ - initialize: function(pointOrMatrix) { - this.base(pointOrMatrix); - this._point = this._matrix.getTranslation(); - }, - - clone: function() { - return this._clone(new PointText(this._matrix)); - }, - - getPoint: function() { - return LinkedPoint.create(this, 'setPoint', - this._point.x, this._point.y); - }, - - setPoint: function(point) { - this.translate(Point.read(arguments).subtract(this._point)); - }, - - _transform: function(matrix) { - matrix._transformPoint(this._point, this._point); - }, - - draw: function(ctx) { - if (!this._content) - return; - this._setStyles(ctx); - var style = this._style, - leading = this.getLeading(), - lines = this._lines; - ctx.font = style.getFontStyle(); - ctx.textAlign = this.getJustification(); - for (var i = 0, l = lines.length; i < l; i++) { - var line = lines[i]; - if (style._fillColor) - ctx.fillText(line, 0, 0); - if (style._strokeColor) - ctx.strokeText(line, 0, 0); - ctx.translate(0, leading); - } - } -}, new function() { - var context = null; - - return { - _getBounds: function(type, matrix) { - if (!context) - context = CanvasProvider.getCanvas( - Size.create(1, 1)).getContext('2d'); - var justification = this.getJustification(), - x = 0; - context.font = this._style.getFontStyle(); - var width = 0; - for (var i = 0, l = this._lines.length; i < l; i++) - width = Math.max(width, context.measureText( - this._lines[i]).width); - if (justification !== 'left') - x -= width / (justification === 'center' ? 2: 1); - var leading = this.getLeading(), - count = this._lines.length, - bounds = Rectangle.create(x, - count ? leading / 4 + (count - 1) * leading : 0, - width, -count * leading); - return matrix ? matrix._transformBounds(bounds, bounds) : bounds; - } - }; -}); - -var Style = Item.extend({ - initialize: function(style) { - var clone = style instanceof Style; - return Base.each(this._defaults, function(value, key) { - value = style && style[key] || value; - this[key] = value && clone && value.clone - ? value.clone() : value; - }, this); - }, - - statics: { - create: function(item) { - var style = new this(this.dont); - style._item = item; - return style; - }, - - extend: function(src) { - var styleKey = '_' + src._style, - stylePart = Base.capitalize(src._style), - flags = src._flags || {}, - owner = {}; - - owner['get' + stylePart] = function() { - return this[styleKey]; - }; - - owner['set' + stylePart] = function(style) { - this[styleKey].initialize(style); - }; - - Base.each(src._defaults, function(value, key) { - var isColor = !!key.match(/Color$/), - part = Base.capitalize(key), - set = 'set' + part, - get = 'get' + part; - src[set] = function(value) { - var children = this._item && this._item._children; - value = isColor ? Color.read(arguments) : value; - if (children) { - for (var i = 0, l = children.length; i < l; i++) - children[i][styleKey][set](value); - } else { - var old = this['_' + key]; - if (old != value && !(old && old.equals - && old.equals(value))) { - this['_' + key] = value; - if (isColor) { - if (old) - old._removeOwner(this._item); - if (value) - value._addOwner(this._item); - } - if (this._item) - this._item._changed(flags[key] || Change.STYLE); - } - } - return this; - }; - src[get] = function() { - var children = this._item && this._item._children, - style; - if (!children) - return this['_' + key]; - for (var i = 0, l = children.length; i < l; i++) { - var childStyle = children[i][styleKey][get](); - if (!style) { - style = childStyle; - } else if (style != childStyle && !(style - && style.equals && style.equals(childStyle))) { - return undefined; - } - } - return style; - }; - owner[set] = function(value) { - this[styleKey][set](value); - return this; - }; - owner[get] = function() { - return this[styleKey][get](); - }; - }); - src._owner.inject(owner); - return this.base.apply(this, arguments); - } - } -}); - -var PathStyle = this.PathStyle = Style.extend({ - _owner: Item, - _style: 'style', - _defaults: { - fillColor: undefined, - strokeColor: undefined, - strokeWidth: 1, - strokeCap: 'butt', - strokeJoin: 'miter', - miterLimit: 10, - dashOffset: 0, - dashArray: [] - }, - _flags: { - strokeWidth: Change.STROKE, - strokeCap: Change.STROKE, - strokeJoin: Change.STROKE, - miterLimit: Change.STROKE - } - -}); - -var ParagraphStyle = this.ParagraphStyle = Style.extend({ - _owner: TextItem, - _style: 'paragraphStyle', - _defaults: { - justification: 'left' - }, - _flags: { - justification: Change.GEOMETRY - } - -}); - -var CharacterStyle = this.CharacterStyle = PathStyle.extend({ - _owner: TextItem, - _style: 'style', - _defaults: Base.merge(PathStyle.prototype._defaults, { - fillColor: 'black', - fontSize: 12, - leading: null, - font: 'sans-serif' - }), - _flags: { - fontSize: Change.GEOMETRY, - leading: Change.GEOMETRY, - font: Change.GEOMETRY - } - -}, { - getLeading: function() { - var leading = this.base(); - return leading != null ? leading : this.getFontSize() * 1.2; - }, - - getFontStyle: function() { - return this._fontSize + 'px ' + this._font; - } -}); - -var Color = this.Color = Base.extend(new function() { - - var components = { - gray: ['gray'], - rgb: ['red', 'green', 'blue'], - hsb: ['hue', 'saturation', 'brightness'], - hsl: ['hue', 'saturation', 'lightness'] - }; - - var colorCache = {}, - colorContext; - - function nameToRgbColor(name) { - var color = colorCache[name]; - if (color) - return color.clone(); - if (!colorContext) { - var canvas = CanvasProvider.getCanvas(Size.create(1, 1)); - colorContext = canvas.getContext('2d'); - colorContext.globalCompositeOperation = 'copy'; - } - colorContext.fillStyle = 'rgba(0,0,0,0)'; - colorContext.fillStyle = name; - colorContext.fillRect(0, 0, 1, 1); - var data = colorContext.getImageData(0, 0, 1, 1).data, - rgb = [data[0] / 255, data[1] / 255, data[2] / 255]; - return (colorCache[name] = RgbColor.read(rgb)).clone(); - } - - function hexToRgbColor(string) { - var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - if (hex.length >= 4) { - var rgb = new Array(3); - for (var i = 0; i < 3; i++) { - var channel = hex[i + 1]; - rgb[i] = parseInt(channel.length == 1 - ? channel + channel : channel, 16) / 255; - } - return RgbColor.read(rgb); - } - } - - var hsbIndices = [ - [0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2] - ]; - - var converters = { - 'rgb-hsb': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - h = delta == 0 ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - s = max == 0 ? 0 : delta / max, - v = max; - return new HsbColor(h, s, v, color._alpha); - }, - - 'hsb-rgb': function(color) { - var h = (color._hue / 60) % 6, - s = color._saturation, - b = color._brightness, - i = Math.floor(h), - f = h - i, - i = hsbIndices[i], - v = [ - b, - b * (1 - s), - b * (1 - s * f), - b * (1 - s * (1 - f)) - ]; - return new RgbColor(v[i[0]], v[i[1]], v[i[2]], color._alpha); - }, - - 'rgb-hsl': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - achromatic = delta == 0, - h = achromatic ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - l = (max + min) / 2, - s = achromatic ? 0 : l < 0.5 - ? delta / (max + min) - : delta / (2 - max - min); - return new HslColor(h, s, l, color._alpha); - }, - - 'hsl-rgb': function(color) { - var s = color._saturation, - h = color._hue / 360, - l = color._lightness, - t1, t2, c; - if (s == 0) - return new RgbColor(l, l, l, color._alpha); - var t3s = [ h + 1 / 3, h, h - 1 / 3 ], - t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, - t1 = 2 * l - t2, - c = []; - for (var i = 0; i < 3; i++) { - var t3 = t3s[i]; - if (t3 < 0) t3 += 1; - if (t3 > 1) t3 -= 1; - c[i] = 6 * t3 < 1 - ? t1 + (t2 - t1) * 6 * t3 - : 2 * t3 < 1 - ? t2 - : 3 * t3 < 2 - ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 - : t1; - } - return new RgbColor(c[0], c[1], c[2], color._alpha); - }, - - 'rgb-gray': function(color) { - return new GrayColor(1 - (color._red * 0.2989 + color._green * 0.587 - + color._blue * 0.114), color._alpha); - }, - - 'gray-rgb': function(color) { - var comp = 1 - color._gray; - return new RgbColor(comp, comp, comp, color._alpha); - }, - - 'gray-hsb': function(color) { - return new HsbColor(0, 0, 1 - color._gray, color._alpha); - }, - - 'gray-hsl': function(color) { - return new HslColor(0, 0, 1 - color._gray, color._alpha); - } - }; - - var fields = { - _readNull: true, - - initialize: function(arg) { - var isArray = Array.isArray(arg), - type = this._colorType; - if (typeof arg === 'object' && !isArray) { - if (!type) { - return arg.red !== undefined - ? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha) - : arg.gray !== undefined - ? new GrayColor(arg.gray, arg.alpha) - : arg.lightness !== undefined - ? new HslColor(arg.hue, arg.saturation, arg.lightness, - arg.alpha) - : arg.hue !== undefined - ? new HsbColor(arg.hue, arg.saturation, arg.brightness, - arg.alpha) - : new RgbColor(); - } else { - return Color.read(arguments).convert(type); - } - } else if (typeof arg === 'string') { - var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i) - ? hexToRgbColor(arg) - : nameToRgbColor(arg); - return type - ? rgbColor.convert(type) - : rgbColor; - } else { - var components = isArray ? arg - : Array.prototype.slice.call(arguments); - if (!type) { - if (components.length >= 3) - return new RgbColor(components); - return new GrayColor(components); - } else { - Base.each(this._components, - function(name, i) { - var value = components[i]; - this['_' + name] = value !== undefined - ? value : null; - }, - this); - } - } - }, - - clone: function() { - var ctor = this.constructor, - copy = new ctor(ctor.dont), - components = this._components; - for (var i = 0, l = components.length; i < l; i++) { - var key = '_' + components[i]; - copy[key] = this[key]; - } - return copy; - }, - - convert: function(type) { - var converter; - return this._colorType == type - ? this.clone() - : (converter = converters[this._colorType + '-' + type]) - ? converter(this) - : converters['rgb-' + type]( - converters[this._colorType + '-rgb'](this)); - }, - - statics: { - extend: function(src) { - if (src._colorType) { - var comps = components[src._colorType]; - src._components = comps.concat(['alpha']); - Base.each(comps, function(name) { - var isHue = name === 'hue', - part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - this[name] = isHue - ? ((value % 360) + 360) % 360 - : Math.min(Math.max(value, 0), 1); - this._changed(); - return this; - }; - }, src); - } - return this.base(src); - } - } - }; - - Base.each(components, function(comps, type) { - Base.each(comps, function(component) { - var part = Base.capitalize(component); - fields['get' + part] = function() { - return this.convert(type)[component]; - }; - fields['set' + part] = function(value) { - var color = this.convert(type); - color[component] = value; - color = color.convert(this._colorType); - for (var i = 0, l = this._components.length; i < l; i++) { - var key = this._components[i]; - this[key] = color[key]; - } - }; - }); - }); - - return fields; -}, { - - _changed: function() { - this._cssString = null; - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) - this._owners[i]._changed(Change.STYLE); - }, - - _addOwner: function(item) { - if (!this._owners) - this._owners = []; - this._owners.push(item); - }, - - _removeOwner: function(item) { - var index = this._owners ? this._owners.indexOf(item) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (this._owners.length == 0) - delete this._owners; - } - }, - - getType: function() { - return this._colorType; - }, - - getComponents: function() { - var length = this._components.length; - var comps = new Array(length); - for (var i = 0; i < length; i++) - comps[i] = this['_' + this._components[i]]; - return comps; - }, - - getAlpha: function() { - return this._alpha != null ? this._alpha : 1; - }, - - setAlpha: function(alpha) { - this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); - this._changed(); - return this; - }, - - hasAlpha: function() { - return this._alpha != null; - }, - - equals: function(color) { - if (color && color._colorType === this._colorType) { - for (var i = 0, l = this._components.length; i < l; i++) { - var component = '_' + this._components[i]; - if (this[component] !== color[component]) - return false; - } - return true; - } - return false; - }, - - toString: function() { - var parts = [], - format = Base.formatNumber; - for (var i = 0, l = this._components.length; i < l; i++) { - var component = this._components[i], - value = this['_' + component]; - if (component === 'alpha' && value == null) - value = 1; - parts.push(component + ': ' + format(value)); - } - return '{ ' + parts.join(', ') + ' }'; - }, - - toCssString: function() { - if (!this._cssString) { - var color = this.convert('rgb'), - alpha = color.getAlpha(), - components = [ - Math.round(color._red * 255), - Math.round(color._green * 255), - Math.round(color._blue * 255), - alpha != null ? alpha : 1 - ]; - this._cssString = 'rgba(' + components.join(', ') + ')'; - } - return this._cssString; - }, - - getCanvasStyle: function() { - return this.toCssString(); - } - -}); - -var GrayColor = this.GrayColor = Color.extend({ - - _colorType: 'gray' -}); - -var RgbColor = this.RgbColor = this.RGBColor = Color.extend({ - - _colorType: 'rgb' -}); - -var HsbColor = this.HsbColor = this.HSBColor = Color.extend({ - - _colorType: 'hsb' -}); - -var HslColor = this.HslColor = this.HSLColor = Color.extend({ - - _colorType: 'hsl' -}); - -var GradientColor = this.GradientColor = Color.extend({ - - initialize: function(gradient, origin, destination, hilite) { - this.gradient = gradient || new Gradient(); - this.gradient._addOwner(this); - this.setOrigin(origin); - this.setDestination(destination); - if (hilite) - this.setHilite(hilite); - }, - - clone: function() { - return new GradientColor(this.gradient, this._origin, this._destination, - this._hilite); - }, - - getOrigin: function() { - return this._origin; - }, - - setOrigin: function(origin) { - origin = Point.read(arguments).clone(); - this._origin = origin; - if (this._destination) - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getDestination: function() { - return this._destination; - }, - - setDestination: function(destination) { - destination = Point.read(arguments).clone(); - this._destination = destination; - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getHilite: function() { - return this._hilite; - }, - - setHilite: function(hilite) { - hilite = Point.read(arguments).clone(); - var vector = hilite.subtract(this._origin); - if (vector.getLength() > this._radius) { - this._hilite = this._origin.add( - vector.normalize(this._radius - 0.1)); - } else { - this._hilite = hilite; - } - this._changed(); - return this; - }, - - getCanvasStyle: function(ctx) { - var gradient; - if (this.gradient.type === 'linear') { - gradient = ctx.createLinearGradient(this._origin.x, this._origin.y, - this._destination.x, this._destination.y); - } else { - var origin = this._hilite || this._origin; - gradient = ctx.createRadialGradient(origin.x, origin.y, - 0, this._origin.x, this._origin.y, this._radius); - } - for (var i = 0, l = this.gradient._stops.length; i < l; i++) { - var stop = this.gradient._stops[i]; - gradient.addColorStop(stop._rampPoint, stop._color.toCssString()); - } - return gradient; - }, - - equals: function(color) { - return color == this || color && color._colorType === this._colorType - && this.gradient.equals(color.gradient) - && this._origin.equals(color._origin) - && this._destination.equals(color._destination); - }, - - transform: function(matrix) { - matrix._transformPoint(this._origin, this._origin, true); - matrix._transformPoint(this._destination, this._destination, true); - if (this._hilite) - matrix._transformPoint(this._hilite, this._hilite, true); - this._radius = this._destination.getDistance(this._origin); - } -}); - -var Gradient = this.Gradient = Base.extend({ - initialize: function(stops, type) { - this.setStops(stops || ['white', 'black']); - this.type = type || 'linear'; - }, - - _changed: function() { - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) - this._owners[i]._changed(); - }, - - _addOwner: function(color) { - if (!this._owners) - this._owners = []; - this._owners.push(color); - }, - - _removeOwner: function(color) { - var index = this._owners ? this._owners.indexOf(color) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (this._owners.length == 0) - delete this._owners; - } - }, - - clone: function() { - var stops = []; - for (var i = 0, l = this._stops.length; i < l; i++) - stops[i] = this._stops[i].clone(); - return new Gradient(stops, this.type); - }, - - getStops: function() { - return this._stops; - }, - - setStops: function(stops) { - if (this.stops) { - for (var i = 0, l = this._stops.length; i < l; i++) { - this._stops[i]._removeOwner(this); - } - } - if (stops.length < 2) - throw new Error( - 'Gradient stop list needs to contain at least two stops.'); - this._stops = GradientStop.readAll(stops); - for (var i = 0, l = this._stops.length; i < l; i++) { - var stop = this._stops[i]; - stop._addOwner(this); - if (stop._defaultRamp) - stop.setRampPoint(i / (l - 1)); - } - this._changed(); - }, - - equals: function(gradient) { - if (gradient.type != this.type) - return false; - if (this._stops.length == gradient._stops.length) { - for (var i = 0, l = this._stops.length; i < l; i++) { - if (!this._stops[i].equals(gradient._stops[i])) - return false; - } - return true; - } - return false; - } -}); - -var GradientStop = this.GradientStop = Base.extend({ - initialize: function(arg0, arg1) { - if (arg1 === undefined && Array.isArray(arg0)) { - this.setColor(arg0[0]); - this.setRampPoint(arg0[1]); - } else if (arg0.color) { - this.setColor(arg0.color); - this.setRampPoint(arg0.rampPoint); - } else { - this.setColor(arg0); - this.setRampPoint(arg1); - } - }, - - clone: function() { - return new GradientStop(this._color.clone(), this._rampPoint); - }, - - _changed: function() { - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) - this._owners[i]._changed(Change.STYLE); - }, - - _addOwner: function(gradient) { - if (!this._owners) - this._owners = []; - this._owners.push(gradient); - }, - - _removeOwner: function(gradient) { - var index = this._owners ? this._owners.indexOf(gradient) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (this._owners.length == 0) - delete this._owners; - } - }, - - getRampPoint: function() { - return this._rampPoint; - }, - - setRampPoint: function(rampPoint) { - this._defaultRamp = rampPoint == null; - this._rampPoint = rampPoint || 0; - this._changed(); - }, - - getColor: function() { - return this._color; - }, - - setColor: function(color) { - if (this._color) - this._color._removeOwner(this); - this._color = Color.read(arguments); - this._color._addOwner(this); - this._changed(); - }, - - equals: function(stop) { - return stop == this || stop instanceof GradientStop - && this._color.equals(stop._color) - && this._rampPoint == stop._rampPoint; - } -}); - -var DomElement = { - getBounds: function(el, viewport) { - var rect = el.getBoundingClientRect(), - doc = el.ownerDocument, - body = doc.body, - docEl = doc.documentElement, - x = rect.left - (docEl.clientLeft || body.clientLeft || 0), - y = rect.top - (docEl.clientTop || body.clientTop || 0); - if (!viewport) { - var win = DomElement.getViewport(doc); - x += win.pageXOffset || docEl.scrollLeft || body.scrollLeft; - y += win.pageYOffset || docEl.scrollTop || body.scrollTop; - } - return new Rectangle(x, y, rect.width, rect.height); - }, - - getOffset: function(el, viewport) { - return this.getBounds(el, viewport).getPoint(); - }, - - getSize: function(el) { - return this.getBounds(el, true).getSize(); - }, - - isInvisible: function(el) { - return this.getSize(el).equals([0, 0]); - }, - - isVisible: function(el) { - return !this.isInvisible(el) && this.getViewportBounds(el).intersects( - this.getBounds(el, true)); - }, - - getViewport: function(doc) { - return doc.defaultView || doc.parentWindow; - }, - - getViewportBounds: function(el) { - var doc = el.ownerDocument, - view = this.getViewport(doc), - body = doc.getElementsByTagName( - doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; - return Rectangle.create(0, 0, - view.innerWidth || body.clientWidth, - view.innerHeight || body.clientHeight - ); - }, - - getComputedStyle: function(el, name) { - if (el.currentStyle) - return el.currentStyle[Base.camelize(name)]; - var style = this.getViewport(el.ownerDocument) - .getComputedStyle(el, null); - return style ? style.getPropertyValue(Base.hyphenate(name)) : null; - } -}; - -var DomEvent = { - add: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.addEventListener) { - el.addEventListener(type, func, false); - } else if (el.attachEvent) { - el.attachEvent('on' + type, func.bound = function() { - func.call(el, window.event); - }); - } - } - }, - - remove: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.removeEventListener) { - el.removeEventListener(type, func, false); - } else if (el.detachEvent) { - el.detachEvent('on' + type, func.bound); - } - } - }, - - getPoint: function(event) { - var pos = event.targetTouches - ? event.targetTouches.length - ? event.targetTouches[0] - : event.changedTouches[0] - : event; - return Point.create( - pos.pageX || pos.clientX + document.documentElement.scrollLeft, - pos.pageY || pos.clientY + document.documentElement.scrollTop - ); - }, - - getTarget: function(event) { - return event.target || event.srcElement; - }, - - getOffset: function(event, target) { - return DomEvent.getPoint(event).subtract(DomElement.getOffset( - target || DomEvent.getTarget(event))); - }, - - preventDefault: function(event) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - }, - - stopPropagation: function(event) { - if (event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - }, - - stop: function(event) { - DomEvent.stopPropagation(event); - DomEvent.preventDefault(event); - } -}; - -DomEvent.requestAnimationFrame = new function() { - var part = 'equestAnimationFrame', - request = window['r' + part] || window['webkitR' + part] - || window['mozR' + part] || window['oR' + part] - || window['msR' + part]; - if (request) { - request(function(time) { - if (time == undefined) - request = null; - }); - } - - var callbacks = [], - focused = true, - timer; - - DomEvent.add(window, { - focus: function() { - focused = true; - }, - blur: function() { - focused = false; - } - }); - - return function(callback, element) { - if (request) - return request(callback, element); - callbacks.push([callback, element]); - if (timer) - return; - timer = window.setInterval(function() { - for (var i = callbacks.length - 1; i >= 0; i--) { - var entry = callbacks[i], - func = entry[0], - el = entry[1]; - if (!el || (PaperScript.getAttribute(el, 'keepalive') == 'true' - || focused) && DomElement.isVisible(el)) { - callbacks.splice(i, 1); - func(Date.now()); - } - } - }, 1000 / 60); - }; -}; - -var View = this.View = Base.extend(Callback, { - _events: { - onFrame: { - install: function() { - var that = this, - requested = false, - before, - time = 0, - count = 0; - this._onFrameCallback = function(param, dontRequest) { - requested = false; - if (!that._onFrameCallback) - return; - paper = that._scope; - if (!dontRequest) { - requested = true; - DomEvent.requestAnimationFrame(that._onFrameCallback, - that._element); - } - var now = Date.now() / 1000, - delta = before ? now - before : 0; - that.fire('frame', Base.merge({ - delta: delta, - time: time += delta, - count: count++ - })); - before = now; - if (that._stats) - that._stats.update(); - that.draw(true); - }; - if (!requested) - this._onFrameCallback(); - }, - - uninstall: function() { - delete this._onFrameCallback; - } - }, - - onResize: {} - }, - - initialize: function(element) { - this._scope = paper; - this._project = paper.project; - this._element = element; - var size; - this._id = element.getAttribute('id'); - if (this._id == null) - element.setAttribute('id', this._id = 'view-' + View._id++); - DomEvent.add(element, this._handlers); - if (PaperScript.hasAttribute(element, 'resize')) { - var offset = DomElement.getOffset(element, true), - that = this; - size = DomElement.getViewportBounds(element) - .getSize().subtract(offset); - element.width = size.width; - element.height = size.height; - DomEvent.add(window, { - resize: function(event) { - if (!DomElement.isInvisible(element)) - offset = DomElement.getOffset(element, true); - that.setViewSize(DomElement.getViewportBounds(element) - .getSize().subtract(offset)); - } - }); - } else { - size = DomElement.isInvisible(element) - ? Size.create(parseInt(element.getAttribute('width')), - parseInt(element.getAttribute('height'))) - : DomElement.getSize(element); - } - if (PaperScript.hasAttribute(element, 'stats')) { - this._stats = new Stats(); - var stats = this._stats.domElement, - style = stats.style, - offset = DomElement.getOffset(element); - style.position = 'absolute'; - style.left = offset.x + 'px'; - style.top = offset.y + 'px'; - document.body.appendChild(stats); - } - View._views.push(this); - View._viewsById[this._id] = this; - this._viewSize = LinkedSize.create(this, 'setViewSize', - size.width, size.height); - this._matrix = new Matrix(); - this._zoom = 1; - if (!View._focused) - View._focused = this; - }, - - remove: function() { - if (!this._project) - return false; - if (View._focused == this) - View._focused = null; - View._views.splice(View._views.indexOf(this), 1); - delete View._viewsById[this._id]; - if (this._project.view == this) - this._project.view = null; - DomEvent.remove(this._element, this._handlers); - this._element = this._project = null; - this.detach('frame'); - return true; - }, - - _redraw: function() { - this._redrawNeeded = true; - if (this._onFrameCallback) { - this._onFrameCallback(0, true); - } else { - this.draw(); - } - }, - - _transform: function(matrix) { - this._matrix.preConcatenate(matrix); - this._bounds = null; - this._inverse = null; - this._redraw(); - }, - - getElement: function() { - return this._element; - }, - - getViewSize: function() { - return this._viewSize; - }, - - setViewSize: function(size) { - size = Size.read(arguments); - var delta = size.subtract(this._viewSize); - if (delta.isZero()) - return; - this._element.width = size.width; - this._element.height = size.height; - this._viewSize.set(size.width, size.height, true); - this._bounds = null; - this._redrawNeeded = true; - this.fire('resize', { - size: size, - delta: delta - }); - this._redraw(); - }, - - getBounds: function() { - if (!this._bounds) - this._bounds = this._getInverse()._transformBounds( - new Rectangle(new Point(), this._viewSize)); - return this._bounds; - }, - - getSize: function() { - return this.getBounds().getSize(); - }, - - getCenter: function() { - return this.getBounds().getCenter(); - }, - - setCenter: function(center) { - this.scrollBy(Point.read(arguments).subtract(this.getCenter())); - }, - - getZoom: function() { - return this._zoom; - }, - - setZoom: function(zoom) { - this._transform(new Matrix().scale(zoom / this._zoom, - this.getCenter())); - this._zoom = zoom; - }, - - isVisible: function() { - return DomElement.isVisible(this._element); - }, - - scrollBy: function(point) { - this._transform(new Matrix().translate(Point.read(arguments).negate())); - }, - - projectToView: function(point) { - return this._matrix._transformPoint(Point.read(arguments)); - }, - - viewToProject: function(point) { - return this._getInverse()._transformPoint(Point.read(arguments)); - }, - - _getInverse: function() { - if (!this._inverse) - this._inverse = this._matrix.createInverse(); - return this._inverse; - } - -}, { - statics: { - _views: [], - _viewsById: {}, - _id: 0, - - create: function(element) { - if (typeof element === 'string') - element = document.getElementById(element); - return new CanvasView(element); - } - } -}, new function() { - var tool, - curPoint, - tempFocus, - dragging = false; - - function getView(event) { - return View._viewsById[DomEvent.getTarget(event).getAttribute('id')]; - } - - function viewToProject(view, event) { - return view.viewToProject(DomEvent.getOffset(event, view._element)); - } - - function updateFocus() { - if (!View._focused || !View._focused.isVisible()) { - for (var i = 0, l = View._views.length; i < l; i++) { - var view = View._views[i]; - if (view && view.isVisible()) { - View._focused = tempFocus = view; - break; - } - } - } - } - - function mousedown(event) { - var view = View._focused = getView(event); - curPoint = viewToProject(view, event); - dragging = true; - if (view._onMouseDown) - view._onMouseDown(event, curPoint); - if (tool = view._scope.tool) - tool._onHandleEvent('mousedown', curPoint, event); - view.draw(true); - } - - function mousemove(event) { - var view; - if (!dragging) { - view = getView(event); - if (view) { - View._focused = tempFocus = view; - } else if (tempFocus && tempFocus == View._focused) { - View._focused = null; - updateFocus(); - } - } - if (!(view = view || View._focused)) - return; - var point = event && viewToProject(view, event); - if (view._onMouseMove) - view._onMouseMove(event, point); - if (tool = view._scope.tool) { - var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove); - if (dragging && !onlyMove) { - if ((curPoint = point || curPoint) - && tool._onHandleEvent('mousedrag', curPoint, event)) - DomEvent.stop(event); - } else if ((!dragging || onlyMove) - && tool._onHandleEvent('mousemove', point, event)) { - DomEvent.stop(event); - } - } - view.draw(true); - } - - function mouseup(event) { - var view = View._focused; - if (!view || !dragging) - return; - var point = viewToProject(view, event); - curPoint = null; - dragging = false; - if (view._onMouseUp) - view._onMouseUp(event, point); - if (tool && tool._onHandleEvent('mouseup', point, event)) - DomEvent.stop(event); - view.draw(true); - } - - function selectstart(event) { - if (dragging) - DomEvent.stop(event); - } - - DomEvent.add(document, { - mousemove: mousemove, - mouseup: mouseup, - touchmove: mousemove, - touchend: mouseup, - selectstart: selectstart, - scroll: updateFocus - }); - - DomEvent.add(window, { - load: updateFocus - }); - - return { - _handlers: { - mousedown: mousedown, - touchstart: mousedown, - selectstart: selectstart - }, - - statics: { - updateFocus: updateFocus - } - }; -}); - -var CanvasView = View.extend({ - initialize: function(canvas) { - if (!(canvas instanceof HTMLCanvasElement)) { - var size = Size.read(arguments, 1); - if (size.isZero()) - size = Size.create(1024, 768); - canvas = CanvasProvider.getCanvas(size); - } - this._context = canvas.getContext('2d'); - this._eventCounters = {}; - this.base(canvas); - }, - - draw: function(checkRedraw) { - if (checkRedraw && !this._redrawNeeded) - return false; - var ctx = this._context, - size = this._viewSize; - ctx.clearRect(0, 0, size._width + 1, size._height + 1); - this._project.draw(ctx, this._matrix); - this._redrawNeeded = false; - return true; - } -}, new function() { - - var hitOptions = { - fill: true, - stroke: true, - tolerance: 0 - }; - - var downPoint, - lastPoint, - overPoint, - downItem, - overItem, - hasDrag, - doubleClick, - clickTime; - - function callEvent(type, event, point, target, lastPoint, bubble) { - var item = target, - mouseEvent, - called = false; - while (item) { - if (item.responds(type)) { - if (!mouseEvent) - mouseEvent = new MouseEvent(type, event, point, target, - lastPoint ? point.subtract(lastPoint) : null); - called = item.fire(type, mouseEvent) || called; - if (called && (!bubble || mouseEvent._stopped)) - break; - } - item = item.getParent(); - } - return called; - } - - function handleEvent(view, type, event, point, lastPoint) { - if (view._eventCounters[type]) { - var hit = view._project.hitTest(point, hitOptions), - item = hit && hit.item; - if (item) { - if (type == 'mousemove' && item != overItem) - lastPoint = point; - if (type != 'mousemove' || !hasDrag) - callEvent(type, event, point, item, lastPoint); - return item; - } - } - } - - return { - _onMouseDown: function(event, point) { - var item = handleEvent(this, 'mousedown', event, point); - doubleClick = downItem == item && Date.now() - clickTime < 300; - downItem = item; - downPoint = lastPoint = overPoint = point; - hasDrag = downItem && downItem.responds('mousedrag'); - }, - - _onMouseUp: function(event, point) { - var item = handleEvent(this, 'mouseup', event, point); - if (hasDrag) { - if (lastPoint && !lastPoint.equals(point)) - callEvent('mousedrag', event, point, downItem, lastPoint); - if (item != downItem) { - overPoint = point; - callEvent('mousemove', event, point, item, overPoint); - } - } - if (item == downItem) { - clickTime = Date.now(); - callEvent(doubleClick ? 'doubleclick' : 'click', event, - downPoint, overItem); - doubleClick = false; - } - downItem = null; - hasDrag = false; - }, - - _onMouseMove: function(event, point) { - if (downItem) - callEvent('mousedrag', event, point, downItem, lastPoint); - var item = handleEvent(this, 'mousemove', event, point, overPoint); - lastPoint = overPoint = point; - if (item != overItem) { - callEvent('mouseleave', event, point, overItem); - overItem = item; - callEvent('mouseenter', event, point, item); - } - } - }; -}); - -var Event = this.Event = Base.extend({ - initialize: function(event) { - this.event = event; - }, - - preventDefault: function() { - this._prevented = true; - DomEvent.preventDefault(this.event); - return this; - }, - - stopPropagation: function() { - this._stopped = true; - DomEvent.stopPropagation(this.event); - return this; - }, - - stop: function() { - return this.stopPropagation().preventDefault(); - }, - - getModifiers: function() { - return Key.modifiers; - } -}); - -var KeyEvent = this.KeyEvent = Event.extend({ - initialize: function(down, key, character, event) { - this.base(event); - this.type = down ? 'keydown' : 'keyup'; - this.key = key; - this.character = character; - }, - - toString: function() { - return '{ type: ' + this.type - + ', key: ' + this.key - + ', character: ' + this.character - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Key = this.Key = new function() { - - var keys = { - 8: 'backspace', - 13: 'enter', - 16: 'shift', - 17: 'control', - 18: 'option', - 19: 'pause', - 20: 'caps-lock', - 27: 'escape', - 32: 'space', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 46: 'delete', - 91: 'command', - 93: 'command', - 224: 'command' - }, - - modifiers = Base.merge({ - shift: false, - control: false, - option: false, - command: false, - capsLock: false - }), - - charCodeMap = {}, - keyMap = {}, - downCode; - - function handleKey(down, keyCode, charCode, event) { - var character = String.fromCharCode(charCode), - key = keys[keyCode] || character.toLowerCase(), - type = down ? 'keydown' : 'keyup', - view = View._focused, - scope = view && view.isVisible() && view._scope, - tool = scope && scope.tool; - keyMap[key] = down; - if (tool && tool.responds(type)) { - tool.fire(type, new KeyEvent(down, key, character, event)); - if (view) - view.draw(true); - } - } - - DomEvent.add(document, { - keydown: function(event) { - var code = event.which || event.keyCode; - var key = keys[code], name; - if (key) { - if ((name = Base.camelize(key)) in modifiers) - modifiers[name] = true; - charCodeMap[code] = 0; - handleKey(true, code, null, event); - } else { - downCode = code; - } - }, - - keypress: function(event) { - if (downCode != null) { - var code = event.which || event.keyCode; - charCodeMap[downCode] = code; - handleKey(true, downCode, code, event); - downCode = null; - } - }, - - keyup: function(event) { - var code = event.which || event.keyCode, - key = keys[code], name; - if (key && (name = Base.camelize(key)) in modifiers) - modifiers[name] = false; - if (charCodeMap[code] != null) { - handleKey(false, code, charCodeMap[code], event); - delete charCodeMap[code]; - } - } - }); - - return { - modifiers: modifiers, - - isDown: function(key) { - return !!keyMap[key]; - } - }; -}; - -var MouseEvent = this.MouseEvent = Event.extend({ - initialize: function(type, event, point, target, delta) { - this.base(event); - this.type = type; - this.point = point; - this.target = target; - this.delta = delta; - }, - - toString: function() { - return '{ type: ' + this.type - + ', point: ' + this.point - + ', target: ' + this.target - + (this.delta ? ', delta: ' + this.delta : '') - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var ToolEvent = this.ToolEvent = Event.extend({ - initialize: function(tool, type, event) { - this.tool = tool; - this.type = type; - this.event = event; - }, - - _choosePoint: function(point, toolPoint) { - return point ? point : toolPoint ? toolPoint.clone() : null; - }, - - getPoint: function() { - return this._choosePoint(this._point, this.tool._point); - }, - - setPoint: function(point) { - this._point = point; - }, - - getLastPoint: function() { - return this._choosePoint(this._lastPoint, this.tool._lastPoint); - }, - - setLastPoint: function(lastPoint) { - this._lastPoint = lastPoint; - }, - - getDownPoint: function() { - return this._choosePoint(this._downPoint, this.tool._downPoint); - }, - - setDownPoint: function(downPoint) { - this._downPoint = downPoint; - }, - - getMiddlePoint: function() { - if (!this._middlePoint && this.tool._lastPoint) { - return this.tool._point.add(this.tool._lastPoint).divide(2); - } - return this.middlePoint; - }, - - setMiddlePoint: function(middlePoint) { - this._middlePoint = middlePoint; - }, - - getDelta: function() { - return !this._delta && this.tool._lastPoint - ? this.tool._point.subtract(this.tool._lastPoint) - : this._delta; - }, - - setDelta: function(delta) { - this._delta = delta; - }, - - getCount: function() { - return /^mouse(down|up)$/.test(this.type) - ? this.tool._downCount - : this.tool._count; - }, - - setCount: function(count) { - this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] - = count; - }, - - getItem: function() { - if (!this._item) { - var result = this.tool._scope.project.hitTest(this.getPoint()); - if (result) { - var item = result.item, - parent = item._parent; - while ((parent instanceof Group && !(parent instanceof Layer)) - || parent instanceof CompoundPath) { - item = parent; - parent = parent._parent; - } - this._item = item; - } - } - return this._item; - }, - setItem: function(item) { - this._item = item; - }, - - toString: function() { - return '{ type: ' + this.type - + ', point: ' + this.getPoint() - + ', count: ' + this.getCount() - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Tool = this.Tool = PaperScopeItem.extend(Callback, { - _list: 'tools', - _reference: '_tool', - _events: [ 'onEditOptions', 'onSelect', 'onDeselect', 'onReselect', - 'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove', - 'onKeyDown', 'onKeyUp' ], - - initialize: function() { - this.base(); - this._firstMove = true; - this._count = 0; - this._downCount = 0; - }, - - getMinDistance: function() { - return this._minDistance; - }, - - setMinDistance: function(minDistance) { - this._minDistance = minDistance; - if (this._minDistance != null && this._maxDistance != null - && this._minDistance > this._maxDistance) { - this._maxDistance = this._minDistance; - } - }, - - getMaxDistance: function() { - return this._maxDistance; - }, - - setMaxDistance: function(maxDistance) { - this._maxDistance = maxDistance; - if (this._minDistance != null && this._maxDistance != null - && this._maxDistance < this._minDistance) { - this._minDistance = maxDistance; - } - }, - - getFixedDistance: function() { - return this._minDistance == this._maxDistance - ? this._minDistance : null; - }, - - setFixedDistance: function(distance) { - this._minDistance = distance; - this._maxDistance = distance; - }, - - _updateEvent: function(type, pt, minDistance, maxDistance, start, - needsChange, matchMaxDistance) { - if (!start) { - if (minDistance != null || maxDistance != null) { - var minDist = minDistance != null ? minDistance : 0; - var vector = pt.subtract(this._point); - var distance = vector.getLength(); - if (distance < minDist) - return false; - var maxDist = maxDistance != null ? maxDistance : 0; - if (maxDist != 0) { - if (distance > maxDist) { - pt = this._point.add(vector.normalize(maxDist)); - } else if (matchMaxDistance) { - return false; - } - } - } - if (needsChange && pt.equals(this._point)) - return false; - } - this._lastPoint = start && type == 'mousemove' ? pt : this._point; - this._point = pt; - switch (type) { - case 'mousedown': - this._lastPoint = this._downPoint; - this._downPoint = this._point; - this._downCount++; - break; - case 'mouseup': - this._lastPoint = this._downPoint; - break; - } - this._count = start ? 0 : this._count + 1; - return true; - }, - - _onHandleEvent: function(type, pt, event) { - paper = this._scope; - var sets = Tool._removeSets; - if (sets) { - if (type === 'mouseup') - sets.mousedrag = null; - var set = sets[type]; - if (set) { - for (var id in set) { - var item = set[id]; - for (var key in sets) { - var other = sets[key]; - if (other && other != set && other[item._id]) - delete other[item._id]; - } - item.remove(); - } - sets[type] = null; - } - } - var called = false; - switch (type) { - case 'mousedown': - this._updateEvent(type, pt, null, null, true, false, false); - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - break; - case 'mousedrag': - var needsChange = false, - matchMaxDistance = false; - while (this._updateEvent(type, pt, this.minDistance, - this.maxDistance, false, needsChange, matchMaxDistance)) { - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - needsChange = true; - matchMaxDistance = true; - } - break; - case 'mouseup': - if ((this._point.x != pt.x || this._point.y != pt.y) - && this._updateEvent('mousedrag', pt, this.minDistance, - this.maxDistance, false, false, false)) { - if (this.responds('mousedrag')) - called = this.fire('mousedrag', - new ToolEvent(this, type, event)); - } - this._updateEvent(type, pt, null, this.maxDistance, false, - false, false); - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - this._updateEvent(type, pt, null, null, true, false, false); - this._firstMove = true; - break; - case 'mousemove': - while (this._updateEvent(type, pt, this.minDistance, - this.maxDistance, this._firstMove, true, false)) { - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - this._firstMove = false; - } - break; - } - return called; - } - -}); - -var CanvasProvider = { - canvases: [], - getCanvas: function(size) { - if (this.canvases.length) { - var canvas = this.canvases.pop(); - if ((canvas.width != size.width) - || (canvas.height != size.height)) { - canvas.width = size.width; - canvas.height = size.height; - } else { - canvas.getContext('2d').clearRect(0, 0, - size.width + 1, size.height + 1); - } - return canvas; - } else { - var canvas = document.createElement('canvas'); - canvas.width = size.width; - canvas.height = size.height; - return canvas; - } - }, - - returnCanvas: function(canvas) { - this.canvases.push(canvas); - } -}; - -var Numerical = new function() { - - var abscissas = [ - [ 0.5773502691896257645091488], - [0,0.7745966692414833770358531], - [ 0.3399810435848562648026658,0.8611363115940525752239465], - [0,0.5384693101056830910363144,0.9061798459386639927976269], - [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], - [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], - [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], - [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], - [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], - [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], - [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], - [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], - [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], - [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], - [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] - ]; - - var weights = [ - [1], - [0.8888888888888888888888889,0.5555555555555555555555556], - [0.6521451548625461426269361,0.3478548451374538573730639], - [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], - [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], - [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], - [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], - [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], - [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], - [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], - [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], - [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], - [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], - [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], - [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] - ]; - - var abs = Math.abs, - sqrt = Math.sqrt, - cos = Math.cos, - PI = Math.PI; - - return { - TOLERANCE: 10e-6, - EPSILON: 10e-12, - - integrate: function(f, a, b, n) { - var x = abscissas[n - 2], - w = weights[n - 2], - A = 0.5 * (b - a), - B = A + a, - i = 0, - m = (n + 1) >> 1, - sum = n & 1 ? w[i++] * f(B) : 0; - while (i < m) { - var Ax = A * x[i]; - sum += w[i++] * (f(B + Ax) + f(B - Ax)); - } - return A * sum; - }, - - findRoot: function(f, df, x, a, b, n, tolerance) { - for (var i = 0; i < n; i++) { - var fx = f(x), - dx = fx / df(x); - if (abs(dx) < tolerance) - return x; - var nx = x - dx; - if (fx > 0) { - b = x; - x = nx <= a ? 0.5 * (a + b) : nx; - } else { - a = x; - x = nx >= b ? 0.5 * (a + b) : nx; - } - } - }, - - solveQuadratic: function(a, b, c, roots, tolerance) { - if (abs(a) < tolerance) { - if (abs(b) >= tolerance) { - roots[0] = -c / b; - return 1; - } - if (abs(c) < tolerance) - return -1; - return 0; - } - var q = b * b - 4 * a * c; - if (q < 0) - return 0; - q = sqrt(q); - if (b < 0) - q = -q; - q = (b + q) * -0.5; - var n = 0; - if (abs(q) >= tolerance) - roots[n++] = c / q; - if (abs(a) >= tolerance) - roots[n++] = q / a; - return n; - }, - - solveCubic: function(a, b, c, d, roots, tolerance) { - if (abs(a) < tolerance) - return Numerical.solveQuadratic(b, c, d, roots, tolerance); - b /= a; - c /= a; - d /= a; - var Q = (b * b - 3 * c) / 9, - R = (2 * b * b * b - 9 * b * c + 27 * d) / 54, - Q3 = Q * Q * Q, - R2 = R * R; - b /= 3; - if (R2 < Q3) { - var theta = Math.acos(R / sqrt(Q3)), - q = -2 * sqrt(Q); - roots[0] = q * cos(theta / 3) - b; - roots[1] = q * cos((theta + 2 * PI) / 3) - b; - roots[2] = q * cos((theta - 2 * PI) / 3) - b; - return 3; - } else { - var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3); - if (R < 0) A = -A; - var B = (abs(A) < tolerance) ? 0 : Q / A; - roots[0] = (A + B) - b; - return 1; - } - return 0; - } - }; -}; - -var BlendMode = { - process: function(blendMode, srcContext, dstContext, alpha, offset) { - var srcCanvas = srcContext.canvas, - dstData = dstContext.getImageData(offset.x, offset.y, - srcCanvas.width, srcCanvas.height), - dst = dstData.data, - src = srcContext.getImageData(0, 0, - srcCanvas.width, srcCanvas.height).data, - min = Math.min, - max = Math.max, - abs = Math.abs, - sr, sg, sb, sa, - br, bg, bb, ba, - dr, dg, db; - - function getLum(r, g, b) { - return 0.2989 * r + 0.587 * g + 0.114 * b; - } - - function setLum(r, g, b, l) { - var d = l - getLum(r, g, b); - dr = r + d; - dg = g + d; - db = b + d; - var l = getLum(dr, dg, db), - mn = min(dr, dg, db), - mx = max(dr, dg, db); - if (mn < 0) { - var lmn = l - mn; - dr = l + (dr - l) * l / lmn; - dg = l + (dg - l) * l / lmn; - db = l + (db - l) * l / lmn; - } - if (mx > 255) { - var ln = 255 - l, mxl = mx - l; - dr = l + (dr - l) * ln / mxl; - dg = l + (dg - l) * ln / mxl; - db = l + (db - l) * ln / mxl; - } - } - - function getSat(r, g, b) { - return max(r, g, b) - min(r, g, b); - } - - function setSat(r, g, b, s) { - var col = [r, g, b], - mx = max(r, g, b), - mn = min(r, g, b), - md; - mn = mn == r ? 0 : mn == g ? 1 : 2; - mx = mx == r ? 0 : mx == g ? 1 : 2; - md = min(mn, mx) == 0 ? max(mn, mx) == 1 ? 2 : 1 : 0; - if (col[mx] > col[mn]) { - col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); - col[mx] = s; - } else { - col[md] = col[mx] = 0; - } - col[mn] = 0; - dr = col[0]; - dg = col[1]; - db = col[2]; - } - - var modes = { - multiply: function() { - dr = br * sr / 255; - dg = bg * sg / 255; - db = bb * sb / 255; - }, - - screen: function() { - dr = 255 - (255 - br) * (255 - sr) / 255; - dg = 255 - (255 - bg) * (255 - sg) / 255; - db = 255 - (255 - bb) * (255 - sb) / 255; - }, - - overlay: function() { - dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; - dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; - db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; - }, - - 'soft-light': function() { - var t = sr * br / 255; - dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; - t = sg * bg / 255; - dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; - t = sb * bb / 255; - db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; - }, - - 'hard-light': function() { - dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; - dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; - db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; - }, - - 'color-dodge': function() { - dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr)); - dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg)); - db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb)); - }, - - 'color-burn': function() { - dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0); - dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0); - db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0); - }, - - darken: function() { - dr = br < sr ? br : sr; - dg = bg < sg ? bg : sg; - db = bb < sb ? bb : sb; - }, - - lighten: function() { - dr = br > sr ? br : sr; - dg = bg > sg ? bg : sg; - db = bb > sb ? bb : sb; - }, - - difference: function() { - dr = br - sr; - if (dr < 0) - dr = -dr; - dg = bg - sg; - if (dg < 0) - dg = -dg; - db = bb - sb; - if (db < 0) - db = -db; - }, - - exclusion: function() { - dr = br + sr * (255 - br - br) / 255; - dg = bg + sg * (255 - bg - bg) / 255; - db = bb + sb * (255 - bb - bb) / 255; - }, - - hue: function() { - setSat(sr, sg, sb, getSat(br, bg, bb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - saturation: function() { - setSat(br, bg, bb, getSat(sr, sg, sb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - luminosity: function() { - setLum(br, bg, bb, getLum(sr, sg, sb)); - }, - - color: function() { - setLum(sr, sg, sb, getLum(br, bg, bb)); - }, - - add: function() { - dr = min(br + sr, 255); - dg = min(bg + sg, 255); - db = min(bb + sb, 255); - }, - - subtract: function() { - dr = max(br - sr, 0); - dg = max(bg - sg, 0); - db = max(bb - sb, 0); - }, - - average: function() { - dr = (br + sr) / 2; - dg = (bg + sg) / 2; - db = (bb + sb) / 2; - }, - - negation: function() { - dr = 255 - abs(255 - sr - br); - dg = 255 - abs(255 - sg - bg); - db = 255 - abs(255 - sb - bb); - } - }; - - var process = modes[blendMode]; - if (!process) - return; - - for (var i = 0, l = dst.length; i < l; i += 4) { - sr = src[i]; - br = dst[i]; - sg = src[i + 1]; - bg = dst[i + 1]; - sb = src[i + 2]; - bb = dst[i + 2]; - sa = src[i + 3]; - ba = dst[i + 3]; - process(); - var a1 = sa * alpha / 255, - a2 = 1 - a1; - dst[i] = a1 * dr + a2 * br; - dst[i + 1] = a1 * dg + a2 * bg; - dst[i + 2] = a1 * db + a2 * bb; - dst[i + 3] = sa * alpha + a2 * ba; - } - dstContext.putImageData(dstData, offset.x, offset.y); - } -}; - -var PaperScript = this.PaperScript = new function() { -var parse_js=new function(){function W(a,b,c){var d=[];for(var e=0;e0,g=j(function(){return h(a[0]?k(["case",z(a[0])+":"]):"default:")},.5)+(f?e+j(function(){return u(a[1]).join(e)}):"");!c&&f&&d0?h(a):a}).join(e)},block:w,"var":function(a){return"var "+l(W(a,x))+";"},"const":function(a){return"const "+l(W(a,x))+";"},"try":function(a,b,c){var d=["try",w(a)];b&&d.push("catch","("+b[0]+")",w(b[1])),c&&d.push("finally",w(c));return k(d)},"throw":function(a){return k(["throw",z(a)])+";"},"new":function(a,b){b=b.length>0?"("+l(W(b,z))+")":"";return k(["new",m(a,"seq","binary","conditional","assign",function(a){var b=N(),c={};try{b.with_walkers({call:function(){throw c},"function":function(){return this}},function(){b.walk(a)})}catch(d){if(d===c)return!0;throw d}})+b])},"switch":function(a,b){return k(["switch","("+z(a)+")",v(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+g(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+g(a));return b+";"},conditional:function(a,b,c){return k([m(a,"assign","seq","conditional"),"?",m(b,"seq"),":",m(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return k([z(b),a,m(c,"seq")])},dot:function(a){var b=z(a),c=1;a[0]=="num"?/\./.test(a[1])||(b+="."):o(a)&&(b="("+b+")");while(cB[b[1]])d="("+d+")";if(L(c[0],["assign","conditional","seq"])||c[0]=="binary"&&B[a]>=B[c[1]]&&(c[1]!=a||!L(a,["&&","||","*"])))e="("+e+")";return k([d,a,e])},"unary-prefix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-prefix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return a+(p(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-postfix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=z(a);o(a)&&(c="("+c+")");return c+"["+z(b)+"]"},object:function(a){return a.length==0?"{}":"{"+e+j(function(){return W(a,function(a){if(a.length==3)return h(t(a[0],a[1][2],a[1][3],a[2]));var d=a[0],e=z(a[1]);b.quote_keys?d=Q(d):(typeof d=="number"||!c&&+d+""==d)&&parseFloat(d)>=0?d=q(+d):V(d)||(d=Q(d));return h(k(c&&b.space_colon?[d,":",e]:[d+":",e]))}).join(","+e)})+e+h("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){return a.length==0?"[]":k(["[",l(W(a,function(a){return!c&&a[0]=="atom"&&a[1]=="undefined"?"":m(a,"seq")})),"]"])},stat:function(a){return z(a).replace(/;*\s*$/,";")},seq:function(){return l(W(J(arguments),z))},label:function(a,b){return k([g(a),":",z(b)])},"with":function(a,b){return k(["with","("+z(a)+")",z(b)])},atom:function(a){return g(a)}},y=[];return z(a)}function Q(a){var b=0,c=0;a=a.replace(/[\\\b\f\n\r\t\x22\x27]/g,function(a){switch(a){case"\\":return"\\\\";case"\b":return"\\b";case"\f":return"\\f";case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";case'"':++b;return'"';case"'":++c;return"'"}return a});return b>c?"'"+a.replace(/\x27/g,"\\'")+"'":'"'+a.replace(/\x22/g,'\\"')+'"'}function O(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function N(){function g(a,b){var c={},e;for(e in a)M(a,e)&&(c[e]=d[e],d[e]=a[e]);var f=b();for(e in c)M(c,e)&&(c[e]?d[e]=c[e]:delete d[e]);return f}function f(a){if(a==null)return null;try{e.push(a);var b=a[0],f=d[b];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=c[b];return f.apply(a,a.slice(1))}finally{e.pop()}}function b(a){var b=[this[0]];a!=null&&b.push(W(a,f));return b}function a(a){return[this[0],W(a,function(a){var b=[a[0]];a.length>1&&(b[1]=f(a[1]));return b})]}var c={string:function(a){return[this[0],a]},num:function(a){return[this[0],a]},name:function(a){return[this[0],a]},toplevel:function(a){return[this[0],W(a,f)]},block:b,splice:b,"var":a,"const":a,"try":function(a,b,c){return[this[0],W(a,f),b!=null?[b[0],W(b[1],f)]:null,c!=null?W(c,f):null]},"throw":function(a){return[this[0],f(a)]},"new":function(a,b){return[this[0],f(a),W(b,f)]},"switch":function(a,b){return[this[0],f(a),W(b,function(a){return[a[0]?f(a[0]):null,W(a[1],f)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],f(a),f(b),f(c)]},assign:function(a,b,c){return[this[0],a,f(b),f(c)]},dot:function(a){return[this[0],f(a)].concat(J(arguments,1))},call:function(a,b){return[this[0],f(a),W(b,f)]},"function":function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},defun:function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},"if":function(a,b,c){return[this[0],f(a),f(b),f(c)]},"for":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"for-in":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"while":function(a,b){return[this[0],f(a),f(b)]},"do":function(a,b){return[this[0],f(a),f(b)]},"return":function(a){return[this[0],f(a)]},binary:function(a,b,c){return[this[0],a,f(b),f(c)]},"unary-prefix":function(a,b){return[this[0],a,f(b)]},"unary-postfix":function(a,b){return[this[0],a,f(b)]},sub:function(a,b){return[this[0],f(a),f(b)]},object:function(a){return[this[0],W(a,function(a){return a.length==2?[a[0],f(a[1])]:[a[0],f(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],W(a,f)]},stat:function(a){return[this[0],f(a)]},seq:function(){return[this[0]].concat(W(J(arguments),f))},label:function(a,b){return[this[0],a,f(b)]},"with":function(a,b){return[this[0],f(a),f(b)]},atom:function(a){return[this[0],a]}},d={},e=[];return{walk:f,with_walkers:g,parent:function(){return e[e.length-2]},stack:function(){return e}}}function M(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function L(a,b){for(var c=b.length;--c>=0;)if(b[c]===a)return!0;return!1}function K(a){return a.split("")}function J(a,b){return Array.prototype.slice.call(a,b||0)}function I(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function G(a){var b=J(arguments,1);return function(){return a.apply(this,b.concat(J(arguments)))}}function F(a,b,c){function bk(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){var b=bg(a),c=d.token.value;if(e("operator")&&M(A,c)){if(bh(b)){g();return p("assign",A[c],b,bi(a))}i("Invalid assignment")}return b}function bh(a){if(!b)return!0;switch(a[0]){case"dot":case"sub":case"new":case"call":return!0;case"name":return a[1]!="this"}}function bg(a){var b=bf(a);if(e("operator","?")){g();var c=bj(!1);m(":");return p("conditional",b,c,bj(!1,a))}return b}function bf(a){return be(Y(!0),0,a)}function be(a,b,c){var f=e("operator")?d.token.value:null;f&&f=="in"&&c&&(f=null);var h=f!=null?B[f]:null;if(h!=null&&h>b){g();var i=be(Y(!0),h,c);return be(p("binary",f,a,i),b,c)}return a}function bd(a,b,c){(b=="++"||b=="--")&&!bh(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bc(a,b){if(e("punc",".")){g();return bc(p("dot",a,bb()),b)}if(e("punc","[")){g();return bc(p("sub",a,H(bj,G(m,"]"))),b)}if(b&&e("punc","(")){g();return bc(p("call",a,Z(")")),!0)}return b&&e("operator")&&M(z,d.token.value)?H(G(bd,"unary-postfix",d.token.value,a),g):a}function bb(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return H(d.token.value,g);default:k()}}function ba(){switch(d.token.type){case"num":case"string":return H(d.token.value,g)}return bb()}function _(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=ba();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bj(!1)])):c.push([bb(),P(!1),h])}g();return p("object",c)}function $(){return p("array",Z("]",!b,!0))}function Z(a,b,c){var d=!0,f=[];while(!e("punc",a)){d?d=!1:m(",");if(b&&e("punc",a))break;e("punc",",")&&c?f.push(["atom","undefined"]):f.push(bj(!1))}g();return f}function X(){var a=Y(!1),b;e("punc","(")?(g(),b=Z(")")):b=[];return bc(p("new",a,b),!0)}function W(){return p("const",U())}function V(a){return p("var",U(a))}function U(a){var b=[];for(;;){e("name")||k();var c=d.token.value;g(),e("operator","=")?(g(),b.push([c,bj(!1,a)])):b.push([c]);if(!e("punc",","))break;g()}return b}function T(){var a=R(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,R()]}e("keyword","finally")&&(g(),c=R()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function R(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(t());g();return a}function Q(){var a=q(),b=t(),c;e("keyword","else")&&(g(),c=t());return p("if",a,b,c)}function O(a){var b=a[0]=="var"?p("name",a[1][0]):a;g();var c=bj();m(")");return p("for-in",a,b,c,bk(t))}function N(a){m(";");var b=e("punc",";")?null:bj();m(";");var c=e("punc",")")?null:bj();m(")");return p("for",a,b,c,bk(t))}function K(){m("(");var a=null;if(!e("punc",";")){a=e("keyword","var")?(g(),V(!0)):bj(!0,!0);if(e("operator","in"))return O(a)}return N(a)}function I(a){var b;n()||(b=e("name")?d.token.value:null),b!=null?(g(),L(b,d.labels)||i("Label "+b+" without matching loop or statement")):d.in_loop==0&&i(a+" not inside a loop or switch"),o();return p(a,b)}function F(){return p("stat",H(bj,o))}function w(a){d.labels.push(a);var c=d.token,e=t();b&&!M(C,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function s(a){return c?function(){var b=d.token,c=a.apply(this,arguments);c[0]=r(c[0],b,h());return c}:a}function r(a,b,c){return a instanceof E?a:new E(a,b,c)}function q(){m("(");var a=bj();m(")");return a}function p(){return J(arguments)}function o(){e("punc",";")?g():n()||k()}function n(){return!b&&(d.token.nlb||e("eof")||e("punc","}"))}function m(a){return l("punc",a)}function l(a,b){if(e(a,b))return g();j(d.token,"Unexpected token "+d.token.type+", expected "+a)}function k(a){a==null&&(a=d.token),j(a,"Unexpected token: "+a.type+" ("+a.value+")")}function j(a,b){i(b,a.line,a.col)}function i(a,b,c,e){var f=d.input.context();u(a,b!=null?b:f.tokline,c!=null?c:f.tokcol,e!=null?e:f.tokpos)}function h(){return d.prev}function g(){d.prev=d.token,d.peeked?(d.token=d.peeked,d.peeked=null):d.token=d.input();return d.token}function f(){return d.peeked||(d.peeked=d.input())}function e(a,b){return v(d.token,a,b)}var d={input:typeof a=="string"?x(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var t=s(function(){e("operator","/")&&(d.peeked=null,d.token=d.input(!0));switch(d.token.type){case"num":case"string":case"regexp":case"operator":case"atom":return F();case"name":return v(f(),"punc",":")?w(H(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",R());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(H(d.token.value,g)){case"break":return I("break");case"continue":return I("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",H(q,o),a)}(bk(t));case"for":return K();case"function":return P(!0);case"if":return Q();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:H(bj,o));case"switch":return p("switch",q(),S());case"throw":return p("throw",H(bj,o));case"try":return T();case"var":return H(V,o);case"const":return H(W,o);case"while":return p("while",q(),bk(t));case"with":return p("with",q(),t());default:k()}}}),P=s(function(a){var b=e("name")?H(d.token.value,g):null;a&&!b&&k(),m("(");return p(a?"defun":"function",b,function(a,b){while(!e("punc",")"))a?a=!1:m(","),e("name")||k(),b.push(d.token.value),g();g();return b}(!0,[]),function(){++d.in_function;var a=d.in_loop;d.in_loop=0;var b=R();--d.in_function,d.in_loop=a;return b}())}),S=G(bk,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bj(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(t()));g();return a}),Y=s(function(a){if(e("operator","new")){g();return X()}if(e("operator")&&M(y,d.token.value))return bd("unary-prefix",H(d.token.value,g),Y(a));if(e("punc")){switch(d.token.value){case"(":g();return bc(H(bj,G(m,")")),a);case"[":g();return bc($(),a);case"{":g();return bc(_(),a)}k()}if(e("keyword","function")){g();return bc(P(!1),a)}if(M(D,d.token.type)){var b=d.token.type=="regexp"?p("regexp",d.token.value[0],d.token.value[1]):p(d.token.type,d.token.value);return bc(H(b,g),a)}k()}),bj=s(function(a,b){arguments.length==0&&(a=!0);var c=bi(b);if(a&&e("punc",",")){g();return p("seq",c,bj(!0,b))}return c});return p("toplevel",function(a){while(!e("eof"))a.push(t());return a}([]))}function E(a,b,c){this.name=a,this.start=b,this.end=c}function x(b){function P(a){if(a)return I();y(),v();var b=g();if(!b)return x("eof");if(o(b))return C();if(b=='"'||b=="'")return F();if(M(l,b))return x("punc",h());if(b==".")return L();if(b=="/")return K();if(M(e,b))return J();if(b=="\\"||q(b))return N();B("Unexpected character '"+b+"'")}function O(a,b){try{return b()}catch(c){if(c===w)B(a);else throw c}}function N(){var b=A(r);return M(a,b)?M(i,b)?x("operator",b):M(d,b)?x("atom",b):x("keyword",b):x("name",b)}function L(){h();return o(g())?C("."):x("punc",".")}function K(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(G()),f.regex_allowed=a;return P();case"*":f.comments_before.push(H()),f.regex_allowed=a;return P()}return f.regex_allowed?I():J("/")}function J(a){function b(a){if(!g())return a;var c=a+g();if(M(i,c)){h();return b(c)}return a}return x("operator",b(a||h()))}function I(){return O("Unterminated regular expression",function(){var a=!1,b="",c,d=!1;while(c=h(!0))if(a)b+="\\"+c,a=!1;else if(c=="[")d=!0,b+=c;else if(c=="]"&&d)d=!1,b+=c;else{if(c=="/"&&!d)break;c=="\\"?a=!0:b+=c}var e=A(function(a){return M(m,a)});return x("regexp",[b,e])})}function H(){h();return O("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=x("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function G(){h();var a=t("\n"),b;a==-1?(b=f.text.substr(f.pos),f.pos=f.text.length):(b=f.text.substring(f.pos,a),f.pos=a);return x("comment1",b,!0)}function F(){return O("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=D();else if(c==a)break;b+=c}return x("string",b)})}function E(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&B("Invalid hex-character pattern in string"),b=b<<4|c}return b}function D(){var a=h(!0);switch(a){case"n":return"\n";case"r":return"\r";case"t":return"\t";case"b":return"\b";case"v":return" ";case"f":return"\f";case"0":return"";case"x":return String.fromCharCode(E(2));case"u":return String.fromCharCode(E(4));case"\n":return"";default:return a}}function C(a){var b=!1,c=!1,d=!1,e=a==".",f=A(function(f,g){if(f=="x"||f=="X")return d?!1:d=!0;if(!d&&(f=="E"||f=="e"))return b?!1:b=c=!0;if(f=="-")return c||g==0&&!a?!0:!1;if(f=="+")return c;c=!1;if(f==".")return!e&&!d?e=!0:!1;return p(f)});a&&(f=a+f);var g=s(f);if(!isNaN(g))return x("num",g);B("Invalid syntax: "+f)}function B(a){u(a,f.tokline,f.tokcol,f.tokpos)}function A(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(M(j,g()))h()}function x(a,b,d){f.regex_allowed=a=="operator"&&!M(z,b)||a=="keyword"&&M(c,b)||a=="punc"&&M(k,b);var e={type:a,value:b,line:f.tokline,col:f.tokcol,pos:f.tokpos,nlb:f.newline_before};d||(e.comments_before=f.comments_before,f.comments_before=[]),f.newline_before=!1;return e}function v(){f.tokline=f.line,f.tokcol=f.col,f.tokpos=f.pos}function t(a,b){var c=f.text.indexOf(a,f.pos);if(b&&c==-1)throw w;return c}function n(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw w;b=="\n"?(f.newline_before=!0,++f.line,f.col=0):++f.col;return b}function g(){return f.text.charAt(f.pos)}var f={text:b.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,""),pos:0,tokpos:0,line:0,tokline:0,col:0,tokcol:0,newline_before:!1,regex_allowed:!1,comments_before:[]};P.context=function(a){a&&(f=a);return f};return P}function v(a,b,c){return a.type==b&&(c==null||a.value==c)}function u(a,b,c,d){throw new t(a,b,c,d)}function t(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d}function s(a){if(f.test(a))return parseInt(a.substr(2),16);if(g.test(a))return parseInt(a.substr(1),8);if(h.test(a))return parseFloat(a)}function r(a){return q(a)||o(a)}function q(a){return a=="$"||a=="_"||n(a)}function p(a){return o(a)||n(a)}function o(a){a=a.charCodeAt(0);return a>=48&&a<=57}function n(a){a=a.charCodeAt(0);return a>=65&&a<=90||a>=97&&a<=122}var a=I(["break","case","catch","const","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","throw","try","typeof","var","void","while","with"]),b=I(["abstract","boolean","byte","char","class","debugger","double","enum","export","extends","final","float","goto","implements","import","int","interface","long","native","package","private","protected","public","short","static","super","synchronized","throws","transient","volatile"]),c=I(["return","new","delete","throw","else","case"]),d=I(["false","null","true","undefined"]),e=I(K("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=I(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","|=","^=","&=","&&","||"]),j=I(K(" \n\r\t")),k=I(K("[{}(,.;:")),l=I(K("[]{}(),;:")),m=I(K("gmsiy"));t.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"};var w={},y=I(["typeof","void","delete","--","++","!","~","-","+"]),z=I(["--","++"]),A=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),B=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),C=I(["for","do","while","switch"]),D=I(["atom","num","string","regexp","name"]);E.prototype.toString=function(){return this.name};var P=I(["name","array","object","string","dot","sub","call","regexp"]),R=I(["if","while","do","for","for-in","with"]);return{parse:F,gen_code:S,tokenizer:x,ast_walker:N}} - - // Math Operators - - var operators = { - '+': 'add', - '-': 'subtract', - '*': 'multiply', - '/': 'divide', - '%': 'modulo', - '==': 'equals', - '!=': 'equals' - }; - - function $eval(left, operator, right) { - var handler = operators[operator]; - if (left && left[handler]) { - var res = left[handler](right); - return operator == '!=' ? !res : res; - } - switch (operator) { - case '+': return left + right; - case '-': return left - right; - case '*': return left * right; - case '/': return left / right; - case '%': return left % right; - case '==': return left == right; - case '!=': return left != right; - default: - throw new Error('Implement Operator: ' + operator); - } - }; - - // Sign Operators - - var signOperators = { - '-': 'negate' - }; - - function $sign(operator, value) { - var handler = signOperators[operator]; - if (value && value[handler]) { - return value[handler](); - } - switch (operator) { - case '+': return +value; - case '-': return -value; - default: - throw new Error('Implement Sign Operator: ' + operator); - } - } - - // AST Helpers - - function isDynamic(exp) { - var type = exp[0]; - return type != 'num' && type != 'string'; - } - - function handleOperator(operator, left, right) { - // Only replace operators with calls to $operator if the left hand side - // is potentially an object. - if (operators[operator] && isDynamic(left)) { - // Replace with call to $operator(left, operator, right): - return ['call', ['name', '$eval'], - [left, ['string', operator], right]]; - } - } - - /** - * Compiles PaperScript code into JavaScript code. - * - * @name PaperScript.compile - * @function - * @param {String} code The PaperScript code. - * @return {String} The compiled PaperScript as JavaScript code. - */ - function compile(code) { - // Use parse-js to translate the code into a AST structure which is then - // walked and parsed for operators to overload. The resulting AST is - // translated back to code and evaluated. - var ast = parse_js.parse(code), - walker = parse_js.ast_walker(), - walk = walker.walk; - - ast = walker.with_walkers({ - 'binary': function(operator, left, right) { - // Handle simple mathematical operators here: - return handleOperator(operator, left = walk(left), - right = walk(right)) - // Always return something since we're walking left and - || [this[0], operator, left, right]; - }, - - 'assign': function(operator, left, right) { - var res = handleOperator(operator, left = walk(left), - right = walk(right)); - if (res) - return [this[0], true, left, res]; - return [this[0], operator, left, right]; - }, - - 'unary-prefix': function(operator, exp) { - if (signOperators[operator] && isDynamic(exp)) { - return ['call', ['name', '$sign'], - [['string', operator], walk(exp)]]; - } - } - }, function() { - return walk(ast); - }); - - return parse_js.gen_code(ast, { - beautify: true - }); - } - - function evaluate(code, scope) { - paper = scope; - var view = scope.project.view, - res; - with (scope) { - (function() { - var onEditOptions, onSelect, onDeselect, onReselect, - onMouseDown, onMouseUp, onMouseDrag, onMouseMove, - onKeyDown, onKeyUp, onFrame, onResize; - res = eval(compile(code)); - if (/on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)) { - Base.each(Tool.prototype._events, function(key) { - var value = eval(key); - if (value) { - scope.getTool()[key] = value; - } - }); - } - if (view) { - view.setOnResize(onResize); - view.fire('resize', { - size: view.size, - delta: new Point() - }); - view.setOnFrame(onFrame); - view.draw(); - } - }).call(scope); - } - return res; - } - - function request(url, scope) { - var xhr = new (window.ActiveXObject || XMLHttpRequest)( - 'Microsoft.XMLHTTP'); - xhr.open('GET', url, true); - if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain'); - } - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - return evaluate(xhr.responseText, scope); - } - }; - return xhr.send(null); - } - - function load() { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, l = scripts.length; i < l; i++) { - var script = scripts[i]; - if (/^text\/(?:x-|)paperscript$/.test(script.type) - && !script.getAttribute('data-paper-loaded')) { - var scope = new PaperScope(script); - scope.setup(PaperScript.getAttribute(script, 'canvas')); - if (script.src) { - request(script.src, scope); - } else { - evaluate(script.innerHTML, scope); - } - script.setAttribute('data-paper-loaded', true); - } - } - } - - DomEvent.add(window, { load: load }); - - function handleAttribute(name) { - name += 'Attribute'; - return function(el, attr) { - return el[name](attr) || el[name]('data-paper-' + attr); - }; - } - - return { - compile: compile, - evaluate: evaluate, - load: load, - getAttribute: handleAttribute('get'), - hasAttribute: handleAttribute('has') - }; - -}; - -this.load = PaperScript.load; - -Base.each(this, function(val, key) { - if (val && val.prototype instanceof Base) { - val._name = key; - } -}); - -this.enumerable = true; -return new (PaperScope.inject(this)); -}; diff --git a/test/tests/ImportSVG.js b/test/tests/ImportSVG.js index a964224d..e7fd358e 100644 --- a/test/tests/ImportSVG.js +++ b/test/tests/ImportSVG.js @@ -12,11 +12,21 @@ * Distributed under the MIT license. See LICENSE file for details. * * All rights reserved. +* +* This test file created by Stetson-Team-Alpha */ module('ImportSVG'); -/** -*TODO: Create SVGs utilizing ImportSVG methods -* WILL ADD MORE AFTER LEARNING SVG -*/ +test('Make a circle', function() +{ + var svgDocument = evt.target.ownerDocument; + var svgcircle = svgDocument.createElementNS(svgns, "circle"); + svgCircle.setAttributeNS(null, "cx", 25); + svgCircle.setAttributeNS(null, "cy", 25); + svgCircle.setAttributeNS(null, "r", 20); + svgCircle.setAttributeNS(null, "fill", "green"); + var circle = new ImportSVG(svgCircle) + equals(circle); +}); +/ From 350fc91c4decef00e80ff63eb67d8b1aac19d7c0 Mon Sep 17 00:00:00 2001 From: Jt Whissel Date: Tue, 25 Sep 2012 16:22:13 -0300 Subject: [PATCH 34/51] Update AUTHORS.md --- AUTHORS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 488ef858..6c907bd9 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -7,5 +7,4 @@ - Jacob Lites - Justin Ridgewell - Andrew Wagenheim -- Scott Kieronski -- Lily the Puppy \ No newline at end of file +- Scott Kieronski \ No newline at end of file From f46c77c699517597be1f05c87429a5f1ca4ed093 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 30 Sep 2012 17:24:18 -0400 Subject: [PATCH 35/51] Reset files to stubs --- src/svg/ExportSVG.js | 109 +-------------- src/svg/ImportSVG.js | 285 +++++++--------------------------------- test/tests/ImportSVG.js | 32 ----- 3 files changed, 49 insertions(+), 377 deletions(-) delete mode 100644 test/tests/ImportSVG.js diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index e4906664..79d88b78 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -6,23 +6,16 @@ * var svg=document.createElementNS(NS,"svg"); */ - - var ExportSVG = function() { var svgObj = null; // xml dom object (svg typed) - //var blarg = this; //initialize the svgObj and what ever else. - /*function initialize() + function initialize() { - var NS = "http://www.w3.org/2000/svg"; - svgObj = document.createElementNS(NS,"svg"); - console.log(svgObj); - - };*/ + }; /** * @@ -90,100 +83,8 @@ var ExportSVG = function() */ this.exportPath = function(path) { - //this.initialize(); - //console.log(blarg.svgObj); - var pathClone = path.clone(); - var NS = "http://www.w3.org/2000/svg"; - svgObj = document.createElementNS(NS,"svg"); - svgPath = document.createElementNS(NS, "path"); - - //Getting all of the segments(a point, a HandleIn and a HandleOut) in the path - var segArray = pathClone.getSegments(); - - var pointArray = new Array(); - var handleInArray = new Array(); - var handleOutArray = new Array(); - for(i = 0; i < segArray.length; i++) - { - - console.log(segArray[i].toString()); - pointArray[i] = segArray[i].getPoint(); - handleInArray[i] = segArray[i].getHandleIn(); - handleOutArray[i] = segArray[i].getHandleOut(); - } - //pointstring is formatted in the way the SVG XML will be reading - //Namely, a point and the way to traverse to that point - var pointString = ""; - for(i = 0; i < pointArray.length; i++) - { - var x = pointArray[i].getX(); - //x = x - (x % 1); //Possible for simplifying - var y = pointArray[i].getY(); - //y = y - (x % 1); - if(i === 0) - { - //M is moveto, moving to a point without drawing - pointString+= "M " + x + " " + y + " "; - } - else - { - //L is lineto, moving to a point with drawing - pointString+= "L " + x + " " + y + " "; - } - } - if(pathClone.getClosed()) - { - //Z implies a closed path, connecting the first and last points - pointString += "z"; - } - - svgPath.setAttribute("d",pointString); - - //If the stroke doesn't have a color, there's no attribute for it - if(pathClone.strokeColor != undefined) - { - //Using rgb, each value between 0 and 1 - var strokeRed = pathClone.strokeColor.red; - var strokeGreen = pathClone.strokeColor.green; - var strokeBlue = pathClone.strokeColor.blue; - var strokeRGB = RGBtoHex(strokeRed, strokeGreen, strokeBlue); - svgPath.setAttribute("stroke", strokeRGB); - } - - //If the fill doesn't have a color, there's no attribute for it - if(pathClone.fillColor != undefined) - { - var fillRed = pathClone.fillColor.red; - var fillGreen = pathClone.fillColor.green; - var fillBlue = pathClone.fillColor.blue; - var fillRGB = RGBtoHex(fillRed, fillGreen, fillBlue); - svgPath.setAttribute("fill", fillRGB); - } - svgPath.setAttribute("stroke-width",pathClone.strokeWidth); - svgObj.appendChild(svgPath); //appends path to svgObj - return svgObj; + return svgObj; }; - function RGBConverter(deciColor) - { - //since value is scaled from 0 to 1, must round the - //multiplication by 255 - var decColor = Math.round(deciColor * 255); - var hexColor = decColor.toString(16); //to hex - //R, G, and B need to take up at 2 characters - hexColor = hexColor.length > 1? hexColor : "0" + hexColor; - return hexColor; - }; - - function RGBtoHex(red, green, blue) - { - var redVal = RGBConverter(red); - var greenVal = RGBConverter(green); - var blueVal = RGBConverter(blue); - //Returns hex for colors - return "#" + redVal + greenVal + blueVal; - } - - - //initialize(); // calls the init function after class is loaded -}; + initialize(); // calls the init function after class is loaded +}; \ No newline at end of file diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index a0d497a9..08f6f557 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -1,252 +1,55 @@ -/* -* Paper.js -* -* This file is part of Paper.js, a JavaScript Vector Graphics Library, -* based on Scriptographer.org and designed to be largely API compatible. -* http://paperjs.org/ -* http://scriptographer.org/ -* -* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -* http://lehni.org/ & http://jonathanpuckey.com/ -* -* Distributed under the MIT license. See LICENSE file for details. -* -* All rights reserved. -* -* -* -* This class and all methods therein designed by Stetson-Team-Alpha -* @author Stetson-Team-Alpha -*/ - /** - * @name ImportSVG - * @class The ImportSVG object represents an object created using the SVG - * Canvas that will be converted into a Paper.js object. - * The SVG object is imported into Paper.js by converting it into items - * within groups. - * + * Imports svg into items with groups + * Stetson Alpha - Paper.js + * */ -var ImportSVG = this.ImportSVG = Base.extend(/** @Lends ImportSVG# */{ - - /** - * Creates a Paper.js object using data parsed from the selected SVG - * Document Object Model (DOM). The SVG object is imported, than a layer - * is created (with groups for the items if needed). - * - * Supports nested groups - * - * @param {SVG DOM} svg An SVG DOM object with parameters - * @return {Layer} A Paper.js layer - */ - - importSVG: function(svg) +var ImportSVG = function() +{ + //initialize + function initialize() { - var layer = new Layer(); - groups = this.importGroup(svg); - layer.addChild(groups); - - return layer; - }, + + }; /** - * Creates a Paper.js group by parsing a specific GNode of the imported - * SVG DOM * - * @name ImportSVG#importGroup - * @function - * @param {XML DOM} svg A node passed in by the imported SVG - * @return {Group} group A Paper.js group - * - * + * Takes the svg dom obj and parses the data + * to create a layer with groups (if needed) with + * items inside. Should support nested groups. + * + * takes in a svg object (xml dom) + * returns Paper.js Layer */ - importGroup: function(svg) - { - var group = new Group(); - var child; - for (var i in svg.childNodes) { - child = svg.childNodes[i]; - if (child.nodeType != 1) { - continue; - } - item = this.importPath(child); - group.addChild(item); - } - - return group; - }, - + this.importSVG = function(svg) + { + return layer; + }; + + /** + * Creates a Paper.js Group by parsing + * a specific svg g node + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + function importGroup(svg) + { + return group; + }; + /** * Creates a Paper.js Path by parsing - * a specific SVG node (rectangle, path, circle, polygon, etc.) - * and creating the right Path object based on the SVG type. - * - * @name ImportSVG#importPath - * @function - * @param {XML DOM} svg An SVG object - * @return {Item} item A Paper.js item + * a specific svg node (rect, path, circle, polygon, etc) + * and creating the right path object based on the svg type. + * + * takes in a svg object (xml dom) + * returns Paper.js Group */ - importPath: function(svg) - { - switch (svg.nodeName.toLowerCase()) { - case 'line': - item = this._importLine(svg); - break; - case 'rect': - item = this._importRectangle(svg); - break; - case 'ellipse': - item = this._importOval(svg); - break; - case 'g': - item = this.importGroup(svg); - break; - case 'text': - item = this._importText(svg); - break; - default: - break; - } - - return item; - }, - - /** - * Creates a Path.Circle item in Paper.js using an imported Circle from - * SVG - * - * @name ImportSVG#importCircle - * @function - * @param {XML DOM} svgCircle An SVG circle node - * @return {Path.Circle} circle A Path.Circle item for Paper.js - */ - _importCircle: function(svgCircle) - { - var cx = svgCircle.cx.baseVal.value || 0; - var cy = svgCircle.cy.baseVal.value || 0; - var r = svgCircle.r.baseVal.value || 0; - var center = new Point(cx, cy); - var circle = new Path.Circle(center, r); - - return circle; - }, - - /** - * Creates a Path.Oval item in Paper.js using an imported Oval from SVG - * - * @name ImportSVG#importOval - * @function - * @param {XML DOM} svgOval An SVG ellipse node - * @return {Path.Oval} oval A Path.Oval item for Paper.js - */ - _importOval: function(svgOval) - { - var cx = svgOval.cx.baseVal.value || 0; - var cy = svgOval.cy.baseVal.value || 0; - var rx = svgOval.rx.baseVal.value || 0; - var ry = svgOval.ry.baseVal.value || 0; - - var center = new Point(cx, cy); - var offset = new Point(rx, ry); - var topLeft = center.subtract(offset); - var bottomRight = center.add(offset); - - var rect = new Rectangle(topLeft, bottomRight); - var oval = new Path.Oval(rect); - - return oval; - }, - - /** - * Creates a Path.Rectangle item from an imported SVG rectangle - * - * @name ImportSVG#importRectangle - * @function - * @param {XML DOM} svgRectangle An SVG rectangle node - * @return {Path.Rectangle} rectangle A Path.Rectangle item for Paper.js - */ - /** - * Creates a Path.RoundRectangle item from an imported SVG rectangle - * with rounded corners - * - * @name ImportSVG#importRectangle - * @function - * @param {XML DOM} svgRectangle An SVG rectangle node with rounded - * corners - * @return {Path.RoundRectangle} rectangle A Path.Rectangle item for - * Paper.js - */ - _importRectangle: function(svgRectangle) - { - var x = svgRectangle.x.baseVal.value || 0; - var y = svgRectangle.y.baseVal.value || 0; - var rx = svgRectangle.rx.baseVal.value || 0; - var ry = svgRectangle.ry.baseVal.value || 0; - var width = svgRectangle.width.baseVal.value || 0; - var height = svgRectangle.height.baseVal.value || 0; - - var topLeft = new Point(x, y); - var size = new Size(width, height); - var rectangle = new Rectangle(topLeft, size); - - if (rx > 0 || ry > 0) { - var cornerSize = new Size(rx, ry); - rectangle = new Path.RoundRectangle(rectangle, cornerSize); - } else { - rectangle = new Path.Rectangle(rectangle); - } - - return rectangle; - }, - - /** - * Creates a Path.Line item in Paper.js from an imported SVG line - * - * @name ImportSVG#importLine - * @function - * @param {XML DOM} svgLine An SVG line node - * @return {Path.Line} line A Path.Line item for Paper.js - */ - _importLine: function(svgLine) - { - var x1 = svgLine.x1.baseVal.value || 0; - var y1 = svgLine.y1.baseVal.value || 0; - var x2 = svgLine.x2.baseVal.value || 0; - var y2 = svgLine.y2.baseVal.value || 0; - - var from = new Point(x1, y1); - var to = new Point(x2, y2); - var line = new Path.Line(from, to); - - return line; - }, - - /** - * Creates a PointText item in Paper.js from an imported SVG text node - * - * @name ImportSVG#importText - * @function - * @param {XML DOM} svgText An SVG text node - * @return {Path.Text} text A PointText item for Paper.js - */ - _importText: function(svgText) - { - //TODO: Extend this for multiple values - var x = svgText.x.baseVal.getItem(0).value || 0; - var y = svgText.y.baseVal.getItem(0).value || 0; - //END:Todo - - var dx; //character kerning - var dy; //character baseline - var rotate; //character rotation - var textLength; //the width of the containing box - var lengthAdjust; // - var textContent = svgText.textContent || ""; - - var topLeft = new Point(x, y); - var text = new PointText(topLeft); - text.content = textContent; - return text; - } -}); + function importPath(svg) + { + return path; + }; + + initialize(); // calls the init function after class is loaded +}; \ No newline at end of file diff --git a/test/tests/ImportSVG.js b/test/tests/ImportSVG.js deleted file mode 100644 index e7fd358e..00000000 --- a/test/tests/ImportSVG.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Paper.js -* -* This file is part of Paper.js, a JavaScript Vector Graphics Library, -* based on Scriptographer.org and designed to be largely API compatible. -* http://paperjs.org/ -* http://scriptographer.org/ -* -* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -* http://lehni.org/ & http://jonathanpuckey.com/ -* -* Distributed under the MIT license. See LICENSE file for details. -* -* All rights reserved. -* -* This test file created by Stetson-Team-Alpha -*/ - -module('ImportSVG'); - -test('Make a circle', function() -{ - var svgDocument = evt.target.ownerDocument; - var svgcircle = svgDocument.createElementNS(svgns, "circle"); - svgCircle.setAttributeNS(null, "cx", 25); - svgCircle.setAttributeNS(null, "cy", 25); - svgCircle.setAttributeNS(null, "r", 20); - svgCircle.setAttributeNS(null, "fill", "green"); - var circle = new ImportSVG(svgCircle) - equals(circle); -}); -/ From c6c460519e058ca55ab4995d196ae2ad2573372e Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 30 Sep 2012 17:51:50 -0400 Subject: [PATCH 36/51] Merging all the magic --- examples/ExportSVGTests/Circle Testing.html | 48 ++ .../ExportSVGTests/Empty Path Testing.html | 42 ++ examples/ExportSVGTests/Line Testing.html | 61 ++ .../ExportSVGTests/Random Path Testing.html | 54 ++ .../Rect and Attribute Testing.html | 70 ++ examples/ExportSVGTests/Text Testing.html | 60 ++ examples/ExportSVGTests/Transform Test 1.html | 46 ++ examples/ExportSVGTests/Transform Test 2.html | 41 ++ .../Circle and Oval Testing.html | 33 + examples/ImportSVGTests/Line Testing.html | 32 + .../ImportSVGTests/Multiple Paths Test 1.html | 49 ++ .../ImportSVGTests/Multiple Paths Test 2.html | 45 ++ .../ImportSVGTests/Nested Groups Test.html | 85 +++ examples/ImportSVGTests/Rect Testing.html | 30 + examples/ImportSVGTests/Testing.html | 47 ++ examples/ImportSVGTests/Text Testing.html | 27 + .../ImportSVGTests/Transform Testing.html | 29 + src/svg/ExportSVG.js | 528 +++++++++++++-- src/svg/ImportSVG.js | 622 ++++++++++++++++-- test/tests/ExportSVG.js | 556 ++++++++++++++++ test/tests/ImportSVG.js | 451 +++++++++++++ 21 files changed, 2837 insertions(+), 119 deletions(-) create mode 100644 examples/ExportSVGTests/Circle Testing.html create mode 100644 examples/ExportSVGTests/Empty Path Testing.html create mode 100644 examples/ExportSVGTests/Line Testing.html create mode 100644 examples/ExportSVGTests/Random Path Testing.html create mode 100644 examples/ExportSVGTests/Rect and Attribute Testing.html create mode 100644 examples/ExportSVGTests/Text Testing.html create mode 100644 examples/ExportSVGTests/Transform Test 1.html create mode 100644 examples/ExportSVGTests/Transform Test 2.html create mode 100644 examples/ImportSVGTests/Circle and Oval Testing.html create mode 100644 examples/ImportSVGTests/Line Testing.html create mode 100644 examples/ImportSVGTests/Multiple Paths Test 1.html create mode 100644 examples/ImportSVGTests/Multiple Paths Test 2.html create mode 100644 examples/ImportSVGTests/Nested Groups Test.html create mode 100644 examples/ImportSVGTests/Rect Testing.html create mode 100644 examples/ImportSVGTests/Testing.html create mode 100644 examples/ImportSVGTests/Text Testing.html create mode 100644 examples/ImportSVGTests/Transform Testing.html create mode 100644 test/tests/ExportSVG.js create mode 100644 test/tests/ImportSVG.js diff --git a/examples/ExportSVGTests/Circle Testing.html b/examples/ExportSVGTests/Circle Testing.html new file mode 100644 index 00000000..b81d0035 --- /dev/null +++ b/examples/ExportSVGTests/Circle Testing.html @@ -0,0 +1,48 @@ + + + + + Circle Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Empty Path Testing.html b/examples/ExportSVGTests/Empty Path Testing.html new file mode 100644 index 00000000..da75294e --- /dev/null +++ b/examples/ExportSVGTests/Empty Path Testing.html @@ -0,0 +1,42 @@ + + + + + Empty Path Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Line Testing.html b/examples/ExportSVGTests/Line Testing.html new file mode 100644 index 00000000..97e1a874 --- /dev/null +++ b/examples/ExportSVGTests/Line Testing.html @@ -0,0 +1,61 @@ + + + + + Line Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Random Path Testing.html b/examples/ExportSVGTests/Random Path Testing.html new file mode 100644 index 00000000..6a38bb85 --- /dev/null +++ b/examples/ExportSVGTests/Random Path Testing.html @@ -0,0 +1,54 @@ + + + + + Random Path Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Rect and Attribute Testing.html b/examples/ExportSVGTests/Rect and Attribute Testing.html new file mode 100644 index 00000000..e384fc0e --- /dev/null +++ b/examples/ExportSVGTests/Rect and Attribute Testing.html @@ -0,0 +1,70 @@ + + + + + Rectangle Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Text Testing.html b/examples/ExportSVGTests/Text Testing.html new file mode 100644 index 00000000..c7c824e7 --- /dev/null +++ b/examples/ExportSVGTests/Text Testing.html @@ -0,0 +1,60 @@ + + + + + Text Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Transform Test 1.html b/examples/ExportSVGTests/Transform Test 1.html new file mode 100644 index 00000000..d44566cd --- /dev/null +++ b/examples/ExportSVGTests/Transform Test 1.html @@ -0,0 +1,46 @@ + + + + + Transform Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ExportSVGTests/Transform Test 2.html b/examples/ExportSVGTests/Transform Test 2.html new file mode 100644 index 00000000..9e9da551 --- /dev/null +++ b/examples/ExportSVGTests/Transform Test 2.html @@ -0,0 +1,41 @@ + + + + + Rectangle Testing + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Circle and Oval Testing.html b/examples/ImportSVGTests/Circle and Oval Testing.html new file mode 100644 index 00000000..3491aa02 --- /dev/null +++ b/examples/ImportSVGTests/Circle and Oval Testing.html @@ -0,0 +1,33 @@ + + + + + Circle and Oval Testing + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Line Testing.html b/examples/ImportSVGTests/Line Testing.html new file mode 100644 index 00000000..8a1987ef --- /dev/null +++ b/examples/ImportSVGTests/Line Testing.html @@ -0,0 +1,32 @@ + + + + + Line Testing + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Multiple Paths Test 1.html b/examples/ImportSVGTests/Multiple Paths Test 1.html new file mode 100644 index 00000000..e8093601 --- /dev/null +++ b/examples/ImportSVGTests/Multiple Paths Test 1.html @@ -0,0 +1,49 @@ + + + + + Multiple Paths Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + I love SVG + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Multiple Paths Test 2.html b/examples/ImportSVGTests/Multiple Paths Test 2.html new file mode 100644 index 00000000..76074cd0 --- /dev/null +++ b/examples/ImportSVGTests/Multiple Paths Test 2.html @@ -0,0 +1,45 @@ + + + + + Stroke Bounds + + + + + + + + + + + + + + + + + + + A + B + C + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Nested Groups Test.html b/examples/ImportSVGTests/Nested Groups Test.html new file mode 100644 index 00000000..555e2d5c --- /dev/null +++ b/examples/ImportSVGTests/Nested Groups Test.html @@ -0,0 +1,85 @@ + + + + + + Nested Groups Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Rect Testing.html b/examples/ImportSVGTests/Rect Testing.html new file mode 100644 index 00000000..dea89180 --- /dev/null +++ b/examples/ImportSVGTests/Rect Testing.html @@ -0,0 +1,30 @@ + + + + + Rect Testing + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Testing.html b/examples/ImportSVGTests/Testing.html new file mode 100644 index 00000000..434107ee --- /dev/null +++ b/examples/ImportSVGTests/Testing.html @@ -0,0 +1,47 @@ + + + + + Stroke Bounds + + + + + + + + + + + + + + + + + + + + + + + + + + + + + I love SVG + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Text Testing.html b/examples/ImportSVGTests/Text Testing.html new file mode 100644 index 00000000..63a5b21a --- /dev/null +++ b/examples/ImportSVGTests/Text Testing.html @@ -0,0 +1,27 @@ + + + + + Text Testing + + + + + + + Plain SVG Text + + Rotated SVG Text + + + + + \ No newline at end of file diff --git a/examples/ImportSVGTests/Transform Testing.html b/examples/ImportSVGTests/Transform Testing.html new file mode 100644 index 00000000..5576486f --- /dev/null +++ b/examples/ImportSVGTests/Transform Testing.html @@ -0,0 +1,29 @@ + + + + + Circle and Oval Testing + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 79d88b78..9c1346bd 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -1,90 +1,476 @@ -/** - * Exports items, layers or whole projects as a svg - * Stetson Alpha - Paper.js - * - * var NS="http://www.w3.org/2000/svg"; - * var svg=document.createElementNS(NS,"svg"); + /* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + * + * This class and all methods therein programmed by Stetson-Team-Alpha + * @author Stetson-Team-Alpha */ -var ExportSVG = function() -{ - var svgObj = null; // xml dom object (svg typed) - - //initialize the svgObj and what ever else. - function initialize() - { - - }; - + /** + * @name ExportSVG + * + * @class The ExportSVG object represents a Paper.js object that will be + * converted into an SVG canvas design. + * The Paper.js object is converted by changing its items into groups + * + */ + +var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ + //initialize the svgObj + initialize: function() { + this.NS = 'http://www.w3.org/2000/svg'; + this.svgObj = document.createElementNS(this.NS, 'svg'); + }, + + /** + * Takes the selected Paper.js project and parses all of its layers and + * groups to be placed into SVG groups, converting the project into one + * SVG group. + * + * @function + * @param {Paper.js Project} project A Paper.js project + * @return {SVG DOM} this.svgObj The imported project converted to an + * SVG project + */ + exportProject: function(project) { + var layerArray = project.layers; + var layer; + for (var i = 0; i < layerArray.length; ++i) { + layer = layerArray[i]; + this.svgObj.appendChild(this.exportLayer(layer)); + } + return this.svgObj; + }, + /** * - * Takes the whole project and parses - * all the layers to be put into svg groups and - * groups into svg groups making all the projects - * items into one svg. + * Takes the selected Paper.js layer and parses all groups + * and items on the layer into one SVG * - * takes in a Paper.js Project - * returns svg object (xml dom) + * @name ExportSVG#exportLayer + * @function + * @param {Paper.js Layer} layer A Paper.js layer + * @return {SVG DOM} this.exportGroup(layer) The layer converted into an + * SVG group */ - this.exportProject = function(project) - { - return svgObj; - }; - - + exportLayer: function(layer) { + return this.exportGroup(layer); + }, + /** * - * Takes the layer and then parses all groups - * and items into one svg + * Takes a Paper.js group and puts its items in a SVG file. * - * takes in a Paper.js Layer - * returns svg object (xml dom) + * @name ExportSVG#exportGroup + * @function + * @param {Paper.js Group} group A Paper.js group + * @return {SVG DOM} svgG An SVG object */ - this.exportLayer = function(layer) - { - return svgObj; - }; + exportGroup: function(group) { + var svgG = document.createElementNS(this.NS, 'g'); + var curChild; + + for (var i in group.children) { + curChild = group.children[i]; + if (curChild.children) { + svgG.appendChild(this.exportGroup(curChild)); + } else { + svgG.appendChild(this.exportPath(curChild)); + } + } + return svgG; + }, - - /** - * - * Takes the group and puts it's items - * in a svg file. - * - * takes in a Paper.js Group - * returns svg object (xml dom) - */ - this.exportGroup = function(group) - { - return svgObj; - }; - - /** - * - * Takes the item and puts it in - * a svg file. - * - * takes in a Paper.js Item - * returns svg object (xml dom) - */ - this.exportItem = function(item) - { - return svgObj; - }; - /** * * Takes the path and puts it in * a svg file. * - * takes in a Paper.js Path - * returns svg object (xml dom) + * @name ExportSVG#exportPath + * @function + * @param {Paper.js Path} path A Paper.js path object + * @return {SVG DOM} svgPath An SVG object of the imported path */ - this.exportPath = function(path) - { - return svgObj; - }; + exportPath: function(path) { + var svgEle; + //Getting all of the segments(a point, a HandleIn and a HandleOut) in the path + var segArray; + var pointArray; + var handleInArray; + var handleOutArray; + //finding the type of path to export + if(path.content) { + type = 'text'; + } else { + //Values are only defined if the path is not text because + // text does not have these values + segArray = path.getSegments(); + pointArray = new Array(); + handleInArray = new Array(); + handleOutArray = new Array(); + for (i = 0; i < segArray.length; i++) { + pointArray[i] = segArray[i].getPoint(); + handleInArray[i] = segArray[i].getHandleIn(); + handleOutArray[i] = segArray[i].getHandleOut(); + } + var exp = this; + var type = exp._determineType(path, segArray, pointArray, handleInArray, handleOutArray); + } + //switch statement that determines what type of SVG element to add to the SVG Object + switch (type) { + case 'rect': + var width = pointArray[0].getDistance(pointArray[3], false); + var height = pointArray[0].getDistance(pointArray[1], false); + svgEle = document.createElementNS(this.NS, 'rect'); + svgEle.setAttribute('x', path.bounds.topLeft.getX()); + svgEle.setAttribute('y', path.bounds.topLeft.getY()); + svgEle.setAttribute('width', width); + svgEle.setAttribute('height', height); + break; + case 'roundRect': + //d variables and point are used to determine the rounded corners for the rounded rectangle + var dx1 = pointArray[1].getDistance(pointArray[6], false); + var dx2 = pointArray[0].getDistance(pointArray[7], false); + var dx3 = (dx1 - dx2) / 2; + var dy1 = pointArray[0].getDistance(pointArray[3], false); + var dy2 = pointArray[1].getDistance(pointArray[2], false); + var dy3 = (dy1 - dy2) / 2; + var point = new Point((pointArray[3].getX() - dx3), (pointArray[2].getY() - dy3)); + var width = Math.round(dx1); + var height = Math.round(dy1); + var rx = pointArray[3].getX() - point.x; + var ry = pointArray[2].getY() - point.y; + svgEle = document.createElementNS(this.NS, 'rect'); + svgEle.setAttribute('x', path.bounds.topLeft.getX()); + svgEle.setAttribute('y', path.bounds.topLeft.getY()); + svgEle.setAttribute('rx', rx); + svgEle.setAttribute('ry', ry); + svgEle.setAttribute('width', width); + svgEle.setAttribute('height', height); + break; + case'line': + svgEle = document.createElementNS(this.NS, 'line'); + svgEle.setAttribute('x1', pointArray[0].getX()); + svgEle.setAttribute('y1', pointArray[0].getY()); + svgEle.setAttribute('x2', pointArray[pointArray.length - 1].getX()); + svgEle.setAttribute('y2', pointArray[pointArray.length - 1].getY()); + break; + case 'circle': + svgEle = document.createElementNS(this.NS, 'circle'); + var radius = (pointArray[0].getDistance(pointArray[2], false)) /2; + svgEle.setAttribute('cx', path.bounds.center.x); + svgEle.setAttribute('cy', path.bounds.center.y); + svgEle.setAttribute('r', radius); + break; + case 'ellipse': + svgEle = document.createElementNS(this.NS, 'ellipse'); + var radiusX = (pointArray[2].getDistance(pointArray[0], false)) / 2; + var radiusY = (pointArray[3].getDistance(pointArray[1], false)) /2; + svgEle.setAttribute('cx', path.bounds.center.x); + svgEle.setAttribute('cy', path.bounds.center.y); + svgEle.setAttribute('rx', radiusX); + svgEle.setAttribute('ry', radiusY); + break; + case 'polyline': + svgEle = document.createElementNS(this.NS, 'polyline'); + var pointString = ''; + for(i = 0; i < pointArray.length; ++i) { + pointString += pointArray[i].getX() + ',' + pointArray[i].getY() + ' '; + } + svgEle.setAttribute('points', pointString); + break; + case 'polygon': + svgEle = document.createElementNS(this.NS, 'polygon'); + var pointString = ''; + for(i = 0; i < pointArray.length; ++i) { + pointString += pointArray[i].getX() + ',' + pointArray[i].getY() + ' '; + } + svgEle.setAttribute('points', pointString); + break; + case 'text': + svgEle = document.createElementNS(this.NS, 'text'); + svgEle.setAttribute('x', path.getPoint().getX()); + svgEle.setAttribute('y', path.getPoint().getY()); + if(path.style.font != undefined) { + svgEle.setAttribute('font', path.style.font); + } + if(path.characterStyle.font != undefined) { + svgEle.setAttribute('font-family', path.characterStyle.font); + } + if(path.characterStyle.fontSize != undefined) { + svgEle.setAttribute('font-size',path.characterStyle.fontSize); + } + svgEle.textContent = path.getContent(); + break; + default: + svgEle = document.createElementNS(this.NS, 'path'); + svgEle = this.pathSetup(path, pointArray, handleInArray, handleOutArray); + break; + } + //If the object is a circle, ellipse, rectangle, or rounded rectangle, it will find the angle + //found by the transformCheck method and make a path that accommodates for the transformed object + if(type != 'text' && type != undefined && type != 'polygon' && type != 'polyline' && type != 'line') { + var angle = this._transformCheck(path, pointArray, type) + 90; + console.log(angle); + if(angle != 0) { + if(type == 'rect' || type == 'roundRect') { + svgEle = document.createElementNS(this.NS, 'path'); + svgEle = this.pathSetup(path, pointArray, handleInArray, handleOutArray); + } else { + svgEle = document.createElementNS(this.NS, 'path'); + svgEle = this.pathSetup(path, pointArray, handleInArray, handleOutArray); + } + } + } + if(type == 'text') { + svgEle.setAttribute('transform','rotate(' + path.matrix.getRotation() + ',' + path.getPoint().getX() + ',' +path.getPoint().getY() +')'); + } + if(path.id != undefined) { + svgEle.setAttribute('id', path.id); + } + //checks if there is a stroke color in the passed in path + //adds an SVG element attribute with the defined stroke color + if (path.strokeColor != undefined) { + svgEle.setAttribute('stroke', path.strokeColor.toCssString()); + } + //same thing as above except checking for a fill color + if (path.fillColor != undefined) { + svgEle.setAttribute('fill', path.fillColor.toCssString()); + } else { + svgEle.setAttribute('fill', 'rgba(0,0,0,0)'); + } + //same thing as stroke color except with stroke width + if(path.strokeWidth != undefined){ + svgEle.setAttribute('stroke-width', path.strokeWidth); + } + //same thing as stroke color except with the path name + if(path.name != undefined) { + svgEle.setAttribute('name', path.name); + } + //same thing as stroke color except with the strokeCap + if(path.strokeCap != undefined) { + svgEle.setAttribute('stroke-linecap', path.strokeCap); + } + //same thing as stroke color except with the strokeJoin + if(path.strokeJoin != undefined) { + svgEle.setAttribute('stroke-linejoin', path.strokeJoin); + } + //same thing as stroke color except with the opacity + if(path.opacity != undefined) { + svgEle.setAttribute('opacity', path.opacity); + } + //checks to see if there the dashArray is set, then adds the attribute if there is. + if(path.dashArray[0] != undefined) { + var dashVals = ''; + for (var i in path.dashArray) { + if(i != path.dashArray.length -1) { + dashVals += path.dashArray[i] + ", "; + } else { + dashVals += path.dashArray[i]; + } + } + svgEle.setAttribute('stroke-dasharray', dashVals); + } + //same thing as stroke color except with the dash offset + if(path.dashOffset != undefined) { + svgEle.setAttribute('stroke-dashoffset', path.dashOffset); + } + //same thing as stroke color except with the miter limit + if(path.miterLimit != undefined) { + svgEle.setAttribute('stroke-miterlimit', path.miterLimit); + } + //same thing as stroke color except with the visibility + if(path.visibility != undefined) { + var visString = ''; + if(path.visibility) { + visString = 'visible'; + } else { + visString = 'hidden'; + } + svgEle.setAttribute('visibility', visString); + } + return svgEle; + }, - initialize(); // calls the init function after class is loaded -}; \ No newline at end of file + //Determines whether the object has been transformed or not through determining the angle + _determinesIfTransformed: function(path, pointArray, type) { + var topMidBoundx = (path.bounds.topRight.getX() + path.bounds.topLeft.getX() )/2; + var topMidBoundy = (path.bounds.topRight.getY() + path.bounds.topLeft.getY() )/2; + var topMidBound = new Point(topMidBoundx, topMidBoundy); + var centerPoint = path.getPosition(); + var topMidPathx; + var topMidPathy; + var topMidPath; + switch (type) { + case 'rect': + topMidPathx = (pointArray[1].getX() + pointArray[2].getX() )/2; + topMidPathy = (pointArray[1].getY() + pointArray[2].getY() )/2; + topMidPath = new Point(topMidPathx, topMidPathy); + break; + case 'ellipse': + topMidPath = new Point(pointArray[1].getX(), pointArray[1].getY()); + break; + case 'circle': + topMidPath = new Point(pointArray[1].getX(), pointArray[1].getY()); + break; + case 'roundRect': + topMidPathx = (pointArray[3].getX() + pointArray[4].getX())/2; + topMidPathy = (pointArray[3].getY() + pointArray[4].getY())/2; + topMidPath = new Point(topMidPathx, topMidPathy); + break; + default: + //Nothing happens here + break; + } + var deltaY = topMidPath.y - centerPoint.getY(); + var deltaX = topMidPath.x - centerPoint.getX(); + var angleInDegrees = Math.atan2(deltaY, deltaX) * 180 / Math.PI; + return angleInDegrees; + }, + + //pointstring is formatted in the way the SVG XML will be reading + //Namely, a point and the way to traverse to that point + pathSetup: function(path, pointArray, hIArray, hOArray) { + var svgPath = document.createElementNS(this.NS, 'path'); + var pointString = ''; + var x1; + var x2; + var y1; + var y2; + var handleOut1; + var handleIn2; + pointString += 'M' + pointArray[0].getX() + ',' + pointArray[0].getY() + ' '; + //Checks 2 points and the angles in between the 2 points + for (i = 0; i < pointArray.length-1; i++) { + x1 = pointArray[i].getX(); + y1 = pointArray[i].getY(); + x2 = pointArray[i + 1].getX(); + y2 = pointArray[i + 1].getY(); + handleOut1 = hOArray[i]; + handleIn2 = hIArray[i+1]; + if(handleOut1.getX() == 0 && handleOut1.getY() == 0 && handleIn2.getX() == 0 && handleIn2.getY() ==0) { + //L is lineto, moving to a point with drawing + pointString+= 'L' + x2 + ',' + y2 + ' '; + } else { + //c is curveto, relative: handleOut, handleIn - endpoint, endpoint - startpoint + pointString+= 'c' + (handleOut1.getX()) + ',' + (handleOut1.getY()) + ' '; + pointString+= (x2 - x1 + handleIn2.getX()) + ',' + (y2 - y1 + handleIn2.getY()) + ' '; + pointString+= (x2 - x1) + ',' + (y2-y1) + ' '; + } + } + if (!hOArray[hOArray.length - 1].equals([0,0]) && !hIArray[0].equals([0,0])) { + handleOut1 = hOArray[hOArray.length - 1]; + handleIn2 = hIArray[0]; + // Bezier curve from last point to first + x1 = pointArray[pointArray.length - 1].getX(); + y1 = pointArray[pointArray.length - 1].getY(); + x2 = pointArray[0].getX(); + y2 = pointArray[0].getY(); + pointString+= 'c' + (handleOut1.getX()) + ',' + (handleOut1.getY()) + ' '; + pointString+= (x2 - x1 + handleIn2.getX()) + ',' + (y2 - y1 + handleIn2.getY()) + ' '; + pointString+= (x2 - x1) + ',' + (y2-y1) + ' '; + } + if (path.getClosed()) + { + //Z implies a closed path, connecting the first and last points + pointString += 'z'; + } + svgPath.setAttribute('d',pointString); + return svgPath; + }, + + /** + * Checks the type SVG object created by converting from Paper.js + * + * @name ExportSVG#checkType + * @function + * @param {SVG Object Array} segArray An array of objects for the newly + * converted SVG object + * @return {String} type A string labeling which type of object the + * passed in object is + */ + _determineType: function(path, segArray, pointArray, handleInArray, handleOutArray) { + var type; + var dPoint12; + var dPoint34; + var curves = false; + var segHandleIn; + var segHandleOut; + for( var i in segArray){ + //Checks for any curves (if the handles have values). Differentiates between straight objects(line, polyline, rect, and polygon) and + //and objects with curves(circle, ellipse, roundedRectangle). + segHandleIn = segArray[i].getHandleIn(); + segHandleOut = segArray[i].getHandleOut(); + curves = segHandleIn.getX() != 0 || segHandleIn.getY() != 0 ? true : curves; + curves = segHandleOut.getX() != 0 || segHandleOut.getY() != 0 ? true : curves; + } + //Checks for curves in the passed in segments + //Checks if the type of the passed in path is a rounded rectangle, an ellipse, a circle, or if it's simply a path + //If there aren't any curves (if curves = false), then it checks if the type is a rectangle, a polygon, a polyline, or simply a line. + if(curves){ + if(segArray.length == 8) { + //if the distance between (point0 and point3) and (point7 and point4) are equal then it is a roundedRectangle + dPoint12 = Math.round(pointArray[0].getDistance(pointArray[3], false)); + dPoint34 = Math.round(pointArray[7].getDistance(pointArray[4], false)); + if(dPoint12 == dPoint34) { + type = 'roundRect'; + } + } else if(segArray.length == 4) { + //checks if the values of the point have values similar to circles and ellipses + var checkPointValues = true; + for(i = 0; i < pointArray.length && checkPointValues == true; i++) { + if(handleInArray[i].getX() != 0 || handleInArray[i].getY() != 0 && Math.round(Math.abs(handleInArray[i].getX())) === Math.round(Math.abs(handleOutArray[i].getX())) && Math.round(Math.abs(handleInArray[i].getY())) === Math.round(Math.abs(handleOutArray[i].getY()))) { + checkPointValues = true; + } else { + checkPointValues = false; + } + } + if(checkPointValues == true) { + //if the distance between (point0 and point2) and (point1 and point3) are equal, then it is a circle + var d1 = Math.round(pointArray[0].getDistance(pointArray[2], false)); + var d2 = Math.round(pointArray[1].getDistance(pointArray[3], false)); + if(d1 == d2) { + type = 'circle'; + } else { + type = 'ellipse'; + } + } + } + } else if(!curves) { + if(segArray.length == 4) { + //if the distance between (point0 and point1) and (point2 and point3) are equal, then it is a rectangle + dPoint12 = Math.round(pointArray[0].getDistance(pointArray[1], false)); + dPoint34 = Math.round(pointArray[3].getDistance(pointArray[2], false)); + if(dPoint12 == dPoint34) { + type = 'rect'; + } + } else if(segArray.length >= 3) { + //If it is an object with more than 3 segments and the path is closed, it is a polygon + if(path.getClosed()) { + type = 'polygon'; + } else { + type = 'polyline'; + } + } else { + //if all of the handle values are == 0 and there are only 2 segments, it is a line + type = 'line'; + } + } else { + type = null; + } + console.log(type); + return type; + } +}); diff --git a/src/svg/ImportSVG.js b/src/svg/ImportSVG.js index 08f6f557..30277395 100644 --- a/src/svg/ImportSVG.js +++ b/src/svg/ImportSVG.js @@ -1,55 +1,581 @@ -/** - * Imports svg into items with groups - * Stetson Alpha - Paper.js - * - */ +/* +* Paper.js +* +* This file is part of Paper.js, a JavaScript Vector Graphics Library, +* based on Scriptographer.org and designed to be largely API compatible. +* http://paperjs.org/ +* http://scriptographer.org/ +* +* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +* http://lehni.org/ & http://jonathanpuckey.com/ +* +* Distributed under the MIT license. See LICENSE file for details. +* +* All rights reserved. +* +* +* +* This class and all methods therein designed by Stetson-Team-Alpha +* @author Stetson-Team-Alpha +*/ -var ImportSVG = function() -{ - //initialize - function initialize() - { +/** +* @name ImportSVG +* @class The ImportSVG object represents an object created using the SVG +* Canvas that will be converted into a Paper.js object. +* The SVG object is imported into Paper.js by converting it into items +* within groups. +* +*/ + +var ImportSVG = this.ImportSVG = Base.extend(/** @Lends ImportSVG# */{ + /** + * Creates a Paper.js object using data parsed from the selected + * SVG Document Object Model (DOM). The SVG object is imported, + * than a layer is created (with groups for the items if needed). + * + * Supports nested groups + * + * @param {SVG DOM} svg An SVG DOM object with parameters + * @return {item} A Paper.js layer + */ + importSVG: function(svg) { + var item; + var symbol; + switch (svg.nodeName.toLowerCase()) { + case 'line': + item = this._importLine(svg); + break; + case 'rect': + item = this._importRectangle(svg); + break; + case 'circle': + item = this._importCircle(svg); + break; + case 'ellipse': + item = this._importOval(svg); + break; + case 'g': + case 'svg': + item = this._importGroup(svg); + break; + case 'text': + item = this._importText(svg); + break; + case 'path': + item = this._importPath(svg); + break; + case 'polygon': + case 'polyline': + item = this._importPoly(svg); + break; + case 'symbol': + item = this._importGroup(svg); + this._importAttributesAndStyles(svg, item); + symbol = new Symbol(item); + item = null; + default: + //Not supported yet. + } + + if (item) { + this._importAttributesAndStyles(svg, item); + } + + return item; + }, + + /** + * Creates a Paper.js group by parsing a specific GNode of the + * imported SVG DOM + * + * @name ImportSVG#importGroup + * @function + * @param {XML DOM} svg A node passed in by the imported SVG + * @return {Group} group A Paper.js group + * + * + */ + _importGroup: function(svg) { + var group = new Group(); + var child; + for (var i in svg.childNodes) { + child = svg.childNodes[i]; + if (child.nodeType != 1) { + continue; + } + item = this.importSVG(child); + if (item) { + group.addChild(item); + } + } + + return group; + }, + + /** + * Creates a Path.Circle item in Paper.js using an imported + * Circle from SVG + * + * @name ImportSVG#importCircle + * @function + * @param {XML DOM} svgCircle An SVG circle node + * @return {Path.Circle} circle A Path.Circle item for Paper.js + */ + _importCircle: function(svgCircle) { + var cx = svgCircle.cx.baseVal.value || 0; + var cy = svgCircle.cy.baseVal.value || 0; + var r = svgCircle.r.baseVal.value || 0; + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + return circle; + }, + + + /** + * Creates a Path.Oval item in Paper.js using an imported Oval from SVG + * + * @name ImportSVG#importOval + * @function + * @param {XML DOM} svgOval An SVG ellipse node + * @return {Path.Oval} oval A Path.Oval item for Paper.js + */ + _importOval: function(svgOval) { + var cx = svgOval.cx.baseVal.value || 0; + var cy = svgOval.cy.baseVal.value || 0; + var rx = svgOval.rx.baseVal.value || 0; + var ry = svgOval.ry.baseVal.value || 0; + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + return oval; + }, + + /** + * Creates a Path.Rectangle item from an imported SVG rectangle + * + * @name ImportSVG#importRectangle + * @function + * @param {XML DOM} svgRectangle An SVG rectangle node + * @return {Path.Rectangle} rectangle A Path.Rectangle item for + * Paper.js + */ + /** + * Creates a Path.RoundRectangle item from an imported SVG + * rectangle with rounded corners + * + * @name ImportSVG#importRectangle + * @function + * @param {XML DOM} svgRectangle An SVG rectangle node with + * rounded corners + * @return {Path.RoundRectangle} rectangle A Path.Rectangle item + * for Paper.js + */ + _importRectangle: function(svgRectangle) { + var x = svgRectangle.x.baseVal.value || 0; + var y = svgRectangle.y.baseVal.value || 0; + var rx = svgRectangle.rx.baseVal.value || 0; + var ry = svgRectangle.ry.baseVal.value || 0; + var width = svgRectangle.width.baseVal.value || 0; + var height = svgRectangle.height.baseVal.value || 0; + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + + if (rx && ry) { + var cornerSize = new Size(rx, ry); + rectangle = new Path.RoundRectangle(rectangle, cornerSize); + } else { + rectangle = new Path.Rectangle(rectangle); + } + + return rectangle; + }, + + /** + * Creates a Path.Line item in Paper.js from an imported SVG line + * + * @name ImportSVG#importLine + * @function + * @param {XML DOM} svgLine An SVG line node + * @return {Path.Line} line A Path.Line item for Paper.js + */ + _importLine: function(svgLine) { + var x1 = svgLine.x1.baseVal.value || 0; + var y1 = svgLine.y1.baseVal.value || 0; + var x2 = svgLine.x2.baseVal.value || 0; + var y2 = svgLine.y2.baseVal.value || 0; + + var from = new Point(x1, y1); + var to = new Point(x2, y2); + var line = new Path.Line(from, to); + + return line; + }, + + /** + * Creates a PointText item in Paper.js from an imported SVG text node + * + * @name ImportSVG#importText + * @function + * @param {XML DOM} svgText An SVG text node + * @return {Path.Text} text A PointText item for Paper.js + */ + _importText: function(svgText) { + var x = svgText.x.baseVal.getItem(0).value || 0; + var y = svgText.y.baseVal.getItem(0).value || 0; + + var dx = 0; + var dy = 0; + if (svgText.dx.baseVal.numberOfItems) { + dx = svgText.dx.baseVal.getItem(0).value || 0; + } + if (svgText.dy.baseVal.numberOfItems) { + dy = svgText.dy.baseVal.getItem(0).value || 0; + } - }; - + var textLength = svgText.textLength.baseVal.value || 0; + + /* Not supported by Paper.js + x; //multiple values for x + y; //multiple values for y + dx; //multiple values for x + dy; //multiple values for y + var rotate; //character rotation + var lengthAdjust; + */ + var textContent = svgText.textContent || ""; + var bottomLeft = new Point(x, y); + + bottomLeft = bottomLeft.add([dx, dy]); + bottomLeft = bottomLeft.subtract([textLength / 2, 0]); + var text = new PointText(bottomLeft); + text.content = textContent; + + return text; + }, + /** - * - * Takes the svg dom obj and parses the data - * to create a layer with groups (if needed) with - * items inside. Should support nested groups. - * - * takes in a svg object (xml dom) - * returns Paper.js Layer - */ - this.importSVG = function(svg) - { - return layer; - }; - + * Creates a Paper.js Path by parsing + * a specific SVG node (rectangle, path, circle, polygon, etc.) + * and creating the right Path object based on the SVG type. + * + * @name ImportSVG#importPath + * @function + * @param {XML DOM} svg An SVG object + * @return {Item} item A Paper.js item + */ + _importPath: function(svgPath) { + var path = new Path(); + var segments = svgPath.pathSegList; + var segment; + var j; + var relativeToPoint; + var controlPoint; + var prevCommand; + var segmentTo; + for (var i = 0; i < segments.numberOfItems; ++i){ + segment = segments.getItem(i); + if (segment.pathSegType == SVGPathSeg.PATHSEG_UNKNOWN) { + continue; + } + if (segment.pathSegType % 2 == 1 && path.segments.length > 0) { + relativeToPoint = path.lastSegment.point; + } else { + relativeToPoint = new Point(0, 0); + } + segmentTo = new Point(segment.x, segment.y); + segmentTo = segmentTo.add(relativeToPoint); + switch (segment.pathSegType) { + case SVGPathSeg.PATHSEG_CLOSEPATH: + path.closePath(); + break; + case SVGPathSeg.PATHSEG_MOVETO_ABS: + case SVGPathSeg.PATHSEG_MOVETO_REL: + path.moveTo(segmentTo); + break; + case SVGPathSeg.PATHSEG_LINETO_ABS: + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + case SVGPathSeg.PATHSEG_LINETO_REL: + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + path.lineTo(segmentTo); + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + path.cubicCurveTo( + relativeToPoint.add([segment.x1, segment.y1]), + relativeToPoint.add([segment.x2, segment.y2]), + segmentTo + ); + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + path.quadraticCurveTo( + relativeToPoint.add([segment.x1, segment.y1]), + segmentTo + ); + break; + case SVGPathSeg.PATHSEG_ARC_ABS: + case SVGPathSeg.PATHSEG_ARC_REL: + //TODO: Implement Arcs. + //TODO: Requires changes in Paper.js's Path to do. + //TODO: http://www.w3.org/TR/SVG/implnote.html + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + prevCommand = segments.getItem(i - 1); + controlPoint = new Point(prevCommand.x2, prevCommand.y2); + controlPoint = controlPoint.subtract([prevCommand.x, prevCommand.y]); + controlPoint = controlPoint.add(path.lastSegment.point); + controlPoint = path.lastSegment.point.subtract(controlPoint); + controlPoint = path.lastSegment.point.add(controlPoint); + path.cubicCurveTo( + controlPoint, + relativeToPoint.add([segment.x2, segment.y2]), + segmentTo + ); + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + for (j = i; j >= 0; --j) { + prevCommand = segments.getItem(j); + if (prevCommand.pathSegType == SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS || + prevCommand.pathSegType == SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL + ) { + controlPoint = new Point(prevCommand.x1, prevCommand.y1); + controlPoint = controlPoint.subtract([prevCommand.x, prevCommand.y]); + controlPoint = controlPoint.add(path.segments[j].point); + break; + } + } + for (j; j < i; ++j) { + controlPoint = path.segments[j].point.subtract(controlPoint); + controlPoint = path.segments[j].point.add(controlPoint); + } + path.quadraticCurveTo(controlPoint, segmentTo); + break; + } + } + + return path; + }, + /** - * Creates a Paper.js Group by parsing - * a specific svg g node - * - * takes in a svg object (xml dom) - * returns Paper.js Group + * Creates a Path.Poly item in Paper.js using an imported Polygon or + * Polyline SVG node + * + * @name ImportSVG#importPoly + * @function + * @param {XML DOM} svgPoly An SVG polygon or polyline node + * @return {Path.Poly} poly A Path.Poly item for Paper.js + * - svg polyline node (xml dom) + * - svg polygon node (xml dom) + * returns a Path item */ - function importGroup(svg) - { - return group; - }; - + _importPoly: function(svgPoly) { + var poly = new Path(); + var points = svgPoly.points; + var start = points.getItem(0); + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (svgPoly.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + return poly; + }, + /** - * Creates a Paper.js Path by parsing - * a specific svg node (rect, path, circle, polygon, etc) - * and creating the right path object based on the svg type. - * - * takes in a svg object (xml dom) - * returns Paper.js Group + * Converts various SVG styles and attributes into Paper.js styles and + * attributes + * This method is destructive to item (changes happen to it) + * + * @name ImportSVG#importAttributesAndStyles + * @function + * @param {XML DOM} svg An SVG node + * @param {Item} item A Paper.js item */ - function importPath(svg) - { - return path; - }; - - initialize(); // calls the init function after class is loaded -}; \ No newline at end of file + _importAttributesAndStyles: function(svg, item) { + var name, + value, + cssName; + for (var i = 0; i < svg.style.length; ++i) { + name = svg.style[i]; + cssName = name.replace(/-(.)/g, function(match, p) { + return p.toUpperCase(); + }); + value = svg.style[cssName]; + this._applyAttributeOrStyle(name, value, item, svg); + } + for (var i = 0; i < svg.attributes.length; ++i) { + name = svg.attributes[i].name; + value = svg.attributes[i].value; + this._applyAttributeOrStyle(name, value, item, svg); + } + }, + + /** + * Parses an SVG style attibute and applies it to a Paper.js item + * This method is destructive to item (changes happen to it) + * + * @name ImportSVG#applyAttributeOrStyle + * @function + * @param {Style Name} name An SVG style name + * @param {Style Value} value The value of an SVG style + * @param {Item} item A Paper.js item + * @param {XML DOM} svg An SVG node + */ + _applyAttributeOrStyle: function(name, value, item, svg) { + if (!value) { + return; + } + switch (name) { + case 'id': + item.name = value; + break; + case 'fill': + if (value != 'none') { + item.fillColor = value; + } + break; + case 'stroke': + if (value != 'none') { + item.strokeColor = value; + } + break; + case 'stroke-width': + item.strokeWidth = parseFloat(value, 10); + break; + case 'stroke-linecap': + item.strokeCap = value; + break; + case 'stroke-linejoin': + item.strokeJoin = value; + break; + case 'stroke-dasharray': + value = value.replace(/px/g, ''); + value = value.replace(/, /g, ','); + value = value.replace(/ /g, ','); + value = value.split(','); + for (var i in value) { + value[i] = parseFloat(value[i], 10); + } + item.dashArray = value; + break; + case 'stroke-dashoffset': + item.dashOffset = parseFloat(value, 10); + break; + case 'stroke-miterlimit': + item.miterLimit = parseFloat(value, 10); + break; + case 'transform': + this._applyTransform(item, svg); + case 'opacity': + item.opacity = parseFloat(value, 10); + case 'visibility': + item.visibility = (value == 'visible') ? true : false; + break; + case 'font': + case 'font-family': + case 'font-size': + //Implemented in characterStyle below. + break; + default: + // Not supported yet. + break; + } + if (item.characterStyle) { + switch (name) { + case 'font': + var text = document.createElement('span'); + text.style.font = value; + for (var i = 0; i < text.style.length; ++i) { + var n = text.style[i]; + this._applyAttributeOrStyle(n, text.style[n], item, svg); + } + break; + case 'font-family': + var fonts = value.split(','); + fonts[0] = fonts[0].replace(/^\s+|\s+$/g, ""); + item.characterStyle.font = fonts[0]; + break; + case 'font-size': + item.characterStyle.fontSize = parseFloat(value, 10); + break; + } + } + }, + + /** + * Applies the transformations specified on the SVG node to the newly + * made Paper.js item + * This method is destructive to item + * + * @name ImportSVG#applyTransform + * @function + * @param {XML DOM} An SVG node + * @param {Item} A Paper.js item + */ + _applyTransform: function(item, svg) { + var transforms = svg.transform.baseVal; + var transform; + var matrix = new Matrix(); + + for (var i = 0; i < transforms.numberOfItems; ++i) { + transform = transforms.getItem(i); + if (transform.type == SVGTransform.SVG_TRANSFORM_UNKNOWN) { + continue; + } + var transformMatrix = new Matrix( + transform.matrix.a, + transform.matrix.c, + transform.matrix.b, + transform.matrix.d, + transform.matrix.e, + transform.matrix.f + ); + switch (transform.type) { + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + break; + case SVGTransform.SVG_TRANSFORM_SCALE: + break; + + //Compensate for SVG's theta rotation going the opposite direction + case SVGTransform.SVG_TRANSFORM_MATRIX: + var temp = transformMatrix.getShearX(); + transformMatrix.setShearX(transformMatrix.getShearY()); + transformMatrix.setShearY(temp); + break; + case SVGTransform.SVG_TRANSFORM_SKEWX: + transformMatrix.setShearX(transformMatrix.getShearY()); + transformMatrix.setShearY(0); + break; + case SVGTransform.SVG_TRANSFORM_SKEWY: + transformMatrix.setShearY(transformMatrix.getShearX()); + transformMatrix.setShearX(0); + break; + case SVGTransform.SVG_TRANSFORM_ROTATE: + transformMatrix.setShearX(transformMatrix.getShearX() * -1); + transformMatrix.setShearY(transformMatrix.getShearY() * -1); + break; + } + matrix.concatenate(transformMatrix); + } + item.transform(matrix); + } +}); diff --git a/test/tests/ExportSVG.js b/test/tests/ExportSVG.js new file mode 100644 index 00000000..9bdbda24 --- /dev/null +++ b/test/tests/ExportSVG.js @@ -0,0 +1,556 @@ +/** +* Paper.js +* +* This file is part of Paper.js, a JavaScript Vector Graphics Library, +* based on Scriptographer.org and designed to be largely API compatible. +* http://paperjs.org/ +* http://scriptographer.org/ +* +* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +* http://lehni.org/ & http://jonathanpuckey.com/ +* +* Distributed under the MIT license. See LICENSE file for details. +* +* All rights reserved. +* +* This test file created by Stetson-Team-Alpha +*/ + +module('ExportSVG'); + +test('compare line path functions', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'line'); + var x1 = 5, + x2 = 45, + y1 = 5, + y2 = 45; + shape.setAttribute('x1', x1); + shape.setAttribute('y1', y1); + shape.setAttribute('x2', x2); + shape.setAttribute('y2', y2); + + var line = new Path.Line([x1, y1], [x2, y2]); + + var epjs = new ExportSVG(); + var exportedLine = epjs.exportPath(line); + + var shapex1 = shape.getAttribute('x1'); + var shapey1 = shape.getAttribute('y1'); + var shapex2 = shape.getAttribute('x2'); + var shapey2 = shape.getAttribute('y2'); + + var exportedx1 = exportedLine.getAttribute('x1'); + var exportedy1 = exportedLine.getAttribute('y1'); + var exportedx2 = exportedLine.getAttribute('x2'); + var exportedy2 = exportedLine.getAttribute('y2'); + + equals(shapex1, exportedx1); + equals(shapey1, exportedy1); + equals(shapex2, exportedx2); + equals(shapey2, exportedy2); + +}); + +test('compare negative line path functions', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'line'); + var x1 = -5, + x2 = -45, + y1 = -5, + y2 = -45; + shape.setAttribute('x1', x1); + shape.setAttribute('y1', y1); + shape.setAttribute('x2', x2); + shape.setAttribute('y2', y2); + + var line = new Path.Line([x1, y1], [x2, y2]); + + var epjs = new ExportSVG(); + var exportedLine = epjs.exportPath(line); + + var shapex1 = shape.getAttribute('x1'); + var shapey1 = shape.getAttribute('y1'); + var shapex2 = shape.getAttribute('x2'); + var shapey2 = shape.getAttribute('y2'); + + var exportedx1 = exportedLine.getAttribute('x1'); + var exportedy1 = exportedLine.getAttribute('y1'); + var exportedx2 = exportedLine.getAttribute('x2'); + var exportedy2 = exportedLine.getAttribute('y2'); + + equals(shapex1, exportedx1); + equals(shapey1, exportedy1); + equals(shapex2, exportedx2); + equals(shapey2, exportedy2); + +}); + +test('compare invalid line path functions', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'line'); + var x1 = null, + x2 = null, + y1 = null, + y2 = null; + shape.setAttribute('x1', x1); + shape.setAttribute('y1', y1); + shape.setAttribute('x2', x2); + shape.setAttribute('y2', y2); + + var line = new Path.Line([x1, y1], [x2, y2]); + + var epjs = new ExportSVG(); + var exportedLine = epjs.exportPath(line); + + var shapex1 = shape.getAttribute('x1'); + var shapey1 = shape.getAttribute('y1'); + var shapex2 = shape.getAttribute('x2'); + var shapey2 = shape.getAttribute('y2'); + + var exportedx1 = exportedLine.getAttribute('x1'); + var exportedy1 = exportedLine.getAttribute('y1'); + var exportedx2 = exportedLine.getAttribute('x2'); + var exportedy2 = exportedLine.getAttribute('y2'); + + equals(shapex1, exportedx1); + equals(shapey1, exportedy1); + equals(shapex2, exportedx2); + equals(shapey2, exportedy2); + +}); + +/*test('compare rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = 25, + y = 25, + width = 100, + height = 100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var point = new Point(100, 100); + var size = new Size(100, 100); + var path = new Path.Rectangle(point, size); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(path); + + var shapex1 = shape.getAttribute('x'); + var shapey1 = shape.getAttribute('y1'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x1'); + var exportedy = exportedRectangle.getAttribute('y1'); + + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +}); + +test('compare negative rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = -25, + y = -25, + width = -100, + height = -100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rect = new Rectangle(topLeft, size); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(rect); + + var shapex = shape.getAttribute('x'); + var shapey = shape.getAttribute('y'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x'); + var exportedy = exportedRectangle.getAttribute('y'); + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +}); + +test('compare invalid rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = null, + y = null, + width = null, + height = 100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rect = new Rectangle(topLeft, size); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(rect); + + var shapex = shape.getAttribute('x'); + var shapey = shape.getAttribute('y'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x'); + var exportedy = exportedRectangle.getAttribute('y'); + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +}); + +test('compare rounded rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = 25, + y = 25, + rx = 50, + ry = 50, + width = 100, + height = 100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rect = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rect, cornerSize); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(rect); + + var shapex = shape.getAttribute('x'); + var shapey = shape.getAttribute('y'); + var shapecx = shape.getAttribute('rx'); + var shapecy = shape.getAttribute('ry'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x'); + var exportedy = exportedRectangle.getAttribute('y'); + var exportedcx = exportedRectangle.getAttribute('rx'); + var exportedcy = exportedRectangle.getAttribute('ry'); + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +}); + +test('compare negative rounded rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = -25, + y = -25, + rx = -50, + ry = -50, + width = -100, + height = -100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rect = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rect, cornerSize); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(rect); + + var shapex = shape.getAttribute('x'); + var shapey = shape.getAttribute('y'); + var shapecx = shape.getAttribute('rx'); + var shapecy = shape.getAttribute('ry'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x'); + var exportedy = exportedRectangle.getAttribute('y'); + var exportedcx = exportedRectangle.getAttribute('rx'); + var exportedcy = exportedRectangle.getAttribute('ry'); + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +}); + +test('compare invalid rounded rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'rect'); + var x = null, + y = null, + rx = null, + ry = null, + width = null, + height = null; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rect = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rect, cornerSize); + + var epjs = new ExportSVG(); + var exportedRectangle = new epjs.exportPath(rect); + + var shapex = shape.getAttribute('x'); + var shapey = shape.getAttribute('y'); + var shapecx = shape.getAttribute('rx'); + var shapecy = shape.getAttribute('ry'); + var shapewidth = shape.getAttribute('width'); + var shapeheight = shape.getAttribute('height'); + + var exportedx = exportedRectangle.getAttribute('x'); + var exportedy = exportedRectangle.getAttribute('y'); + var exportedcx = exportedRectangle.getAttribute('rx'); + var exportedcy = exportedRectangle.getAttribute('ry'); + var exportedwidth = exportedRectangle.getAttribute('width'); + var exportedheight = exportedRectangle.getAttribute('height'); + + equals(shapex, exportedx); + equals(shapey, exportedy); + equals(shapewidth, exportedwidth); + equals(shapeheight, exportedheight); +});*/ + +test('compare oval values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'ellipse'); + var cx = 100, + cy = 80, + rx = 50; + ry = 30; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + var epjs = new ExportSVG(); + var exportedOval = epjs.exportPath(oval); + + var shapecx = shape.getAttribute('cx'); + var shapecy = shape.getAttribute('cy'); + var shaperx = shape.getAttribute('rx'); + var shapery = shape.getAttribute('ry'); + + var exportedcx = exportedOval.getAttribute('cx'); + var exportedcy = exportedOval.getAttribute('cy'); + var exportedrx = exportedOval.getAttribute('rx'); + var exportedry = exportedOval.getAttribute('ry'); + + equals(shapecx, exportedcx); + equals(shapecy, exportedcy); + equals(shaperx, exportedrx); + equals(shapery, exportedry); + +}); + +test('compare circle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'circle'); + var cx = 100, + cy = 80, + r = 50; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('r', r); + + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + var epjs = new ExportSVG(); + var exportedCircle = epjs.exportPath(circle); + + var shapecx = shape.getAttribute('cx'); + var shapecy = shape.getAttribute('cy'); + var shaper = shape.getAttribute('r'); + + var exportedcx = exportedCircle.getAttribute('cx'); + var exportedcy = exportedCircle.getAttribute('cy'); + var exportedr = exportedCircle.getAttribute('r'); + + equals(shapecx, exportedcx); + equals(shapecy, exportedcy); + equals(shaper, exportedr); + +}); + +test('compare polygon values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polygon'); + var svgpoints = "100,10 40,180 190,60 10,60 160,180"; + shape.setAttribute('points', svgpoints); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + var epjs = new ExportSVG(); + var exportedPolygon = epjs.exportPath(poly); + + var svgPoints = shape.getAttribute('points'); + + var exportedPoints = shape.getAttribute('points'); + + equals(svgPoints, exportedPoints); + +}); + +test('compare negative polygon values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polygon'); + var svgpoints = "-100,-10 -40,-180 -190,-60 -10,-60 -160,-180"; + shape.setAttribute('points', svgpoints); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + var epjs = new ExportSVG(); + var exportedPolygon = epjs.exportPath(poly); + + var svgPoints = shape.getAttribute('points'); + + var exportedPoints = shape.getAttribute('points'); + + equals(svgPoints, exportedPoints); + +}); + +test('compare polyline values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polyline'); + var svgpoints = "5,5 45,45 5,45 45,5"; + shape.setAttribute('points', svgpoints); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + var epjs = new ExportSVG(); + var exportedPolygon = epjs.exportPath(poly); + + var svgPoints = shape.getAttribute('points'); + + var exportedPoints = shape.getAttribute('points'); + + equals(svgPoints, exportedPoints); + +}); + +test('compare negative polyline values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polyline'); + var svgpoints = "-5,-5 -45,-45 -5,-45 -45,-5"; + shape.setAttribute('points', svgpoints); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + var epjs = new ExportSVG(); + var exportedPolygon = epjs.exportPath(poly); + + var svgPoints = shape.getAttribute('points'); + + var exportedPoints = shape.getAttribute('points'); + + equals(svgPoints, exportedPoints); + +}); diff --git a/test/tests/ImportSVG.js b/test/tests/ImportSVG.js new file mode 100644 index 00000000..0f3f613f --- /dev/null +++ b/test/tests/ImportSVG.js @@ -0,0 +1,451 @@ +/* +* Paper.js +* +* This file is part of Paper.js, a JavaScript Vector Graphics Library, +* based on Scriptographer.org and designed to be largely API compatible. +* http://paperjs.org/ +* http://scriptographer.org/ +* +* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +* http://lehni.org/ & http://jonathanpuckey.com/ +* +* Distributed under the MIT license. See LICENSE file for details. +* +* All rights reserved. +* +* This test file created by Stetson-Team-Alpha +*/ + +module('ImportSVG'); + +test('make an svg line', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'line'); + var x1 = 5, + x2 = 45, + y1 = 5, + y2 = 45; + shape.setAttribute('x1', x1); + shape.setAttribute('y1', y1); + shape.setAttribute('x2', x2); + shape.setAttribute('y2', y2); + + var isvg = new ImportSVG(); + var importedLine = isvg.importSVG(shape); + + var line = new Path.Line([x1, y1], [x2, y2]); + + compareSegmentLists(importedLine.segments, line.segments, true); +}); + +test('make an svg line with invalid values', function() { + var svgns = 'http://www.w3.org/2000/svg'; + var shape = document.createElementNS(svgns, 'line'); + shape.setAttribute('x1', null); + shape.setAttribute('y1', null); + shape.setAttribute('x2', null); + shape.setAttribute('y2', null); + + var isvg = new ImportSVG(); + var importedLine = isvg.importSVG(shape); + + var line = new Path.Line([0, 0], [0, 0]); + + compareSegmentLists(importedLine.segments, line.segments, true); + +}); + +test('compare rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + var x = 25, + y = 25, + width = 100, + height = 100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + var realRectangle = new Path.Rectangle(rectangle); + + compareSegmentLists(importedRectangle.segments, realRectangle.segments, true); +}); + + +test('compare negative rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + var x = -925, + y = -111, + width = -100, + height = -18; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + var realRectangle = new Path.Rectangle(rectangle); + + compareSegmentLists(importedRectangle.segments, realRectangle.segments, true); + }); + + +test('compare invalid rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + + shape.setAttribute('x', null); + shape.setAttribute('y', null); + shape.setAttribute('width', null); + shape.setAttribute('height', null); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + + var topLeft = new Point(0, 0); + var size = new Size(0, 0); + var rectangle = new Rectangle(topLeft, size); + var realRectangle = new Path.Rectangle(rectangle); + + compareSegmentLists(importedRectangle.segments, realRectangle.segments, true); + }); + +test('compare round rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + var x = 25, + y = 25, + rx = 50, + ry = 50, + width = 100, + height = 100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rectangle = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rectangle, cornerSize); + + compareSegmentLists(importedRectangle.segments, roundRect.segments, true); +}); + +test('compare negative round rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + var x = -25, + y = -25, + rx = -50, + ry = -50, + width = -100, + height = -100; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rectangle = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rectangle, cornerSize); + + compareSegmentLists(importedRectangle.segments, roundRect.segments, true); +}); + +test('compare invalid round rectangle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'rect'); + var x = null, + y = null, + rx = null, + ry = null, + width = null, + height = null; + shape.setAttribute('x', x); + shape.setAttribute('y', y); + shape.setAttribute('rx', 1); + shape.setAttribute('ry', 1); + shape.setAttribute('width', width); + shape.setAttribute('height', height); + + var isvg = new ImportSVG(); + var importedRectangle = isvg.importSVG(shape); + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var cornerSize = new Size(rx, ry); + var rectangle = new Rectangle(topLeft, size); + var roundRect = new Path.RoundRectangle(rectangle, cornerSize); + + compareSegmentLists(importedRectangle.segments, roundRect.segments, true); +}); + +test('compare oval values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'ellipse'); + var cx = 300, + cy = 80, + rx = 100, + ry = 50; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + + var isvg = new ImportSVG(); + var importedOval = isvg.importSVG(shape); + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + compareSegmentLists(importedOval.segments, oval.segments, true); + + +}); + +test('compare negative oval values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'ellipse'); + var cx = -111, + cy = -2, + rx = -292, + ry = -1; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('rx', rx); + shape.setAttribute('ry', ry); + + var isvg = new ImportSVG(); + var importedOval = isvg.importSVG(shape); + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + compareSegmentLists(importedOval.segments, oval.segments, true); + +}); + +test('compare invalid oval values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'ellipse'); + shape.setAttribute('cx', null); + shape.setAttribute('cy', null); + shape.setAttribute('rx', null); + shape.setAttribute('ry', null); + + var isvg = new ImportSVG(); + var importedOval = isvg.importSVG(shape); + + var center = new Point(0, 0); + var offset = new Point(0, 0); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + compareSegmentLists(importedOval.segments, oval.segments, true); + +}); + +test('compare circle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'circle'); + var cx = 100, + cy = 80, + r = 50; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('r', r); + + var isvg = new ImportSVG(); + var importedCircle = isvg.importSVG(shape); + + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + compareSegmentLists(importedCircle.segments, circle.segments, true); + +}); + +test('compare negative circle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'circle'); + var cx = -234, + cy = -77, + r = -1110; + shape.setAttribute('cx', cx); + shape.setAttribute('cy', cy); + shape.setAttribute('r', r); + + var isvg = new ImportSVG(); + var importedCircle = isvg.importSVG(shape); + + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + compareSegmentLists(importedCircle.segments, circle.segments, true); + +}); + + +test('compare invalid circle values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'circle'); + shape.setAttribute('cx', null); + shape.setAttribute('cy', null); + shape.setAttribute('r', null); + + var isvg = new ImportSVG(); + var importedCircle = isvg.importSVG(shape); + + var center = new Point(0, 0); + var circle = new Path.Circle(center, 0); + + compareSegmentLists(importedCircle.segments, circle.segments, true); + +}); + +test('compare polygon values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polygon'); + var svgpoints = "100,10 40,180 190,60 10,60 160,180"; + shape.setAttribute('points', svgpoints); + + var isvg = new ImportSVG(); + var importedPolygon = isvg.importSVG(shape); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + compareSegmentLists(importedPolygon.segments, poly.segments, true); + +}); + +test('compare negative polygon values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polygon'); + var svgpoints = "-100,-10 -40,-180 -190,-60 -10,-60 -160,-180"; + shape.setAttribute('points', svgpoints); + + var isvg = new ImportSVG(); + var importedPolygon = isvg.importSVG(shape); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + compareSegmentLists(importedPolygon.segments, poly.segments, true); + +}); + +test('compare polyline values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polyline'); + var svgpoints = "5,5 45,45 5,45 45,5"; + shape.setAttribute('points', svgpoints); + + var isvg = new ImportSVG(); + var importedPolyline = isvg.importSVG(shape); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + compareSegmentLists(importedPolyline.segments, poly.segments, true); + +}); + + test('compare negative polyline values', function() { + var svgns = 'http://www.w3.org/2000/svg' + var shape = document.createElementNS(svgns, 'polyline'); + var svgpoints = "-5,-5 -45,-45 -5,-45 -45,-5"; + shape.setAttribute('points', svgpoints); + + var isvg = new ImportSVG(); + var importedPolyline = isvg.importSVG(shape); + + var poly = new Path(); + var points = shape.points; + var start = points.getItem(0) + var point; + poly.moveTo([start.x, start.y]); + + for (var i = 1; i < points.length; ++i) { + point = points.getItem(i); + poly.lineTo([point.x, point.y]); + } + if (shape.nodeName.toLowerCase() == 'polygon') { + poly.closePath(); + } + + compareSegmentLists(importedPolyline.segments, poly.segments, true); + +}); From 71edb9ed88fdd188b0d707551dd15fc8864ac35a Mon Sep 17 00:00:00 2001 From: skierons Date: Sun, 30 Sep 2012 19:01:08 -0300 Subject: [PATCH 37/51] Added the Import/Export to the load script --- test/tests/load.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/tests/load.js b/test/tests/load.js index f08f287a..26d33e03 100644 --- a/test/tests/load.js +++ b/test/tests/load.js @@ -27,3 +27,6 @@ /*#*/ include('PlacedSymbol.js'); /*#*/ include('HitResult.js'); + +/*#*/ include('ImportSVG.js'); +/*#*/ include('ExportSVG.js'); From a1bb8651a3716f8cc9c58774ea18acafdd0f22ba Mon Sep 17 00:00:00 2001 From: skierons Date: Sun, 30 Sep 2012 19:05:21 -0300 Subject: [PATCH 38/51] Update src/svg/ExportSVG.js --- src/svg/ExportSVG.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index 9c1346bd..fb24a2ee 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -44,6 +44,7 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ * @return {SVG DOM} this.svgObj The imported project converted to an * SVG project */ + //TODO: Implement symbols and Gradients exportProject: function(project) { var layerArray = project.layers; var layer; @@ -222,7 +223,9 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ //If the object is a circle, ellipse, rectangle, or rounded rectangle, it will find the angle //found by the transformCheck method and make a path that accommodates for the transformed object if(type != 'text' && type != undefined && type != 'polygon' && type != 'polyline' && type != 'line') { - var angle = this._transformCheck(path, pointArray, type) + 90; + //TODO: Need to implement exported transforms for circle, ellipse, and rectangles instead of + //making them paths + var angle = this._determineIfTransformed(path, pointArray, type) + 90; console.log(angle); if(angle != 0) { if(type == 'rect' || type == 'roundRect') { @@ -305,7 +308,7 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ }, //Determines whether the object has been transformed or not through determining the angle - _determinesIfTransformed: function(path, pointArray, type) { + _determineIfTransformed: function(path, pointArray, type) { var topMidBoundx = (path.bounds.topRight.getX() + path.bounds.topLeft.getX() )/2; var topMidBoundy = (path.bounds.topRight.getY() + path.bounds.topLeft.getY() )/2; var topMidBound = new Point(topMidBoundx, topMidBoundy); From 19c4449165fc372ddd9f2036f1a61a55697b809b Mon Sep 17 00:00:00 2001 From: skierons Date: Sun, 30 Sep 2012 19:09:58 -0300 Subject: [PATCH 39/51] Update dist/paper.js --- dist/paper.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/paper.js b/dist/paper.js index e69de29b..d2dbb9ac 100644 --- a/dist/paper.js +++ b/dist/paper.js @@ -0,0 +1,3 @@ +// Paper.js loader for development, as produced by the build/load.sh script +document.write(''); +document.write(''); \ No newline at end of file From 8bafd1d73d58e032d2b41df5f2c8cfa6cc321bb3 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 30 Sep 2012 20:56:59 -0400 Subject: [PATCH 40/51] Setting up for merge --- build/.gitignore | 3 - build/build.sh | 38 - build/dist.sh | 21 - build/docs.sh | 38 - build/jsdoc-toolkit | 1 - build/load.sh | 22 - build/parse-js.sh | 20 - build/prepro.js | 174 - build/preprocess.sh | 51 - build/zip.sh | 39 - dist/.gitignore | 3 - dist/docs/classes/CharacterStyle.html | 569 -- dist/docs/classes/Color.html | 712 --- dist/docs/classes/CompoundPath.html | 4382 -------------- dist/docs/classes/Curve.html | 878 --- dist/docs/classes/CurveLocation.html | 505 -- dist/docs/classes/Event.html | 73 - dist/docs/classes/Gradient.html | 200 - dist/docs/classes/GradientColor.html | 465 -- dist/docs/classes/GradientStop.html | 258 - dist/docs/classes/GrayColor.html | 749 --- dist/docs/classes/Group.html | 3587 ----------- dist/docs/classes/HitResult.html | 242 - dist/docs/classes/HsbColor.html | 766 --- dist/docs/classes/HslColor.html | 730 --- dist/docs/classes/Item.html | 3289 ---------- dist/docs/classes/Key.html | 100 - dist/docs/classes/KeyEvent.html | 220 - dist/docs/classes/Layer.html | 3588 ----------- dist/docs/classes/Line.html | 329 - dist/docs/classes/Matrix.html | 1824 ------ dist/docs/classes/PaperScope.html | 475 -- dist/docs/classes/PaperScript.html | 137 - dist/docs/classes/ParagraphStyle.html | 92 - dist/docs/classes/Path.html | 6698 --------------------- dist/docs/classes/PathItem.html | 4279 ------------- dist/docs/classes/PathStyle.html | 497 -- dist/docs/classes/PlacedItem.html | 3493 ----------- dist/docs/classes/PlacedSymbol.html | 3620 ----------- dist/docs/classes/Point.html | 2196 ------- dist/docs/classes/PointText.html | 3688 ------------ dist/docs/classes/Project.html | 567 -- dist/docs/classes/Raster.html | 4204 ------------- dist/docs/classes/Rectangle.html | 1380 ----- dist/docs/classes/RgbColor.html | 765 --- dist/docs/classes/Segment.html | 544 -- dist/docs/classes/Size.html | 1247 ---- dist/docs/classes/Symbol.html | 271 - dist/docs/classes/TextItem.html | 3600 ----------- dist/docs/classes/Tool.html | 584 -- dist/docs/classes/ToolEvent.html | 406 -- dist/docs/classes/View.html | 538 -- dist/docs/classes/global.html | 529 -- dist/docs/classes/index.html | 96 - dist/docs/index.html | 13 - dist/docs/resources/css/assets/bullet.gif | Bin 44 -> 0 bytes dist/docs/resources/css/codemirror.css | 141 - dist/docs/resources/css/paperscript.css | 64 - dist/docs/resources/css/reference.css | 128 - dist/docs/resources/css/style.css | 86 - dist/docs/resources/js/bootstrap.js | 4040 ------------- dist/docs/resources/js/codemirror.js | 1 - dist/docs/resources/js/paper.js | 0 dist/docs/resources/js/reference.js | 258 - dist/paper.js | 3 - lib/bootstrap.js | 411 -- lib/parse-js-min.js | 14 - lib/parse-js-unicode.js | 1997 ------ lib/parse-js.js | 1916 ------ lib/prepro.js | 43 - lib/stats.js | 10 - node.js/index.js | 58 - 72 files changed, 72965 deletions(-) delete mode 100644 build/.gitignore delete mode 100755 build/build.sh delete mode 100755 build/dist.sh delete mode 100755 build/docs.sh delete mode 160000 build/jsdoc-toolkit delete mode 100755 build/load.sh delete mode 100755 build/parse-js.sh delete mode 100755 build/prepro.js delete mode 100755 build/preprocess.sh delete mode 100755 build/zip.sh delete mode 100644 dist/.gitignore delete mode 100644 dist/docs/classes/CharacterStyle.html delete mode 100644 dist/docs/classes/Color.html delete mode 100644 dist/docs/classes/CompoundPath.html delete mode 100644 dist/docs/classes/Curve.html delete mode 100644 dist/docs/classes/CurveLocation.html delete mode 100644 dist/docs/classes/Event.html delete mode 100644 dist/docs/classes/Gradient.html delete mode 100644 dist/docs/classes/GradientColor.html delete mode 100644 dist/docs/classes/GradientStop.html delete mode 100644 dist/docs/classes/GrayColor.html delete mode 100644 dist/docs/classes/Group.html delete mode 100644 dist/docs/classes/HitResult.html delete mode 100644 dist/docs/classes/HsbColor.html delete mode 100644 dist/docs/classes/HslColor.html delete mode 100644 dist/docs/classes/Item.html delete mode 100644 dist/docs/classes/Key.html delete mode 100644 dist/docs/classes/KeyEvent.html delete mode 100644 dist/docs/classes/Layer.html delete mode 100644 dist/docs/classes/Line.html delete mode 100644 dist/docs/classes/Matrix.html delete mode 100644 dist/docs/classes/PaperScope.html delete mode 100644 dist/docs/classes/PaperScript.html delete mode 100644 dist/docs/classes/ParagraphStyle.html delete mode 100644 dist/docs/classes/Path.html delete mode 100644 dist/docs/classes/PathItem.html delete mode 100644 dist/docs/classes/PathStyle.html delete mode 100644 dist/docs/classes/PlacedItem.html delete mode 100644 dist/docs/classes/PlacedSymbol.html delete mode 100644 dist/docs/classes/Point.html delete mode 100644 dist/docs/classes/PointText.html delete mode 100644 dist/docs/classes/Project.html delete mode 100644 dist/docs/classes/Raster.html delete mode 100644 dist/docs/classes/Rectangle.html delete mode 100644 dist/docs/classes/RgbColor.html delete mode 100644 dist/docs/classes/Segment.html delete mode 100644 dist/docs/classes/Size.html delete mode 100644 dist/docs/classes/Symbol.html delete mode 100644 dist/docs/classes/TextItem.html delete mode 100644 dist/docs/classes/Tool.html delete mode 100644 dist/docs/classes/ToolEvent.html delete mode 100644 dist/docs/classes/View.html delete mode 100644 dist/docs/classes/global.html delete mode 100644 dist/docs/classes/index.html delete mode 100644 dist/docs/index.html delete mode 100644 dist/docs/resources/css/assets/bullet.gif delete mode 100644 dist/docs/resources/css/codemirror.css delete mode 100644 dist/docs/resources/css/paperscript.css delete mode 100644 dist/docs/resources/css/reference.css delete mode 100644 dist/docs/resources/css/style.css delete mode 100644 dist/docs/resources/js/bootstrap.js delete mode 100644 dist/docs/resources/js/codemirror.js delete mode 100644 dist/docs/resources/js/paper.js delete mode 100644 dist/docs/resources/js/reference.js delete mode 100644 dist/paper.js delete mode 100644 lib/bootstrap.js delete mode 100644 lib/parse-js-min.js delete mode 100644 lib/parse-js-unicode.js delete mode 100644 lib/parse-js.js delete mode 100644 lib/prepro.js delete mode 100644 lib/stats.js delete mode 100644 node.js/index.js diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index baa4f768..00000000 --- a/build/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/scriptographer.sh -/*.tmproj -/sync.sh diff --git a/build/build.sh b/build/build.sh deleted file mode 100755 index e57127be..00000000 --- a/build/build.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -# Usage: -# build.sh MODE -# -# MODE: -# commented Preprocessed but still formated and commented -# stripped Formated but without comments (default) -# compressed Uses UglifyJS to reduce file size - -if [ $# -eq 0 ] -then - MODE="stripped" -else - MODE=$1 -fi - -# Create the dist folder if it does not exist yet. -if [ ! -d ../dist/ ] -then - mkdir ../dist/ -fi - -./preprocess.sh $MODE ../src/paper.js ../dist/paper.js '{ "browser": true }' -#./preprocess.sh $MODE ../src/paper.js ../dist/paper-server.js '{ "server": true }' diff --git a/build/dist.sh b/build/dist.sh deleted file mode 100755 index 6283502a..00000000 --- a/build/dist.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -echo "Building paper.js" -./build.sh -echo "Building docs" -./docs.sh -echo "Zipping paperjs.zip" -./zip.sh diff --git a/build/docs.sh b/build/docs.sh deleted file mode 100755 index b55606a0..00000000 --- a/build/docs.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -# Generate documentation -# -# MODE: -# docs Generates the JS API docs - Default -# serverdocs Generates the website templates for the online JS API docs - -if [ $# -eq 0 ] -then - MODE="docs" -else - MODE=$1 -fi - -cd jsdoc-toolkit -java -jar jsrun.jar app/run.js -c=conf/$MODE.conf -D="renderMode:$MODE" -cd .. - -if [ $MODE = "docs" ] -then - # Build paper.js library for documentation - ./preprocess.sh stripped ../src/paper.js ../dist/docs/resources/js/paper.js\ - '{ "browser": true }' -fi diff --git a/build/jsdoc-toolkit b/build/jsdoc-toolkit deleted file mode 160000 index 55bd0b74..00000000 --- a/build/jsdoc-toolkit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 55bd0b74e927683748aeace6e89a57e618d1f78f diff --git a/build/load.sh b/build/load.sh deleted file mode 100755 index 8ed8a3cc..00000000 --- a/build/load.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -# Generate a paper.js file that uses load.js to directly load the library -# through the seperate source files in the src directory. Very useful during -# development of the library itself. - -echo "// Paper.js loader for development, as produced by the build/load.sh script -document.write(''); -document.write('');" > ../dist/paper.js; \ No newline at end of file diff --git a/build/parse-js.sh b/build/parse-js.sh deleted file mode 100755 index 7410b68a..00000000 --- a/build/parse-js.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -# Generate a paper.js file that uses load.js to directly load the library -# through the seperate source files in the src directory. Very useful during -# development of the library itself. - -./preprocess.sh compressed ../lib/parse-js.js ../lib/parse-js-min.js '{}' diff --git a/build/prepro.js b/build/prepro.js deleted file mode 100755 index 1ba879dd..00000000 --- a/build/prepro.js +++ /dev/null @@ -1,174 +0,0 @@ -#! /usr/bin/env node -/* - * Paper.js - * - * This file is part of Paper.js, a JavaScript Vector Graphics Library, - * based on Scriptographer.org and designed to be largely API compatible. - * http://paperjs.org/ - * http://scriptographer.org/ - * - * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey - * http://lehni.org/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - */ - -/** - * Prepro.js - A simple preprocesssor for JavaScript that speaks JavaScript, - * written in JavaScript, allowing preprocessing to either happen at build time - * or compile time. Very useful for libraries that are built for distribution, - * but can be also compiled from seperate sources directly for development, - * supporting build time switches. - */ - -// Required libs - -var fs = require('fs'), - path = require('path'); - -// Parse arguments - -var args = process.argv.slice(2), - options = {}, - files = [], - strip = false; - -while (args.length > 0) { - var arg = args.shift(); - switch (arg) { - case '-d': - // Definitions are provided as JSON and supposed to be object literals - var def = JSON.parse(args.shift()); - // Merge new definitions into options object. - for (var key in def) - options[key] = def[key]; - break; - case '-c': - strip = true; - break; - default: - files.push(arg); - } -} - -// Preprocessing - -var code = [], - out = []; - -function include(base, file) { - // Compose a pathname from base and file, which is specified relatively, - // and normalize the new path, to get rid of .. - file = path.normalize(path.join(base, file)); - var content = fs.readFileSync(file).toString(); - content.split(/\r\n|\n|\r/mg).forEach(function(line) { - // See if our line starts with the preprocess prefix. - var match = line.match(/^\s*\/\*#\*\/\s*(.*)$/); - if (match) { - // Check if the preprocessing line is an include statement, and if - // so, handle it straight away - line = match[1]; - if (match = line.match(/^include\(['"]([^;]*)['"]\);?$/)) { - // Pass on the dirname of the current file as the new base - include(path.dirname(file), match[1]); - } else { - // Any other preprocessing code is simply added, for later - // evaluation. - code.push(line); - } - } else { - // Perhaps we need to replace some values? Supported formats are: - // /*#=*/ options.NAME (outside comments) - // *#=* options.NAME (inside comments) - line = line.replace(/\/?\*#=\*\/?\s*options\.([\w]*)/g, - function(all, name) { - return options[name]; - } - ); - // Now add a statement that when evaluated writes out this code line - code.push('out.push(' + JSON.stringify(line) + ');'); - } - }); -} - -// Include all files. Everything else happens from there, through include() -files.forEach(function(file) { - include(path.resolve(), file); -}); - -// Evaluate the resulting code: Calls puts() and writes the result to stdout. -eval(code.join('\n')); - -// Convert the resulting lines to one string again. -var out = out.join('\n'); - -if (strip) { - out = stripComments(out); - // Strip empty lines that contain only white space and line breaks, as they - // are left-overs from comment removal. - out = out.replace(/^[ \t]+(\r\n|\n|\r)/gm, function(all) { - return ''; - }); - // Replace a sequence of more than two line breaks with only two. - out = out.replace(/(\r\n|\n|\r)(\r\n|\n|\r)+/g, function(all, lineBreak) { - return lineBreak + lineBreak; - }); -} - -// Write the result out -process.stdout.write(out); - -/** - * Strips comments out of JavaScript code, based on: - * http://james.padolsey.com/javascript/removing-comments-in-javascript/ -*/ -function stripComments(str) { - str = ('__' + str + '__').split(''); - var singleQuote = false, - doubleQuote = false, - blockComment = false, - lineComment = false, - preserveComment = false; - for (var i = 0, l = str.length; i < l; i++) { - if (singleQuote) { - if (str[i] == "'" && str[i - 1] !== '\\') - singleQuote = false; - } else if (doubleQuote) { - if (str[i] == '"' && str[i - 1] !== '\\') - doubleQuote = false; - } else if (blockComment) { - // Is the block comment closing? - if (str[i] == '*' && str[i + 1] == '/') { - if (!preserveComment) - str[i] = str[i + 1] = ''; - blockComment = preserveComment = false; - } else if (!preserveComment) { - str[i] = ''; - } - } else if (lineComment) { - // One-line comments end with the line-break - if (str[i + 1] == '\n' || str[i + 1] == '\r') - lineComment = false; - str[i] = ''; - } else { - doubleQuote = str[i] == '"'; - singleQuote = str[i] == "'"; - if (!blockComment && str[i] == '/') { - if (str[i + 1] == '*') { - // Do not filter out conditional comments and comments marked - // as protected (/*! */) - preserveComment = str[i + 2] == '@' || str[i + 2] == '!'; - if (!preserveComment) - str[i] = ''; - blockComment = true; - } else if (str[i + 1] == '/') { - str[i] = ''; - lineComment = true; - } - } - } - } - return str.join('').slice(2, -2); -} diff --git a/build/preprocess.sh b/build/preprocess.sh deleted file mode 100755 index 860fdd73..00000000 --- a/build/preprocess.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -# preprocess.sh -# -# A simple code preprocessing wrapper that uses a combination of cpp, jssrip.py -# and sed to preprocess JavaScript files containing C-style preprocess macros -# (#include, #ifdef, etc.). Three options offer control over wether comments -# are preserved or stripped and whitespaces are compressed. -# -# Usage: -# preprocess.sh MODE SOURCE DESTINATION ARGUMENTS -# -# ARGUMENTS: -# e.g. "-DBROWSER" -# -# MODE: -# commented Preprocessed but still formated and commented -# stripped Formated but without comments -# compressed Uses UglifyJS to reduce file size - -VERSION=0.22 -DATE=$(git log -1 --pretty=format:%ad) - -COMMAND="./prepro.js -d '{ \"version\": $VERSION, \"date\": \"$DATE\" }' -d '$4' $2" - -case $1 in - stripped) - eval "$COMMAND -c" > $3 - ;; - commented) - eval $COMMAND > $3 - ;; - compressed) - eval $COMMAND > temp.js - ../../uglifyjs/bin/uglifyjs temp.js --extra --unsafe --reserved-names "$eval,$sign" > $3 - rm temp.js - ;; -esac diff --git a/build/zip.sh b/build/zip.sh deleted file mode 100755 index afc07257..00000000 --- a/build/zip.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -# Paper.js -# -# This file is part of Paper.js, a JavaScript Vector Graphics Library, -# based on Scriptographer.org and designed to be largely API compatible. -# http://scriptographer.org/ -# -# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey -# http://lehni.org/ & http://jonathanpuckey.com/ -# -# Distributed under the MIT license. See LICENSE file for details. -# -# All rights reserved. - -if [ -f paperjs.zip ] -then - rm paperjs.zip -fi -# Create a temporary folder to copy all files in for zipping -mkdir zip -cd zip -BASE=../.. -# Copy license over -cp $BASE/LICENSE.txt . -# Make library folder and copy paper.js there -mkdir lib -cp $BASE/dist/paper.js lib -# Copy examples over -cp -r $BASE/examples . -# Replace ../../dist/ with ../../lib/ in each example -find examples -type f -print0 | xargs -0 perl -i -pe 's/\.\.\/\.\.\/dist\//\.\.\/\.\.\/lib\//g' -# Copy docs over -cp -r $BASE/dist/docs . -# Zip the whole thing -zip -9 -r $BASE/dist/paperjs.zip * LICENSE.txt -x "*/.DS_Store" -cd .. -# Remove the temporary folder again -rm -fr zip diff --git a/dist/.gitignore b/dist/.gitignore deleted file mode 100644 index 61f11ea6..00000000 --- a/dist/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/paper-server.js -/serverdocs/ -/paperjs.zip diff --git a/dist/docs/classes/CharacterStyle.html b/dist/docs/classes/CharacterStyle.html deleted file mode 100644 index 359b7469..00000000 --- a/dist/docs/classes/CharacterStyle.html +++ /dev/null @@ -1,569 +0,0 @@ - - - - -CharacterStyle - - - - - - - - - - - -
-

CharacterStyle

- -

Extends PathStyle

- -

The CharacterStyle object represents the character style of a text -item (textItem.characterStyle)

-

-Example -

- - -
var text = new PointText(new Point(50, 50));
-text.content = 'Hello world.';
-text.characterStyle = {
-	fontSize: 50,
-	fillColor: 'black',
-};
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- -
- - - - - - - -

Properties inherited from PathStyle

- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Color.html b/dist/docs/classes/Color.html deleted file mode 100644 index c230d9b0..00000000 --- a/dist/docs/classes/Color.html +++ /dev/null @@ -1,712 +0,0 @@ - - - - -Color - - - - - - - - - - - -
-

Color

- -

All properties and functions that expect color values accept -instances of the different color classes such as RgbColor, -HsbColor and GrayColor, and also accept named colors -and hex values as strings which are then converted to instances of -RgbColor internally.

-

-Example — Named color values: -

- -
-
Run
- -
-
- - -

-Example — Hex color values: -

- -
-
Run
- -
-
- - -
- - - - -

Operators

- -
- - -
- - -
- - - -

Properties

- - -
- - -
- - -
- - -
- - -

RGB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

Gray Components

- -
- - -
- - -

HSB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

HSL Components

- -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -

String Representations

- -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/CompoundPath.html b/dist/docs/classes/CompoundPath.html deleted file mode 100644 index 302ea309..00000000 --- a/dist/docs/classes/CompoundPath.html +++ /dev/null @@ -1,4382 +0,0 @@ - - - - -CompoundPath - - - - - - - - - - - -
-

CompoundPath

- -

Extends PathItem, Item

- -

A compound path contains two or more paths, holes are drawn -where the paths overlap. All the paths in a compound path take on the -style of the backmost path and can be accessed through its -item.children list.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - - - - -

Methods

- - -
- - -
- -
- - - - - - -

Methods inherited from PathItem

- - -
- - -
- - -

Postscript Style Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Relative Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Curve.html b/dist/docs/classes/Curve.html deleted file mode 100644 index 97d51079..00000000 --- a/dist/docs/classes/Curve.html +++ /dev/null @@ -1,878 +0,0 @@ - - - - -Curve - - - - - - - - - - - -
-

Curve

- -

The Curve object represents the parts of a path that are connected by -two following Segment objects. The curves of a path can be accessed -through its path.curves array.

-

While a segment describe the anchor point and its incoming and outgoing -handles, a Curve object describes the curve passing between two such -segments. Curves and segments represent two different ways of looking at the -same thing, but focusing on different aspects. Curves for example offer many -convenient ways to work with parts of the path, finding lengths, positions or -tangents at given offsets.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/CurveLocation.html b/dist/docs/classes/CurveLocation.html deleted file mode 100644 index 86dbcaae..00000000 --- a/dist/docs/classes/CurveLocation.html +++ /dev/null @@ -1,505 +0,0 @@ - - - - -CurveLocation - - - - - - - - - - - -
-

CurveLocation

- -

CurveLocation objects describe a location on Curve -objects, as defined by the curve parameter, a value between -0 (beginning of the curve) and 1 (end of the curve). If -the curve is part of a Path item, its index inside the -path.curves array is also provided.

-

The class is in use in many places, such as -path.getLocationAt(offset), Path#getNearestLocation(point), etc.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Event.html b/dist/docs/classes/Event.html deleted file mode 100644 index d0848eb9..00000000 --- a/dist/docs/classes/Event.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - -Event - - - - - - - - - - - -
-

Event

- - - -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Gradient.html b/dist/docs/classes/Gradient.html deleted file mode 100644 index f95530ea..00000000 --- a/dist/docs/classes/Gradient.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - -Gradient - - - - - - - - - - - -
-

Gradient

- -

The Gradient object.

- -
- - -

Constructors

- - -
- - -
- -
- - - - -

Operators

- -
- - -
- - -
- - - -

Properties

- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/GradientColor.html b/dist/docs/classes/GradientColor.html deleted file mode 100644 index 76f32a67..00000000 --- a/dist/docs/classes/GradientColor.html +++ /dev/null @@ -1,465 +0,0 @@ - - - - -GradientColor - - - - - - - - - - - -
-

GradientColor

- -

The GradientColor object.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/GradientStop.html b/dist/docs/classes/GradientStop.html deleted file mode 100644 index 0e879e34..00000000 --- a/dist/docs/classes/GradientStop.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - -GradientStop - - - - - - - - - - - -
-

GradientStop

- -

The GradientStop object.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/GrayColor.html b/dist/docs/classes/GrayColor.html deleted file mode 100644 index c3987ba6..00000000 --- a/dist/docs/classes/GrayColor.html +++ /dev/null @@ -1,749 +0,0 @@ - - - - -GrayColor - - - - - - - - - - - -
-

GrayColor

- -

Extends Color

- -

A GrayColor object is used to represent any gray color value.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - -

Properties inherited from Color

- - -
- - -
- - -
- - -
- - -

RGB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

HSB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

HSL Components

- -
- - -
- -
- - - -

Methods inherited from Color

- - -
- - -
- - -
- - -
- - -
- - -
- - -

String Representations

- -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Group.html b/dist/docs/classes/Group.html deleted file mode 100644 index 426e459f..00000000 --- a/dist/docs/classes/Group.html +++ /dev/null @@ -1,3587 +0,0 @@ - - - - -Group - - - - - - - - - - - -
-

Group

- -

Extends Item

- -

A Group is a collection of items. When you transform a Group, its -children are treated as a single unit without changing their relative -positions.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/HitResult.html b/dist/docs/classes/HitResult.html deleted file mode 100644 index 78b14184..00000000 --- a/dist/docs/classes/HitResult.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - -HitResult - - - - - - - - - - - -
-

HitResult

- -

A HitResult object contains information about the results of a hit -test. It is returned by item.hitTest(point) and -project.hitTest(point).

- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/HsbColor.html b/dist/docs/classes/HsbColor.html deleted file mode 100644 index b02271d5..00000000 --- a/dist/docs/classes/HsbColor.html +++ /dev/null @@ -1,766 +0,0 @@ - - - - -HsbColor - - - - - - - - - - - -
-

HsbColor

- -

Extends Color

- -

An HsbColor object is used to represent any HSB color value.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - - -

Properties inherited from Color

- - -
- - -
- - -
- - -
- - -

RGB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

Gray Components

- -
- - -
- - -

HSL Components

- -
- - -
- -
- - - -

Methods inherited from Color

- - -
- - -
- - -
- - -
- - -
- - -
- - -

String Representations

- -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/HslColor.html b/dist/docs/classes/HslColor.html deleted file mode 100644 index c22ca01c..00000000 --- a/dist/docs/classes/HslColor.html +++ /dev/null @@ -1,730 +0,0 @@ - - - - -HslColor - - - - - - - - - - - -
-

HslColor

- -

Extends Color

- -

An HslColor object is used to represent any HSL color value.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - - -

Properties inherited from Color

- - -
- - -
- - -
- - -
- - -

RGB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

Gray Components

- -
- - -
- - -
- - -
- -
- - - -

Methods inherited from Color

- - -
- - -
- - -
- - -
- - -
- - -
- - -

String Representations

- -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Item.html b/dist/docs/classes/Item.html deleted file mode 100644 index 43952d74..00000000 --- a/dist/docs/classes/Item.html +++ /dev/null @@ -1,3289 +0,0 @@ - - - - -Item - - - - - - - - - - - -
-

Item

- -

The Item type allows you to access and modify the items in -Paper.js projects. Its functionality is inherited by different project -item types such as Path, CompoundPath, Group, -Layer and Raster. They each add a layer of functionality that -is unique to their type, but share the underlying properties and functions -that they inherit from Item.

- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Key.html b/dist/docs/classes/Key.html deleted file mode 100644 index 4f5f511f..00000000 --- a/dist/docs/classes/Key.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - -Key - - - - - - - - - - - -
-

Key

- - - -
- - - - - - - - -

Static Methods

- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/KeyEvent.html b/dist/docs/classes/KeyEvent.html deleted file mode 100644 index 3a19161f..00000000 --- a/dist/docs/classes/KeyEvent.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - -KeyEvent - - - - - - - - - - - -
-

KeyEvent

- -

Extends Event

- -

KeyEvent The KeyEvent object is received by the Tool's -keyboard handlers tool.onKeyDown, tool.onKeyUp, -The KeyEvent object is the only parameter passed to these functions -and contains information about the keyboard event.

- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- -
- - - - - -

Properties inherited from Event

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Layer.html b/dist/docs/classes/Layer.html deleted file mode 100644 index 3f626910..00000000 --- a/dist/docs/classes/Layer.html +++ /dev/null @@ -1,3588 +0,0 @@ - - - - -Layer - - - - - - - - - - - -
-

Layer

- -

Extends Item, Group

- -

The Layer item represents a layer in a Paper.js project.

-

The layer which is currently active can be accessed through -project.activeLayer.

-

An array of all layers in a project can be accessed through -project.layers.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - - - - -

Methods

- - -
- - -
- -
- - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from Group

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Line.html b/dist/docs/classes/Line.html deleted file mode 100644 index fc195f83..00000000 --- a/dist/docs/classes/Line.html +++ /dev/null @@ -1,329 +0,0 @@ - - - - -Line - - - - - - - - - - - -
-

Line

- -

The Line object represents..

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Matrix.html b/dist/docs/classes/Matrix.html deleted file mode 100644 index 844dc516..00000000 --- a/dist/docs/classes/Matrix.html +++ /dev/null @@ -1,1824 +0,0 @@ - - - - -Matrix - - - - - - - - - - - -
-

Matrix

- -

An affine transform performs a linear mapping from 2D coordinates -to other 2D coordinates that preserves the "straightness" and -"parallelness" of lines.

-

Such a coordinate transformation can be represented by a 3 row by 3 -column matrix with an implied last row of [ 0 0 1 ]. This matrix -transforms source coordinates (x,y) into destination coordinates (x',y') -by considering them to be a column vector and multiplying the coordinate -vector by the matrix according to the following process:

-
-     [ x ]   [ a  b  tx ] [ x ]   [ a * x + b * y + tx ]
-     [ y ] = [ c  d  ty ] [ y ] = [ c * x + d * y + ty ]
-     [ 1 ]   [ 0  0  1  ] [ 1 ]   [         1          ]
-
-

This class is optimized for speed and minimizes calculations based on its -knowledge of the underlying matrix (as opposed to say simply performing -matrix multiplication).

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - -

Static Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PaperScope.html b/dist/docs/classes/PaperScope.html deleted file mode 100644 index e32769d1..00000000 --- a/dist/docs/classes/PaperScope.html +++ /dev/null @@ -1,475 +0,0 @@ - - - - -PaperScope - - - - - - - - - - - -
-

PaperScope

- -

The PaperScope class represents the scope associated with a -Paper context. When working with PaperScript, these scopes are automatically -created for us, and through clever scoping the properties and methods of the -active scope seem to become part of the global scope.

-

When working with normal JavaScript code, PaperScope objects need to -be manually created and handled.

-

Paper classes can only be accessed through PaperScope objects. Thus -in PaperScript they are global, while in JavaScript, they are available on -the global paper object. For JavaScript you can use -paperScope.install(scope) to install the Paper classes and objects -on the global scope. Note that when working with more than one scope, this -still works for classes, but not for objects like paperScope.project, -since they are not updated in the injected scope if scopes are switched.

-

The global paper object is simply a reference to the currently active -PaperScope.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- -
- - -

Static Methods

- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PaperScript.html b/dist/docs/classes/PaperScript.html deleted file mode 100644 index 9714c10d..00000000 --- a/dist/docs/classes/PaperScript.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - -PaperScript - - - - - - - - - - - -
-

PaperScript

- - - -
- - - - - - - - -

Static Methods

- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/ParagraphStyle.html b/dist/docs/classes/ParagraphStyle.html deleted file mode 100644 index b0b4aa4d..00000000 --- a/dist/docs/classes/ParagraphStyle.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -ParagraphStyle - - - - - - - - - - - -
-

ParagraphStyle

- -

The ParagraphStyle object represents the paragraph style of a text -item (textItem.paragraphStyle).

-

Currently, the ParagraphStyle object may seem a bit empty, with just the -justification property. Yet, we have lots in store for Paper.js -when it comes to typography. Please stay tuned.

-

-Example -

- - -
var text = new PointText(new Point(0,0));
-text.fillColor = 'black';
-text.content = 'Hello world.';
-text.paragraphStyle.justification = 'center';
- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Path.html b/dist/docs/classes/Path.html deleted file mode 100644 index a55fc047..00000000 --- a/dist/docs/classes/Path.html +++ /dev/null @@ -1,6698 +0,0 @@ - - - - -Path - - - - - - - - - - - -
-

Path

- -

Extends PathItem, Item

- -

The Path item represents a path in a Paper.js project.

- -
- - -

Constructors

- - -
- - -
- -

Shaped Paths

-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Positions on Paths and Curves

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -

Methods inherited from PathItem

- - -
- - -
- - -

Postscript Style Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Relative Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PathItem.html b/dist/docs/classes/PathItem.html deleted file mode 100644 index 105888d1..00000000 --- a/dist/docs/classes/PathItem.html +++ /dev/null @@ -1,4279 +0,0 @@ - - - - -PathItem - - - - - - - - - - - -
-

PathItem

- -

Extends Item

- -

The PathItem class is the base for any items that describe paths -and offer standardised methods for drawing and path manipulation, such as -Path and CompoundPath.

- -
- - - - - - - - -

Methods

- - -
- - -
- - -

Postscript Style Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Relative Drawing Commands

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PathStyle.html b/dist/docs/classes/PathStyle.html deleted file mode 100644 index 2b1ecdf4..00000000 --- a/dist/docs/classes/PathStyle.html +++ /dev/null @@ -1,497 +0,0 @@ - - - - -PathStyle - - - - - - - - - - - -
-

PathStyle

- -

PathStyle is used for changing the visual styles of items -contained within a Paper.js project and is returned by -item.style and project.currentStyle.

-

All properties of PathStyle are also reflected directly in Item, -i.e.: item.fillColor.

-

To set multiple style properties in one go, you can pass an object to -item.style. This is a convenient way to define a style once and -apply it to a series of items:

-

-Example -

- -
-
Run
- -
-
- - -
- - - - - -

Properties

- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PlacedItem.html b/dist/docs/classes/PlacedItem.html deleted file mode 100644 index 959080f6..00000000 --- a/dist/docs/classes/PlacedItem.html +++ /dev/null @@ -1,3493 +0,0 @@ - - - - -PlacedItem - - - - - - - - - - - -
-

PlacedItem

- -

Extends Item

- -

The PlacedItem class is the base for any items that have a matrix -associated with them, describing their placement in the project, such as -Raster and PlacedSymbol.

- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PlacedSymbol.html b/dist/docs/classes/PlacedSymbol.html deleted file mode 100644 index 8780cc5c..00000000 --- a/dist/docs/classes/PlacedSymbol.html +++ /dev/null @@ -1,3620 +0,0 @@ - - - - -PlacedSymbol - - - - - - - - - - - -
-

PlacedSymbol

- -

Extends Item, PlacedItem

- -

A PlacedSymbol represents an instance of a symbol which has been -placed in a Paper.js project.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from PlacedItem

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Point.html b/dist/docs/classes/Point.html deleted file mode 100644 index 16e29e6a..00000000 --- a/dist/docs/classes/Point.html +++ /dev/null @@ -1,2196 +0,0 @@ - - - - -Point - - - - - - - - - - - -
-

Point

- -

The Point object represents a point in the two dimensional space -of the Paper.js project. It is also used to represent two dimensional -vector objects.

-

-Example — Create a point at x: 10, y: 5 -

- - -
var point = new Point(10, 5);
-console.log(point.x); // 10
-console.log(point.y); // 5
- -
- - -

Constructors

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Operators

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -

Distance & Length

- -
- - -
- - -
- - -
- - -

Angle & Rotation

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Vector Math Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -

Math Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - -

Static Methods

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/PointText.html b/dist/docs/classes/PointText.html deleted file mode 100644 index a25c35a9..00000000 --- a/dist/docs/classes/PointText.html +++ /dev/null @@ -1,3688 +0,0 @@ - - - - -PointText - - - - - - - - - - - -
-

PointText

- -

Extends Item, TextItem

- -

A PointText item represents a piece of typography in your Paper.js -project which starts from a certain point and extends by the amount of -characters contained in it.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- -
- - - - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from TextItem

- - -
- - -
- - -

Style Properties

- -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Project.html b/dist/docs/classes/Project.html deleted file mode 100644 index d1948071..00000000 --- a/dist/docs/classes/Project.html +++ /dev/null @@ -1,567 +0,0 @@ - - - - -Project - - - - - - - - - - - -
-

Project

- -

A Project object in Paper.js is what usually is referred to as the -document: The top level object that holds all the items contained in the -scene graph. As the term document is already taken in the browser context, -it is called Project.

-

Projects allow the manipluation of the styles that are applied to all newly -created items, give access to the selected items, and will in future versions -offer ways to query for items in the scene graph defining specific -requirements, and means to persist and load from different formats, such as -SVG and PDF.

-

The currently active project can be accessed through the -paperScope.project variable.

-

An array of all open projects is accessible through the -paperScope.projects variable.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Raster.html b/dist/docs/classes/Raster.html deleted file mode 100644 index f54df035..00000000 --- a/dist/docs/classes/Raster.html +++ /dev/null @@ -1,4204 +0,0 @@ - - - - -Raster - - - - - - - - - - - -
-

Raster

- -

Extends Item, PlacedItem

- -

The Raster item represents an image in a Paper.js project.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -

Pixels

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Image Data

- -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Properties inherited from PlacedItem

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Rectangle.html b/dist/docs/classes/Rectangle.html deleted file mode 100644 index 34eb81b2..00000000 --- a/dist/docs/classes/Rectangle.html +++ /dev/null @@ -1,1380 +0,0 @@ - - - - -Rectangle - - - - - - - - - - - -
-

Rectangle

- -

A Rectangle specifies an area that is enclosed by it's top-left -point (x, y), its width, and its height. It should not be confused with a -rectangular path, it is not an item.

- -
- - -

Constructors

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Operators

- -
- - -
- - -
- - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Side Positions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Corner and Center Point Positions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -

Geometric Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -

Boolean Operations

- -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/RgbColor.html b/dist/docs/classes/RgbColor.html deleted file mode 100644 index a2fcd2cd..00000000 --- a/dist/docs/classes/RgbColor.html +++ /dev/null @@ -1,765 +0,0 @@ - - - - -RgbColor - - - - - - - - - - - -
-

RgbColor

- -

Extends Color

- -

An RgbColor object is used to represent any RGB color value.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - - -

Properties inherited from Color

- - -
- - -
- - -
- - -
- - -

Gray Components

- -
- - -
- - -

HSB Components

- -
- - -
- - -
- - -
- - -
- - -
- - -

HSL Components

- -
- - -
- -
- - - -

Methods inherited from Color

- - -
- - -
- - -
- - -
- - -
- - -
- - -

String Representations

- -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Segment.html b/dist/docs/classes/Segment.html deleted file mode 100644 index 6075d937..00000000 --- a/dist/docs/classes/Segment.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - -Segment - - - - - - - - - - - -
-

Segment

- -

The Segment object represents the points of a path through which its -Curve objects pass. The segments of a path can be accessed through -its path.segments array.

-

Each segment consists of an anchor point (segment.point) and -optionaly an incoming and an outgoing handle (segment.handleIn and -segment.handleOut), describing the tangents of the two Curve -objects that are connected by this segment.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -

Sibling Segments

- -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Size.html b/dist/docs/classes/Size.html deleted file mode 100644 index 30c692d1..00000000 --- a/dist/docs/classes/Size.html +++ /dev/null @@ -1,1247 +0,0 @@ - - - - -Size - - - - - - - - - - - -
-

Size

- -

The Size object is used to describe the size of something, through -its width and height properties.

-

-Example — Create a size that is 10pt wide and 5pt high -

- - -
var size = new Size(10, 5);
-console.log(size.width); // 10
-console.log(size.height); // 5
- -
- - -

Constructors

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Operators

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - - -

Properties

- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -

Tests

- -
- - -
- - -
- - -
- - -

Math Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - -

Static Methods

- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Symbol.html b/dist/docs/classes/Symbol.html deleted file mode 100644 index 1da24cec..00000000 --- a/dist/docs/classes/Symbol.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - -Symbol - - - - - - - - - - - -
-

Symbol

- -

Symbols allow you to place multiple instances of an item in your -project. This can save memory, since all instances of a symbol simply refer -to the original item and it can speed up moving around complex objects, since -internal properties such as segment lists and gradient positions don't need -to be updated with every transformation.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/TextItem.html b/dist/docs/classes/TextItem.html deleted file mode 100644 index 9654093b..00000000 --- a/dist/docs/classes/TextItem.html +++ /dev/null @@ -1,3600 +0,0 @@ - - - - -TextItem - - - - - - - - - - - -
-

TextItem

- -

Extends Item

- -

The TextItem type allows you to create typography. Its -functionality is inherited by different text item types such as -PointText, and AreaText (coming soon). They each add a -layer of functionality that is unique to their type, but share the -underlying properties and functions that they inherit from TextItem.

- -
- - - - - -

Properties

- - -
- - -
- - -

Style Properties

- -
- - -
- - -
- - -
- -
- - - - - - - -

Properties inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Project Hierarchy

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Bounding Rectangles

- -
- - -
- - -
- - -
- - -
- - -
- - -

Stroke Style

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Fill Style

- -
- - -
- -
- - - -

Methods inherited from Item

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Operations

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Hierarchy Tests

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Transform Functions

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Remove On Event

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/Tool.html b/dist/docs/classes/Tool.html deleted file mode 100644 index 8c5f0347..00000000 --- a/dist/docs/classes/Tool.html +++ /dev/null @@ -1,584 +0,0 @@ - - - - -Tool - - - - - - - - - - - -
-

Tool

- -

The Tool object refers to a script that the user can interact with -by using the mouse and keyboard and can be accessed through the global -tool variable. All its properties are also available in the paper -scope.

-

The global tool variable only exists in scripts that contain mouse -handler functions (onMouseMove, onMouseDown, -onMouseDrag, onMouseUp) or a keyboard handler -function (onKeyDown, onKeyUp).

-

-Example -

- - -
var path;
-
-// Only execute onMouseDrag when the mouse
-// has moved at least 10 points:
-tool.distanceThreshold = 10;
-
-function onMouseDown(event) {
-	// Create a new path every time the mouse is clicked
-	path = new Path();
-	path.add(event.point);
-	path.strokeColor = 'black';
-}
-
-function onMouseDrag(event) {
-	// Add a point to the path every time the mouse is dragged
-	path.add(event.point);
-}
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Mouse Event Handlers

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Keyboard Event Handlers

- -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/ToolEvent.html b/dist/docs/classes/ToolEvent.html deleted file mode 100644 index cc13b2dd..00000000 --- a/dist/docs/classes/ToolEvent.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - -ToolEvent - - - - - - - - - - - -
-

ToolEvent

- -

Extends Event

- -

ToolEvent The ToolEvent object is received by the Tool's mouse -event handlers tool.onMouseDown, tool.onMouseDrag, -tool.onMouseMove and tool.onMouseUp. The ToolEvent -object is the only parameter passed to these functions and contains -information about the mouse event.

- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- -
- - - - - -

Properties inherited from Event

- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/View.html b/dist/docs/classes/View.html deleted file mode 100644 index bfcb8e9e..00000000 --- a/dist/docs/classes/View.html +++ /dev/null @@ -1,538 +0,0 @@ - - - - -View - - - - - - - - - - - -
-

View

- -

The View object wraps a canvas element and handles drawing and user -interaction through mouse and keyboard for it. It offer means to scroll the -view, find the currently visible bounds in project coordinates, or the -center, both useful for constructing artwork that should appear centered on -screen.

- -
- - -

Constructors

- - -
- - -
- -
- - - - - -

Properties

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Event Handlers

- -
- - -
- - -
- - -
- -
- - - - -

Methods

- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/global.html b/dist/docs/classes/global.html deleted file mode 100644 index 76ed322d..00000000 --- a/dist/docs/classes/global.html +++ /dev/null @@ -1,529 +0,0 @@ - - - - -_global_ - - - - - - - - - - - -
-

Global Scope

- - - -
- - - - - -

Properties

- - -
- - -
- - -

Global PaperScope Properties (for PaperScript)

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

View Event Handlers (for PaperScript)

- -
- - -
- - -
- - -
- - -

Mouse Event Handlers (for PaperScript)

- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -

Keyboard Event Handlers (for PaperScript)

- -
- - -
- - -
- - -
- -
- - - - - - - - -
- - \ No newline at end of file diff --git a/dist/docs/classes/index.html b/dist/docs/classes/index.html deleted file mode 100644 index 871e0c3c..00000000 --- a/dist/docs/classes/index.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - -Paper.js - - - - - - - -
-

Paper.js

- - - \ No newline at end of file diff --git a/dist/docs/index.html b/dist/docs/index.html deleted file mode 100644 index 198c41b4..00000000 --- a/dist/docs/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Paper.js API - - - - - - - diff --git a/dist/docs/resources/css/assets/bullet.gif b/dist/docs/resources/css/assets/bullet.gif deleted file mode 100644 index 1789496d2e8f2b05ba41eef2d231489051507b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44 tcmZ?wbhEHbWM^PxXkcJ4H8o{mU{L(Y0wft2bU*}1hJlH>g`btd8UTw21o{8~ diff --git a/dist/docs/resources/css/codemirror.css b/dist/docs/resources/css/codemirror.css deleted file mode 100644 index 98bbf7d3..00000000 --- a/dist/docs/resources/css/codemirror.css +++ /dev/null @@ -1,141 +0,0 @@ -.CodeMirror, -.CodeMirror textarea, -.CodeMirror pre { - font-family: Menlo, Consolas, "Vera Mono", monospace; - font-size: 12px; -} - -.CodeMirror { - overflow: auto; - height: 100%; -} - -.CodeMirror-gutter { - position: absolute; - left: 0; - top: 0; - min-width: 30px; - height: 100%; - background-color: #f4f4f4; - border-right: 1px solid #999; -} - -.CodeMirror-gutter-text { - color: #aaa; - text-align: right; - padding: 2px 8px 2px 8px; /* 2px required for CodeMirror-selected */ -} - -.CodeMirror-gutter-text pre { - font-size: 10px; -} - -.CodeMirror-lines { - background: #ffffff; - padding: 2px 0 2px 8px; /* 2px required for CodeMirror-selected */ -} - -.CodeMirror-lines pre.highlight { - background-color: #edf5fc; -} - -/* -.CodeMirror-lines pre:hover { - background-color: #edf5fc; -} - -.CodeMirror-lines pre.highlight:hover { - background-color: #ffffff; -} -*/ - -.CodeMirror pre { - line-height: 16px; - margin: 0; - padding: 0; - background: transparent; - font-family: inherit; -} - -.CodeMirror-cursor { - z-index: 10; - position: absolute; - visibility: hidden; - border-left: 1px solid #7c7c7c !important; - height: 16px; -} - -.CodeMirror-focused .CodeMirror-cursor { - visibility: visible; -} - -span.CodeMirror-selected { - background: #ccc !important; - color: HighlightText !important; - padding: 2px 0 2px 0; -} - -.CodeMirror-focused span.CodeMirror-selected { - background: Highlight !important; -} - -.CodeMirror-matchingbracket { - background: #e3fc8d !important; -} - -.CodeMirror-nonmatchingbracket { - color: #d62a28 !important; -} - -/* JavaScript */ - -span.cm-keyword { - color: #ff7800; -} -span.cm-atom, -span.cm-number { - color: #3b5bb5; -} -span.cm-def, -span.cm-variable-2, -span.cm-variable-3 { - color: #3a4a64; -} -span.cm-variable { - color: #000; -} -span.cm-property { - color: #000; -} -span.cm-operator { - color: #000; -} -span.cm-comment { - color: #8c868f; -} -span.cm-string { - color: #409b1c; -} -span.cm-meta { - color: #555; -} -span.cm-error { - color: #f30; -} -span.cm-qualifier { - color: #555; -} -span.cm-builtin { - color: #30a; -} -span.cm-bracket { - color: #cc7; -} -span.cm-tag { - font-weight: bold; - color: #3b5bb5; -} -span.cm-attribute { - font-style: italic; - color: #3b5bb5; -} diff --git a/dist/docs/resources/css/paperscript.css b/dist/docs/resources/css/paperscript.css deleted file mode 100644 index c296c3c1..00000000 --- a/dist/docs/resources/css/paperscript.css +++ /dev/null @@ -1,64 +0,0 @@ -.paperscript .button, -.paperscript .explain { - display: none; - position: relative; /* position (top / right) relative to paperscriptcontainer */ - float: right; /* align right as block */ - font-size: 11px; - line-height: 16px; - padding: 2px 6px; - margin-bottom: -20px; /* move canvas up by 16px (height) + 2 * 2px (padding) */ - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - z-index: 1; - top: 8px; /* margin to top */ -} - -.paperscript .button { - right: 8px; /* margin to right */ - background: #eee; -} - -.paperscript .explain { - display: block; - right: 64px; /* margin to right */ - background: #e3f4fc; - margin-bottom: -36px; /* (height) + 2 * 2px (padding) */ -} - -.paperscript:hover .button { - display: block; -} - -.paperscript .button:hover { - background: #ddd; - cursor: pointer; -} - -.paperscript .source { - overflow: auto; - border: 1px solid #999; -} - -.paperscript .CodeMirror { - margin: 0 !important; /* Override any potential margins again */ -} - -.paperscript .CodeMirror-gutter-text, -.paperscript .CodeMirror-lines { - padding-top: 10px; - padding-bottom: 10px; -} - -.paperscript .canvas { - line-height: 0; /* prevent weird 5px padding under canvas elements */ -} - -.paperscript .canvas.border canvas { - border: 1px solid #999; -} - -.paperscript.split .canvas { - border: 1px solid #999; - border-top: 0; -} diff --git a/dist/docs/resources/css/reference.css b/dist/docs/resources/css/reference.css deleted file mode 100644 index d9e152c3..00000000 --- a/dist/docs/resources/css/reference.css +++ /dev/null @@ -1,128 +0,0 @@ -/* These styles are shared with the server version of docs */ - -.reference h1, .reference h2, .reference h3 { - font-size: 13px; - font-weight: normal; - height: 18px; /* -2px so border-bottom aligns with contained links */ - border-bottom: 1px solid; - margin-top: 0; - margin-bottom: 16px; -} - -.reference h3 { - margin-top: 16px; - border-bottom-style: dotted; -} - -.reference a tt { - line-height: 18px; -} - -.reference p { - margin: 0 0 16px 0; -} - -.reference ul { - margin: 0; - padding: 0; - list-style: none; -} - -.reference-list ul, .reference-inherited ul { - margin-left: 16px; -} - -.reference hr { - border: none; - border-bottom: 1px dotted; -} - -.reference-packages { - margin-left: 0px; -} - -.reference-packages h2, .reference-packages h3, .reference-packages hr { - margin: 10px 0 10px 0; -} - -.reference-packages .first h2 { - margin-top: 0; -} - -* html .reference-packages img { - margin-top: 5px; -} - -.reference-packages li { - list-style: none; - list-style-image: none; /* needed for ie 6 */ -} - -.reference-members { - margin-bottom: 16px; -} - -.member-group-text { - margin-bottom: 16px; -} - -.member-description { - border: 1px solid #999; - /* .member-header defines border-top for operator lists */ - border-top: 0; - margin: 16px 0 16px 0; -} - -.member-header { - border-top: 1px solid #999; - padding: 10px; -} - -.member-title { - float: left; - width: 400px; -} - -.member-close { - float: right; -} - -.member-text { - border-top: 1px dashed #999; - padding: 10px 10px 0 10px; - margin-bottom: -6px; /* Compensate margins of p and ul to end up with 10px */ -} - -.reference ul, -.reference .paperscript, -.reference .CodeMirror { - margin-top: -8px; /* Move half way up close to previous paragraph */ - margin-bottom: 16px; -} - -.reference ul { - margin-top: 0; /* Clear the above -10px for ul again */ -} - -.member-link { - text-indent: -30px; - padding-left: 30px; -} - -.reference-inherited ul li { - text-indent: -30px; - padding-left: 30px; -} - -.package-classes { - padding-bottom: 4px; -} - -.package-classes ul { - margin-left: 10px; - margin-bottom: 10px; -} - -.reference h2 a { - font-weight: bold; -} diff --git a/dist/docs/resources/css/style.css b/dist/docs/resources/css/style.css deleted file mode 100644 index e74a2dea..00000000 --- a/dist/docs/resources/css/style.css +++ /dev/null @@ -1,86 +0,0 @@ -body, select, input, textarea { - font-family: "Lucida Grande", Geneva, Verdana, Arial, sans-serif; -} - -body { - background: #fff; - margin: 16px; - font-size: 13px; - line-height: 20px; - color: #000; - max-width: 540px; -} - -select, input, textarea { - font-size: 11px; - margin: 0; - color: #000; -} - -tt, pre { - font-family: Menlo, Consolas, "Vera Mono", monospace; - font-size: 12px; - line-height: 20px; -} - -a { - color: #000; - text-decoration: none; - border-bottom: 1px solid #000; -} - -img { - border: 0; -} - -a:hover { - background: #e5e5e5; -} - -p { - margin: 0 0 20px 0; -} - -ul { - padding: 0; - margin: 0 0 20px 16px; - list-style: disc outside url(assets/bullet.gif); -} - -ol { - padding: 0; - margin: 0 0 20px 0; -} - -.clear { - clear: both; -} - -.hidden { - display: none; -} - -.reference-packages, .reference-packages a { - color: #009dec; - border-bottom: 0px; -} - -/* Border-bottom color for headers and ruler */ -.reference-packages h2, .reference-packages h3, .reference-packages hr { - border-color: #009dec; -} - -.reference-packages a:hover { - background: #e3f4fc; -} - -.reference h1 { - font-size: 18px; - font-weight: normal; - line-height: 24px; - border: none; -} - -.footer { - margin-top: 20px; -} diff --git a/dist/docs/resources/js/bootstrap.js b/dist/docs/resources/js/bootstrap.js deleted file mode 100644 index 59d03a88..00000000 --- a/dist/docs/resources/js/bootstrap.js +++ /dev/null @@ -1,4040 +0,0 @@ -new function() { - var fix = !this.__proto__ && [Function, Number, Boolean, String, Array, Date, RegExp]; - if (fix) - for (var i in fix) - fix[i].prototype.__proto__ = fix[i].prototype; - - var has = {}.hasOwnProperty - ? function(obj, name) { - return (!fix || name != '__proto__') && obj.hasOwnProperty(name); - } - : function(obj, name) { - return obj[name] !== (obj.__proto__ || Object.prototype)[name]; - }; - - function inject(dest, src, enumerable, base, preserve, generics) { - - function field(name, dontCheck, generics) { - var val = src[name], func = typeof val == 'function', res = val, prev = dest[name]; - if (generics && func && (!preserve || !generics[name])) generics[name] = function(bind) { - return bind && dest[name].apply(bind, - Array.prototype.slice.call(arguments, 1)); - } - if ((dontCheck || val !== undefined && has(src, name)) && (!preserve || !prev)) { - if (func) { - if (prev && /\bthis\.base\b/.test(val)) { - var fromBase = base && base[name] == prev; - res = (function() { - var tmp = this.base; - this.base = fromBase ? base[name] : prev; - try { return val.apply(this, arguments); } - finally { tmp ? this.base = tmp : delete this.base; } - }).pretend(val); - } - } - dest[name] = res; - } - } - if (src) { - for (var name in src) - if (has(src, name) && !/^(statics|generics|preserve|prototype|constructor|__proto__|toString|valueOf)$/.test(name)) - field(name, true, generics); - field('toString'); - field('valueOf'); - } - } - - function extend(obj) { - function ctor(dont) { - if (fix) this.__proto__ = obj; - if (this.initialize && dont !== ctor.dont) - return this.initialize.apply(this, arguments); - } - ctor.prototype = obj; - ctor.toString = function() { - return (this.prototype.initialize || function() {}).toString(); - } - return ctor; - } - - inject(Function.prototype, { - inject: function(src) { - if (src) { - var proto = this.prototype, base = proto.__proto__ && proto.__proto__.constructor; - inject(proto, src, false, base && base.prototype, src.preserve, src.generics && this); - inject(this, src.statics, true, base, src.preserve); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src) { - var proto = new this(this.dont), ctor = proto.constructor = extend(proto); - ctor.dont = {}; - inject(ctor, this, true); - return arguments.length ? this.inject.apply(ctor, arguments) : ctor; - }, - - pretend: function(fn) { - this.toString = function() { - return fn.toString(); - } - this.valueOf = function() { - return fn.valueOf(); - } - return this; - } - }); - - function each(obj, iter, bind) { - return obj ? (typeof obj.length == 'number' - ? Array : Hash).prototype.each.call(obj, iter, bind) : bind; - } - - Base = Object.extend({ - has: function(name) { - return has(this, name); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) - inject(this, arguments[i]); - return this; - }, - - extend: function() { - var res = new (extend(this)); - return res.inject.apply(res, arguments); - }, - - statics: { - has: has, - each: each, - - type: function(obj) { - return (obj || obj === 0) && ( - obj._type || obj.nodeName && ( - obj.nodeType == 1 && 'element' || - obj.nodeType == 3 && 'textnode' || - obj.nodeType == 9 && 'document') - || obj.location && obj.frames && obj.history && 'window' - || typeof obj) || null; - }, - - check: function(obj) { - return !!(obj || obj === 0); - }, - - pick: function() { - for (var i = 0, l = arguments.length; i < l; i++) - if (arguments[i] !== undefined) - return arguments[i]; - return null; - }, - - iterator: function(iter) { - return !iter - ? function(val) { return val } - : typeof iter != 'function' - ? function(val) { return val == iter } - : iter; - }, - - stop: {} - } - }, { - generics: true, - - debug: function() { - return /^(string|number|function|regexp)$/.test(Base.type(this)) ? this - : Base.each(this, function(val, key) { this.push(key + ': ' + val); }, []).join(', '); - }, - - clone: function() { - return Base.each(this, function(val, i) { - this[i] = val; - }, new this.constructor()); - }, - - toQueryString: function() { - return Base.each(this, function(val, key) { - this.push(key + '=' + encodeURIComponent(val)); - }, []).join('&'); - } - }); -} - -$each = Base.each; -$type = Base.type; -$check = Base.check; -$pick = Base.pick; -$stop = $break = Base.stop; - -Enumerable = { - generics: true, - preserve: true, - - findEntry: function(iter, bind) { - var that = this, iter = Base.iterator(iter), ret = null; - Base.each(this, function(val, key) { - var res = iter.call(bind, val, key, that); - if (res) { - ret = { key: key, value: val, result: res }; - throw Base.stop; - } - }); - return ret; - }, - - find: function(iter, bind) { - var entry = this.findEntry(iter, bind); - return entry && entry.result; - }, - - contains: function(iter) { - return !!this.findEntry(iter); - }, - - remove: function(iter, bind) { - var entry = this.findEntry(iter, bind); - if (entry) { - delete this[entry.key]; - return entry.value; - } - }, - - filter: function(iter, bind) { - var that = this; - return Base.each(this, function(val, i) { - if (iter.call(bind, val, i, that)) - this[this.length] = val; - }, []); - }, - - map: function(iter, bind) { - var that = this; - return Base.each(this, function(val, i) { - this[this.length] = iter.call(bind, val, i, that); - }, []); - }, - - every: function(iter, bind) { - var that = this; - return this.find(function(val, i) { - return !iter.call(this, val, i, that); - }, bind || null) == null; - }, - - some: function(iter, bind) { - return this.find(iter, bind || null) != null; - }, - - collect: function(iter, bind) { - var that = this, iter = Base.iterator(iter); - return Base.each(this, function(val, i) { - val = iter.call(bind, val, i, that); - if (val != null) - this[this.length] = val; - }, []); - }, - - max: function(iter, bind) { - var that = this, iter = Base.iterator(iter); - return Base.each(this, function(val, i) { - val = iter.call(bind, val, i, that); - if (val >= (this.max || val)) this.max = val; - }, {}).max; - }, - - min: function(iter, bind) { - var that = this, iter = Base.iterator(iter); - return Base.each(this, function(val, i) { - val = iter.call(bind, val, i, that); - if (val <= (this.min || val)) this.min = val; - }, {}).min; - }, - - pluck: function(prop) { - return this.map(function(val) { - return val[prop]; - }); - }, - - sortBy: function(iter, bind) { - var that = this, iter = Base.iterator(iter); - return this.map(function(val, i) { - return { value: val, compare: iter.call(bind, val, i, that) }; - }, bind).sort(function(left, right) { - var a = left.compare, b = right.compare; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(function(value) { - return value; - }); - } -}; - -Hash = Base.extend(Enumerable, { - generics: true, - - initialize: function(arg) { - if (typeof arg == 'string') { - for (var i = 0, l = arguments.length; i < l; i += 2) - this[arguments[i]] = arguments[i + 1]; - } else { - this.append.apply(this, arguments); - } - return this; - }, - - each: function(iter, bind) { - var bind = bind || this, iter = Base.iterator(iter), has = Base.has; - try { - for (var i in this) - if (has(this, i)) - iter.call(bind, this[i], i, this); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - }, - - append: function() { - for (var i = 0, l = arguments.length; i < l; i++) { - var obj = arguments[i]; - for (var key in obj) - if (Base.has(obj, key)) - this[key] = obj[key]; - } - return this; - }, - - merge: function() { - return Array.each(arguments, function(obj) { - Base.each(obj, function(val, key) { - this[key] = Base.type(this[key]) == 'object' - ? Hash.prototype.merge.call(this[key], val) - : Base.type(val) == 'object' ? Base.clone(val) : val; - }, this); - }, this); - }, - - getKeys: function() { - return Hash.getKeys(this); - }, - - getValues: Enumerable.toArray, - - getSize: function() { - return this.each(function() { - this.size++; - }, { size: 0 }).size; - }, - - statics: { - create: function(obj) { - return arguments.length == 1 && obj.constructor == Hash - ? obj : Hash.prototype.initialize.apply(new Hash(), arguments); - }, - - getKeys: Object.keys || function(obj) { - return Hash.map(function(val, key) { - return key; - }); - } - } -}); - -$H = Hash.create; - -Array.inject({ - generics: true, - preserve: true, - _type: 'array', - - forEach: function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - iter.call(bind, this[i], i, this); - }, - - indexOf: function(obj, i) { - i = i || 0; - if (i < 0) i = Math.max(0, this.length + i); - for (var l = this.length; i < l; i++) - if (this[i] == obj) return i; - return -1; - }, - - lastIndexOf: function(obj, i) { - i = i != null ? i : this.length - 1; - if (i < 0) i = Math.max(0, this.length + i); - for (; i >= 0; i--) - if (this[i] == obj) return i; - return -1; - }, - - filter: function(iter, bind) { - var res = []; - for (var i = 0, l = this.length; i < l; i++) { - var val = this[i]; - if (iter.call(bind, val, i, this)) - res[res.length] = val; - } - return res; - }, - - map: function(iter, bind) { - var res = new Array(this.length); - for (var i = 0, l = this.length; i < l; i++) - res[i] = iter.call(bind, this[i], i, this); - return res; - }, - - every: function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - if (!iter.call(bind, this[i], i, this)) - return false; - return true; - }, - - some: function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - if (iter.call(bind, this[i], i, this)) - return true; - return false; - }, - - reduce: function(fn, value) { - var i = 0; - if (arguments.length < 2 && this.length) value = this[i++]; - for (var l = this.length; i < l; i++) - value = fn.call(null, value, this[i], i, this); - return value; - }, - - statics: { - isArray: function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - } - } -}, Enumerable, { - generics: true, - - each: function(iter, bind) { - try { - Array.prototype.forEach.call(this, Base.iterator(iter), bind = bind || this); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - }, - - collect: function(iter, bind) { - var that = this; - return this.each(function(val, i) { - if ((val = iter.call(bind, val, i, that)) != null) - this[this.length] = val; - }, []); - }, - - findEntry: function(iter, bind) { - if (typeof iter != 'function') { - var i = this.indexOf(iter); - return i == -1 ? null : { key: i, value: iter, result: iter }; - } - return Enumerable.findEntry.call(this, iter, bind); - }, - - remove: function(iter, bind) { - var entry = this.findEntry(iter, bind); - if (entry) { - this.splice(entry.key, 1); - return entry.value; - } - }, - - toArray: function() { - return Array.prototype.slice.call(this); - }, - - clone: function() { - return this.toArray(); - }, - - clear: function() { - this.length = 0; - }, - - compact: function() { - return this.filter(function(value) { - return value != null; - }); - }, - - append: function(items) { - for (var i = 0, l = items.length; i < l; i++) - this[this.length++] = items[i]; - return this; - }, - - associate: function(obj) { - if (!obj) - obj = this; - else if (typeof obj == 'function') - obj = this.map(obj); - if (obj.length != null) { - var that = this; - return Base.each(obj, function(name, index) { - this[name] = that[index]; - if (index == that.length) - throw Base.stop; - }, {}); - } else { - obj = Hash.append({}, obj); - return Array.each(this, function(val) { - var type = Base.type(val); - Base.each(obj, function(hint, name) { - if (hint == 'any' || type == hint) { - this[name] = val; - delete obj[name]; - throw Base.stop; - } - }, this); - }, {}); - } - }, - - flatten: function() { - return Array.each(this, function(val) { - if (val != null && val.flatten) this.append(val.flatten()); - else this.push(val); - }, []); - }, - - swap: function(i, j) { - var tmp = this[j]; - this[j] = this[i]; - this[i] = tmp; - return tmp; - }, - - shuffle: function() { - var res = this.clone(); - var i = this.length; - while (i--) res.swap(i, Math.rand(i + 1)); - return res; - }, - - pick: function() { - return this[Math.rand(this.length)]; - }, - - getFirst: function() { - return this[0]; - }, - - getLast: function() { - return this[this.length - 1]; - } -}, new function() { - function combine(subtract) { - return function(items) { - var res = new this.constructor(); - for (var i = this.length - 1; i >= 0; i--) - if (subtract == !Array.find(items, this[i])) - res.push(this[i]); - return res; - } - } - - return { - subtract: combine(true), - - intersect: combine(false) - } -}); - -Array.inject(new function() { - var proto = Array.prototype, fields = ['push','pop','shift','unshift','sort', - 'reverse','join','slice','splice','forEach','indexOf','lastIndexOf', - 'filter','map','every','some','reduce','concat'].each(function(name) { - this[name] = proto[name]; - }, { generics: true, preserve: true }); - - Array.inject(fields); - - Hash.append(fields, proto, { - clear: function() { - for (var i = 0, l = this.length; i < l; i++) - delete this[i]; - this.length = 0; - }, - - concat: function(list) { - return Browser.WEBKIT - ? new Array(this.length + list.length).append(this).append(list) - : Array.concat(this, list); - }, - - toString: proto.join, - - length: 0 - }); - - return { - statics: { - create: function(obj) { - if (obj == null) - return []; - if (obj.toArray) - return obj.toArray(); - if (typeof obj.length == 'number') - return Array.prototype.slice.call(obj); - return [obj]; - }, - - convert: function(obj) { - return Base.type(obj) == 'array' ? obj : Array.create(obj); - }, - - extend: function(src) { - var ret = Base.extend(fields, src); - ret.extend = Function.extend; - return ret; - } - } - }; -}); - -$A = Array.create; - -Function.inject(new function() { - - function timer(set) { - return function(delay, bind, args) { - var func = this.wrap(bind, args); - if (delay === undefined) - return func(); - var timer = set(func, delay); - func.clear = function() { - clearTimeout(timer); - clearInterval(timer); - }; - return func; - }; - } - - return { - generics: true, - preserve: true, - - delay: timer(setTimeout), - periodic: timer(setInterval), - - bind: function(bind) { - var that = this, slice = Array.prototype.slice, - args = arguments.length > 1 ? slice.call(arguments, 1) : null; - return function() { - return that.apply(bind, args ? arguments.length > 0 - ? args.concat(slice.call(arguments)) : args : arguments); - } - }, - - wrap: function(bind, args) { - var that = this; - return function() { - return that.apply(bind, args || arguments); - } - } - } -}); - -Number.inject({ - _type: 'number', - - limit: function(min, max) { - return Math.min(max, Math.max(min, this)); - }, - - times: function(func, bind) { - for (var i = 0; i < this; i++) - func.call(bind, i); - return bind || this; - }, - - toInt: function(base) { - return parseInt(this, base || 10); - }, - - toFloat: function() { - return parseFloat(this); - }, - - toPaddedString: function(length, base, prefix) { - var str = this.toString(base || 10); - return (prefix || '0').times(length - str.length) + str; - } -}); - -String.inject({ - _type: 'string', - - test: function(exp, param) { - return new RegExp(exp, param || '').test(this); - }, - - toArray: function() { - return this ? this.split(/\s+/) : []; - }, - - toInt: Number.prototype.toInt, - - toFloat: Number.prototype.toFloat, - - camelize: function(separator) { - return this.replace(separator ? new RegExp('[' + separator + '](\\w)', 'g') : /-(\w)/g, function(all, chr) { - return chr.toUpperCase(); - }); - }, - - uncamelize: function(separator) { - separator = separator || ' '; - return this.replace(/[a-z][A-Z0-9]|[0-9][a-zA-Z]|[A-Z]{2}[a-z]/g, function(match) { - return match.charAt(0) + separator + match.substring(1); - }); - }, - - hyphenate: function(separator) { - return this.uncamelize(separator || '-').toLowerCase(); - }, - - capitalize: function() { - return this.replace(/\b[a-z]/g, function(match) { - return match.toUpperCase(); - }); - }, - - escapeRegExp: function() { - return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); - }, - - trim: function(exp) { - exp = exp ? '[' + exp + ']' : '\\s'; - return this.replace(new RegExp('^' + exp + '+|' + exp + '+$', 'g'), ''); - }, - - clean: function() { - return this.replace(/\s{2,}/g, ' ').trim(); - }, - - contains: function(string, sep) { - return (sep ? (sep + this + sep).indexOf(sep + string + sep) : this.indexOf(string)) != -1; - }, - - times: function(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - }, - - isHtml: function() { - return /^[^<]*(<(.|\s)+>)[^>]*$/.test(this); - } -}); - -RegExp.inject({ - _type: 'regexp' -}); - -Date.inject({ - statics: { - SECOND: 1000, - MINUTE: 60000, - HOUR: 3600000, - DAY: 86400000, - WEEK: 604800000, - MONTH: 2592000000, - YEAR: 31536000000, - - now: Date.now || function() { - return +new Date(); - } - } -}); - -Math.rand = function(first, second) { - return second == undefined - ? Math.rand(0, first) - : Math.floor(Math.random() * (second - first) + first); -} - -Array.inject({ - hexToRgb: function(toArray) { - if (this.length >= 3) { - var rgb = []; - for (var i = 0; i < 3; i++) - rgb.push((this[i].length == 1 ? this[i] + this[i] : this[i]).toInt(16)); - return toArray ? rgb : 'rgb(' + rgb.join(',') + ')'; - } - }, - - rgbToHex: function(toArray) { - if (this.length >= 3) { - if (this.length == 4 && this[3] == 0 && !toArray) return 'transparent'; - var hex = []; - for (var i = 0; i < 3; i++) { - var bit = (this[i] - 0).toString(16); - hex.push(bit.length == 1 ? '0' + bit : bit); - } - return toArray ? hex : '#' + hex.join(''); - } - }, - - rgbToHsb: function() { - var r = this[0], g = this[1], b = this[2]; - var hue, saturation, brightness; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var delta = max - min; - brightness = max / 255; - saturation = (max != 0) ? delta / max : 0; - if (saturation == 0) { - hue = 0; - } else { - var rr = (max - r) / delta; - var gr = (max - g) / delta; - var br = (max - b) / delta; - if (r == max) hue = br - gr; - else if (g == max) hue = 2 + rr - br; - else hue = 4 + gr - rr; - hue /= 6; - if (hue < 0) hue++; - } - return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)]; - }, - - hsbToRgb: function() { - var br = Math.round(this[2] / 100 * 255); - if (this[1] == 0) { - return [br, br, br]; - } else { - var hue = this[0] % 360; - var f = hue % 60; - var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255); - var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255); - var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255); - switch (Math.floor(hue / 60)) { - case 0: return [br, t, p]; - case 1: return [q, br, p]; - case 2: return [p, br, t]; - case 3: return [p, q, br]; - case 4: return [t, p, br]; - case 5: return [br, p, q]; - } - } - } -}); - -String.inject({ - hexToRgb: function(toArray) { - var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - return hex && hex.slice(1).hexToRgb(toArray); - }, - - rgbToHex: function(toArray) { - var rgb = this.match(/\d{1,3}/g); - return rgb && rgb.rgbToHex(toArray); - } -}); - -Json = function(JSON) { - var special = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', "'" : "\\'", '\\': '\\\\' }; - return { - encode: JSON - ? function(obj, properties) { - return JSON.stringify(obj, properties || Browser.TRIDENT && function(key, value) { - return key == '__proto__' ? undefined : value; - }); - } - : function(obj, properties) { - if (Base.type(properties) == 'array') { - properties = properties.each(function(val) { - this[val] = true; - }, {}); - } - switch (Base.type(obj)) { - case 'string': - return '"' + obj.replace(/[\x00-\x1f\\"]/g, function(chr) { - return special[chr] || '\\u' + chr.charCodeAt(0).toPaddedString(4, 16); - }) + '"'; - case 'array': - return '[' + obj.collect(function(val) { - return Json.encode(val, properties); - }) + ']'; - case 'object': - case 'hash': - return '{' + Hash.collect(obj, function(val, key) { - if (!properties || properties[key]) { - val = Json.encode(val, properties); - if (val !== undefined) - return Json.encode(key) + ':' + val; - } - }) + '}'; - case 'function': - return undefined; - default: - return obj + ''; - } - return null; - }, - - decode: JSON - ? function(str, secure) { - try { - return JSON.parse(str); - } catch (e) { - return null; - } - } - : function(str, secure) { - try { - return Base.type(str) == 'string' && (str = str.trim()) && - (!secure || /^[\],:{}\s]*$/.test( - str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") - .replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) - ? (new Function('return ' + str))() : null; - } catch (e) { - return null; - } - } - }; -}(this.JSON); - -Browser = new function() { - var name = window.orientation != undefined ? 'ipod' - : (navigator.platform.match(/mac|win|linux|nix/i) || ['other'])[0].toLowerCase(); - var fields = { - PLATFORM: name, - XPATH: !!document.evaluate, - QUERY: !!document.querySelector - }; - fields[name.toUpperCase()] = true; - - function getVersion(prefix, min, max) { - var ver = (new RegExp(prefix + '([\\d.]+)', 'i').exec(navigator.userAgent) || [0, '0'])[1].split('.'); - return (ver.slice(0, min).join('') + '.' + ver.slice(min, max || ver.length).join('')).toFloat(); - } - - var engines = { - presto: function() { - return !window.opera ? false : getVersion('Presto/', 2) || getVersion('Opera[/ ]', 1); - }, - - trident: function() { - return !window.ActiveXObject ? false : getVersion('MSIE ', 1); - }, - - webkit: function() { - return navigator.taintEnabled ? false : getVersion('WebKit/', 1, 2); - }, - - gecko: function() { - return !document.getBoxObjectFor && window.mozInnerScreenX == null ? false : getVersion('rv:', 2); - } - }; - - for (var engine in engines) { - var version = engines[engine](); - if (version) { - fields.ENGINE = engine; - fields.VERSION = version; - engine = engine.toUpperCase(); - fields[engine] = true; - fields[(engine + version).replace(/\./g, '')] = true; - break; - } - } - - fields.log = function() { - if (!Browser.TRIDENT && window.console && console.log) - console.log.apply(console, arguments); - else - (window.console && console.log - || window.opera && opera.postError - || alert)(Array.join(arguments, ' ')); - } - - return fields; -}; - -DomNodes = Array.extend(new function() { - var unique = 0; - return { - initialize: function(nodes) { - this._unique = unique++; - this.append(nodes && nodes.length != null && !nodes.nodeType - ? nodes : arguments); - }, - - push: function() { - this.append(arguments); - return this.length; - }, - - append: function(items) { - for (var i = 0, l = items.length; i < l; i++) { - var el = items[i]; - if ((el = el && (el._wrapper || DomNode.wrap(el))) && el._unique != this._unique) { - el._unique = this._unique; - this[this.length++] = el; - } - } - return this; - }, - - toNode: function() { - return this; - }, - - statics: { - inject: function(src) { - var proto = this.prototype; - this.base(Base.each(src || {}, function(val, key) { - if (typeof val == 'function') { - var func = val, prev = proto[key]; - var count = func.length, prevCount = prev && prev.length; - val = function() { - var args = arguments, values; - if (prev && args.length == prevCount - || (args.length > count && args.length <= prevCount)) - return prev.apply(this, args); - this.each(function(obj) { - var ret = (obj[key] || func).apply(obj, args); - if (ret !== undefined && ret != obj) { - values = values || (DomNode.isNode(ret) - ? new obj._collection() : []); - values.push(ret); - } - }); - return values || this; - } - } - this[key] = val; - }, {})); - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - } - } - }; -}); - -DomNode = Base.extend(new function() { - var nodes = []; - var tags = {}, classes = {}, classCheck, unique = 0; - - function dispose(force) { - for (var i = nodes.length - 1; i >= 0; i--) { - var el = nodes[i]; - if (force || (!el || el != window && el != document && - (!el.parentNode || !el.offsetParent))) { - if (el) { - var obj = el._wrapper; - if (obj && obj.finalize) obj.finalize(); - el._wrapper = el._unique = null; - } - if (!force) nodes.splice(i, 1); - } - } - } - - function inject(src) { - src = src || {}; - (src._methods || []).each(function(name) { - src[name] = function(arg) { - var ret = this.$[name] && this.$[name](arg); - return ret === undefined ? this : ret; - } - }); - (src._properties || []).each(function(name) { - var part = name.capitalize(), prop = name.toLowerCase(); - src['get' + part] = function() { - return this.getProperty(prop); - } - src['set' + part] = function(value) { - return this.setProperty(prop, value); - } - }); - delete src._methods; - delete src._properties; - return Function.inject.call(this, src); - } - - function getConstructor(el) { - var match; - return classCheck && el.className && (match = el.className.match(classCheck)) && match[2] && classes[match[2]] || - el.tagName && tags[el.tagName] || - el.className !== undefined && HtmlElement || - el.nodeType == 1 && DomElement || - el.nodeType == 3 && DomTextNode || - el.nodeType == 9 && (el.documentElement.nodeName.toLowerCase() == 'html' && HtmlDocument || DomDocument) || - el.location && el.frames && el.history && DomWindow || - DomNode; - } - - var dont = {}; - - return { - _type: 'node', - _collection: DomNodes, - _initialize: true, - - initialize: function(el, props, doc) { - if (!el) return null; - if (this._tag && Base.type(el) == 'object') { - props = el; - el = this._tag; - } - if (typeof(el) == 'string') { - el = DomElement.create(el, props, doc); - } else if (el._wrapper) { - return el._wrapper; - } - if (props === dont) { - props = null; - } else { - var ctor = getConstructor(el); - if (ctor != this.constructor) - return new ctor(el, props); - } - this.$ = el; - try { - el._wrapper = this; - nodes[nodes.length] = el; - } catch (e) {} - if (props) this.set(props); - }, - - statics: { - inject: function(src) { - if (src) { - var proto = this.prototype, that = this; - src.statics = Base.each(src, function(val, name) { - if (typeof val == 'function' && !this[name] && !that[name]) { - this[name] = function(el, param1, param2) { - if (el) try { - proto.$ = el.$ || el; - return proto[name](param1, param2); - } finally { - delete proto.$; - } - } - } - }, src.statics || {}); - inject.call(this, src); - delete src.toString; - proto._collection.inject(src); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src) { - var ret = this.base(); - var init = src.initialize; - if (init) src.initialize = function(el, props) { - var ret = this._initialize && this.base(el, props); - if (ret) return ret; - init.apply(this, arguments); - } - inject.call(ret, src); - if (ret.prototype._collection == this.prototype._collection) - ret.inject = inject; - if (src) { - if (src._tag) - tags[src._tag.toLowerCase()] = tags[src._tag.toUpperCase()] = ret; - if (src._class) { - classes[src._class] = ret; - classCheck = new RegExp('(^|\\s)(' + Base.each(classes, function(val, name) { - this.push(name); - }, []).join('|') + ')(\\s|$)'); - if (!src._lazy && src.initialize) Browser.document.addEvent('domready', function() { - this.getElements('.' + src._class); - }); - } - } - return ret; - }, - - wrap: function(el) { - return el ? typeof el == 'string' - ? DomElement.get(el) - : el._wrapper || el._collection && el || new (getConstructor(el))(el, dont) - : null; - }, - - unwrap: function(el) { - return el && el.$ || el; - }, - - unique: function(el) { - if (!el._unique) { - nodes.push(el); - el._unique = ++unique; - } - }, - - isNode: function(obj) { - return /^(element|node|textnode|document)$/.test( - typeof obj == 'string' ? obj : Base.type(obj)); - }, - - dispose: function() { - dispose(true); - } - } - } -}); - -DomNode.inject(new function() { - var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', - 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer' - ].associate(); - var properties = Hash.append({ - text: Browser.TRIDENT || Browser.WEBKIT && Browser.VERSION < 420 || Browser.PRESTO && Browser.VERSION < 9 - ? function(node) { - return node.$.innerText !== undefined ? 'innerText' : 'nodeValue' - } : 'textContent', - html: 'innerHTML', 'class': 'className', className: 'className', 'for': 'htmlFor' - }, [ - 'value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', - 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', - 'selectedIndex', 'useMap', 'width', 'height' - ].associate(function(name) { - return name.toLowerCase(); - }), bools); - - var clones = { input: 'checked', option: 'selected', textarea: Browser.WEBKIT && Browser.VERSION < 420 ? 'innerHTML' : 'value' }; - - function handle(that, prefix, name, value) { - var ctor = that.__proto__.constructor; - var handlers = ctor.handlers = ctor.handlers || { get: {}, set: {} }; - var list = handlers[prefix]; - var fn = name == 'events' && prefix == 'set' ? that.addEvents : list[name]; - if (fn === undefined) - fn = list[name] = that[prefix + name.capitalize()] || null; - return fn - ? fn[Base.type(value) == 'array' ? 'apply' : 'call'](that, value) - : that[prefix + 'Property'](name, value); - } - - function toNodes(elements) { - var els = Base.type(elements) == 'array' ? elements : Array.create(arguments); - var created = els.find(function(el) { - return !DomNode.isNode(el); - }); - var result = els.toNode(this.getDocument()); - return { - array: result ? (Base.type(result) == 'array' ? result : [result]) : [], - result: created && result - }; - } - - var fields = { - _properties: ['text'], - - set: function(name, value) { - switch (Base.type(name)) { - case 'string': - return handle(this, 'set', name, value); - case 'object': - return Base.each(name, function(value, key) { - handle(this, 'set', key, value); - }, this); - } - return this; - }, - - get: function(name) { - return handle(this, 'get', name); - }, - - getDocument: function() { - return DomNode.wrap(this.$.ownerDocument); - }, - - getWindow: function() { - return this.getDocument().getWindow(); - }, - - getPreviousNode: function() { - return DomNode.wrap(this.$.previousSibling); - }, - - getNextNode: function() { - return DomNode.wrap(this.$.nextSibling); - }, - - getFirstNode: function() { - return DomNode.wrap(this.$.firstChild); - }, - - getLastNode: function() { - return DomNode.wrap(this.$.lastChild); - }, - - getParentNode: function() { - return DomNode.wrap(this.$.parentNode); - }, - - getChildNodes: function() { - return new DomNodes(this.$.childNodes); - }, - - hasChildNodes: function() { - return this.$.hasChildNodes(); - }, - - appendChild: function(el) { - if (el = DomNode.wrap(el)) { - var text = Browser.TRIDENT && el.$.text; - if (text) el.$.text = ''; - this.$.appendChild(el.$); - if (text) el.$.text = text; - } - return this; - }, - - appendChildren: function() { - return Array.flatten(arguments).each(function(el) { - this.appendChild($(DomNode.wrap(el))); - }, this); - }, - - appendText: function(text) { - return this.injectBottom(this.getDocument().createTextNode(text)); - }, - - prependText: function(text) { - return this.injectTop(this.getDocument().createTextNode(text)); - }, - - remove: function() { - if (this.$.parentNode) - this.$.parentNode.removeChild(this.$); - return this; - }, - - removeChild: function(el) { - el = DomNode.wrap(el); - this.$.removeChild(el.$); - return el; - }, - - removeChildren: function() { - var nodes = this.getChildNodes(); - nodes.remove(); - return nodes; - }, - - replaceWith: function(el) { - if (this.$.parentNode) { - el = toNodes.apply(this, arguments); - var els = el.array; - if (els.length > 0) - this.$.parentNode.replaceChild(els[0].$, this.$); - for (var i = els.length - 1; i > 0; i--) - els[i].insertAfter(els[0]); - return el.result; - } - return null; - }, - - wrap: function() { - var el = this.injectBefore.apply(this, arguments), last; - do { - last = el; - el = el.getFirst(); - } while(el); - last.appendChild(this); - return last; - }, - - clone: function(contents) { - var clone = this.$.cloneNode(!!contents); - function clean(left, right) { - if (Browser.TRIDENT) { - left.clearAttributes(); - left.mergeAttributes(right); - left.removeAttribute('_wrapper'); - left.removeAttribute('_unique'); - if (left.options) - for (var l = left.options, r = right.options, i = l.length; i--;) - l[i].selected = r[i].selected; - } - var name = clones[right.tagName.toLowerCase()]; - if (name && right[name]) - left[name] = right[name]; - if (contents) - for (var l = left.childNodes, r = right.childNodes, i = l.length; i--;) - clean(l[i], r[i]); - } - clean(clone, this.$); - return DomNode.wrap(clone); - }, - - hasProperty: function(name) { - var key = properties[name]; - key = key && typeof key == 'function' ? key(this) : key; - return key ? this.$[key] !== undefined : this.$.hasAttribute(name); - }, - - getProperty: function(name) { - var key = properties[name], value; - key = key && typeof key == 'function' ? key(this) : key; - var value = key ? this.$[key] : this.$.getAttribute(name); - return bools[name] ? !!value : value; - }, - - setProperty: function(name, value) { - var key = properties[name], defined = value !== undefined; - key = key && typeof key == 'function' ? key(this) : key; - if (key && bools[name]) value = value || !defined ? true : false; - else if (!defined) return this.removeProperty(name); - key ? this.$[key] = value : this.$.setAttribute(name, value); - return this; - }, - - removeProperty: function(name) { - var key = properties[name], bool = key && bools[name]; - key = key && typeof key == 'function' ? key(this) : key; - key ? this.$[key] = bool ? false : '' : this.$.removeAttribute(name); - return this; - }, - - getProperties: function() { - var props = {}; - for (var i = 0; i < arguments.length; i++) - props[arguments[i]] = this.getProperty(arguments[i]); - return props; - }, - - setProperties: function(src) { - return Base.each(src, function(value, name) { - this.setProperty(name, value); - }, this); - }, - - removeProperties: function() { - return Array.each(arguments, this.removeProperty, this); - } - }; - - var inserters = { - before: function(source, dest) { - if (source && dest && dest.$.parentNode) { - var text = Browser.TRIDENT && dest.$.text; - if (text) dest.$.text = ''; - dest.$.parentNode.insertBefore(source.$, dest.$); - if (text) dest.$.text = text; - } - }, - - after: function(source, dest) { - if (source && dest && dest.$.parentNode) { - var next = dest.$.nextSibling; - if (next) source.insertBefore(next); - else dest.getParent().appendChild(source); - } - }, - - bottom: function(source, dest) { - if (source && dest) - dest.appendChild(source); - }, - - top: function(source, dest) { - if (source && dest) { - var first = dest.$.firstChild; - if (first) source.insertBefore(first); - else dest.appendChild(source); - } - } - }; - - inserters.inside = inserters.bottom; - - Base.each(inserters, function(inserter, name) { - var part = name.capitalize(); - fields['insert' + part] = function(el) { - el = toNodes.apply(this, arguments); - for (var i = 0, list = el.array, l = list.length; i < l; i++) - inserter(i == 0 ? this : this.clone(true), list[i]); - return el.result || this; - } - - fields['inject' + part] = function(el) { - el = toNodes.apply(this, arguments); - for (var i = 0, list = el.array, l = list.length; i < l; i++) - inserter(list[i], this); - return el.result || this; - } - }); - - return fields; -}); - -DomElements = DomNodes.extend(); - -DomElement = DomNode.extend({ - _type: 'element', - _collection: DomElements, - - statics: { - get: function(selector, root) { - return (root && DomNode.wrap(root) || Browser.document).getElement(selector); - }, - - getAll: function(selector, root) { - return (root && DomNode.wrap(root) || Browser.document).getElements(selector); - }, - - create: function(tag, props, doc) { - if (Browser.TRIDENT && props) { - ['name', 'type', 'checked'].each(function(key) { - if (props[key]) { - tag += ' ' + key + '="' + props[key] + '"'; - if (key != 'checked') - delete props[key]; - } - }); - tag = '<' + tag + '>'; - } - return (DomElement.unwrap(doc) || document).createElement(tag); - }, - - isAncestor: function(el, parent) { - return !el ? false : el.ownerDocument == parent ? true - : Browser.WEBKIT && Browser.VERSION < 420 - ? Array.contains(parent.getElementsByTagName(el.tagName), el) - : parent.contains - ? parent != el && parent.contains(el) - : !!(parent.compareDocumentPosition(el) & 16) - } - } -}); - -DomElement.inject(new function() { - function walk(el, walk, start, match, all) { - var elements = all && new el._collection(); - el = el.$[start || walk]; - while (el) { - if (el.nodeType == 1 && (!match || DomElement.match(el, match))) { - if (!all) return DomNode.wrap(el); - elements.push(el); - } - el = el[walk]; - } - return elements; - } - - return { - _properties: ['id'], - - getTag: function() { - return (this.$.tagName || '').toLowerCase(); - }, - - getPrevious: function(match) { - return walk(this, 'previousSibling', null, match); - }, - - getAllPrevious: function(match) { - return walk(this, 'previousSibling', null, match, true); - }, - - getNext: function(match) { - return walk(this, 'nextSibling', null, match); - }, - - getAllNext: function(match) { - return walk(this, 'nextSibling', null, match, true); - }, - - getFirst: function(match) { - return walk(this, 'nextSibling', 'firstChild', match); - }, - - getLast: function(match) { - return walk(this, 'previousSibling', 'lastChild', match); - }, - - hasChild: function(match) { - return DomNode.isNode(match) - ? DomElement.isAncestor(DomElement.unwrap(match), this.$) - : !!this.getFirst(match); - }, - - getParent: function(match) { - return walk(this, 'parentNode', null, match); - }, - - getParents: function(match) { - return walk(this, 'parentNode', null, match, true); - }, - - hasParent: function(match) { - return DomNode.isNode(match) - ? DomElement.isAncestor(this.$, DomElement.unwrap(match)) - : !!this.getParent(match); - }, - - getChildren: function(match) { - return walk(this, 'nextSibling', 'firstChild', match, true); - }, - - hasChildren: function(match) { - return !!this.getChildren(match).length; - }, - - toString: function() { - return (this.$.tagName || this._type).toLowerCase() + - (this.$.id ? '#' + this.$.id : ''); - }, - - toNode: function() { - return this; - } - }; -}); - -$ = DomElement.get; -$$ = DomElement.getAll; - -DomTextNode = DomNode.extend({ - _type: 'textnode' -}); - -DomDocument = DomElement.extend({ - _type: 'document', - - initialize: function() { - if (Browser.TRIDENT && Browser.VERSION < 7) - try { - this.$.execCommand('BackgroundImageCache', false, true); - } catch (e) {} - }, - - createElement: function(tag, props) { - return DomNode.wrap(DomElement.create(tag, props, this.$)).set(props); - }, - - createTextNode: function(text) { - return $(this.$.createTextNode(text)); - }, - - getDocument: function() { - return this; - }, - - getWindow: function() { - return DomNode.wrap(this.$.defaultView || this.$.parentWindow); - }, - - open: function() { - this.$.open(); - }, - - close: function() { - this.$.close(); - }, - - write: function(markup) { - this.$.write(markup); - }, - - writeln: function(markup) { - this.$.writeln(markup); - } -}); - -Window = DomWindow = DomElement.extend({ - _type: 'window', - _initialize: false, - _methods: ['close', 'alert', 'prompt', 'confirm', 'blur', 'focus', 'reload'], - - getDocument: function() { - return DomNode.wrap(this.$.document); - }, - - getWindow: function() { - return this; - }, - - initialize: function(param) { - var win; - if (param.location && param.frames && param.history) { - win = this.base(param) || this; - } else { - if (typeof param == 'string') - param = { url: param }; - (['toolbar','menubar','location','status','resizable','scrollbars']).each(function(key) { - param[key] = param[key] ? 1 : 0; - }); - if (param.width && param.height) { - if (param.left == null) param.left = Math.round( - Math.max(0, (screen.width - param.width) / 2)); - if (param.top == null) param.top = Math.round( - Math.max(0, (screen.height - param.height) / 2 - 40)); - } - var str = Base.each(param, function(val, key) { - if (!/^(focus|confirm|url|name)$/.test(key)) - this.push(key + '=' + (val + 0)); - }, []).join(); - win = this.base(window.open(param.url, param.name.replace(/\s+|\.+|-+/gi, ''), str)) || this; - if (win && param.focus) - win.focus(); - } - return ['location', 'frames', 'history'].each(function(key) { - this[key] = this.$[key]; - }, win); - } -}); - -DomElement.inject(new function() { - function cumulate(name, parent, iter) { - var left = name + 'Left', top = name + 'Top'; - return function(that) { - var cur, next = that, x = 0, y = 0; - do { - cur = next; - x += cur.$[left] || 0; - y += cur.$[top] || 0; - } while((next = DomNode.wrap(cur.$[parent])) && (!iter || iter(cur, next))) - return { x: x, y: y }; - } - } - - function setBounds(fields, offset) { - return function(values) { - var vals = /^(object|array)$/.test(Base.type(values)) ? values : arguments; - if (offset) { - if (vals.x) vals.left = vals.x; - if (vals.y) vals.top = vals.y; - } - var i = 0; - return fields.each(function(name) { - var val = vals.length ? vals[i++] : vals[name]; - if (val != null) this.setStyle(name, val); - }, this); - } - } - - function isBody(that) { - return that.getTag() == 'body'; - } - - var getAbsolute = cumulate('offset', 'offsetParent', Browser.WEBKIT ? function(cur, next) { - return next.$ != document.body || cur.getStyle('position') != 'absolute'; - } : null, true); - - var getPositioned = cumulate('offset', 'offsetParent', function(cur, next) { - return next.$ != document.body && !/^(relative|absolute)$/.test(next.getStyle('position')); - }); - - var getScrollOffset = cumulate('scroll', 'parentNode'); - - var fields = { - - getSize: function() { - return isBody(this) - ? this.getWindow().getSize() - : { width: this.$.offsetWidth, height: this.$.offsetHeight }; - }, - - getOffset: function(relative, scroll) { - if (isBody(this)) - return this.getWindow().getOffset(); - if (relative && !DomNode.isNode(relative)) - return getPositioned(this); - var off = getAbsolute(this); - if (relative) { - var rel = getAbsolute(DomNode.wrap(relative)); - off = { x: off.x - rel.x, y: off.y - rel.y }; - } - if (scroll) { - scroll = this.getScrollOffset(); - off.x -= scroll.x; - off.y -= scroll.y; - } - return off; - }, - - getScrollOffset: function() { - return isBody(this) - ? this.getWindow().getScrollOffset() - : getScrollOffset(this); - }, - - getScrollSize: function() { - return isBody(this) - ? this.getWindow().getScrollSize() - : { width: this.$.scrollWidth, height: this.$.scrollHeight }; - }, - - getBounds: function(relative, scroll) { - if (isBody(this)) - return this.getWindow().getBounds(); - var off = this.getOffset(relative, scroll), - el = this.$; - return { - left: off.x, - top: off.y, - right: off.x + el.offsetWidth, - bottom: off.y + el.offsetHeight, - width: el.offsetWidth, - height: el.offsetHeight - }; - }, - - setBounds: setBounds(['left', 'top', 'width', 'height', 'clip'], true), - - setOffset: setBounds(['left', 'top'], true), - - setSize: setBounds(['width', 'height', 'clip']), - - setScrollOffset: function(x, y) { - if (isBody(this)) { - this.getWindow().setScrollOffset(x, y); - } else { - var off = typeof x == 'object' ? x : { x: x, y: y }; - this.$.scrollLeft = off.x; - this.$.scrollTop = off.y; - } - return this; - }, - - scrollTo: function(x, y) { - return this.setScrollOffset(x, y); - }, - - contains: function(pos) { - var bounds = this.getBounds(); - return pos.x >= bounds.left && pos.x < bounds.right && - pos.y >= bounds.top && pos.y < bounds.bottom; - }, - - isVisible: function(fully) { - var win = this.getWindow(), top = win.getScrollOffset().y, - bottom = top + win.getSize().height, - bounds = this.getBounds(false, true); - return (bounds.height > 0 || bounds.width > 0) - && (bounds.top >= top && bounds.bottom <= bottom - || (fully && bounds.top <= top && bounds.bottom >= bottom) - || !fully && (bounds.top <= top && bounds.bottom >= top - || bounds.top <= bottom && bounds.bottom >= bottom)); - } - }; - - ['left', 'top', 'right', 'bottom', 'width', 'height'].each(function(name) { - var part = name.capitalize(); - fields['get' + part] = function() { - return this.$['offset' + part]; - }; - fields['set' + part] = function(value) { - this.$.style[name] = isNaN(value) ? value : value + 'px'; - }; - }); - - return fields; -}); - -[DomDocument, DomWindow].each(function(ctor) { - ctor.inject(this); -}, { - - getSize: function() { - if (Browser.PRESTO || Browser.WEBKIT) { - var win = this.getWindow().$; - return { width: win.innerWidth, height: win.innerHeight }; - } - var doc = this.getCompatElement(); - return { width: doc.clientWidth, height: doc.clientHeight }; - }, - - getScrollOffset: function() { - var win = this.getWindow().$, doc = this.getCompatElement(); - return { x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop }; - }, - - getScrollSize: function() { - var doc = this.getCompatElement(), min = this.getSize(); - return { width: Math.max(doc.scrollWidth, min.width), height: Math.max(doc.scrollHeight, min.height) }; - }, - - getOffset: function() { - return { x: 0, y: 0 }; - }, - - getBounds: function() { - var size = this.getSize(); - return { - left: 0, top: 0, - right: size.width, bottom: size.height, - width: size.width, height: size.height - }; - }, - - setScrollOffset: function(x, y) { - var off = typeof x == 'object' ? x : { x: x, y: y }; - this.getWindow().$.scrollTo(off.x, off.y); - return this; - }, - - getElementAt: function(pos, exclude) { - var el = this.getDocument().getElement('body'); - while (true) { - var max = -1; - var ch = el.getFirst(); - while (ch) { - if (ch.contains(pos) && ch != exclude) { - var z = ch.$.style.zIndex.toInt() || 0; - if (z >= max) { - el = ch; - max = z; - } - } - ch = ch.getNext(); - } - if (max < 0) break; - } - return el; - }, - - getCompatElement: function() { - var doc = this.getDocument(); - return doc.getElement(!doc.$.compatMode - || doc.$.compatMode == 'CSS1Compat' ? 'html' : 'body').$; - } -}); - -DomEvent = Base.extend(new function() { - var keys = { - '8': 'backspace', - '13': 'enter', - '27': 'escape', - '32': 'space', - '37': 'left', - '38': 'up', - '39': 'right', - '40': 'down', - '46': 'delete' - }; - - function hover(name, type) { - return { - type: type, - listener: function(event) { - if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) - this.fireEvent(name, [event]); - } - } - } - - return { - initialize: function(event) { - this.event = event = event || window.event; - this.type = event.type; - this.target = DomNode.wrap(event.target || event.srcElement); - if (this.target && this.target.$.nodeType == 3) - this.target = this.target.getParentNode(); - this.shift = event.shiftKey; - this.control = event.ctrlKey; - this.alt = event.altKey; - this.meta = event.metaKey; - if (/^(mousewheel|DOMMouseScroll)$/.test(this.type)) { - this.wheel = event.wheelDelta ? - event.wheelDelta / (window.opera ? -120 : 120) : - - (event.detail || 0) / 3; - } else if (/^key/.test(this.type)) { - this.code = event.which || event.keyCode; - this.key = keys[this.code] || String.fromCharCode(this.code).toLowerCase(); - } else if (/^mouse|^click$/.test(this.type)) { - this.page = { - x: event.pageX || event.clientX + document.documentElement.scrollLeft, - y: event.pageY || event.clientY + document.documentElement.scrollTop - }; - this.client = { - x: event.pageX ? event.pageX - window.pageXOffset : event.clientX, - y: event.pageY ? event.pageY - window.pageYOffset : event.clientY - }; - var offset = this.target.getOffset(); - this.offset = { - x: this.page.x - offset.x, - y: this.page.y - offset.y - } - this.rightClick = event.which == 3 || event.button == 2; - if (/^mouse(over|out)$/.test(this.type)) - this.relatedTarget = DomNode.wrap(event.relatedTarget || - this.type == 'mouseout' ? event.toElement : event.fromElement); - } - }, - - stop: function() { - this.stopPropagation(); - this.preventDefault(); - return this; - }, - - stopPropagation: function() { - if (this.event.stopPropagation) this.event.stopPropagation(); - else this.event.cancelBubble = true; - this.stopped = true; - return this; - }, - - preventDefault: function() { - if (this.event.preventDefault) this.event.preventDefault(); - else this.event.returnValue = false; - return this; - }, - - statics: { - events: new Hash({ - mouseenter: hover('mouseenter', 'mouseover'), - - mouseleave: hover('mouseleave', 'mouseout'), - - mousewheel: { type: Browser.GECKO ? 'DOMMouseScroll' : 'mousewheel' }, - - domready: function(func) { - var win = this.getWindow(), doc = this.getDocument(); - if (Browser.loaded) { - func.call(this); - } else if (!doc.onDomReady) { - doc.onDomReady = function() { - if (!Browser.loaded) { - Browser.loaded = true; - doc.fireEvent('domready'); - win.fireEvent('domready'); - } - } - if (Browser.TRIDENT) { - var temp = doc.createElement('div'); - (function() { - try { - temp.$.doScroll('left'); - temp.insertBottom(DomElement.get('body')).setHtml('temp').remove(); - doc.onDomReady(); - } catch (e) { - arguments.callee.delay(50); - } - }).delay(0); - } else if (Browser.WEBKIT && Browser.VERSION < 525) { - (function() { - /^(loaded|complete)$/.test(doc.$.readyState) - ? doc.onDomReady() : arguments.callee.delay(50); - })(); - } else { - win.addEvent('load', doc.onDomReady); - doc.addEvent('DOMContentLoaded', doc.onDomReady); - } - } - } - }), - - add: function(events) { - this.events.append(events); - } - } - }; -}); - -DomElement.inject(new function() { - function callEvent(fire) { - return function(type, args, delay) { - var entries = (this.events || {})[type]; - if (entries) { - var event = args && args[0]; - if (event) - args[0] = event.event ? event : new DomEvent(event); - entries.each(function(entry) { - entry[fire ? 'func' : 'bound'].delay(delay, this, args); - }, this); - } - return !!entries; - } - } - - return { - addEvent: function(type, func) { - this.events = this.events || {}; - var entries = this.events[type] = this.events[type] || []; - if (func && !entries.find(function(entry) { return entry.func == func })) { - var listener = func, name = type, pseudo = DomEvent.events[type]; - if (pseudo) { - if (typeof pseudo == 'function') pseudo = pseudo.call(this, func); - listener = pseudo && pseudo.listener || listener; - name = pseudo && pseudo.type; - } - var that = this, bound = function(event) { - if (event || window.event) - event = event && event.event ? event : new DomEvent(event); - if (listener.call(that, event) === false && event) - event.stop(); - }; - if (name) { - if (this.$.addEventListener) { - this.$.addEventListener(name, bound, false); - } else if (this.$.attachEvent) { - this.$.attachEvent('on' + name, bound); - } - } - entries.push({ func: func, name: name, bound: bound }); - } - return this; - }, - - removeEvent: function(type, func) { - var entries = (this.events || {})[type], entry; - if (func && entries) { - if (entry = entries.remove(function(entry) { return entry.func == func })) { - var name = entry.name, pseudo = DomEvent.events[type]; - if (pseudo && pseudo.remove) pseudo.remove.call(this, func); - if (name) { - if (this.$.removeEventListener) { - this.$.removeEventListener(name, entry.bound, false); - } else if (this.$.detachEvent) { - this.$.detachEvent('on' + name, entry.bound); - } - } - } - } - return this; - }, - - addEvents: function(events) { - return Base.each(events || [], function(fn, type) { - this.addEvent(type, fn); - }, this); - }, - - removeEvents: function(type) { - if (this.events) { - if (type) { - (this.events[type] || []).each(function(fn) { - this.removeEvent(type, fn); - }, this); - delete this.events[type]; - } else { - Base.each(this.events, function(ev, type) { - this.removeEvents(type); - }, this); - this.events = null; - } - } - return this; - }, - - fireEvent: callEvent(true), - - triggerEvent: callEvent(false), - - finalize: function() { - this.removeEvents(); - } - }; -}); - -DomEvent.add(new function() { - var object, last; - - function dragStart(event) { - if (object != this) { - event.type = 'dragstart'; - last = event.page; - this.fireEvent('dragstart', [event]); - if (!event.stopped) { - event.stop(); - var doc = this.getDocument(); - doc.addEvent('mousemove', drag); - doc.addEvent('mouseup', dragEnd); - object = this; - } - } - } - - function drag(event) { - event.type = 'drag'; - event.delta = { - x: event.page.x - last.x, - y: event.page.y - last.y - } - last = event.page; - object.fireEvent('drag', [event]); - event.preventDefault(); - } - - function dragEnd(event) { - if (object) { - event.type = 'dragend'; - object.fireEvent('dragend', [event]); - event.preventDefault(); - var doc = object.getDocument(); - doc.removeEvent('mousemove', drag); - doc.removeEvent('mouseup', dragEnd); - object = null; - } - } - - return { - dragstart: { - type: 'mousedown', - listener: dragStart - }, - - drag: { - type: 'mousedown', - listener: dragStart - }, - - dragend: {} - }; -}); - -DomElement.inject(new function() { - var XPATH= 0, FILTER = 1; - - var methods = [{ - getParam: function(items, separator, context, params) { - var str = context.namespaceURI ? 'xhtml:' + params.tag : params.tag; - if (separator && (separator = DomElement.separators[separator])) - str = separator[XPATH] + str; - for (var i = params.pseudos.length; i--;) { - var pseudo = params.pseudos[i]; - str += pseudo.handler[XPATH](pseudo.argument); - } - if (params.id) str += '[@id="' + params.id + '"]'; - for (var i = params.classes.length; i--;) - str += '[contains(concat(" ", @class, " "), " ' + params.classes[i] + ' ")]'; - for (var i = params.attributes.length; i--;) { - var attribute = params.attributes[i]; - var operator = DomElement.operators[attribute[1]]; - if (operator) str += operator[XPATH](attribute[0], attribute[2]); - else str += '[@' + attribute[0] + ']'; - } - items.push(str); - return items; - }, - - getElements: function(items, elements, context) { - function resolver(prefix) { - return prefix == 'xhtml' ? 'http://www.w3.org/1999/xhtml' : false; - } - var res = (context.ownerDocument || context).evaluate('.//' + items.join(''), context, - resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, l = res.snapshotLength; i < l; i++) - elements.push(res.snapshotItem(i)); - } - }, { - getParam: function(items, separator, context, params, data) { - var found = []; - var tag = params.tag; - if (separator && (separator = DomElement.separators[separator])) { - separator = separator[FILTER]; - var uniques = {}; - function add(item) { - if (!item._unique) - DomNode.unique(item); - if (!uniques[item._unique] && match(item, params, data)) { - uniques[item._unique] = true; - found.push(item); - return true; - } - } - for (var i = 0, l = items.length; i < l; i++) - separator(items[i], params, add); - if (params.clearTag) - params.tag = params.clearTag = null; - return found; - } - if (params.id) { - var el = (context.ownerDocument || context).getElementById(params.id); - params.id = null; - return el && DomElement.isAncestor(el, context) - && match(el, params, data) ? [el] : null; - } else { - if (!items.length) { - items = context.getElementsByTagName(tag); - params.tag = null; - } - for (var i = 0, l = items.length; i < l; i++) - if (match(items[i], params, data)) - found.push(items[i]); - } - return found; - }, - - getElements: function(items, elements, context) { - elements.append(items); - } - }]; - - function parse(selector) { - var params = { tag: '*', id: null, classes: [], attributes: [], pseudos: [] }; - selector.replace(/:([^:(]+)*(?:\((["']?)(.*?)\2\))?|\[([\w-]+)(?:([!*^$~|]?=)(["']?)(.*?)\6)?\]|\.[\w-]+|#[\w-]+|\w+|\*/g, function(part) { - switch (part.charAt(0)) { - case '.': params.classes.push(part.slice(1)); break; - case '#': params.id = part.slice(1); break; - case '[': params.attributes.push([arguments[4], arguments[5], arguments[7]]); break; - case ':': - var handler = DomElement.pseudos[arguments[1]]; - if (!handler) { - params.attributes.push([arguments[1], arguments[3] ? '=' : '', arguments[3]]); - break; - } - params.pseudos.push({ - name: arguments[1], - argument: handler && handler.parser - ? (handler.parser.apply ? handler.parser(arguments[3]) : handler.parser) - : arguments[3], - handler: handler.handler || handler - }); - break; - default: params.tag = part; - } - return ''; - }); - return params; - } - - function match(el, params, data) { - if (params.id && params.id != el.id) - return false; - - if (params.tag && params.tag != '*' && params.tag != (el.tagName || '').toLowerCase()) - return false; - - for (var i = params.classes.length; i--;) - if (!el.className || !el.className.contains(params.classes[i], ' ')) - return false; - - var proto = DomElement.prototype; - for (var i = params.attributes.length; i--;) { - var attribute = params.attributes[i]; - proto.$ = el; - var val = proto.getProperty(attribute[0]); - if (!val) return false; - var operator = DomElement.operators[attribute[1]]; - operator = operator && operator[FILTER]; - if (operator && (!val || !operator(val, attribute[2]))) - return false; - } - - for (var i = params.pseudos.length; i--;) { - var pseudo = params.pseudos[i]; - if (!pseudo.handler[FILTER](el, pseudo.argument, data)) - return false; - } - - return true; - } - - function filter(items, selector, context, elements, data) { - var method = methods[!Browser.XPATH || items.length || - typeof selector == 'string' && selector.contains('option[') - ? FILTER : XPATH]; - var separators = []; - selector = selector.trim().replace(/\s*([+>~\s])[a-zA-Z#.*\s]/g, function(match) { - if (match.charAt(2)) match = match.trim(); - separators.push(match.charAt(0)); - return ':)' + match.charAt(1); - }).split(':)'); - for (var i = 0, l = selector.length; i < l; i++) { - var params = parse(selector[i]); - if (!params) return elements; - var next = method.getParam(items, separators[i - 1], context, params, data); - if (!next) break; - items = next; - } - method.getElements(items, elements, context); - return elements; - } - - return { - - getElements: function(selectors, nowrap) { - var elements = nowrap ? [] : new this._collection(); - selectors = !selectors ? ['*'] : typeof selectors == 'string' - ? selectors.split(',') - : selectors.length != null ? selectors : [selectors]; - for (var i = 0, l = selectors.length; i < l; i++) { - var selector = selectors[i]; - if (Base.type(selector) == 'element') elements.push(selector); - else filter([], selector, this.$, elements, {}); - } - return elements; - }, - - getElement: function(selector) { - var el, type = Base.type(selector), match; - if (type == 'window') { - el = selector; - } else { - if (type == 'string' && (match = selector.match(/^#?([\w-]+)$/))) - el = this.getDocument().$.getElementById(match[1]); - else if (DomNode.isNode(type)) - el = DomElement.unwrap(selector); - if (el && el != this.$ && !DomElement.isAncestor(el, this.$)) - el = null; - if (!el) - el = this.getElements(selector, true)[0]; - } - return DomNode.wrap(el); - }, - - hasElement: function(selector) { - return !!this.getElement(selector); - }, - - match: function(selector) { - return !selector || match(this.$, parse(selector), {}); - }, - - filter: function(elements, selector) { - return filter(elements, selector, this.$, new this._collection(), {}); - }, - - statics: { - match: function(el, selector) { - return !selector || match(DomElement.unwrap(el), parse(selector), {}); - } - } - }; -}); - -DomElement.separators = { - '~': [ - '/following-sibling::', - function(item, params, add) { - while (item = item.nextSibling) - if (item.nodeType == 1 && add(item)) - break; - } - ], - - '+': [ - '/following-sibling::*[1]/self::', - function(item, params, add) { - while (item = item.nextSibling) { - if (item.nodeType == 1) { - add(item); - break; - } - } - } - ], - - '>': [ - '/', - function(item, params, add) { - var children = item.childNodes; - for (var i = 0, l = children.length; i < l; i++) - if (children[i].nodeType == 1) - add(children[i]); - } - ], - - ' ': [ - '//', - function(item, params, add) { - var children = item.getElementsByTagName(params.tag); - params.clearTag = true; - for (var i = 0, l = children.length; i < l; i++) - add(children[i]); - } - ] -}; - -DomElement.operators = new function() { - function contains(sep) { - return [ - function(a, v) { - return '[contains(' + (sep ? 'concat("' + sep + '", @' + a + ', "' + sep + '")' : '@' + a) + ', "' + sep + v + sep + '")]'; - }, - function(a, v) { - return a.contains(v, sep); - } - ] - } - - return { - '=': [ - function(a, v) { - return '[@' + a + '="' + v + '"]'; - }, - function(a, v) { - return a == v; - } - ], - - '^=': [ - function(a, v) { - return '[starts-with(@' + a + ', "' + v + '")]'; - }, - function(a, v) { - return a.substring(0, v.length) == v; - } - ], - - '$=': [ - function(a, v) { - return '[substring(@' + a + ', string-length(@' + a + ') - ' + v.length + ' + 1) = "' + v + '"]'; - }, - function(a, v) { - return a.substring(a.length - v.length) == v; - } - ], - - '!=': [ - function(a, v) { - return '[@' + a + '!="' + v + '"]'; - }, - function(a, v) { - return a != v; - } - ], - - '*=': contains(''), - - '|=': contains('-'), - - '~=': contains(' ') - }; -}; - -DomElement.pseudos = new function() { - var nthChild = [ - function(argument) { - switch (argument.special) { - case 'n': return '[count(preceding-sibling::*) mod ' + argument.a + ' = ' + argument.b + ']'; - case 'first': return '[count(preceding-sibling::*) = 0]'; - case 'last': return '[count(following-sibling::*) = 0]'; - case 'only': return '[not(preceding-sibling::* or following-sibling::*)]'; - case 'index': return '[count(preceding-sibling::*) = ' + argument.a + ']'; - } - }, - function(el, argument, data) { - var count = 0; - switch (argument.special) { - case 'n': - data.indices = data.indices || {}; - if (!data.indices[el._unique]) { - var children = el.parentNode.childNodes; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - if (child.nodeType == 1) { - if (!child._unique) - DomNode.unique(item); - data.indices[child._unique] = count++; - } - } - } - return data.indices[el._unique] % argument.a == argument.b; - case 'first': - while (el = el.previousSibling) - if (el.nodeType == 1) - return false; - return true; - case 'last': - while (el = el.nextSibling) - if (el.nodeType == 1) - return false; - return true; - case 'only': - var prev = el; - while(prev = prev.previousSibling) - if (prev.nodeType == 1) - return false; - var next = el; - while (next = next.nextSibling) - if (next.nodeType == 1) - return false; - return true; - case 'index': - while (el = el.previousSibling) - if (el.nodeType == 1 && ++count > argument.a) - return false; - return true; - } - return false; - } - ]; - - function contains(caseless) { - var abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - return [ - function(argument) { - return '[contains(' + (caseless ? 'translate(text(), "' + abc - + '", "' + abc.toLowerCase() + '")' : 'text()') + ', "' - + (caseless && argument ? argument.toLowerCase() : argument) + '")]'; - }, - function(el, argument) { - if (caseless && argument) argument = argument.toLowerCase(); - var nodes = el.childNodes; - for (var i = nodes.length - 1; i >= 0; i--) { - var child = nodes[i]; - if (child.nodeName && child.nodeType == 3 && - (caseless ? child.nodeValue.toLowerCase() : child.nodeValue).contains(argument)) - return true; - } - return false; - } - ]; - } - - return { - 'nth-child': { - parser: function(argument) { - var match = argument ? argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/) : [null, 1, 'n', 0]; - if (!match) return null; - var i = parseInt(match[1]), - a = isNaN(i) ? 1 : i, - special = match[2], - b = parseInt(match[3]) || 0; - if (a != 0) { - b--; - while (b < 1) b += a; - while (b >= a) b -= a; - } else { - a = b; - special = 'index'; - } - switch (special) { - case 'n': return { a: a, b: b, special: 'n' }; - case 'odd': return { a: 2, b: 0, special: 'n' }; - case 'even': return { a: 2, b: 1, special: 'n' }; - case 'first': return { special: 'first' }; - case 'last': return { special: 'last' }; - case 'only': return { special: 'only' }; - default: return { a: a - 1, special: 'index' }; - } - }, - handler: nthChild - }, - - 'even': { - parser: { a: 2, b: 1, special: 'n' }, - handler: nthChild - }, - - 'odd': { - parser: { a: 2, b: 0, special: 'n' }, - handler: nthChild - }, - - 'first-child': { - parser: { special: 'first' }, - handler: nthChild - }, - - 'last-child': { - parser: { special: 'last' }, - handler: nthChild - }, - - 'only-child': { - parser: { special: 'only' }, - handler: nthChild - }, - - 'enabled': [ - function() { - return '[not(@disabled)]'; - }, - function(el) { - return !el.disabled; - } - ], - - 'empty': [ - function() { - return '[not(node())]'; - }, - function(el) { - return !(el.innerText || el.textContent || '').length; - } - ], - - 'contains': contains(false), - - 'contains-caseless': contains(true) - }; -}; - -HtmlElements = DomElements.extend(); - -HtmlElement = DomElement.extend({ - _collection: HtmlElements -}); - -HtmlElement.inject({ - _properties: ['html'], - - getClass: function() { - return this.$.className; - }, - - setClass: function(cls) { - this.$.className = cls; - }, - - modifyClass: function(name, add) { - if (!this.hasClass(name) ^ !add) - this.$.className = (add ? this.$.className + ' ' + name : - this.$.className.replace(name, '')).clean(); - return this; - }, - - addClass: function(name) { - return this.modifyClass(name, true); - }, - - removeClass: function(name) { - return this.modifyClass(name, false); - }, - - toggleClass: function(name) { - return this.modifyClass(name, !this.hasClass(name)); - }, - - hasClass: function(name) { - return this.$.className.contains(name, ' '); - } -}); - -Array.inject({ - toNode: function(doc) { - doc = DomNode.wrap(doc || document); - var elements = new HtmlElements(); - for (var i = 0; i < this.length;) { - var value = this[i++], element = null, type = Base.type(value); - if (type == 'string') { - var props = /^(object|hash)$/.test(Base.type(this[i])) && this[i++]; - element = value.isHtml() - ? value.toNode(doc).set(props) - : doc.createElement(value, props); - if (Base.type(this[i]) == 'array') - element.injectBottom(this[i++].toNode(doc)); - } else if (DomNode.isNode(type)) { - element = value; - } else if (value && value.toNode) { - element = value.toNode(doc); - } - if (element) - elements[Base.type(element) == 'array' ? 'append' : 'push'](element); - } - return elements.length == 1 ? elements[0] : elements; - } -}); - -String.inject({ - toNode: function(doc) { - var doc = doc || document, elements; - if (this.isHtml()) { - var str = this.trim().toLowerCase(); - var div = DomElement.unwrap(doc).createElement('div'); - - var wrap = - !str.indexOf('', ''] || - !str.indexOf('', ''] || - (!str.indexOf('', ''] || - !str.indexOf('', ''] || - (!str.indexOf('', ''] || - !str.indexOf('', ''] || - [0,'','']; - - div.innerHTML = wrap[1] + this + wrap[2]; - while (wrap[0]--) - div = div.firstChild; - if (Browser.TRIDENT) { - var els = []; - if (!str.indexOf('' && str.indexOf('= 0 ; --i) { - var el = els[i]; - if (el.nodeName.toLowerCase() == 'tbody' && !el.childNodes.length) - el.parentNode.removeChild(el); - } - } - elements = new HtmlElements(div.childNodes); - } else { - elements = DomNode.wrap(doc).getElements(this); - } - return elements.length == 1 ? elements[0] : elements; - } -}); - -HtmlDocument = DomDocument.extend({ - _collection: HtmlElements -}); - -HtmlElement.inject(new function() { - var styles = { - all: { - width: '@px', height: '@px', left: '@px', top: '@px', right: '@px', bottom: '@px', - color: 'rgb(@, @, @)', backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', - fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', textIndent: '@px', - margin: '@px @px @px @px', padding: '@px @px @px @px', - border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', - borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', - borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', - clip: 'rect(@px, @px, @px, @px)', opacity: '@' - }, - part: { - 'border': {}, 'borderWidth': {}, 'borderStyle': {}, 'borderColor': {}, - 'margin': {}, 'padding': {} - } - }; - - ['Top', 'Right', 'Bottom', 'Left'].each(function(dir) { - ['margin', 'padding'].each(function(style) { - var sd = style + dir; - styles.part[style][sd] = styles.all[sd] = '@px'; - }); - var bd = 'border' + dir; - styles.part.border[bd] = styles.all[bd] = '@px @ rgb(@, @, @)'; - var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; - styles.part[bd] = {}; - styles.part.borderWidth[bdw] = styles.part[bd][bdw] = '@px'; - styles.part.borderStyle[bds] = styles.part[bd][bds] = '@'; - styles.part.borderColor[bdc] = styles.part[bd][bdc] = 'rgb(@, @, @)'; - }); - - Base.each(styles.all, function(val, name) { - this[name] = val.split(' '); - }); - - var fields = { - - getComputedStyle: function(name) { - if (this.$.currentStyle) return this.$.currentStyle[name.camelize()]; - var style = this.getWindow().$.getComputedStyle(this.$, null); - return style ? style.getPropertyValue(name.hyphenate()) : null; - }, - - getStyle: function(name) { - if (name === undefined) return this.getStyles(); - if (name == 'opacity') { - var op = this.opacity; - return op || op == 0 ? op : this.getVisibility() ? 1 : 0; - } - var el = this.$; - name = name.camelize(); - var style = el.style[name]; - if (!Base.check(style)) { - if (styles.part[name]) { - style = Hash.map(styles.part[name], function(val, key) { - return this.getStyle(key); - }, this); - return style.every(function(val) { - return val == style[0]; - }) ? style[0] : style.join(' '); - } - style = this.getComputedStyle(name); - } - if (name == 'visibility') - return /^(visible|inherit(|ed))$/.test(style); - var color = style && style.match(/rgb[a]?\([\d\s,]+\)/); - if (color) return style.replace(color[0], color[0].rgbToHex()); - if (Browser.PRESTO || Browser.TRIDENT && isNaN(parseInt(style))) { - if (/^(width|height)$/.test(name)) { - var size = 0; - (name == 'width' ? ['left', 'right'] : ['top', 'bottom']).each(function(val) { - size += this.getStyle('border-' + val + '-width').toInt() + this.getStyle('padding-' + val).toInt(); - }, this); - return this.$['offset' + name.capitalize()] - size + 'px'; - } - if (Browser.PRESTO && /px/.test(style)) return style; - if (/border(.+)[wW]idth|margin|padding/.test(name)) return '0px'; - } - return style; - }, - - setStyle: function(name, value) { - if (value === undefined) return this.setStyles(name); - var el = this.$; - switch (name) { - case 'float': - name = Browser.TRIDENT ? 'styleFloat' : 'cssFloat'; - break; - case 'clip': - if (value == true) - value = [0, el.offsetWidth, el.offsetHeight, 0]; - break; - default: - name = name.camelize(); - } - var type = Base.type(value); - if (value != undefined && type != 'string') { - var parts = styles.all[name] || ['@'], index = 0; - value = (type == 'array' ? value.flatten() : [value]).map(function(val) { - var part = parts[index++]; - if (!part) - throw Base.stop; - return Base.type(val) == 'number' ? part.replace('@', name == 'opacity' ? val : Math.round(val)) : val; - }).join(' '); - } - switch (name) { - case 'visibility': - if (!isNaN(value)) value = !!value.toInt() + ''; - value = value == 'true' && 'visible' || value == 'false' && 'hidden' || value; - break; - case 'opacity': - this.opacity = value = parseFloat(value); - this.setStyle('visibility', !!value); - if (!value) value = 1; - if (!el.currentStyle || !el.currentStyle.hasLayout) el.style.zoom = 1; - if (Browser.TRIDENT) el.style.filter = value > 0 && value < 1 ? 'alpha(opacity=' + value * 100 + ')' : ''; - el.style.opacity = value; - return this; - } - el.style[name] = value; - return this; - }, - - getStyles: function() { - return arguments.length ? Array.each(arguments, function(name) { - this[name] = that.getStyle(name); - }, {}) : this.$.style.cssText; - }, - - setStyles: function(styles) { - switch (Base.type(styles)) { - case 'object': - Base.each(styles, function(style, name) { - if (style !== undefined) - this.setStyle(name, style); - }, this); - break; - case 'string': - this.$.style.cssText = styles; - } - return this; - } - }; - - ['opacity', 'color', 'background', 'visibility', 'clip', 'zIndex', - 'border', 'margin', 'padding', 'display'].each(function(name) { - var part = name.capitalize(); - fields['get' + part] = function() { - return this.getStyle(name); - }; - fields['set' + part] = function(value) { - return this.setStyle(name, arguments.length > 1 - ? Array.create(arguments) : value); - }; - }); - - return fields; -}); - -HtmlElement.inject({ - - getFormElements: function() { - return this.getElements(['input', 'select', 'textarea']); - }, - - getValue: function(name) { - var el = this.getElement(name); - return el && el.getValue && el.getValue(); - }, - - setValue: function(name, val) { - var el = this.getElement(name); - if (!el) el = this.injectTop('input', { type: 'hidden', id: name, name: name }); - return el.setValue(val); - }, - - getValues: function() { - return this.getFormElements().each(function(el) { - var name = el.getName(), value = el.getValue(); - if (name && value !== undefined && !el.getDisabled()) - this[name] = value; - }, new Hash()); - }, - - setValues: function(values) { - return Base.each(values, function(val, name) { - this.setValue(name, val); - }, this); - }, - - toQueryString: function() { - return Base.toQueryString(this.getValues()); - } -}); - -HtmlForm = HtmlElement.extend({ - _tag: 'form', - _properties: ['action', 'method', 'target'], - _methods: ['submit'], - - blur: function() { - return this.getFormElements().each(function(el) { - el.blur(); - }, this); - }, - - enable: function(enable) { - return this.getFormElements().each(function(el) { - el.enable(enable); - }, this); - } -}); - -HtmlFormElement = HtmlElement.extend({ - _properties: ['name', 'disabled'], - _methods: ['focus', 'blur'], - - enable: function(enable) { - var disabled = !enable && enable !== undefined; - if (disabled) this.$.blur(); - this.$.disabled = disabled; - return this; - } -}); - -HtmlInput = HtmlFormElement.extend({ - _tag: 'input', - _properties: ['type', 'checked', 'defaultChecked', 'readOnly', 'maxLength'], - _methods: ['click'], - - getValue: function() { - if (this.$.checked && /^(checkbox|radio)$/.test(this.$.type) || - /^(hidden|text|password|button|search)$/.test(this.$.type)) - return this.$.value; - }, - - setValue: function(val) { - if (/^(checkbox|radio)$/.test(this.$.type)) this.$.checked = this.$.value == val; - else this.$.value = val != null ? val : ''; - return this; - } -}); - -HtmlTextArea = HtmlFormElement.extend({ - _tag: 'textarea', - _properties: ['value'] -}); - -HtmlSelect = HtmlFormElement.extend({ - _tag: 'select', - _properties: ['type', 'selectedIndex'], - - getOptions: function() { - return this.getElements('option'); - }, - - getSelected: function() { - return this.getElements('option[selected]'); - }, - - setSelected: function(values) { - this.$.selectedIndex = -1; - if (values) { - Array.each(values.length != null ? values : [values], function(val) { - val = DomElement.unwrap(val); - if (val != null) - this.getElements('option[value="' + (val.value || val) + '"]').setProperty('selected', true); - }, this); - } - return this; - }, - - getValue: function() { - return this.getSelected().getProperty('value'); - }, - - setValue: function(values) { - return this.setSelected(values); - } -}); - -HtmlOption = HtmlFormElement.extend({ - _tag: 'option', - _properties: ['text', 'value', 'selected', 'defaultSelected', 'index'] -}); - -HtmlFormElement.inject({ - setSelection: function(start, end) { - var sel = end == undefined ? start : { start: start, end: end }; - this.focus(); - if (this.$.setSelectionRange) { - this.$.setSelectionRange(sel.start, sel.end); - } else { - var value = this.getValue(); - var len = value.substring(sel.start, sel.end).replace(/\r/g, '').length; - var pos = value.substring(0, sel.start).replace(/\r/g, '').length; - var range = this.$.createTextRange(); - range.collapse(true); - range.moveEnd('character', pos + len); - range.moveStart('character', pos); - range.select(); - } - return this; - }, - - getSelection: function() { - if (this.$.selectionStart !== undefined) { - return { start: this.$.selectionStart, end: this.$.selectionEnd }; - } else { - this.focus(); - var pos = { start: 0, end: 0 }; - var range = this.getDocument().$.selection.createRange(); - var dup = range.duplicate(); - if (this.$.type == 'text') { - pos.start = 0 - dup.moveStart('character', -100000); - pos.end = pos.start + range.text.length; - } else { - var value = this.getValue(); - dup.moveToElementText(this.$); - dup.setEndPoint('StartToEnd', range); - pos.end = value.length - dup.text.length; - dup.setEndPoint('StartToStart', range); - pos.start = value.length - dup.text.length; - } - return pos; - } - }, - - getSelectedText: function() { - var range = this.getSelection(); - return this.getValue().substring(range.start, range.end); - }, - - replaceSelectedText: function(value, select) { - var range = this.getSelection(), current = this.getValue(); - var top = this.$.scrollTop, height = this.$.scrollHeight; - this.setValue(current.substring(0, range.start) + value + current.substring(range.end, current.length)); - if (top != null) - this.$.scrollTop = top + this.$.scrollHeight - height; - return select || select == undefined - ? this.setSelection(range.start, range.start + value.length) - : this.setCaret(range.start + value.length); - }, - - getCaret: function() { - return this.getSelection().start; - }, - - setCaret: function(pos) { - return this.setSelection(pos, pos); - } -}); - -HtmlImage = HtmlElement.extend({ - _tag: 'img', - _properties: ['src', 'alt', 'title'] -}); - -$document = Browser.document = DomNode.wrap(document); -$window = Browser.window = DomNode.wrap(window).addEvent('unload', DomNode.dispose); - -Chain = { - chain: function(fn) { - (this._chain = this._chain || []).push(fn); - return this; - }, - - callChain: function() { - if (this._chain && this._chain.length) - this._chain.shift().apply(this, arguments); - return this; - }, - - clearChain: function() { - this._chain = []; - return this; - } -}; - -Callback = { - addEvent: function(type, fn) { - var ref = this.events = this.events || {}; - ref = ref[type] = ref[type] || []; - if (!ref.find(function(val) { return val == fn })) ref.push(fn); - return this; - }, - - addEvents: function(events) { - return Base.each((events || []), function(fn, type) { - this.addEvent(type, fn); - }, this); - }, - - fireEvent: function(type, args, delay) { - return (this.events && this.events[type] || []).each(function(fn) { - fn.delay(delay, this, args); - }, this); - }, - - removeEvent: function(type, fn) { - if (this.events && this.events[type]) - this.events[type].remove(function(val) { return fn == val; }); - return this; - }, - - setOptions: function(opts) { - return (this.options = Hash.create(this.options, opts)).each(function(val, i) { - if (typeof val == 'function' && (i = i.match(/^on([A-Z]\w*)/))) - this.addEvent(i[1].toLowerCase(), val); - }, this); - }, - - statics: { - inject: function() { - var proto = this.prototype, options = proto.options; - this.base.apply(this, arguments); - if (proto.options != options) - proto.options = Hash.merge({}, options, proto.options); - return this; - } - } -}; - -Request = Base.extend(Chain, Callback, new function() { - var unique = 0; - - function createRequest(that) { - if (!that.transport) - that.transport = window.XMLHttpRequest && new XMLHttpRequest() - || Browser.TRIDENT && new ActiveXObject('Microsoft.XMLHTTP'); - } - - function createFrame(that) { - var id = 'request_' + unique++, load = that.onFrameLoad.bind(that); - var div = DomElement.get('body').injectBottom('div', { - styles: { - position: 'absolute', width: 0, height: 0, top: 0, marginLeft: '-10000px' - } - }, [ - 'iframe', { - name: id, id: id, events: { load: load, readystatechange: load } - } - ] - ); - that.frame = { - id: id, div: div, - iframe: window.frames[id] || document.getElementById(id), - element: DomElement.get(id) - }; - div.offsetWidth; - } - - return { - options: { - headers: { - 'X-Requested-With': 'XMLHttpRequest', - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }, - method: 'post', - async: true, - urlEncoded: true, - encoding: 'utf-8', - emulation: true, - secure: false - }, - - initialize: function() { - var params = Array.associate(arguments, { url: 'string', options: 'object', handler: 'function' }); - this.setOptions(params.options); - if (params.handler) - this.addEvent('complete', params.handler); - if (this.options.update) - this.options.type = 'html'; - this.headers = new Hash(this.options.headers); - if (this.options.type == 'json') { - this.setHeader('Accept', 'application/json'); - this.setHeader('X-Request', 'JSON'); - } - if (this.options.urlEncoded && /^(post|put)$/.test(this.options.method)) { - this.setHeader('Content-Type', 'application/x-www-form-urlencoded' + - (this.options.encoding ? '; charset=' + this.options.encoding : '')); - } - this.headers.append(this.options.headers); - }, - - onStateChange: function() { - if (this.transport.readyState == 4 && this.running) { - this.running = false; - this.status = 0; - try { - this.status = this.transport.status; - delete this.transport.onreadystatechange; - } catch (e) {} - if (!this.status || this.status >= 200 && this.status < 300) { - this.success(this.transport.responseText, this.transport.responseXML); - } else { - this.fireEvent('complete').fireEvent('failure'); - } - } - }, - - onFrameLoad: function() { - var frame = this.frame && this.frame.iframe, loc = frame && frame.location, - doc = frame && (frame.contentDocument || frame.contentWindow || frame).document; - if (this.running && frame && loc && (!loc.href || loc.href.indexOf(this.url) != -1) - && /^(loaded|complete|undefined)$/.test(doc.readyState)) { - this.running = false; - var html = this.options.type == 'html', area = !html - && doc.getElementsByTagName('textarea')[0]; - var text = doc && (area && area.value || doc.body - && (html && doc.body.innerHTML || doc.body.textContent - || doc.body.innerText)) || ''; - this.frame.element.setProperty('src', ''); - this.success(text); - if (!this.options.link) { - var div = this.frame.div; - div.insertBottom(DomElement.get('body')); - div.remove.delay(5000, div); - this.frame = null; - } - } - }, - - success: function(text, xml) { - var args; - switch (this.options.type) { - case 'html': - var match = text.match(/]*>([\u0000-\uffff]*?)<\/body>/i); - var stripped = this.stripScripts(match ? match[1] : text); - if (this.options.update) - DomElement.get(this.options.update).setHtml(stripped.html); - if (this.options.evalScripts) - this.executeScript(stripped.script); - args = [ stripped.html, text ]; - break; - case 'json': - args = [ Json.decode(text, this.options.secure), text ]; - break; - default: - args = [ this.processScripts(text), xml ] - } - this.fireEvent('complete', args) - .fireEvent('success', args) - .callChain(); - }, - - stripScripts: function(html) { - var script = ''; - html = html.replace(/]*>([\u0000-\uffff]*?)<\/script>/gi, function() { - script += arguments[1] + '\n'; - return ''; - }); - return { html: html, script: script }; - }, - - processScripts: function(text) { - if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) { - this.executeScript(text); - return text; - } else { - var stripped = this.stripScripts(text); - if (this.options.evalScripts) - this.executeScript(stripped.script); - return stripped.html; - } - }, - - executeScript: function(script) { - if (window.execScript) { - window.execScript(script); - } else { - DomElement.get('head').injectBottom('script', { - type: 'text/javascript', text: script - }).remove(); - } - }, - - setHeader: function(name, value) { - this.headers[name] = value; - return this; - }, - - getHeader: function(name) { - try { - if (this.transport) - return this.transport.getResponseHeader(name); - } catch (e) {} - return null; - }, - - send: function() { - var params = Array.associate(arguments, { url: 'string', options: 'object', handler: 'function' }); - var opts = params.options ? Hash.merge(params.options, this.options) : this.options; - if (params.handler) - this.addEvent('complete', function() { - params.handler.apply(this, arguments); - this.removeEvent('complete', arguments.callee); - }); - if (this.running) { - switch (opts.link) { - case 'cancel': - this.cancel(); - break; - case 'chain': - this.chain(this.send.wrap(this, arguments)); - default: - return this; - } - } - var data = opts.data || ''; - var url = params.url || opts.url; - switch (Base.type(data)) { - case 'element': - data = DomNode.wrap(data); - if (data.getTag() != 'form' || !data.hasElement('input[type=file]')) - data = data.toQueryString(); - break; - case 'object': - data = Base.toQueryString(data); - break; - default: - data = data.toString(); - } - var string = typeof data == 'string', method = opts.method; - if (opts.emulation && /^(put|delete)$/.test(method)) { - if (string) data += '&_method=' + method; - else data.setValue('_method', method); - method = 'post'; - } - if (string && !this.options.iframe) { - createRequest(this); - if (!this.transport) { - if (!this.frame) - createFrame(this); - method = 'get'; - } - } else if (!this.frame) { - createFrame(this); - } - if (string && data && method == 'get') { - url += (url.contains('?') ? '&' : '?') + data; - data = null; - } - this.running = true; - this.url = url; - if (this.frame) { - var form = !string && data; - if (form) { - form.set({ - target: this.frame.id, action: url, method: method, - enctype: method == 'get' - ? 'application/x-www-form-urlencoded' - : 'multipart/form-data', - 'accept-charset': opts.encoding || '' - }).submit(); - } else { - this.frame.element.setProperty('src', url); - } - } else if (this.transport) { - try { - this.transport.open(method.toUpperCase(), url, opts.async); - this.transport.onreadystatechange = this.onStateChange.bind(this); - new Hash(this.headers, opts.headers).each(function(header, name) { - try{ - this.transport.setRequestHeader(name, header); - } catch (e) { - this.fireEvent('exception', [e, name, header]); - } - }, this); - this.fireEvent('request'); - this.transport.send(data); - if (!opts.async) - this.onStateChange(); - } catch (e) { - this.fireEvent('failure', [e]); - } - } - return this; - }, - - cancel: function() { - if (this.running) { - this.running = false; - if (this.transport) { - this.transport.abort(); - this.transport.onreadystatechange = null; - this.transport = null; - } else if (this.frame) { - this.frame.div.remove(); - this.frame = null; - } - this.fireEvent('cancel'); - } - return this; - } - }; -}); - -HtmlForm.inject({ - send: function(url) { - if (!this.sender) - this.sender = new Request({ link: 'cancel' }); - this.sender.send({ - url: url || this.getProperty('action'), - data: this, method: this.getProperty('method') || 'post' - }); - } -}); - -HtmlElement.inject({ - load: function() { - if (!this.loader) - this.loader = new Request({ link: 'cancel', update: this, method: 'get' }); - this.loader.send(Array.associate(arguments, { data: 'object', url: 'string' })); - return this; - } -}); - -Asset = new function() { - function getProperties(props) { - return props ? Hash.create(props).each(function(val, key) { - if (/^on/.test(key)) delete this[key]; - }) : {}; - } - - function createMultiple(type, sources, options) { - var props = getProperties(options), count = 0; - options = options || {}; - return sources.each(function(src) { - props.onLoad = function() { - if (options.onProgress) - options.onProgress(src); - if (++count == sources.length && options.onComplete) - options.onComplete(); - } - this.push(Asset[type](src, props)); - }, new HtmlElements()); - } - - return { - script: function(src, props) { - var script = DomElement.get('head').injectBottom('script', Hash.merge({ - events: { - load: props.onLoad && function() { - if (!this.loaded) { - this.loaded = true; - props.onLoad.call(this); - } - }, - readystatechange: function() { - if (/loaded|complete/.test(this.$.readyState)) - this.fireEvent('load'); - } - }, - src: src - }, getProperties(props))); - if (Browser.WEBKIT && Browser.VERSION < 420) - new Request({ url: src, method: 'get' }).addEvent('success', function() { - script.fireEvent('load', [], 1); - }).send(); - return script; - }, - - stylesheet: function(src, props) { - return new HtmlElement('link', new Hash({ - rel: 'stylesheet', media: 'screen', type: 'text/css', href: src - }, props)).insertInside(DomElement.get('head')); - }, - - image: function(src, props) { - props = props || {}; - var image = new Image(); - image.src = src; - var element = new HtmlElement('img', { src: src }); - ['load', 'abort', 'error'].each(function(type) { - var name = 'on' + type.capitalize(); - if (props[name]) element.addEvent(type, function() { - this.removeEvent(type, arguments.callee); - props[name].call(this); - }); - }); - if (image.width && image.height) - element.fireEvent('load', [], 1); - return element.setProperties(getProperties(props)); - }, - - scripts: function(sources, options) { - return createMultiple('script', sources, options); - }, - - stylesheets: function(sources, options) { - return createMultiple('stylesheet', sources, options); - }, - - images: function(sources, options) { - return createMultiple('image', sources, options); - } - } -}; - -Cookie = { - set: function(name, value, expires, path) { - document.cookie = name + '=' + encodeURIComponent(value) + (expires ? ';expires=' + - expires.toGMTString() : '') + ';path=' + (path || '/'); - }, - get: function(name) { - var res = document.cookie.match('(?:^|;)\\s*' + name + '=([^;]*)'); - if (res) return decodeURIComponent(res[1]); - }, - - remove: function(name) { - this.set(name, '', -1); - } -}; - -Fx = Base.extend(Chain, Callback, { - options: { - fps: 50, - unit: false, - duration: 500, - wait: true, - transition: function(p) { - return -(Math.cos(Math.PI * p) - 1) / 2; - } - }, - - initialize: function(element, options) { - this.element = DomElement.get(element); - this.setOptions(options); - }, - - step: function() { - var time = Date.now(); - if (time < this.time + this.options.duration) { - this.delta = this.options.transition((time - this.time) / this.options.duration); - this.update(this.get()); - } else { - this.stop(true); - this.update(this.to); - this.fireEvent('complete', [this.element]).callChain(); - } - }, - - set: function(to) { - this.update(to); - this.fireEvent('set', [this.element]); - return this; - }, - - get: function() { - return this.compute(this.from, this.to); - }, - - compute: function(from, to) { - return (to - from) * this.delta + from; - }, - - start: function(from, to) { - if (!this.options.wait) this.stop(); - else if (this.timer) return this; - this.from = from; - this.to = to; - this.time = Date.now(); - if (!this.slave) { - this.timer = this.step.periodic(Math.round(1000 / this.options.fps), this); - this.fireEvent('start', [this.element]); - } - this.step(); - return this; - }, - - stop: function(end) { - if (this.timer) { - this.timer = this.timer.clear(); - if (!end) this.fireEvent('cancel', [this.element]).clearChain(); - } - return this; - } -}); - -Fx.Scroll = Fx.extend({ - options: { - offset: { x: 0, y: 0 }, - wheelStops: true - }, - - initialize: function(element, options) { - this.base(element, options); - if (this.options.wheelStops) { - var stop = this.stop.bind(this), stopper = this.element; - this.addEvent('start', function() { - stopper.addEvent('mousewheel', stop); - }, true); - this.addEvent('complete', function() { - stopper.removeEvent('mousewheel', stop); - }, true); - } - }, - - update: function(x, y) { - var now = Array.flatten(arguments); - this.element.setScrollOffset(now[0], now[1]); - }, - - get: function() { - var now = []; - for (var i = 0; i < 2; i++) - now.push(this.compute(this.from[i], this.to[i])); - return now; - }, - - start: function(x, y) { - var offsetSize = this.element.getSize(), - scrollSize = this.element.getScrollSize(), - scroll = this.element.getScrollOffset(), - values = { x: x, y: y }, - lookup = { x: 'width', y: 'height' }; - for (var i in values) { - var s = lookup[i]; - var max = scrollSize[s] - offsetSize[s]; - if (Base.check(values[i])) - values[i] = Base.type(values[i]) == 'number' - ? values[i].limit(0, max) : max; - else values[i] = scroll[i]; - values[i] += this.options.offset[i]; - } - return this.base([scroll.x, scroll.y], [values.x, values.y]); - }, - - toTop: function() { - return this.start(false, 0); - }, - - toLeft: function() { - return this.start(0, false); - }, - - toRight: function() { - return this.start('right', false); - }, - - toBottom: function() { - return this.start(false, 'bottom'); - }, - - toElement: function(el, options) { - var el = DomElement.get(el), offset = el.getOffset(), - current = el.getWindow().getScrollOffset(); - return this.start( - !options || options.x ? offset.x : current.x, - !options || options.y ? offset.y : current.y); - } -}); - -Fx.SmoothScroll = Fx.Scroll.extend({ - initialize: function(options, context) { - context = DomElement.get(context || document); - var doc = context.getDocument(), win = context.getWindow(); - this.base(doc, options); - var links = this.options.links ? $$(this.options.links) : $$('a', context); - var loc = win.location.href.match(/^[^#]*/)[0] + '#'; - links.each(function(link) { - if (link.$.href.indexOf(loc) != 0) return; - var hash = link.$.href.substring(loc.length); - var anchor = hash && DomElement.get('#' + hash, context); - if (anchor) { - link.addEvent('click', function(event) { - this.toElement(anchor); - var props = anchor.getProperties('name', 'id'); - anchor.removeProperties('name', 'id'); - win.location.hash = hash; - anchor.setProperties(props); - event.stop(); - }.bind(this)); - } - }, this); - } -}); - -Fx.CSS = new function() { - - var parsers = new Hash({ - color: { - match: function(value) { - if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); - return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; - }, - - compute: function(from, to, fx) { - return from.map(function(value, i) { - return Math.round(fx.compute(value, to[i])); - }); - }, - - get: function(value) { - return value.map(Number); - } - }, - - number: { - match: function(value) { - return parseFloat(value); - }, - - compute: function(from, to, fx) { - return fx.compute(from, to); - }, - - get: function(value, unit) { - return (unit) ? value + unit : value; - } - } - }); - - return { - start: function(element, property, values) { - values = Array.convert(values); - if (!Base.check(values[1])) - values = [ element.getStyle(property), values[0] ]; - var parsed = values.map(Fx.CSS.set); - return { from: parsed[0], to: parsed[1] }; - }, - - set: function(value) { - return Array.convert(value).map(function(val) { - val = val + ''; - var res = parsers.find(function(parser, key) { - var value = parser.match(val); - if (Base.check(value)) return { value: value, parser: parser }; - }) || { - value: val, - parser: { - compute: function(from, to) { - return to; - } - } - }; - return res; - }); - }, - - compute: function(from, to, fx) { - return from.map(function(obj, i) { - return { - value: obj.parser.compute(obj.value, to[i].value, fx), - parser: obj.parser - }; - }); - }, - - get: function(now, unit) { - return now.reduce(function(prev, cur) { - var get = cur.parser.get; - return prev.concat(get ? get(cur.value, unit) : cur.value); - }, []); - } - } -}; - -Fx.Style = Fx.extend({ - initialize: function(element, property, options) { - this.base(element, options); - this.property = property; - }, - - hide: function() { - return this.set(0); - }, - - get: function() { - return Fx.CSS.compute(this.from, this.to, this); - }, - - set: function(to) { - return this.base(Fx.CSS.set(to)); - }, - - start: function(from, to) { - if (this.timer && this.options.wait) return this; - var parsed = Fx.CSS.start(this.element, this.property, [from, to]); - return this.base(parsed.from, parsed.to); - }, - - update: function(val) { - this.element.setStyle(this.property, Fx.CSS.get(val, this.options.unit)); - } -}); - -HtmlElement.inject({ - effect: function(prop, opts) { - return new Fx.Style(this, prop, opts); - } -}); - -Fx.Styles = Fx.extend({ - get: function() { - var that = this; - return Base.each(this.from, function(from, key) { - this[key] = Fx.CSS.compute(from, that.to[key], that); - }, {}); - }, - - set: function(to) { - return this.base(Base.each(to, function(val, key) { - this[key] = Fx.CSS.set(val); - }, {})); - }, - - start: function(obj) { - if (this.timer && this.options.wait) return this; - var from = {}, to = {}; - Base.each(obj, function(val, key) { - var parsed = Fx.CSS.start(this.element, key, val); - from[key] = parsed.from; - to[key] = parsed.to; - }, this); - return this.base(from, to); - }, - - update: function(val) { - Base.each(val, function(val, key) { - this.element.setStyle(key, Fx.CSS.get(val, this.options.unit)); - }, this); - } - -}); - -HtmlElement.inject({ - effects: function(opts) { - return new Fx.Styles(this, opts); - } -}); - -Fx.Elements = Fx.extend({ - initialize: function(elements, options) { - this.base(null, options); - this.elements = DomElement.getAll(elements); - }, - - start: function(obj) { - if (this.timer && this.options.wait) return this; - this.effects = {}; - - function start(that, key, val) { - var fx = that.effects[key] = new Fx.Styles(that.elements[key], that.options); - fx.slave = true; - fx.start(val); - } - - Base.each(obj, function(val, key) { - if (key == '*') { - this.elements.each(function(el, key) { - start(this, key, val); - }, this); - } else if (isNaN(parseInt(key))) { - var els = DomElement.getAll(key); - this.elements.append(els); - els.each(function(el) { - start(this, this.elements.indexOf(el), val); - }, this); - } else { - start(this, key, val); - } - }, this); - return this.base(); - }, - - set: function(to) { - }, - - update: function(to) { - Base.each(this.effects, function(fx) { - fx.step(); - }); - } -}); - -Fx.Transitions = new Base().inject({ - inject: function(src) { - return this.base(Base.each(src, function(func, name) { - func.In = func; - - func.Out = function(pos) { - return 1 - func(1 - pos); - } - - func.InOut = function(pos) { - return pos <= 0.5 ? func(2 * pos) / 2 : (2 - func(2 * (1 - pos))) / 2; - } - })); - }, - - Linear: function(p) { - return p; - } -}); - -Fx.Transitions.inject({ - Pow: function(p, x) { - return Math.pow(p, x[0] || 6); - }, - - Expo: function(p) { - return Math.pow(2, 8 * (p - 1)); - }, - - Circ: function(p) { - return 1 - Math.sin(Math.acos(p)); - }, - - Sine: function(p) { - return 1 - Math.sin((1 - p) * Math.PI / 2); - }, - - Back: function(p, x) { - x = x[0] || 1.618; - return Math.pow(p, 2) * ((x + 1) * p - x); - }, - - Bounce: function(p) { - var value; - for (var a = 0, b = 1; 1; a += b, b /= 2) { - if (p >= (7 - 4 * a) / 11) { - value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b; - break; - } - } - return value; - }, - - Elastic: function(p, x) { - return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); - } - -}); - -Fx.Transitions.inject(['Quad', 'Cubic', 'Quart', 'Quint'].each(function(name, i) { - this[name] = function(p) { - return Math.pow(p, i + 2); - } -}, {})); - diff --git a/dist/docs/resources/js/codemirror.js b/dist/docs/resources/js/codemirror.js deleted file mode 100644 index 0c1c6427..00000000 --- a/dist/docs/resources/js/codemirror.js +++ /dev/null @@ -1 +0,0 @@ -var CodeMirror=function(){function O(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c=0&&d>=0;--c,--d)if(a.charAt(c)!=b.charAt(d))break;return d+1}function M(a){L.innerText=L.textContent=a;return L.innerHTML}function K(a){return{line:a.line,ch:a.ch}}function J(a,b){return a.linea&&d.push(h.slice(a-f,Math.min(h.length,b-f)),c[e+1]),i>=a&&(g=1)):g==1&&(i>b?d.push(h.slice(0,b-f),c[e+1]):d.push(h,c[e+1])),f=i}}function h(a,b){this.styles=b||[a,null],this.stateAfter=null,this.text=a,this.marked=this.gutterMarker=this.className=null}function g(a){this.pos=this.start=0,this.string=a}function f(a,b,c){return a.startState?a.startState(b,c):!0}function e(a,b){if(b===!0)return b;if(a.copyState)return a.copyState(b);var c={};for(var d in b){var e=b[d];e instanceof Array&&(e=e.concat([])),c[d]=e}return c}function a(b,c){function cV(a,b,c){this.atOccurrence=!1,c==null&&(c=typeof a=="string"&&a==a.toLowerCase()),b&&typeof b=="object"?b=cj(b):b={line:0,ch:0},this.pos={from:b,to:b};if(typeof a!="string")this.matches=function(b,c){if(b){var d=ba[c.line].text.slice(0,c.ch),e=d.match(a),f=0;while(e){var g=d.indexOf(e[0]);f+=g,d=d.slice(g+1);var h=d.match(a);if(h)e=h;else break;f++}}else var d=ba[c.line].text.slice(c.ch),e=d.match(a),f=e&&c.ch+d.indexOf(e[0]);if(e)return{from:{line:c.line,ch:f},to:{line:c.line,ch:f+e[0].length},match:e}};else{c&&(a=a.toLowerCase());var d=c?function(a){return a.toLowerCase()}:function(a){return a},e=a.split("\n");e.length==1?this.matches=function(b,c){var e=d(ba[c.line].text),f=a.length,g;if(b?c.ch>=f&&(g=e.lastIndexOf(a,c.ch-f))!=-1:(g=e.indexOf(a,c.ch))!=-1)return{from:{line:c.line,ch:g},to:{line:c.line,ch:g+f}}}:this.matches=function(a,b){var c=b.line,f=a?e.length-1:0,g=e[f],h=d(ba[c].text),i=a?h.indexOf(g)+g.length:h.lastIndexOf(g);if(!(a?i>=b.ch||i!=g.length:i<=b.ch||i!=h.length-g.length))for(;;){if(a?!c:c==ba.length-1)return;h=d(ba[c+=a?-1:1].text),g=e[a?--f:++f];if(f>0&&f=ba.length)continue;var d=cM(c),h=d&&ba[d-1].stateAfter;h?h=e(_,h):h=f(_);var i=0,j=_.compareStates;for(var k=d,l=ba.length;ka){bb.push(k),cQ(g.workDelay),bj.push({from:c,to:k+1});return}var o=m.highlight(_,h);m.stateAfter=e(_,h);if(j){if(n&&j(n,h))break}else if(o||!n)i=0;else if(++i>3)break}bj.push({from:c,to:k+1})}b&&g.onHighlightComplete&&g.onHighlightComplete(by)}function cO(a,b){var c=cN(a);for(var d=a;de;--d){if(d==0)return 0;var f=ba[d-1];if(f.stateAfter)return d;var g=f.indentation();if(c==null||b>g)c=d,b=g}return c}function cL(a){function p(a,b,c){if(!!a.text){var d=a.styles,e=g?0:a.text.length-1,f;for(var i=g?0:d.length-2,j=g?d.length:-2;i!=j;i+=2*h){var k=d[i];if(d[i+1]!=null&&d[i+1]!=m){e+=h*k.length;continue}for(var l=g?0:k.length-1,p=g?k.length:-1;l!=p;l+=h,e+=h)if(e>=b&&e"==g)n.push(f);else{if(n.pop()!=q.charAt(0))return{pos:e,match:!1};if(!n.length)return{pos:e,match:!0}}}}}}var b=be.inverted?be.from:be.to,c=ba[b.line],d=b.ch-1,e=d>=0&&cK[c.text.charAt(d)]||cK[c.text.charAt(++d)];if(!!e){var f=e.charAt(0),g=e.charAt(1)==">",h=g?1:-1,i=c.styles;for(var j=d+1,k=0,l=i.length;kF.clientWidth||e-c.top>F.clientHeight))return null;var f=G(V,!0),g=bn+Math.floor((e-f.top)/cE());return cj({line:g,ch:cB(ci(g),d-f.left)})}function cG(){return V.offsetLeft}function cF(){return V.offsetTop}function cE(){var a=X.childNodes.length;if(a)return X.offsetHeight/a||1;M.innerHTML="
x
";return M.firstChild.offsetHeight||1}function cD(a){var b=cC(a,!0),c=G(V);return{x:c.left+b.x,y:c.top+b.y,yBot:c.top+b.yBot}}function cC(a,b){var c=cE(),d=a.line-(b?bn:0);return{x:cA(a.line,a.ch),y:d*c,yBot:(d+1)*c}}function cB(a,b){function e(a){M.innerHTML="
"+c.getHTML(null,null,!1,a)+"
";return M.firstChild.firstChild.offsetWidth}if(b<=0)return 0;var c=ba[a],d=c.text,f=0,g=0,h=d.length,i,j=Math.min(h,Math.ceil(b/cz("x")));for(;;){var k=e(j);if(k<=b&&ji)return h;j=Math.floor(h*.8),k=e(j),kb-g?f:h;var l=Math.ceil((f+h)/2),m=e(l);m>b?(h=l,i=m):(f=l,g=m)}}function cA(a,b){if(b==0)return 0;M.innerHTML="
"+ba[a].getHTML(null,null,!1,b)+"
";return M.firstChild.firstChild.offsetWidth}function cz(a){M.innerHTML="
x
",M.firstChild.firstChild.firstChild.nodeValue=a;return M.firstChild.firstChild.offsetWidth||10}function cy(a){if(typeof a=="number"){var b=a;a=ba[a];if(!a)return null}else{var b=O(ba,a);if(b==-1)return null}var c=a.gutterMarker;return{line:b,text:a.text,markerText:c&&c.text,markerClass:c&&c.style}}function cx(a,b){if(typeof a=="number"){var c=a;a=ba[ci(a)]}else{var c=O(ba,a);if(c==-1)return null}a.className!=b&&(a.className=b,bj.push({from:c,to:c+1}));return a}function cw(a){typeof a=="number"&&(a=ba[ci(a)]),a.gutterMarker=null,cd()}function cv(a,b,c){typeof a=="number"&&(a=ba[ci(a)]),a.gutterMarker={text:b,style:c},cd();return a}function cu(a,b,c){function e(a,b,c,e){var a=ba[a],f=a.addMark(b,c,e);f.line=a,d.push(f)}a=cj(a),b=cj(b);var d=[];if(a.line==b.line)e(a.line,a.ch,b.ch,c);else{e(a.line,a.ch,null,c);for(var f=a.line+1,g=b.line;f-1&&(a==null&&(a=f),b=f)}a!=null&&bj.push({from:a,to:b+1})}}function ct(){var a=g.gutter||g.lineNumbers;T.style.display=a?"":"none",a?cd():X.parentNode.style.marginLeft=0}function cs(){_=a.getMode(g,g.mode);for(var b=0,c=ba.length;b0&&/\w/.test(b.charAt(c-1)))--c;while(d=ba.length)return{line:ba.length-1,ch:ba[ba.length-1].text.length};var b=a.ch,c=ba[a.line].text.length;return b==null||b>c?{line:a.line,ch:c}:b<0?{line:a.line,ch:0}:a}function ci(a){return Math.max(0,Math.min(a,ba.length-1))}function ch(a,b,c){var d=cj({line:a,ch:b||0});(c?cf:cg)(d,d)}function cg(a,b,c,d){if(!I(be.from,a)||!I(be.to,b)){if(J(b,a)){var e=b;b=a,a=e}I(a,b)?be.inverted=!1:I(a,be.to)?be.inverted=!1:I(b,be.from)&&(be.inverted=!0),c==null&&(c=be.from.line,d=be.to.line),I(a,b)?I(be.from,be.to)||bj.push({from:c,to:d+1}):I(be.from,be.to)?bj.push({from:a.line,to:b.line+1}):(I(a,be.from)||(a.line':"
",f,"
")}T.style.display="none",U.innerHTML=c.join("");var h=String(ba.length).length,i=U.firstChild,j=H(i),k="";while(j.length+k.length0;--k)X.removeChild(j?j.previousSibling:X.lastChild);else if(i){for(var k=Math.max(0,i);k>0;--k)X.insertBefore(n.createElement("pre"),j);for(var k=Math.max(0,-i);k>0;--k)X.removeChild(j?j.previousSibling:X.lastChild)}var l=X.childNodes[h.domStart+d],m=b=h.from;for(var k=h.from;kj.from&&f.push({from:j.from,to:e.from,domStart:j.domStart}),e.to=m)break;if(j.domStart>o||j.from>q)n.push({from:q,to:j.from,domSize:j.domStart-o,domStart:o}),r+=j.from-q;q=j.to,o=j.domStart+(j.to-j.from)}if(o!=p||q!=m)r+=Math.abs(m-q),n.push({from:q,to:m,domSize:p-o,domStart:o});if(!n.length)return;X.style.display="none",r>(k.to-k.from)*.3?cb(l=Math.max(k.from-10,0),m=Math.min(k.to+7,ba.length)):cc(n),X.style.display="";var s=l!=bn||m!=bo||bp!=F.clientHeight;bn=l,bo=m,S.style.top=l*cE()+"px",s&&(bp=F.clientHeight,L.style.height=ba.length*cE()+2*cF()+"px",cd()),bu==null&&(bu=cz(bt)),bu>F.clientWidth?(V.style.width=bu+"px",L.style.width="",L.style.width=F.scrollWidth+"px"):V.style.width=L.style.width="";if(X.childNodes.length!=bo-bn)throw new Error("BAD PATCH! "+JSON.stringify(n)+" size="+(bo-bn)+" nodes="+X.childNodes.length);ce()}}function b_(){var a=cE(),b=F.scrollTop-cF();return{from:Math.min(ba.length,Math.max(0,Math.floor(b/a))),to:Math.min(ba.length,Math.ceil((b+F.clientHeight)/a))}}function b$(a,b,c,d){var e=cG(),f=cF(),h=cE();b+=f,d+=f,a+=e,c+=e;var i=F.clientHeight,j=F.scrollTop,k=!1,l=!0;bj+i&&(F.scrollTop=d+h-i,k=!0);var m=F.clientWidth,n=F.scrollLeft;am+n&&(F.scrollLeft=c+10-m,k=!0,c>L.clientWidth&&(l=!1)),k&&g.onScroll&&g.onScroll(by);return l}function bZ(){var a=cC(be.inverted?be.from:be.to);return b$(a.x,a.y,a.x,a.yBot)}function bY(){g.readOnly!="nocursor"&&E.focus()}function bX(){var a=[],b=Math.max(0,be.from.line-1),c=Math.min(ba.length,be.to.line+2);for(var d=b;d=a)return{line:c,ch:a-d};++c,d=e+1}}if(!bm&&!!bd){var a=!1,b=E.value,c=Q(E);if(!c)return!1;var a=br.text!=b,d=bg,e=a||c.start!=br.start||c.end!=(d?br.start:br.end);if(!e&&!d)return!1;if(a){bf=bg=null;if(g.readOnly){bi=!0;return"changed"}}var h=f(c.start,br.from),i=f(c.end,br.from);if(d){var j=c.start==d.anchor?i:h,k=bf?be.to:c.start==d.anchor?h:i;(be.inverted=J(j,k))?(h=j,i=k):(bg=null,h=k,i=j)}h.line==i.line&&h.line==be.from.line&&h.line==be.to.line&&!bf&&(bi=!1);if(a){var l=0,m=b.length,n=Math.min(m,br.text.length),o,p=br.from,q=-1;while(l-1?l-q:l,s=br.to-1,t=br.text.length;for(;;){o=br.text.charAt(t);if(b.charAt(m)!=o){++m,++t;break}o=="\n"&&s--;if(t<=l||m<=l)break;--m,--t}var q=br.text.lastIndexOf("\n",t-1),u=q==-1?t:t-q-1;bJ({line:p,ch:r},{line:s,ch:u},P(b.slice(l,m)),h,i);if(p!=s||h.line!=p)bi=!0}else cg(h,i);br.text=b,br.start=c.start,br.end=c.end;return a?"changed":e?"moved":!1}}function bV(a){function c(){cR();var d=bW();d=="moved"&&a&&(C[a]=!0),!d&&!b?(b=!0,Y.set(80,c)):(bT=!1,bU()),cS()}var b=!1;bT=!0,Y.set(20,c)}function bU(){bT||Y.set(2e3,function(){cR(),bW(),bd&&bU(),cS()})}function bS(){return bR(be.from,be.to)}function bR(a,b){var c=a.line,d=b.line;if(c==d)return ba[c].text.slice(a.ch,b.ch);var e=[ba[c].text.slice(a.ch)];for(var f=c+1;fg&&(bt=o,g=o.length,bu=null,f=!1)}if(f){g=0,bt="",bu=null;for(var i=0,n=ba.length;ig&&(g=o.length,bt=o)}}var p=[],q=c.length-j-1;for(var i=0,o=bb.length;ib.line&&p.push(r+q)}c.length<5?(cO(a.line,a.line+c.length),p.push(a.line+c.length)):p.push(a.line),bb=p,cQ(100),bj.push({from:a.line,to:b.line+1,diff:q}),bk={from:a,to:b,text:c},cg(d,e,s(be.from.line),s(be.to.line)),L.style.height=ba.length*cE()+2*cF()+"px"}function bM(){bK(bc.undone,bc.done)}function bL(){bK(bc.done,bc.undone)}function bK(a,b){var c=a.pop();if(c){var d=[],e=c.start+c.added;for(var f=c.start;fg.undoDepth)bc.done.shift()}bN(a,b,c,d,e)}function bI(){bd&&(g.onBlur&&g.onBlur(by),bd=!1,y.className=y.className.replace(" CodeMirror-focused","")),clearInterval($),setTimeout(function(){bd||(bf=null)},150)}function bH(){g.readOnly!="nocursor"&&(bd||(g.onFocus&&g.onFocus(by),bd=!0,y.className.search(/\bCodeMirror-focused\b/)==-1&&(y.className+=" CodeMirror-focused"),bm||bX()),bU(),cJ())}function bG(a){if(!g.onKeyEvent||!g.onKeyEvent(by,l(a))){if(g.electricChars&&_.electricChars){var b=String.fromCharCode(a.charCode==null?a.keyCode:a.charCode);_.electricChars.indexOf(b)>-1&&setTimeout(cU(function(){cr(be.to.line,"smart")}),50)}var c=a.keyCode;c==13?(g.readOnly||cp(),m(a)):!a.ctrlKey&&!a.altKey&&!a.metaKey&&c==9&&g.tabMode!="default"?m(a):bV(bq)}}function bF(a){if(!g.onKeyEvent||!g.onKeyEvent(by,l(a)))bg&&(bg=null,bi=!0),a.keyCode==16&&(bf=null)}function bE(a){bd||bH();var b=a.keyCode;x&&b==27&&(a.returnValue=!1);var c=(B?a.metaKey:a.ctrlKey)&&!a.altKey,d=a.ctrlKey||a.altKey||a.metaKey;b==16||a.shiftKey?bf=bf||(be.inverted?be.to:be.from):bf=null;if(!g.onKeyEvent||!g.onKeyEvent(by,l(a))){if(b==33||b==34){ck(b==34);return m(a)}if(c&&(b==36||b==35||B&&(b==38||b==40))){cl(b==36||b==38);return m(a)}if(c&&b==65){cm();return m(a)}if(!g.readOnly){if(!d&&b==13)return;if(!d&&b==9&&cq(a.shiftKey))return m(a);if(c&&b==90){bL();return m(a)}if(c&&(a.shiftKey&&b==90||b==89)){bM();return m(a)}}bq=(c?"c":"")+b;if(be.inverted&&C.hasOwnProperty(bq)){var e=Q(E);e&&(bg={anchor:e.start},R(E,e.start,e.start))}bV(bq)}}function bD(a){a.preventDefault();var b=cH(a,!0),c=a.dataTransfer.files;if(!!b&&!g.readOnly)if(c&&c.length&&window.FileReader&&window.File){function d(a,c){var d=new FileReader;d.onload=function(){f[c]=d.result,++h==e&&bO(f.join(""),cj(b),cj(b))},d.readAsText(a)}var e=c.length,f=Array(e),h=0;for(var i=0;i=c.to||b.line=0&&a
'+'
'+'
'+'
'+'
'+'
'+'
 
'+"
"+"
",b.appendChild?b.appendChild(y):b(y);var D=y.firstChild,E=D.firstChild,F=y.lastChild,L=F.firstChild,M=L.firstChild,S=M.nextSibling,T=S.firstChild,U=T.firstChild,V=T.nextSibling.firstChild,W=V.firstChild,X=W.nextSibling;g.tabindex!=null&&(E.tabindex=g.tabindex),!g.gutter&&!g.lineNumbers&&(T.style.display="none");var Y=new u,Z=new u,$,_,ba=[new h("")],bb,bc=new j,bd;cs();var be={from:{line:0,ch:0},to:{line:0,ch:0},inverted:!1},bf,bg,bh,bi,bj,bk,bl,bm,bn=0,bo=0,bp=0,bq=null,br,bs,bt="",bu;cU(function(){bz(g.value||""),bi=!1})(),t(F,"mousedown",cU(bB)),w||t(F,"contextmenu",cI),t(L,"dblclick",cU(bC)),t(F,"scroll",function(){ca([]),g.onScroll&&g.onScroll(by)}),t(window,"resize",function(){ca(!0)}),t(E,"keyup",cU(bF)),t(E,"keydown",cU(bE)),t(E,"keypress",cU(bG)),t(E,"focus",bH),t(E,"blur",bI),t(F,"dragenter",o),t(F,"dragover",o),t(F,"drop",cU(bD)),t(F,"paste",function(){bY(),bV()}),t(E,"paste",function(){bV()}),t(E,"cut",function(){bV()});var bv;try{bv=n.activeElement==E}catch(bw){}bv?setTimeout(bH,20):bI();var by={getValue:bA,setValue:cU(bz),getSelection:bS,replaceSelection:cU(bP),focus:function(){bY(),bH(),bV()},setOption:function(a,b){g[a]=b,a=="lineNumbers"||a=="gutter"?ct():a=="mode"||a=="indentUnit"?cs():a=="readOnly"&&b=="nocursor"?E.blur():a=="theme"&&(F.className=F.className.replace(/cm-s-\w+/,"cm-s-"+b))},getOption:function(a){return g[a]},undo:cU(bL),redo:cU(bM),indentLine:cU(function(a,b){bx(a)&&cr(a,b==null?"smart":b?"add":"subtract")}),historySize:function(){return{undo:bc.done.length,redo:bc.undone.length}},matchBrackets:cU(function(){cL(!0)}),getTokenAt:function(a){a=cj(a);return ba[a.line].getTokenAt(_,cN(a.line),a.ch)},getStateAfter:function(a){a=ci(a==null?ba.length-1:a);return cN(a+1)},cursorCoords:function(a){a==null&&(a=be.inverted);return cD(a?be.from:be.to)},charCoords:function(a){return cD(cj(a))},coordsChar:function(a){var b=G(V),c=ci(Math.min(ba.length-1,bn+Math.floor((a.y-b.top)/cE())));return cj({line:c,ch:cB(ci(c),a.x-b.left)})},getSearchCursor:function(a,b,c){return new cV(a,b,c)},markText:cU(function(a,b,c){return cU(cu(a,b,c))}),setMarker:cv,clearMarker:cw,setLineClass:cU(cx),lineInfo:cy,addWidget:function(a,b,c,d){a=cC(cj(a));var e=a.yBot,f=a.x;b.style.position="absolute",L.appendChild(b),b.style.left=f+"px";if(d=="over")e=a.y;else if(d=="near"){var g=Math.max(F.offsetHeight,ba.length*cE()),h=Math.max(L.clientWidth,V.clientWidth)-cG();a.yBot+b.offsetHeight>g&&a.y>b.offsetHeight&&(e=a.y-b.offsetHeight),f+b.offsetWidth>h&&(f=h-b.offsetWidth)}b.style.top=e+cF()+"px",b.style.left=f+cG()+"px",c&&b$(f,e,f+b.offsetWidth,e+b.offsetHeight)},lineCount:function(){return ba.length},getCursor:function(a){a==null&&(a=be.inverted);return K(a?be.from:be.to)},somethingSelected:function(){return!I(be.from,be.to)},setCursor:cU(function(a,b){b==null&&typeof a.line=="number"?ch(a.line,a.ch):ch(a,b)}),setSelection:cU(function(a,b){cg(cj(a),cj(b||a))}),getLine:function(a){if(bx(a))return ba[a].text},setLine:cU(function(a,b){bx(a)&&bO(b,{line:a,ch:0},{line:a,ch:ba[a].text.length})}),removeLine:cU(function(a){bx(a)&&bO("",{line:a,ch:0},cj({line:a+1,ch:0}))}),replaceRange:cU(bO),getRange:function(a,b){return bR(cj(a),cj(b))},operation:function(a){return cU(a)()},refresh:function(){ca(!0)},getInputField:function(){return E},getWrapperElement:function(){return y},getScrollerElement:function(){return F},getGutterElement:function(){return T}},bT=!1,cK={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},cT=0;cV.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(a){function d(a){var c={line:a,ch:0};b.pos={from:c,to:c},b.atOccurrence=!1;return!1}var b=this,c=cj(a?this.pos.from:this.pos.to);for(;;){if(this.pos=this.matches(a,c)){this.atOccurrence=!0;return this.pos.match||!0}if(a){if(!c.line)return d(0);c={line:c.line-1,ch:ba[c.line-1].text.length}}else{if(c.line==ba.length-1)return d(ba.length);c={line:c.line+1,ch:0}}}},from:function(){if(this.atOccurrence)return K(this.pos.from)},to:function(){if(this.atOccurrence)return K(this.pos.to)},replace:function(a){var b=this;this.atOccurrence&&cU(function(){b.pos.to=bO(a,b.pos.from,b.pos.to)})()}};for(var cW in d)d.propertyIsEnumerable(cW)&&!by.propertyIsEnumerable(cW)&&(by[cW]=d[cW]);return by}a.defaults={value:"",mode:null,theme:"default",indentUnit:2,indentWithTabs:!1,tabMode:"classic",enterMode:"indent",electricChars:!0,onKeyEvent:null,lineNumbers:!1,gutter:!1,firstLineNumber:1,readOnly:!1,onChange:null,onCursorActivity:null,onGutterClick:null,onHighlightComplete:null,onFocus:null,onBlur:null,onScroll:null,matchBrackets:!1,workTime:100,workDelay:200,undoDepth:40,tabindex:null,document:window.document};var b={},c={};a.defineMode=function(c,d){!a.defaults.mode&&c!="null"&&(a.defaults.mode=c),b[c]=d},a.defineMIME=function(a,b){c[a]=b},a.getMode=function(d,e){typeof e=="string"&&c.hasOwnProperty(e)&&(e=c[e]);if(typeof e=="string")var f=e,g={};else if(e!=null)var f=e.name,g=e;var h=b[f];if(!h){window.console&&console.warn("No mode "+f+" found, falling back to plain text.");return a.getMode(d,"text/plain")}return h(d,g||{})},a.listModes=function(){var a=[];for(var c in b)b.propertyIsEnumerable(c)&&a.push(c);return a},a.listMIMEs=function(){var a=[];for(var b in c)c.propertyIsEnumerable(b)&&a.push(b);return a};var d={};a.defineExtension=function(a,b){d[a]=b},a.fromTextArea=function(b,c){function d(){b.value=h.getValue()}c||(c={}),c.value=b.value,!c.tabindex&&b.tabindex&&(c.tabindex=b.tabindex);if(b.form){var e=t(b.form,"submit",d,!0);if(typeof b.form.submit=="function"){var f=b.form.submit;function g(){d(),b.form.submit=f,b.form.submit(),b.form.submit=g}b.form.submit=g}}b.style.display="none";var h=a(function(a){b.parentNode.insertBefore(a,b.nextSibling)},c);h.save=d,h.toTextArea=function(){d(),b.parentNode.removeChild(h.getWrapperElement()),b.style.display="",b.form&&(e(),typeof b.form.submit=="function"&&(b.form.submit=f))};return h},a.startState=f,a.copyState=e,g.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)},next:function(){if(this.posb},eatSpace:function(){var a=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);if(b>-1){this.pos=b;return!0}},backUp:function(a){this.pos-=a},column:function(){return E(this.string,this.start)},indentation:function(){return E(this.string)},match:function(a,b,c){if(typeof a!="string"){var e=this.string.slice(this.pos).match(a);e&&b!==!1&&(this.pos+=e[0].length);return e}function d(a){return c?a.toLowerCase():a}if(d(this.string).indexOf(d(a),this.pos)==this.pos){b!==!1&&(this.pos+=a.length);return!0}},current:function(){return this.string.slice(this.start,this.pos)}},a.StringStream=g,h.prototype={replace:function(a,b,c){var d=[],e=this.marked;i(0,a,this.styles,d),c&&d.push(c,null),i(b,this.text.length,this.styles,d),this.styles=d,this.text=this.text.slice(0,a)+c+this.text.slice(b),this.stateAfter=null;if(e){var f=c.length-(b-a),g=this.text.length;function h(a){return a<=Math.min(b,b+f)?a:a+f}for(var j=0;j=g?l=!0:(k.from=h(k.from),k.to!=null&&(k.to=h(k.to)));if(l||k.from>=k.to)e.splice(j,1),j--}}},split:function(a,b){var c=[b,null];i(a,this.text.length,this.styles,c);return new h(b+this.text.slice(a),c)},addMark:function(a,b,c){var d=this.marked,e={from:a,to:b,style:c};this.marked==null&&(this.marked=[]),this.marked.push(e),this.marked.sort(function(a,b){return a.from-b.from});return e},removeMark:function(a){var b=this.marked;if(!!b)for(var c=0;c5e3){d[e++]=this.text.slice(c.pos),d[e++]=null;break}}d.length!=e&&(d.length=e,f=!0),e&&d[e-2]!=i&&(f=!0);return f||d.length<5&&this.text.length<10},getTokenAt:function(a,b,c){var d=this.text,e=new g(d);while(e.pos',M(a),""):e.push(M(a)))}var e=[];c&&e.push(this.className?'
':"
");var g=this.styles,h=this.text,i=this.marked;a==b&&(a=null);var j=h.length;d!=null&&(j=Math.min(d,j));if(!h&&d==null)f(" ",a!=null&&b==null?"CodeMirror-selected":null);else if(!i&&a==null)for(var k=0,l=0;lj&&(m=m.slice(0,j-l)),l+=n,f(m,"cm-"+g[k+1])}else{var o=0,k=0,p="",q,r=0,s=-1,t=null;function u(){i&&(s+=1,t=so)v=a;else if(b==null||b>o)w=" CodeMirror-selected",b!=null&&(v=Math.min(v,b));while(t&&t.to!=null&&t.to<=o)u();t&&(t.from>o?v=Math.min(v,t.from):(w+=" "+t.style,t.to!=null&&(v=Math.min(v,t.to))));for(;;){var x=o+p.length,y=q;w&&(y=q?q+w:w),f(x>v?p.slice(0,v-o):p,y);if(x>=v){p=p.slice(v-o),o=v;break}o=x,p=g[k++],q="cm-"+g[k++]}}a!=null&&b==null&&f(" ","CodeMirror-selected")}c&&e.push("
");return e.join("")}},j.prototype={addChange:function(a,b,c){this.undone.length=0;var d=+(new Date),e=this.done[this.done.length-1];if(d-this.time>400||!e||e.start>a+b||e.start+e.added=0;--g)e.old.unshift(c[g]);e.added+=e.start-a,e.start=a}else e.start-1&&(z="\r\n")})();var A=8,B=/Mac/.test(navigator.platform),C={};for(var D=35;D<=40;++D)C[D]=C["c"+D]=!0;var L=document.createElement("div");a.htmlEscape=M;var P,Q,R;"\n\nb".split(/\n/).length!=3?P=function(a){var b=0,c,d=[];while((c=a.indexOf("\n",b))>-1)d.push(a.slice(b,a.charAt(c-1)=="\r"?c-1:c)),b=c+1;d.push(a.slice(b));return d}:P=function(a){return a.split(/\r?\n/)},a.splitLines=P,window.getSelection?(Q=function(a){try{return{start:a.selectionStart,end:a.selectionEnd}}catch(b){return null}},y?R=function(a,b,c){b==c?a.setSelectionRange(b,c):(a.setSelectionRange(b,c-1),window.getSelection().modify("extend","forward","character"))}:R=function(a,b,c){try{a.setSelectionRange(b,c)}catch(d){}}):(Q=function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){return null}if(!b||b.parentElement()!=a)return null;var d=a.value,e=d.length,f=a.createTextRange();f.moveToBookmark(b.getBookmark());var g=a.createTextRange();g.collapse(!1);if(f.compareEndPoints("StartToEnd",g)>-1)return{start:e,end:e};var h=-f.moveStart("character",-e);for(var i=d.indexOf("\r");i>-1&&i-1)return{start:h,end:e};var j=-f.moveEnd("character",-e);for(var i=d.indexOf("\r");i>-1&&i-1&&h-1&&h=0;a--)s.cc.push(arguments[a])}function r(a,b,c,e,f){var g=a.cc;s.state=a,s.stream=f,s.marked=null,s.cc=g,a.lexical.hasOwnProperty("align")||(a.lexical.align=!0);for(;;){var h=g.length?g.pop():d?D:C;if(h(c,e)){while(g.length&&g[g.length-1].lex)g.pop()();if(s.marked)return s.marked;if(c=="variable"&&q(a,e))return"variable-2";return b}}}function q(a,b){for(var c=a.localVars;c;c=c.next)if(c.name==b)return!0}function p(a,b,c,d,e,f){this.indented=a,this.column=b,this.type=c,this.prev=e,this.info=f,d!=null&&(this.align=d)}function n(a,b){var c=!1,d;while(d=a.next()){if(d=="/"&&c){b.tokenize=l;break}c=d=="*"}return k("comment","comment")}function m(a){return function(b,c){h(b,a)||(c.tokenize=l);return k("string","string")}}function l(a,b){var c=a.next();if(c=='"'||c=="'")return g(a,b,m(c));if(/[\[\]{}\(\),;\:\.]/.test(c))return k(c);if(c=="0"&&a.eat(/x/i)){a.eatWhile(/[\da-f]/i);return k("number","number")}if(/\d/.test(c)){a.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);return k("number","number")}if(c=="/"){if(a.eat("*"))return g(a,b,n);if(a.eat("/")){a.skipToEnd();return k("comment","comment")}if(b.reAllowed){h(a,"/"),a.eatWhile(/[gimy]/);return k("regexp","string")}a.eatWhile(f);return k("operator",null,a.current())}if(f.test(c)){a.eatWhile(f);return k("operator",null,a.current())}a.eatWhile(/[\w\$_]/);var d=a.current(),i=e.propertyIsEnumerable(d)&&e[d];return i?k(i.type,i.style,d):k("variable","variable",d)}function k(a,b,c){i=a,j=c;return b}function h(a,b){var c=!1,d;while((d=a.next())!=null){if(d==b&&!c)return!1;c=!c&&d=="\\"}return c}function g(a,b,c){b.tokenize=c;return c(a,b)}var c=a.indentUnit,d=b.json,e=function(){function a(a){return{type:a,style:"keyword"}}var b=a("keyword a"),c=a("keyword b"),d=a("keyword c"),e=a("operator"),f={type:"atom",style:"atom"};return{"if":b,"while":b,"with":b,"else":c,"do":c,"try":c,"finally":c,"return":d,"break":d,"continue":d,"new":d,"delete":d,"throw":d,"var":a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),"case":a("case"),"default":a("default"),"in":e,"typeof":e,"instanceof":e,"true":f,"false":f,"null":f,"undefined":f,NaN:f,Infinity:f}}(),f=/[+\-*&%=<>!?|]/,i,j,o={atom:!0,number:!0,variable:!0,string:!0,regexp:!0},s={state:null,column:null,marked:null,cc:null},w={name:"this",next:{name:"arguments"}};A.lex=!0;return{startState:function(a){return{tokenize:l,reAllowed:!0,cc:[],lexical:new p((a||0)-c,0,"block",!1),localVars:null,context:null,indented:0}},token:function(a,b){a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation());if(a.eatSpace())return null;var c=b.tokenize(a,b);if(i=="comment")return c;b.reAllowed=i=="operator"||i=="keyword c"||i.match(/^[\[{}\(,;:]$/);return r(b,c,i,j,a)},indent:function(a,b){if(a.tokenize!=l)return 0;var d=b&&b.charAt(0),e=a.lexical,f=e.type,g=d==f;return f=="vardef"?e.indented+4:f=="form"&&d=="{"?e.indented:f=="stat"||f=="form"?e.indented+c:e.info=="switch"&&!g?e.indented+(/^(?:case|default)\b/.test(b)?c:2*c):e.align?e.column+(g?0:1):e.indented+(g?0:c)},electricChars:":{}"}}),CodeMirror.defineMIME("text/javascript","javascript"),CodeMirror.defineMIME("application/json",{name:"javascript",json:!0}),CodeMirror.defineMode("xml",function(a,b){function w(a){return a=="string"?o(w):n()}function v(a){if(a=="word"&&d.allowUnquoted){m="string";return o()}if(a=="string")return o(w);return n()}function u(a){if(a=="word"){m="attribute";return o(u)}if(a=="equals")return o(v,u);return n()}function t(a){return function(b){a&&(m="error");if(b=="endTag")return o();return n()}}function s(a){return function(b){if(b=="selfcloseTag"||b=="endTag"&&d.autoSelfClosers.hasOwnProperty(l.tagName.toLowerCase()))return o();if(b=="endTag"){p(l.tagName,a);return o()}return o()}}function r(a){if(a=="openTag"){l.tagName=f;return o(u,s(l.startOfLine))}if(a=="closeTag"){var b=!1;l.context?(b=l.context.tagName!=f,q()):b=!0,b&&(m="error");return o(t(b))}if(a=="string"){(!l.context||l.context.name!="!cdata")&&p("!cdata"),l.tokenize==h&&q();return o()}return o()}function q(){l.context&&(l.context=l.context.prev)}function p(a,b){var c=d.doNotIndent.hasOwnProperty(a)||l.context&&l.context.noIndent;l.context={prev:l.context,tagName:a,indent:l.indented,startOfLine:b,noIndent:c}}function o(){n.apply(null,arguments);return!0}function n(){for(var a=arguments.length-1;a>=0;a--)l.cc.push(arguments[a])}function k(a,b){return function(c,d){while(!c.eol()){if(c.match(b)){d.tokenize=h;break}c.next()}return a}}function j(a){return function(b,c){while(!b.eol())if(b.next()==a){c.tokenize=i;break}return"string"}}function i(a,b){var c=a.next();if(c==">"||c=="/"&&a.eat(">")){b.tokenize=h,g=c==">"?"endTag":"selfcloseTag";return"tag"}if(c=="="){g="equals";return null}if(/[\'\"]/.test(c)){b.tokenize=j(c);return b.tokenize(a,b)}a.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);return"word"}function h(a,b){function c(c){b.tokenize=c;return c(a,b)}var d=a.next();if(d=="<"){if(a.eat("!")){if(a.eat("["))return a.match("CDATA[")?c(k("atom","]]>")):null;if(a.match("--"))return c(k("comment","-->"));if(a.match("DOCTYPE",!0,!0)){a.eatWhile(/[\w\._\-]/);return c(k("meta",">"))}return null}if(a.eat("?")){a.eatWhile(/[\w\._\-]/),b.tokenize=k("meta","?>");return"meta"}g=a.eat("/")?"closeTag":"openTag",a.eatSpace(),f="";var e;while(e=a.eat(/[^\s\u00a0=<>\"\'\/?]/))f+=e;b.tokenize=i;return"tag"}if(d=="&"){a.eatWhile(/[^;]/),a.eat(";");return"atom"}a.eatWhile(/[^&<]/);return null}var c=a.indentUnit,d=b.htmlMode?{autoSelfClosers:{br:!0,img:!0,hr:!0,link:!0,input:!0,meta:!0,col:!0,frame:!0,base:!0,area:!0},doNotIndent:{pre:!0,"!cdata":!0},allowUnquoted:!0}:{autoSelfClosers:{},doNotIndent:{"!cdata":!0},allowUnquoted:!1},e=b.alignCDATA,f,g,l,m;return{startState:function(){return{tokenize:h,cc:[],indented:0,startOfLine:!0,tagName:null,context:null}},token:function(a,b){a.sol()&&(b.startOfLine=!0,b.indented=a.indentation());if(a.eatSpace())return null;m=g=f=null;var c=b.tokenize(a,b);if((c||g)&&c!="comment"){l=b;for(;;){var d=b.cc.pop()||r;if(d(g||c))break}}b.startOfLine=!1;return m||c},indent:function(a,b){var d=a.context;if(d&&d.noIndent)return 0;if(e&&/=2&&f==">"){b.tokenize=e;break}c=f=="-"?c+1:0}return d("comment","comment")}function f(a,b){var c=!1,f;while((f=a.next())!=null){if(c&&f=="/"){b.tokenize=e;break}c=f=="*"}return d("comment","comment")}function e(a,b){var c=a.next();if(c=="@"){a.eatWhile(/\w/);return d("meta",a.current())}if(c=="/"&&a.eat("*")){b.tokenize=f;return f(a,b)}if(c=="<"&&a.eat("!")){b.tokenize=g;return g(a,b)}if(c=="=")d(null,"compare");else{if(c!="~"&&c!="|"||!a.eat("=")){if(c=='"'||c=="'"){b.tokenize=h(c);return b.tokenize(a,b)}if(c=="#"){a.eatWhile(/\w/);return d("atom","hash")}if(c=="!"){a.match(/^\s*\w*/);return d("keyword","important")}if(/\d/.test(c)){a.eatWhile(/[\w.%]/);return d("number","unit")}if(/[,.+>*\/]/.test(c))return d(null,"select-op");if(/[;{}:\[\]]/.test(c))return d(null,c);a.eatWhile(/[\w\\\-_]/);return d("variable","variable")}return d(null,"compare")}}function d(a,b){c=b;return a}var b=a.indentUnit,c;return{startState:function(a){return{tokenize:e,baseIndent:a||0,stack:[]}},token:function(a,b){if(a.eatSpace())return null;var d=b.tokenize(a,b),e=b.stack[b.stack.length-1];if(c=="hash"&&e=="rule")d="atom";else if(d=="variable")if(e=="rule")d="number";else if(!e||e=="@media{")d="tag";e=="rule"&&/^[\{\};]$/.test(c)&&b.stack.pop(),c=="{"?e=="@media"?b.stack[b.stack.length-1]="@media{":b.stack.push("{"):c=="}"?b.stack.pop():c=="@media"?b.stack.push("@media"):e=="{"&&c!="comment"&&b.stack.push("rule");return d},indent:function(a,c){var d=a.stack.length;/^\}/.test(c)&&(d-=a.stack[a.stack.length-1]=="rule"?2:1);return a.baseIndent+d*b},electricChars:"}"}}),CodeMirror.defineMIME("text/css","css"),CodeMirror.defineMode("htmlmixed",function(a,b){function i(a,b){if(a.match(/^<\/\s*style\s*>/i,!1)){b.token=f,b.localState=null,b.mode="html";return f(a,b)}return g(a,/<\/\s*style\s*>/,e.token(a,b.localState))}function h(a,b){if(a.match(/^<\/\s*script\s*>/i,!1)){b.token=f,b.curState=null,b.mode="html";return f(a,b)}return g(a,/<\/\s*script\s*>/,d.token(a,b.localState))}function g(a,b,c){var d=a.current(),e=d.search(b);e>-1&&a.backUp(d.length-e);return c}function f(a,b){var f=c.token(a,b.htmlState);f=="tag"&&a.current()==">"&&b.htmlState.context&&(/^script$/i.test(b.htmlState.context.tagName)?(b.token=h,b.localState=d.startState(c.indent(b.htmlState,"")),b.mode="javascript"):/^style$/i.test(b.htmlState.context.tagName)&&(b.token=i,b.localState=e.startState(c.indent(b.htmlState,"")),b.mode="css"));return f}var c=CodeMirror.getMode(a,{name:"xml",htmlMode:!0}),d=CodeMirror.getMode(a,"javascript"),e=CodeMirror.getMode(a,"css");return{startState:function(){var a=c.startState();return{token:f,localState:null,mode:"html",htmlState:a}},copyState:function(a){if(a.localState)var b=CodeMirror.copyState(a.token==i?e:d,a.localState);return{token:a.token,localState:b,mode:a.mode,htmlState:CodeMirror.copyState(c,a.htmlState)}},token:function(a,b){return b.token(a,b)},indent:function(a,b){return a.token==f||/^\s*<\//.test(b)?c.indent(a.htmlState,b):a.token==h?d.indent(a.localState,b):e.indent(a.localState,b)},electricChars:"/{}:"}}),CodeMirror.defineMIME("text/html","htmlmixed") \ No newline at end of file diff --git a/dist/docs/resources/js/paper.js b/dist/docs/resources/js/paper.js deleted file mode 100644 index e69de29b..00000000 diff --git a/dist/docs/resources/js/reference.js b/dist/docs/resources/js/reference.js deleted file mode 100644 index b39ee690..00000000 --- a/dist/docs/resources/js/reference.js +++ /dev/null @@ -1,258 +0,0 @@ -ContentEnd = HtmlElement.extend({ - _class: 'content-end', - - initialize: function() { - var anchor = $$('a[name]').getLast(), - that = this; - if (anchor) { - function resize() { - var bottom = $window.getScrollSize().height - - anchor.getOffset().y - $window.getSize().height; - that.setHeight(that.getHeight() - bottom); - } - $window.addEvents({ - load: resize, - resize: resize - }); - // Not sure why these are required twice, in addition to load().. - resize(); - resize(); - } - } -}); - -function createCodeMirror(place, options, source) { - return new CodeMirror(place, Hash.create({}, { - lineNumbers: true, - matchBrackets: true, - indentUnit: 4, - tabMode: 'shift', - value: source.getText().replace(/\t/gi, ' ').match( - // Remove first & last empty line - /^\s*?[\n\r]?([\u0000-\uffff]*?)[\n\r]?\s*?$/)[1] - }, options)); -} - -Code = HtmlElement.extend({ - _class: 'code', - - initialize: function() { - // Only format this element if it is visible, otherwise wait until - // it is made visible and then call initialize() manually. - if (this.initialized || this.getBounds().height == 0) - return; - var that = this; - var start = this.getProperty('start'); - var highlight = this.getProperty('highlight'); - var editor = createCodeMirror(function(el) { - that.replaceWith(el); - }, { - lineNumbers: !this.hasParent('.resource-text'), - firstLineNumber: (start || 1).toInt(), - readOnly: true - }, this); - if (highlight) { - var highlights = highlight.split(','); - for (var i = 0, l = highlights.length; i < l; i++) { - var highlight = highlights[i].split('-'); - var hlStart = highlight[0].toInt() - 1; - var hlEnd = highlight.length == 2 - ? highlight[1].toInt() - 1 : hlStart; - if (start) { - hlStart -= start - 1; - hlEnd -= start - 1; - } - for (var j = hlStart; j <= hlEnd; j++) { - editor.setLineClass(j, 'highlight'); - } - } - } - this.initialized = true; - } -}); - -PaperScript = HtmlElement.extend({ - _class: 'paperscript', - - initialize: function() { - // Only format this element if it is visible, otherwise wait until - // it is made visible and then call initialize() manually. - if (this.initialized || this.getBounds().height == 0) - return; - var script = $('script', this), - button = $('.button', this); - if (!script || !button) - return; - var source = button.injectAfter('div', { - className: 'source hidden' - }); - var that = this, - canvas = $('canvas', this), - hasResize = canvas.getProperty('resize'), - showSplit = this.hasClass('split'), - sourceFirst = this.hasClass('source'), - width, height, - editor = null, - hasBorders = true; - - function showSource(show) { - source.modifyClass('hidden', !show); - button.setText(show ? 'Run' : 'Source'); - if (show && !editor) { - editor = createCodeMirror(source.$, { - /* - onKeyEvent: function(editor, event) { - event = new DomEvent(event); - if (event.type == 'keydown') { - var pos = editor.getCursor(); - pos.ch += 4; - editor.setCursor(pos); - event.stop(); - } - }, - */ - }, script); - } - } - - function runScript() { - var scope = paper.PaperScope.get(script.$); - if (scope) { - // Update script to edited version - var code = editor.getValue(); - script.setText(code); - // Keep a reference to the used canvas, since we're going to - // fully clear the scope and initialize again with this canvas. - var canvas = scope.view.canvas; - // Clear scope first, then evaluate a new script. - scope.clear(); - scope.initialize(canvas); - scope.evaluate(code); - } - } - - function resize() { - if (!canvas.hasClass('hidden')) { - width = canvas.getWidth(); - height = canvas.getHeight(); - } else if (hasResize) { - // Can't get correct dimensions from hidden canvas, - // so calculate again. - var size = $window.getScrollSize(); - var offset = source.getOffset(); - width = size.width - offset.x; - height = size.height - offset.y; - } - // Resize the main element as well, so that the float:right button - // is always positioned correctly. - that.set({ width: width, height: height }); - source.set({ - width: width - (hasBorders ? 2 : 1), - height: height - (hasBorders ? 2 : 0) - }); - } - - function toggleView() { - var show = source.hasClass('hidden'); - resize(); - canvas.modifyClass('hidden', show); - showSource(show); - if (!show) - runScript(); - // Remove padding - button.setStyle('right', - $('.CodeMirror', source).getScrollSize().height > height - ? 24 : 8); - } - - if (hasResize) { - // Delay the installing of the resize event, so paper.js installs - // its own before us. - (function() { - $window.addEvents({ - resize: resize - }); - }).delay(1); - hasBorders = false; - source.setStyles({ - borderWidth: '0 0 0 1px' - }); - } - - if (showSplit) { - showSource(true); - } else if (sourceFirst) { - toggleView(); - } - - button.addEvents({ - click: function(event) { - if (showSplit) { - runScript(); - } else { - toggleView(); - } - event.stop(); - }, - - mousedown: function(event) { - event.stop(); - } - }); - this.initialized = true; - } -}); - -var lastMemberId = null; -function toggleMember(id, scrollTo, dontScroll) { - var link = $('#' + id + '-link'); - if (!link) - return true; - var desc = $('#' + id + '-description'); - var v = !link.hasClass('hidden'); - // Retrieve y-offset before any changes, so we can correct scrolling after - var offset = (v ? link : desc).getOffset().y; - if (lastMemberId && lastMemberId != id) { - var prevId = lastMemberId; - lastMemberId = null; - toggleMember(prevId, false, true); - } - lastMemberId = v && id; - link.modifyClass('hidden', v); - desc.modifyClass('hidden', !v); - if (!dontScroll) { - // Correct scrolling relatively to where we are, by checking the amount - // the element has shifted due to the above toggleMember call, and - // correcting by 11px offset, caused by 1px border and 10px padding. - var scroll = $window.getScrollOffset(); - $window.setScrollOffset(scroll.x, scroll.y - + (v ? desc : link).getOffset().y - offset + 11 * (v ? 1 : -1)); - } - if (!desc.editor && v) { - desc.editor = $$('pre.code, .paperscript', desc).each(function(code) { - code.initialize(); - }); - } - if (scrollTo) - scrollToMember(id); - return false; -} - -function scrollToElement(id) { - var e = $('#' + id + '-member'); - if (e) { - if (e.hasClass('member')) - toggleMember(id); - var offs = e.getOffset(); - $window.setScrollOffset(offs); - } else { - window.location.hash = id; - } -} - -$document.addEvent('domready', function() { - var h = unescape(window.location.hash); - if (h) scrollToElement(h.substring(1)); - if (window.paper) - paper.load(); -}); diff --git a/dist/paper.js b/dist/paper.js deleted file mode 100644 index d2dbb9ac..00000000 --- a/dist/paper.js +++ /dev/null @@ -1,3 +0,0 @@ -// Paper.js loader for development, as produced by the build/load.sh script -document.write(''); -document.write(''); \ No newline at end of file diff --git a/lib/bootstrap.js b/lib/bootstrap.js deleted file mode 100644 index aaed4e9f..00000000 --- a/lib/bootstrap.js +++ /dev/null @@ -1,411 +0,0 @@ -/** - * Bootstrap JavaScript Library - * (c) 2006 - 2011 Juerg Lehni, http://lehni.org/ - * - * Bootstrap is released under the MIT license - * http://bootstrapjs.org/ - * - * Inspirations: - * http://dean.edwards.name/weblog/2006/03/base/ - * http://dev.helma.org/Wiki/JavaScript+Inheritance+Sugar/ - * http://prototypejs.org/ - */ - -var Base = new function() { // Bootstrap scope - // Fix __proto__ for browsers where it is not implemented (IE and Opera). - var fix = !this.__proto__, - hidden = /^(statics|generics|preserve|enumerable|prototype|__proto__|toString|valueOf)$/, - proto = Object.prototype, - /** - * Private function that checks if an object contains a given property. - * Naming it 'has' causes problems on Opera when defining - * Object.prototype.has, as the local version then seems to be overriden - * by that. Giving it a idfferent name fixes it. - */ - has = fix - ? function(name) { - return name !== '__proto__' && this.hasOwnProperty(name); - } - : proto.hasOwnProperty, - toString = proto.toString, - proto = Array.prototype, - isArray = Array.isArray = Array.isArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }, - slice = proto.slice, - forEach = proto.forEach || function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - iter.call(bind, this[i], i, this); - }, - forIn = function(iter, bind) { - // Do not use Object.keys for iteration as iterators might modify - // the object we're iterating over, making the hasOwnProperty still - // necessary. - for (var i in this) - if (this.hasOwnProperty(i)) - iter.call(bind, this[i], i, this); - }, - _define = Object.defineProperty, - _describe = Object.getOwnPropertyDescriptor; - - // Support a mixed environment of some ECMAScript 5 features present, - // along with __defineGetter/Setter__ functions, as found in browsers today. - function define(obj, name, desc) { - // Unfortunately Safari seems to ignore configurable: true and - // does not override existing properties, so we need to delete - // first: - if (_define) { - try { - delete obj[name]; - return _define(obj, name, desc); - } catch (e) {} - } - if ((desc.get || desc.set) && obj.__defineGetter__) { - desc.get && obj.__defineGetter__(name, desc.get); - desc.set && obj.__defineSetter__(name, desc.set); - } else { - obj[name] = desc.value; - } - return obj; - } - - function describe(obj, name) { - if (_describe) { - try { - return _describe(obj, name); - } catch (e) {} - } - var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); - return get - ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, - configurable: true } - : has.call(obj, name) - ? { value: obj[name], enumerable: true, configurable: true, - writable: true } - : null; - } - - /** - * Private function that injects functions from src into dest, overriding - * (and inherinting from) base. - */ - function inject(dest, src, enumerable, base, preserve, generics) { - var beans, bean; - - /** - * Private function that injects one field with given name and checks if - * the field is a function that needs to be wrapped for calls of base(). - * This is only needed if the function in base is different from the one - * in src, and if the one in src is actually calling base through base. - * The string of the function is parsed for this.base to detect calls. - */ - function field(name, val, dontCheck, generics) { - // This does even work for prop: 0, as it will just be looked up - // again through describe. - var val = val || (val = describe(src, name)) - && (val.get ? val : val.value), - func = typeof val === 'function', - res = val, - // Only lookup previous value if we preserve or define a - // function that might need it for this.base(). If we're - // defining a getter, don't lookup previous value, but look if - // the property exists (name in dest) and store result in prev - prev = preserve || func - ? (val && val.get ? name in dest : dest[name]) : null; - // Make generics first, as we might jump out bellow in the - // val !== (src.__proto__ || Object.prototype)[name] check, - // e.g. when explicitely reinjecting Array.prototype methods - // to produce generics of them. - if (generics && func && (!preserve || !generics[name])) { - generics[name] = function(bind) { - // Do not call Array.slice generic here, as on Safari, - // this seems to confuse scopes (calling another - // generic from generic-producing code). - return bind && dest[name].apply(bind, - slice.call(arguments, 1)); - } - } - if ((dontCheck || val !== undefined && has.call(src, name)) - && (!preserve || !prev)) { - if (func) { - if (prev && /\bthis\.base\b/.test(val)) { - var fromBase = base && base[name] == prev; - res = function() { - // Look up the base function each time if we can, - // to reflect changes to the base class after - // inheritance. - var tmp = describe(this, 'base'); - define(this, 'base', { value: fromBase - ? base[name] : prev, configurable: true }); - try { - return val.apply(this, arguments); - } finally { - tmp ? define(this, 'base', tmp) - : delete this.base; - } - }; - // Make wrapping closure pretend to be the original - // function on inspection - res.toString = function() { - return val.toString(); - } - res.valueOf = function() { - return val.valueOf(); - } - } - // Produce bean properties if getters are specified. This - // does not produce properties for setter-only properties. - // Just collect beans for now, and look them up in dest at - // the end of fields injection. This ensures this.base() - // works in beans too, and inherits setters for redefined - // getters in subclasses. Only add getter beans if they do - // not expect arguments. Functions that should function both - // with optional arguments and as beans should not declare - // the parameters and use the arguments array internally - // instead. - if (beans && val.length == 0 - && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) - beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); - } - // No need to look up getter if this is a function already. - if (!res || func || !res.get) - res = { value: res, writable: true }; - // Only set/change configurable and enumerable if this field is - // configurable - if ((describe(dest, name) - || { configurable: true }).configurable) { - res.configurable = true; - res.enumerable = enumerable; - } - define(dest, name, res); - } - } - // Iterate through all definitions in src now and call field() for each. - if (src) { - beans = []; - for (var name in src) - if (has.call(src, name) && !hidden.test(name)) - field(name, null, true, generics); - // IE (and some other browsers?) never enumerate these, even if - // they are simply set on an object. Force their creation. Do not - // create generics for these, and check them for not being defined - // (by passing undefined for dontCheck). - field('toString'); - field('valueOf'); - // Now finally define beans as well. Look up methods on dest, for - // support of this.base() (See above). - for (var i = 0, l = beans && beans.length; i < l; i++) - try { - var bean = beans[i], part = bean[1]; - field(bean[0], { - get: dest['get' + part] || dest['is' + part], - set: dest['set' + part] - }, true); - } catch (e) {} - } - return dest; - } - - /** - * Private function that creates a constructor to extend the given object. - * When this constructor is called through new, a new object is craeted - * that inherits all from obj. - */ - function extend(obj) { - // Create the constructor for the new prototype that calls initialize - // if it is defined. - var ctor = function(dont) { - // Fix __proto__ - if (fix) define(this, '__proto__', { value: obj }); - // Call the constructor function, if defined and we are not - // inheriting, in which case ctor.dont would be set, see bellow. - if (this.initialize && dont !== ctor.dont) - return this.initialize.apply(this, arguments); - } - ctor.prototype = obj; - // Add a toString function that delegates to initialize if possible - ctor.toString = function() { - return (this.prototype.initialize || function() {}).toString(); - } - return ctor; - } - - /** - * Converts the argument to an iterator function. If none is specified, the - * identity function is returned. - * This supports normal functions, which are returned unmodified, and values - * to compare to. Wherever this function is used in the Enumerable - * functions, a value, a Function or null may be passed. - */ - function iterator(iter) { - return !iter - ? function(val) { return val } - : typeof iter !== 'function' - ? function(val) { return val == iter } - : iter; - } - - function each(obj, iter, bind, asArray) { - try { - if (obj) - (asArray || asArray === undefined && isArray(obj) - ? forEach : forIn).call(obj, iterator(iter), - bind = bind || obj); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - } - - function clone(obj) { - return each(obj, function(val, i) { - this[i] = val; - }, new obj.constructor()); - } - - // Inject into new ctor object that's passed to inject(), and then returned - return inject(function() {}, { - inject: function(src/*, ... */) { - if (src) { - var proto = this.prototype, - base = proto.__proto__ && proto.__proto__.constructor, - // Allow the whole scope to just define statics by defining - // statics: true. - statics = src.statics == true ? src : src.statics; - if (statics != src) - inject(proto, src, src.enumerable, base && base.prototype, - src.preserve, src.generics && this); - // Define new static fields as enumerable, and inherit from - // base. enumerable is necessary so they can be copied over from - // base, and it does not harm to have enumerable properties in - // the constructor. Use the preserve setting in src.preserve for - // statics too, not their own. - inject(this, statics, true, base, src.preserve); - } - // If there are more than one argument, loop through them and call - // inject again. Do not simple inline the above code in one loop, - // since each of the passed objects might override this.inject. - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src/* , ... */) { - // The new prototype extends the constructor on which extend is - // called. Fix constructor. - // TODO: Consider using Object.create instead of using this.dont if - // available? - var proto = new this(this.dont), - ctor = extend(proto); - define(proto, 'constructor', - { value: ctor, writable: true, configurable: true }); - // Define an object to be passed as the first parameter in - // constructors when initialize should not be called. - ctor.dont = {}; - // Copy over static fields, as prototype-like inheritance - // is not possible for static fields. Mark them as enumerable - // so they can be copied over again. - inject(ctor, this, true); - // Inject all the definitions in src. Use the new inject instead of - // the one in ctor, in case it was overriden. this is needed when - // overriding the static .inject(). But only inject if there's - // something to actually inject. - return arguments.length ? this.inject.apply(ctor, arguments) : ctor; - } - // Pass true for enumerable, so inject() and extend() can be passed on - // to subclasses of Base through Base.inject() / extend(). - }, true).inject({ - /** - * Returns true if the object contains a property with the given name, - * false otherwise. - * Just like in .each, objects only contained in the prototype(s) are - * filtered. - */ - has: has, - each: each, - - /** - * Injects the fields from the given object, adding this.base() - * functionality - */ - inject: function(/* src, ... */) { - for (var i = 0, l = arguments.length; i < l; i++) - inject(this, arguments[i]); - return this; - }, - - /** - * Returns a new object that inherits all properties from "this", - * through proper JS inheritance, not copying. - * Optionally, src and hide parameters can be passed to fill in the - * newly created object just like in inject(), to copy the behavior - * of Function.prototype.extend. - */ - extend: function(/* src, ... */) { - // Notice the "new" here: the private extend returns a constructor - // as it's used for Function.prototype.extend as well. But when - // extending objects, we want to return a new object that inherits - // from "this". In that case, the constructor is never used again, - // its just created to create a new object with the proper - // inheritance set and is garbage collected right after. - var res = new (extend(this)); - return res.inject.apply(res, arguments); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - /** - * Creates a new object of the same type and copies over all - * name / value pairs from this object. - */ - clone: function() { - return clone(this); - }, - - statics: { - // Expose some local privates as Base generics. - each: each, - clone: clone, - define: define, - describe: describe, - iterator: iterator, - - has: function(obj, name) { - return has.call(obj, name); - }, - - type: function(obj) { - return (obj || obj === 0) && (obj._type || typeof obj) || null; - }, - - check: function(obj) { - return !!(obj || obj === 0); - }, - - /** - * Returns the first argument that is defined. - * Null is counted as defined too, since !== undefined is used for - * comparisons. In this it differs from Mootools! - */ - pick: function() { - for (var i = 0, l = arguments.length; i < l; i++) - if (arguments[i] !== undefined) - return arguments[i]; - return null; - }, - - /** - * A special constant, to be thrown by closures passed to each() - * - * $continue / Base.next is not implemented, as the same - * functionality can achieved by using return in the closure. - * In prototype, the implementation of $continue also leads to a - * huge speed decrease, as the closure is wrapped in another closure - * that does nothing else than handling $continue. - */ - stop: {} - } - }); -} diff --git a/lib/parse-js-min.js b/lib/parse-js-min.js deleted file mode 100644 index c0bdddac..00000000 --- a/lib/parse-js-min.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * A JavaScript tokenizer / parser / generator, originally written in Lisp. - * Copyright (c) Marijn Haverbeke - * http://marijn.haverbeke.nl/parse-js/ - * - * Ported by to JavaScript by Mihai Bazon - * Copyright (c) 2010, Mihai Bazon - * http://mihai.bazon.net/blog/ - * - * Modifications and adaptions to browser (c) 2011, Juerg Lehni - * http://lehni.org/ - * - * Distributed under the BSD license. - */var parse_js=new function(){function W(a,b,c){var d=[];for(var e=0;e0,g=j(function(){return h(a[0]?k(["case",z(a[0])+":"]):"default:")},.5)+(f?e+j(function(){return u(a[1]).join(e)}):"");!c&&f&&d0?h(a):a}).join(e)},block:w,"var":function(a){return"var "+l(W(a,x))+";"},"const":function(a){return"const "+l(W(a,x))+";"},"try":function(a,b,c){var d=["try",w(a)];b&&d.push("catch","("+b[0]+")",w(b[1])),c&&d.push("finally",w(c));return k(d)},"throw":function(a){return k(["throw",z(a)])+";"},"new":function(a,b){b=b.length>0?"("+l(W(b,z))+")":"";return k(["new",m(a,"seq","binary","conditional","assign",function(a){var b=N(),c={};try{b.with_walkers({call:function(){throw c},"function":function(){return this}},function(){b.walk(a)})}catch(d){if(d===c)return!0;throw d}})+b])},"switch":function(a,b){return k(["switch","("+z(a)+")",v(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+g(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+g(a));return b+";"},conditional:function(a,b,c){return k([m(a,"assign","seq","conditional"),"?",m(b,"seq"),":",m(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return k([z(b),a,m(c,"seq")])},dot:function(a){var b=z(a),c=1;a[0]=="num"?/\./.test(a[1])||(b+="."):o(a)&&(b="("+b+")");while(cB[b[1]])d="("+d+")";if(L(c[0],["assign","conditional","seq"])||c[0]=="binary"&&B[a]>=B[c[1]]&&(c[1]!=a||!L(a,["&&","||","*"])))e="("+e+")";return k([d,a,e])},"unary-prefix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-prefix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return a+(p(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-postfix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=z(a);o(a)&&(c="("+c+")");return c+"["+z(b)+"]"},object:function(a){return a.length==0?"{}":"{"+e+j(function(){return W(a,function(a){if(a.length==3)return h(t(a[0],a[1][2],a[1][3],a[2]));var d=a[0],e=z(a[1]);b.quote_keys?d=Q(d):(typeof d=="number"||!c&&+d+""==d)&&parseFloat(d)>=0?d=q(+d):V(d)||(d=Q(d));return h(k(c&&b.space_colon?[d,":",e]:[d+":",e]))}).join(","+e)})+e+h("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){return a.length==0?"[]":k(["[",l(W(a,function(a){return!c&&a[0]=="atom"&&a[1]=="undefined"?"":m(a,"seq")})),"]"])},stat:function(a){return z(a).replace(/;*\s*$/,";")},seq:function(){return l(W(J(arguments),z))},label:function(a,b){return k([g(a),":",z(b)])},"with":function(a,b){return k(["with","("+z(a)+")",z(b)])},atom:function(a){return g(a)}},y=[];return z(a)}function Q(a){var b=0,c=0;a=a.replace(/[\\\b\f\n\r\t\x22\x27]/g,function(a){switch(a){case"\\":return"\\\\";case"\b":return"\\b";case"\f":return"\\f";case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";case'"':++b;return'"';case"'":++c;return"'"}return a});return b>c?"'"+a.replace(/\x27/g,"\\'")+"'":'"'+a.replace(/\x22/g,'\\"')+'"'}function O(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function N(){function g(a,b){var c={},e;for(e in a)M(a,e)&&(c[e]=d[e],d[e]=a[e]);var f=b();for(e in c)M(c,e)&&(c[e]?d[e]=c[e]:delete d[e]);return f}function f(a){if(a==null)return null;try{e.push(a);var b=a[0],f=d[b];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=c[b];return f.apply(a,a.slice(1))}finally{e.pop()}}function b(a){var b=[this[0]];a!=null&&b.push(W(a,f));return b}function a(a){return[this[0],W(a,function(a){var b=[a[0]];a.length>1&&(b[1]=f(a[1]));return b})]}var c={string:function(a){return[this[0],a]},num:function(a){return[this[0],a]},name:function(a){return[this[0],a]},toplevel:function(a){return[this[0],W(a,f)]},block:b,splice:b,"var":a,"const":a,"try":function(a,b,c){return[this[0],W(a,f),b!=null?[b[0],W(b[1],f)]:null,c!=null?W(c,f):null]},"throw":function(a){return[this[0],f(a)]},"new":function(a,b){return[this[0],f(a),W(b,f)]},"switch":function(a,b){return[this[0],f(a),W(b,function(a){return[a[0]?f(a[0]):null,W(a[1],f)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],f(a),f(b),f(c)]},assign:function(a,b,c){return[this[0],a,f(b),f(c)]},dot:function(a){return[this[0],f(a)].concat(J(arguments,1))},call:function(a,b){return[this[0],f(a),W(b,f)]},"function":function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},defun:function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},"if":function(a,b,c){return[this[0],f(a),f(b),f(c)]},"for":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"for-in":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"while":function(a,b){return[this[0],f(a),f(b)]},"do":function(a,b){return[this[0],f(a),f(b)]},"return":function(a){return[this[0],f(a)]},binary:function(a,b,c){return[this[0],a,f(b),f(c)]},"unary-prefix":function(a,b){return[this[0],a,f(b)]},"unary-postfix":function(a,b){return[this[0],a,f(b)]},sub:function(a,b){return[this[0],f(a),f(b)]},object:function(a){return[this[0],W(a,function(a){return a.length==2?[a[0],f(a[1])]:[a[0],f(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],W(a,f)]},stat:function(a){return[this[0],f(a)]},seq:function(){return[this[0]].concat(W(J(arguments),f))},label:function(a,b){return[this[0],a,f(b)]},"with":function(a,b){return[this[0],f(a),f(b)]},atom:function(a){return[this[0],a]}},d={},e=[];return{walk:f,with_walkers:g,parent:function(){return e[e.length-2]},stack:function(){return e}}}function M(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function L(a,b){for(var c=b.length;--c>=0;)if(b[c]===a)return!0;return!1}function K(a){return a.split("")}function J(a,b){return Array.prototype.slice.call(a,b||0)}function I(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function G(a){var b=J(arguments,1);return function(){return a.apply(this,b.concat(J(arguments)))}}function F(a,b,c){function bk(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){var b=bg(a),c=d.token.value;if(e("operator")&&M(A,c)){if(bh(b)){g();return p("assign",A[c],b,bi(a))}i("Invalid assignment")}return b}function bh(a){if(!b)return!0;switch(a[0]){case"dot":case"sub":case"new":case"call":return!0;case"name":return a[1]!="this"}}function bg(a){var b=bf(a);if(e("operator","?")){g();var c=bj(!1);m(":");return p("conditional",b,c,bj(!1,a))}return b}function bf(a){return be(Y(!0),0,a)}function be(a,b,c){var f=e("operator")?d.token.value:null;f&&f=="in"&&c&&(f=null);var h=f!=null?B[f]:null;if(h!=null&&h>b){g();var i=be(Y(!0),h,c);return be(p("binary",f,a,i),b,c)}return a}function bd(a,b,c){(b=="++"||b=="--")&&!bh(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bc(a,b){if(e("punc",".")){g();return bc(p("dot",a,bb()),b)}if(e("punc","[")){g();return bc(p("sub",a,H(bj,G(m,"]"))),b)}if(b&&e("punc","(")){g();return bc(p("call",a,Z(")")),!0)}return b&&e("operator")&&M(z,d.token.value)?H(G(bd,"unary-postfix",d.token.value,a),g):a}function bb(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return H(d.token.value,g);default:k()}}function ba(){switch(d.token.type){case"num":case"string":return H(d.token.value,g)}return bb()}function _(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=ba();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bj(!1)])):c.push([bb(),P(!1),h])}g();return p("object",c)}function $(){return p("array",Z("]",!b,!0))}function Z(a,b,c){var d=!0,f=[];while(!e("punc",a)){d?d=!1:m(",");if(b&&e("punc",a))break;e("punc",",")&&c?f.push(["atom","undefined"]):f.push(bj(!1))}g();return f}function X(){var a=Y(!1),b;e("punc","(")?(g(),b=Z(")")):b=[];return bc(p("new",a,b),!0)}function W(){return p("const",U())}function V(a){return p("var",U(a))}function U(a){var b=[];for(;;){e("name")||k();var c=d.token.value;g(),e("operator","=")?(g(),b.push([c,bj(!1,a)])):b.push([c]);if(!e("punc",","))break;g()}return b}function T(){var a=R(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,R()]}e("keyword","finally")&&(g(),c=R()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function R(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(t());g();return a}function Q(){var a=q(),b=t(),c;e("keyword","else")&&(g(),c=t());return p("if",a,b,c)}function O(a){var b=a[0]=="var"?p("name",a[1][0]):a;g();var c=bj();m(")");return p("for-in",a,b,c,bk(t))}function N(a){m(";");var b=e("punc",";")?null:bj();m(";");var c=e("punc",")")?null:bj();m(")");return p("for",a,b,c,bk(t))}function K(){m("(");var a=null;if(!e("punc",";")){a=e("keyword","var")?(g(),V(!0)):bj(!0,!0);if(e("operator","in"))return O(a)}return N(a)}function I(a){var b;n()||(b=e("name")?d.token.value:null),b!=null?(g(),L(b,d.labels)||i("Label "+b+" without matching loop or statement")):d.in_loop==0&&i(a+" not inside a loop or switch"),o();return p(a,b)}function F(){return p("stat",H(bj,o))}function w(a){d.labels.push(a);var c=d.token,e=t();b&&!M(C,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function s(a){return c?function(){var b=d.token,c=a.apply(this,arguments);c[0]=r(c[0],b,h());return c}:a}function r(a,b,c){return a instanceof E?a:new E(a,b,c)}function q(){m("(");var a=bj();m(")");return a}function p(){return J(arguments)}function o(){e("punc",";")?g():n()||k()}function n(){return!b&&(d.token.nlb||e("eof")||e("punc","}"))}function m(a){return l("punc",a)}function l(a,b){if(e(a,b))return g();j(d.token,"Unexpected token "+d.token.type+", expected "+a)}function k(a){a==null&&(a=d.token),j(a,"Unexpected token: "+a.type+" ("+a.value+")")}function j(a,b){i(b,a.line,a.col)}function i(a,b,c,e){var f=d.input.context();u(a,b!=null?b:f.tokline,c!=null?c:f.tokcol,e!=null?e:f.tokpos)}function h(){return d.prev}function g(){d.prev=d.token,d.peeked?(d.token=d.peeked,d.peeked=null):d.token=d.input();return d.token}function f(){return d.peeked||(d.peeked=d.input())}function e(a,b){return v(d.token,a,b)}var d={input:typeof a=="string"?x(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var t=s(function(){e("operator","/")&&(d.peeked=null,d.token=d.input(!0));switch(d.token.type){case"num":case"string":case"regexp":case"operator":case"atom":return F();case"name":return v(f(),"punc",":")?w(H(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",R());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(H(d.token.value,g)){case"break":return I("break");case"continue":return I("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",H(q,o),a)}(bk(t));case"for":return K();case"function":return P(!0);case"if":return Q();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:H(bj,o));case"switch":return p("switch",q(),S());case"throw":return p("throw",H(bj,o));case"try":return T();case"var":return H(V,o);case"const":return H(W,o);case"while":return p("while",q(),bk(t));case"with":return p("with",q(),t());default:k()}}}),P=s(function(a){var b=e("name")?H(d.token.value,g):null;a&&!b&&k(),m("(");return p(a?"defun":"function",b,function(a,b){while(!e("punc",")"))a?a=!1:m(","),e("name")||k(),b.push(d.token.value),g();g();return b}(!0,[]),function(){++d.in_function;var a=d.in_loop;d.in_loop=0;var b=R();--d.in_function,d.in_loop=a;return b}())}),S=G(bk,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bj(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(t()));g();return a}),Y=s(function(a){if(e("operator","new")){g();return X()}if(e("operator")&&M(y,d.token.value))return bd("unary-prefix",H(d.token.value,g),Y(a));if(e("punc")){switch(d.token.value){case"(":g();return bc(H(bj,G(m,")")),a);case"[":g();return bc($(),a);case"{":g();return bc(_(),a)}k()}if(e("keyword","function")){g();return bc(P(!1),a)}if(M(D,d.token.type)){var b=d.token.type=="regexp"?p("regexp",d.token.value[0],d.token.value[1]):p(d.token.type,d.token.value);return bc(H(b,g),a)}k()}),bj=s(function(a,b){arguments.length==0&&(a=!0);var c=bi(b);if(a&&e("punc",",")){g();return p("seq",c,bj(!0,b))}return c});return p("toplevel",function(a){while(!e("eof"))a.push(t());return a}([]))}function E(a,b,c){this.name=a,this.start=b,this.end=c}function x(b){function P(a){if(a)return I();y(),v();var b=g();if(!b)return x("eof");if(o(b))return C();if(b=='"'||b=="'")return F();if(M(l,b))return x("punc",h());if(b==".")return L();if(b=="/")return K();if(M(e,b))return J();if(b=="\\"||q(b))return N();B("Unexpected character '"+b+"'")}function O(a,b){try{return b()}catch(c){if(c===w)B(a);else throw c}}function N(){var b=A(r);return M(a,b)?M(i,b)?x("operator",b):M(d,b)?x("atom",b):x("keyword",b):x("name",b)}function L(){h();return o(g())?C("."):x("punc",".")}function K(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(G()),f.regex_allowed=a;return P();case"*":f.comments_before.push(H()),f.regex_allowed=a;return P()}return f.regex_allowed?I():J("/")}function J(a){function b(a){if(!g())return a;var c=a+g();if(M(i,c)){h();return b(c)}return a}return x("operator",b(a||h()))}function I(){return O("Unterminated regular expression",function(){var a=!1,b="",c,d=!1;while(c=h(!0))if(a)b+="\\"+c,a=!1;else if(c=="[")d=!0,b+=c;else if(c=="]"&&d)d=!1,b+=c;else{if(c=="/"&&!d)break;c=="\\"?a=!0:b+=c}var e=A(function(a){return M(m,a)});return x("regexp",[b,e])})}function H(){h();return O("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=x("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function G(){h();var a=t("\n"),b;a==-1?(b=f.text.substr(f.pos),f.pos=f.text.length):(b=f.text.substring(f.pos,a),f.pos=a);return x("comment1",b,!0)}function F(){return O("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=D();else if(c==a)break;b+=c}return x("string",b)})}function E(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&B("Invalid hex-character pattern in string"),b=b<<4|c}return b}function D(){var a=h(!0);switch(a){case"n":return"\n";case"r":return"\r";case"t":return"\t";case"b":return"\b";case"v":return" ";case"f":return"\f";case"0":return"";case"x":return String.fromCharCode(E(2));case"u":return String.fromCharCode(E(4));case"\n":return"";default:return a}}function C(a){var b=!1,c=!1,d=!1,e=a==".",f=A(function(f,g){if(f=="x"||f=="X")return d?!1:d=!0;if(!d&&(f=="E"||f=="e"))return b?!1:b=c=!0;if(f=="-")return c||g==0&&!a?!0:!1;if(f=="+")return c;c=!1;if(f==".")return!e&&!d?e=!0:!1;return p(f)});a&&(f=a+f);var g=s(f);if(!isNaN(g))return x("num",g);B("Invalid syntax: "+f)}function B(a){u(a,f.tokline,f.tokcol,f.tokpos)}function A(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(M(j,g()))h()}function x(a,b,d){f.regex_allowed=a=="operator"&&!M(z,b)||a=="keyword"&&M(c,b)||a=="punc"&&M(k,b);var e={type:a,value:b,line:f.tokline,col:f.tokcol,pos:f.tokpos,nlb:f.newline_before};d||(e.comments_before=f.comments_before,f.comments_before=[]),f.newline_before=!1;return e}function v(){f.tokline=f.line,f.tokcol=f.col,f.tokpos=f.pos}function t(a,b){var c=f.text.indexOf(a,f.pos);if(b&&c==-1)throw w;return c}function n(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw w;b=="\n"?(f.newline_before=!0,++f.line,f.col=0):++f.col;return b}function g(){return f.text.charAt(f.pos)}var f={text:b.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,""),pos:0,tokpos:0,line:0,tokline:0,col:0,tokcol:0,newline_before:!1,regex_allowed:!1,comments_before:[]};P.context=function(a){a&&(f=a);return f};return P}function v(a,b,c){return a.type==b&&(c==null||a.value==c)}function u(a,b,c,d){throw new t(a,b,c,d)}function t(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d}function s(a){if(f.test(a))return parseInt(a.substr(2),16);if(g.test(a))return parseInt(a.substr(1),8);if(h.test(a))return parseFloat(a)}function r(a){return q(a)||o(a)}function q(a){return a=="$"||a=="_"||n(a)}function p(a){return o(a)||n(a)}function o(a){a=a.charCodeAt(0);return a>=48&&a<=57}function n(a){a=a.charCodeAt(0);return a>=65&&a<=90||a>=97&&a<=122}var a=I(["break","case","catch","const","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","throw","try","typeof","var","void","while","with"]),b=I(["abstract","boolean","byte","char","class","debugger","double","enum","export","extends","final","float","goto","implements","import","int","interface","long","native","package","private","protected","public","short","static","super","synchronized","throws","transient","volatile"]),c=I(["return","new","delete","throw","else","case"]),d=I(["false","null","true","undefined"]),e=I(K("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=I(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","|=","^=","&=","&&","||"]),j=I(K(" \n\r\t")),k=I(K("[{}(,.;:")),l=I(K("[]{}(),;:")),m=I(K("gmsiy"));t.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"};var w={},y=I(["typeof","void","delete","--","++","!","~","-","+"]),z=I(["--","++"]),A=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),B=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),C=I(["for","do","while","switch"]),D=I(["atom","num","string","regexp","name"]);E.prototype.toString=function(){return this.name};var P=I(["name","array","object","string","dot","sub","call","regexp"]),R=I(["if","while","do","for","for-in","with"]);return{parse:F,gen_code:S,tokenizer:x,ast_walker:N}} \ No newline at end of file diff --git a/lib/parse-js-unicode.js b/lib/parse-js-unicode.js deleted file mode 100644 index 6baa67f3..00000000 --- a/lib/parse-js-unicode.js +++ /dev/null @@ -1,1997 +0,0 @@ -/** - * A JavaScript tokenizer / parser / generator, originally written in Lisp. - * Copyright (c) Marijn Haverbeke - * http://marijn.haverbeke.nl/parse-js/ - * - * Ported by to JavaScript by Mihai Bazon - * Copyright (c) 2010, Mihai Bazon - * http://mihai.bazon.net/blog/ - * - * Modifications and adaptions to browser (c) 2011, Juerg Lehni - * http://lehni.org/ - * - * Distributed under the BSD license. - */ - -var parse_js = new function() { - -/* -----[ Tokenizer (constants) ]----- */ - -var KEYWORDS = array_to_hash([ - "break", - "case", - "catch", - "const", - "continue", - "default", - "delete", - "do", - "else", - "finally", - "for", - "function", - "if", - "in", - "instanceof", - "new", - "return", - "switch", - "throw", - "try", - "typeof", - "var", - "void", - "while", - "with" -]); - -var RESERVED_WORDS = array_to_hash([ - "abstract", - "boolean", - "byte", - "char", - "class", - "debugger", - "double", - "enum", - "export", - "extends", - "final", - "float", - "goto", - "implements", - "import", - "int", - "interface", - "long", - "native", - "package", - "private", - "protected", - "public", - "short", - "static", - "super", - "synchronized", - "throws", - "transient", - "volatile" -]); - -var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ - "return", - "new", - "delete", - "throw", - "else", - "case" -]); - -var KEYWORDS_ATOM = array_to_hash([ - "false", - "null", - "true", - "undefined" -]); - -var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); - -var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; -var RE_OCT_NUMBER = /^0[0-7]+$/; -var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - -var OPERATORS = array_to_hash([ - "in", - "instanceof", - "typeof", - "new", - "void", - "delete", - "++", - "--", - "+", - "-", - "!", - "~", - "&", - "|", - "^", - "*", - "/", - "%", - ">>", - "<<", - ">>>", - "<", - ">", - "<=", - ">=", - "==", - "===", - "!=", - "!==", - "?", - "=", - "+=", - "-=", - "/=", - "*=", - "%=", - ">>=", - "<<=", - ">>>=", - "|=", - "^=", - "&=", - "&&", - "||" -]); - -var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\v\u200b")); - -var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); - -var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); - -var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); - -/* -----[ Tokenizer ]----- */ - -// regexps adapted from http://xregexp.com/plugins/#unicode -var UNICODE = { - letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), - non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), - space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), - connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") -}; - -function is_letter(ch) { - return UNICODE.letter.test(ch); -}; - -function is_digit(ch) { - ch = ch.charCodeAt(0); - return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 -}; - -function is_alphanumeric_char(ch) { - return is_digit(ch) || is_letter(ch); -}; - -function is_unicode_combining_mark(ch) { - return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); -}; - -function is_unicode_connector_punctuation(ch) { - return UNICODE.connector_punctuation.test(ch); -}; - -function is_identifier_start(ch) { - return ch == "$" || ch == "_" || is_letter(ch); -}; - -function is_identifier_char(ch) { - return is_identifier_start(ch) - || is_unicode_combining_mark(ch) - || is_digit(ch) - || is_unicode_connector_punctuation(ch) - || ch == "\u200c" // zero-width non-joiner - || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) - ; -}; - -function parse_js_number(num) { - if (RE_HEX_NUMBER.test(num)) { - return parseInt(num.substr(2), 16); - } else if (RE_OCT_NUMBER.test(num)) { - return parseInt(num.substr(1), 8); - } else if (RE_DEC_NUMBER.test(num)) { - return parseFloat(num); - } -}; - -function JS_Parse_Error(message, line, col, pos) { - this.message = message; - this.line = line; - this.col = col; - this.pos = pos; -}; - -JS_Parse_Error.prototype.toString = function() { - return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")"; -}; - -function js_error(message, line, col, pos) { - throw new JS_Parse_Error(message, line, col, pos); -}; - -function is_token(token, type, val) { - return token.type == type && (val == null || token.value == val); -}; - -var EX_EOF = {}; - -function tokenizer($TEXT) { - - var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false, - comments_before : [] - }; - - function peek() { return S.text.charAt(S.pos); }; - - function next(signal_eof) { - var ch = S.text.charAt(S.pos++); - if (signal_eof && !ch) - throw EX_EOF; - if (ch == "\n") { - S.newline_before = true; - ++S.line; - S.col = 0; - } else { - ++S.col; - } - return ch; - }; - - function eof() { - return !S.peek(); - }; - - function find(what, signal_eof) { - var pos = S.text.indexOf(what, S.pos); - if (signal_eof && pos == -1) throw EX_EOF; - return pos; - }; - - function start_token() { - S.tokline = S.line; - S.tokcol = S.col; - S.tokpos = S.pos; - }; - - function token(type, value, is_comment) { - S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || - (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || - (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); - var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - nlb : S.newline_before - }; - if (!is_comment) { - ret.comments_before = S.comments_before; - S.comments_before = []; - } - S.newline_before = false; - return ret; - }; - - function skip_whitespace() { - while (HOP(WHITESPACE_CHARS, peek())) - next(); - }; - - function read_while(pred) { - var ret = "", ch = peek(), i = 0; - while (ch && pred(ch, i++)) { - ret += next(); - ch = peek(); - } - return ret; - }; - - function parse_error(err) { - js_error(err, S.tokline, S.tokcol, S.tokpos); - }; - - function read_num(prefix) { - var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; - var num = read_while(function(ch, i){ - if (ch == "x" || ch == "X") { - if (has_x) return false; - return has_x = true; - } - if (!has_x && (ch == "E" || ch == "e")) { - if (has_e) return false; - return has_e = after_e = true; - } - if (ch == "-") { - if (after_e || (i == 0 && !prefix)) return true; - return false; - } - if (ch == "+") return after_e; - after_e = false; - if (ch == ".") { - if (!has_dot && !has_x) - return has_dot = true; - return false; - } - return is_alphanumeric_char(ch); - }); - if (prefix) - num = prefix + num; - var valid = parse_js_number(num); - if (!isNaN(valid)) { - return token("num", valid); - } else { - parse_error("Invalid syntax: " + num); - } - }; - - function read_escaped_char() { - var ch = next(true); - switch (ch) { - case "n" : return "\n"; - case "r" : return "\r"; - case "t" : return "\t"; - case "b" : return "\b"; - case "v" : return "\v"; - case "f" : return "\f"; - case "0" : return "\0"; - case "x" : return String.fromCharCode(hex_bytes(2)); - case "u" : return String.fromCharCode(hex_bytes(4)); - case "\n": return ""; - default : return ch; - } - }; - - function hex_bytes(n) { - var num = 0; - for (; n > 0; --n) { - var digit = parseInt(next(true), 16); - if (isNaN(digit)) - parse_error("Invalid hex-character pattern in string"); - num = (num << 4) | digit; - } - return num; - }; - - function read_string() { - return with_eof_error("Unterminated string constant", function(){ - var quote = next(), ret = ""; - for (;;) { - var ch = next(true); - if (ch == "\\") { - // read OctalEscapeSequence (XXX: deprecated if "strict mode") - // https://github.com/mishoo/UglifyJS/issues/178 - var octal_len = 0, first = null; - ch = read_while(function(ch){ - if (ch >= "0" && ch <= "7") { - if (!first) { - first = ch; - return ++octal_len; - } - else if (first <= "3" && octal_len <= 2) return ++octal_len; - else if (first >= "4" && octal_len <= 1) return ++octal_len; - } - return false; - }); - if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); - else ch = read_escaped_char(); - } - else if (ch == quote) break; - ret += ch; - } - return token("string", ret); - }); - }; - - function read_line_comment() { - next(); - var i = find("\n"), ret; - if (i == -1) { - ret = S.text.substr(S.pos); - S.pos = S.text.length; - } else { - ret = S.text.substring(S.pos, i); - S.pos = i; - } - return token("comment1", ret, true); - }; - - function read_multiline_comment() { - next(); - return with_eof_error("Unterminated multiline comment", function(){ - var i = find("*/", true), - text = S.text.substring(S.pos, i), - tok = token("comment2", text, true); - S.pos = i + 2; - S.line += text.split("\n").length - 1; - S.newline_before = text.indexOf("\n") >= 0; - return tok; - }); - }; - - function read_name() { - var backslash = false, name = "", ch; - while ((ch = peek()) != null) { - if (!backslash) { - if (ch == "\\") backslash = true, next(); - else if (is_identifier_char(ch)) name += next(); - else break; - } - else { - if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); - ch = read_escaped_char(); - if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); - name += ch; - backslash = false; - } - } - return name; - }; - - function read_regexp() { - return with_eof_error("Unterminated regular expression", function(){ - var prev_backslash = false, regexp = "", ch, in_class = false; - while ((ch = next(true))) if (prev_backslash) { - regexp += "\\" + ch; - prev_backslash = false; - } else if (ch == "[") { - in_class = true; - regexp += ch; - } else if (ch == "]" && in_class) { - in_class = false; - regexp += ch; - } else if (ch == "/" && !in_class) { - break; - } else if (ch == "\\") { - prev_backslash = true; - } else { - regexp += ch; - } - var mods = read_name(); - return token("regexp", [ regexp, mods ]); - }); - }; - - function read_operator(prefix) { - function grow(op) { - if (!peek()) return op; - var bigger = op + peek(); - if (HOP(OPERATORS, bigger)) { - next(); - return grow(bigger); - } else { - return op; - } - }; - return token("operator", grow(prefix || next())); - }; - - function handle_slash() { - next(); - var regex_allowed = S.regex_allowed; - switch (peek()) { - case "/": - S.comments_before.push(read_line_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - case "*": - S.comments_before.push(read_multiline_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - } - return S.regex_allowed ? read_regexp() : read_operator("/"); - }; - - function handle_dot() { - next(); - return is_digit(peek()) - ? read_num(".") - : token("punc", "."); - }; - - function read_word() { - var word = read_name(); - return !HOP(KEYWORDS, word) - ? token("name", word) - : HOP(OPERATORS, word) - ? token("operator", word) - : HOP(KEYWORDS_ATOM, word) - ? token("atom", word) - : token("keyword", word); - }; - - function with_eof_error(eof_error, cont) { - try { - return cont(); - } catch(ex) { - if (ex === EX_EOF) parse_error(eof_error); - else throw ex; - } - }; - - function next_token(force_regexp) { - if (force_regexp) - return read_regexp(); - skip_whitespace(); - start_token(); - var ch = peek(); - if (!ch) return token("eof"); - if (is_digit(ch)) return read_num(); - if (ch == '"' || ch == "'") return read_string(); - if (HOP(PUNC_CHARS, ch)) return token("punc", next()); - if (ch == ".") return handle_dot(); - if (ch == "/") return handle_slash(); - if (HOP(OPERATOR_CHARS, ch)) return read_operator(); - if (ch == "\\" || is_identifier_start(ch)) return read_word(); - parse_error("Unexpected character '" + ch + "'"); - }; - - next_token.context = function(nc) { - if (nc) S = nc; - return S; - }; - - return next_token; - -}; - -/* -----[ Parser (constants) ]----- */ - -var UNARY_PREFIX = array_to_hash([ - "typeof", - "void", - "delete", - "--", - "++", - "!", - "~", - "-", - "+" -]); - -var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); - -var ASSIGNMENT = (function(a, ret, i){ - while (i < a.length) { - ret[a[i]] = a[i].substr(0, a[i].length - 1); - i++; - } - return ret; -})( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], - { "=": true }, - 0 -); - -var PRECEDENCE = (function(a, ret){ - for (var i = 0, n = 1; i < a.length; ++i, ++n) { - var b = a[i]; - for (var j = 0; j < b.length; ++j) { - ret[b[j]] = n; - } - } - return ret; -})( - [ - ["||"], - ["&&"], - ["|"], - ["^"], - ["&"], - ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], - [">>", "<<", ">>>"], - ["+", "-"], - ["*", "/", "%"] - ], - {} -); - -var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); - -var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); - -/* -----[ Parser ]----- */ - -function NodeWithToken(str, start, end) { - this.name = str; - this.start = start; - this.end = end; -}; - -NodeWithToken.prototype.toString = function() { return this.name; }; - -function parse($TEXT, exigent_mode, embed_tokens) { - - var S = { - input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, - token : null, - prev : null, - peeked : null, - in_function : 0, - in_loop : 0, - labels : [] - }; - - S.token = next(); - - function is(type, value) { - return is_token(S.token, type, value); - }; - - function peek() { return S.peeked || (S.peeked = S.input()); }; - - function next() { - S.prev = S.token; - if (S.peeked) { - S.token = S.peeked; - S.peeked = null; - } else { - S.token = S.input(); - } - return S.token; - }; - - function prev() { - return S.prev; - }; - - function croak(msg, line, col, pos) { - var ctx = S.input.context(); - js_error(msg, - line != null ? line : ctx.tokline, - col != null ? col : ctx.tokcol, - pos != null ? pos : ctx.tokpos); - }; - - function token_error(token, msg) { - croak(msg, token.line, token.col); - }; - - function unexpected(token) { - if (token == null) - token = S.token; - token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); - }; - - function expect_token(type, val) { - if (is(type, val)) { - return next(); - } - token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); - }; - - function expect(punc) { return expect_token("punc", punc); }; - - function can_insert_semicolon() { - return !exigent_mode && ( - S.token.nlb || is("eof") || is("punc", "}") - ); - }; - - function semicolon() { - if (is("punc", ";")) next(); - else if (!can_insert_semicolon()) unexpected(); - }; - - function as() { - return slice(arguments); - }; - - function parenthesised() { - expect("("); - var ex = expression(); - expect(")"); - return ex; - }; - - function add_tokens(str, start, end) { - return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); - }; - - function maybe_embed_tokens(parser) { - if (embed_tokens) return function() { - var start = S.token; - var ast = parser.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - }; - else return parser; - }; - - var statement = maybe_embed_tokens(function() { - if (is("operator", "/")) { - S.peeked = null; - S.token = S.input(true); // force regexp - } - switch (S.token.type) { - case "num": - case "string": - case "regexp": - case "operator": - case "atom": - return simple_statement(); - - case "name": - return is_token(peek(), "punc", ":") - ? labeled_statement(prog1(S.token.value, next, next)) - : simple_statement(); - - case "punc": - switch (S.token.value) { - case "{": - return as("block", block_()); - case "[": - case "(": - return simple_statement(); - case ";": - next(); - return as("block"); - default: - unexpected(); - } - - case "keyword": - switch (prog1(S.token.value, next)) { - case "break": - return break_cont("break"); - - case "continue": - return break_cont("continue"); - - case "debugger": - semicolon(); - return as("debugger"); - - case "do": - return (function(body){ - expect_token("keyword", "while"); - return as("do", prog1(parenthesised, semicolon), body); - })(in_loop(statement)); - - case "for": - return for_(); - - case "function": - return function_(true); - - case "if": - return if_(); - - case "return": - if (S.in_function == 0) - croak("'return' outside of function"); - return as("return", - is("punc", ";") - ? (next(), null) - : can_insert_semicolon() - ? null - : prog1(expression, semicolon)); - - case "switch": - return as("switch", parenthesised(), switch_block_()); - - case "throw": - return as("throw", prog1(expression, semicolon)); - - case "try": - return try_(); - - case "var": - return prog1(var_, semicolon); - - case "const": - return prog1(const_, semicolon); - - case "while": - return as("while", parenthesised(), in_loop(statement)); - - case "with": - return as("with", parenthesised(), statement()); - - default: - unexpected(); - } - } - }); - - function labeled_statement(label) { - S.labels.push(label); - var start = S.token, stat = statement(); - if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) - unexpected(start); - S.labels.pop(); - return as("label", label, stat); - }; - - function simple_statement() { - return as("stat", prog1(expression, semicolon)); - }; - - function break_cont(type) { - var name; - if (!can_insert_semicolon()) { - name = is("name") ? S.token.value : null; - } - if (name != null) { - next(); - if (!member(name, S.labels)) - croak("Label " + name + " without matching loop or statement"); - } - else if (S.in_loop == 0) - croak(type + " not inside a loop or switch"); - semicolon(); - return as(type, name); - }; - - function for_() { - expect("("); - var init = null; - if (!is("punc", ";")) { - init = is("keyword", "var") - ? (next(), var_(true)) - : expression(true, true); - if (is("operator", "in")) - return for_in(init); - } - return regular_for(init); - }; - - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(); - expect(";"); - var step = is("punc", ")") ? null : expression(); - expect(")"); - return as("for", init, test, step, in_loop(statement)); - }; - - function for_in(init) { - var lhs = init[0] == "var" ? as("name", init[1][0]) : init; - next(); - var obj = expression(); - expect(")"); - return as("for-in", init, lhs, obj, in_loop(statement)); - }; - - var function_ = maybe_embed_tokens(function(in_statement) { - var name = is("name") ? prog1(S.token.value, next) : null; - if (in_statement && !name) - unexpected(); - expect("("); - return as(in_statement ? "defun" : "function", - name, - // arguments - (function(first, a){ - while (!is("punc", ")")) { - if (first) first = false; else expect(","); - if (!is("name")) unexpected(); - a.push(S.token.value); - next(); - } - next(); - return a; - })(true, []), - // body - (function(){ - ++S.in_function; - var loop = S.in_loop; - S.in_loop = 0; - var a = block_(); - --S.in_function; - S.in_loop = loop; - return a; - })()); - }); - - function if_() { - var cond = parenthesised(), body = statement(), belse; - if (is("keyword", "else")) { - next(); - belse = statement(); - } - return as("if", cond, body, belse); - }; - - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } - next(); - return a; - }; - - var switch_block_ = curry(in_loop, function(){ - expect("{"); - var a = [], cur = null; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - next(); - cur = []; - a.push([ expression(), cur ]); - expect(":"); - } - else if (is("keyword", "default")) { - next(); - expect(":"); - cur = []; - a.push([ null, cur ]); - } - else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - next(); - return a; - }); - - function try_() { - var body = block_(), bcatch, bfinally; - if (is("keyword", "catch")) { - next(); - expect("("); - if (!is("name")) - croak("Name expected"); - var name = S.token.value; - next(); - expect(")"); - bcatch = [ name, block_() ]; - } - if (is("keyword", "finally")) { - next(); - bfinally = block_(); - } - if (!bcatch && !bfinally) - croak("Missing catch/finally blocks"); - return as("try", body, bcatch, bfinally); - }; - - function vardefs(no_in) { - var a = []; - for (;;) { - if (!is("name")) - unexpected(); - var name = S.token.value; - next(); - if (is("operator", "=")) { - next(); - a.push([ name, expression(false, no_in) ]); - } else { - a.push([ name ]); - } - if (!is("punc", ",")) - break; - next(); - } - return a; - }; - - function var_(no_in) { - return as("var", vardefs(no_in)); - }; - - function const_() { - return as("const", vardefs()); - }; - - function new_() { - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")"); - } else { - args = []; - } - return subscripts(as("new", newexp, args), true); - }; - - var expr_atom = maybe_embed_tokens(function(allow_calls) { - if (is("operator", "new")) { - next(); - return new_(); - } - if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { - return make_unary("unary-prefix", - prog1(S.token.value, next), - expr_atom(allow_calls)); - } - if (is("punc")) { - switch (S.token.value) { - case "(": - next(); - return subscripts(prog1(expression, curry(expect, ")")), allow_calls); - case "[": - next(); - return subscripts(array_(), allow_calls); - case "{": - next(); - return subscripts(object_(), allow_calls); - } - unexpected(); - } - if (is("keyword", "function")) { - next(); - return subscripts(function_(false), allow_calls); - } - if (HOP(ATOMIC_START_TOKEN, S.token.type)) { - var atom = S.token.type == "regexp" - ? as("regexp", S.token.value[0], S.token.value[1]) - : as(S.token.type, S.token.value); - return subscripts(prog1(atom, next), allow_calls); - } - unexpected(); - }); - - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push([ "atom", "undefined" ]); - } else { - a.push(expression(false)); - } - } - next(); - return a; - }; - - function array_() { - return as("array", expr_list("]", !exigent_mode, true)); - }; - - function object_() { - var first = true, a = []; - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!exigent_mode && is("punc", "}")) - // allow trailing comma - break; - var type = S.token.type; - var name = as_property_name(); - if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { - a.push([ as_name(), function_(false), name ]); - } else { - expect(":"); - a.push([ name, expression(false) ]); - } - } - next(); - return as("object", a); - }; - - function as_property_name() { - switch (S.token.type) { - case "num": - case "string": - return prog1(S.token.value, next); - } - return as_name(); - }; - - function as_name() { - switch (S.token.type) { - case "name": - case "operator": - case "keyword": - case "atom": - return prog1(S.token.value, next); - default: - unexpected(); - } - }; - - function subscripts(expr, allow_calls) { - if (is("punc", ".")) { - next(); - return subscripts(as("dot", expr, as_name()), allow_calls); - } - if (is("punc", "[")) { - next(); - return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - return subscripts(as("call", expr, expr_list(")")), true); - } - if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { - return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), - next); - } - return expr; - }; - - function make_unary(tag, op, expr) { - if ((op == "++" || op == "--") && !is_assignable(expr)) - croak("Invalid use of " + op + " operator"); - return as(tag, op, expr); - }; - - function expr_op(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op && op == "in" && no_in) op = null; - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && prec > min_prec) { - next(); - var right = expr_op(expr_atom(true), prec, no_in); - return expr_op(as("binary", op, left, right), min_prec, no_in); - } - return left; - }; - - function expr_ops(no_in) { - return expr_op(expr_atom(true), 0, no_in); - }; - - function maybe_conditional(no_in) { - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return as("conditional", expr, yes, expression(false, no_in)); - } - return expr; - }; - - function is_assignable(expr) { - if (!exigent_mode) return true; - switch (expr[0]) { - case "dot": - case "sub": - case "new": - case "call": - return true; - case "name": - return expr[1] != "this"; - } - }; - - function maybe_assign(no_in) { - var left = maybe_conditional(no_in), val = S.token.value; - if (is("operator") && HOP(ASSIGNMENT, val)) { - if (is_assignable(left)) { - next(); - return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); - } - croak("Invalid assignment"); - } - return left; - }; - - var expression = maybe_embed_tokens(function(commas, no_in) { - if (arguments.length == 0) - commas = true; - var expr = maybe_assign(no_in); - if (commas && is("punc", ",")) { - next(); - return as("seq", expr, expression(true, no_in)); - } - return expr; - }); - - function in_loop(cont) { - try { - ++S.in_loop; - return cont(); - } finally { - --S.in_loop; - } - }; - - return as("toplevel", (function(a){ - while (!is("eof")) - a.push(statement()); - return a; - })([])); - -}; - -/* -----[ Utilities ]----- */ - -function curry(f) { - var args = slice(arguments, 1); - return function() { return f.apply(this, args.concat(slice(arguments))); }; -}; - -function prog1(ret) { - if (ret instanceof Function) - ret = ret(); - for (var i = 1, n = arguments.length; --n > 0; ++i) - arguments[i](); - return ret; -}; - -function array_to_hash(a) { - var ret = {}; - for (var i = 0; i < a.length; ++i) - ret[a[i]] = true; - return ret; -}; - -function slice(a, start) { - return Array.prototype.slice.call(a, start || 0); -}; - -function characters(str) { - return str.split(""); -}; - -function member(name, array) { - for (var i = array.length; --i >= 0;) - if (array[i] === name) - return true; - return false; -}; - -function HOP(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -}; - -/* -----[ helper for AST traversal ]----- */ - -function ast_walker() { - function _vardefs(defs) { - return [ this[0], MAP(defs, function(def){ - var a = [ def[0] ]; - if (def.length > 1) - a[1] = walk(def[1]); - return a; - }) ]; - }; - function _block(statements) { - var out = [ this[0] ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; - }; - var walkers = { - "string": function(str) { - return [ this[0], str ]; - }, - "num": function(num) { - return [ this[0], num ]; - }, - "name": function(name) { - return [ this[0], name ]; - }, - "toplevel": function(statements) { - return [ this[0], MAP(statements, walk) ]; - }, - "block": _block, - "splice": _block, - "var": _vardefs, - "const": _vardefs, - "try": function(t, c, f) { - return [ - this[0], - MAP(t, walk), - c != null ? [ c[0], MAP(c[1], walk) ] : null, - f != null ? MAP(f, walk) : null - ]; - }, - "throw": function(expr) { - return [ this[0], walk(expr) ]; - }, - "new": function(ctor, args) { - return [ this[0], walk(ctor), MAP(args, walk) ]; - }, - "switch": function(expr, body) { - return [ this[0], walk(expr), MAP(body, function(branch){ - return [ branch[0] ? walk(branch[0]) : null, - MAP(branch[1], walk) ]; - }) ]; - }, - "break": function(label) { - return [ this[0], label ]; - }, - "continue": function(label) { - return [ this[0], label ]; - }, - "conditional": function(cond, t, e) { - return [ this[0], walk(cond), walk(t), walk(e) ]; - }, - "assign": function(op, lvalue, rvalue) { - return [ this[0], op, walk(lvalue), walk(rvalue) ]; - }, - "dot": function(expr) { - return [ this[0], walk(expr) ].concat(slice(arguments, 1)); - }, - "call": function(expr, args) { - return [ this[0], walk(expr), MAP(args, walk) ]; - }, - "function": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "defun": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "if": function(conditional, t, e) { - return [ this[0], walk(conditional), walk(t), walk(e) ]; - }, - "for": function(init, cond, step, block) { - return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; - }, - "for-in": function(vvar, key, hash, block) { - return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; - }, - "while": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "do": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "return": function(expr) { - return [ this[0], walk(expr) ]; - }, - "binary": function(op, left, right) { - return [ this[0], op, walk(left), walk(right) ]; - }, - "unary-prefix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "unary-postfix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "sub": function(expr, subscript) { - return [ this[0], walk(expr), walk(subscript) ]; - }, - "object": function(props) { - return [ this[0], MAP(props, function(p){ - return p.length == 2 - ? [ p[0], walk(p[1]) ] - : [ p[0], walk(p[1]), p[2] ]; // get/set-ter - }) ]; - }, - "regexp": function(rx, mods) { - return [ this[0], rx, mods ]; - }, - "array": function(elements) { - return [ this[0], MAP(elements, walk) ]; - }, - "stat": function(stat) { - return [ this[0], walk(stat) ]; - }, - "seq": function() { - return [ this[0] ].concat(MAP(slice(arguments), walk)); - }, - "label": function(name, block) { - return [ this[0], name, walk(block) ]; - }, - "with": function(expr, block) { - return [ this[0], walk(expr), walk(block) ]; - }, - "atom": function(name) { - return [ this[0], name ]; - } - }; - - var user = {}; - var stack = []; - function walk(ast) { - if (ast == null) - return null; - try { - stack.push(ast); - var type = ast[0]; - var gen = user[type]; - if (gen) { - var ret = gen.apply(ast, ast.slice(1)); - if (ret != null) - return ret; - } - gen = walkers[type]; - return gen.apply(ast, ast.slice(1)); - } finally { - stack.pop(); - } - }; - - function with_walkers(walkers, cont){ - var save = {}, i; - for (i in walkers) if (HOP(walkers, i)) { - save[i] = user[i]; - user[i] = walkers[i]; - } - var ret = cont(); - for (i in save) if (HOP(save, i)) { - if (!save[i]) delete user[i]; - else user[i] = save[i]; - } - return ret; - }; - - return { - walk: walk, - with_walkers: with_walkers, - parent: function() { - return stack[stack.length - 2]; // last one is current node - }, - stack: function() { - return stack; - } - }; -}; - -function empty(b) { - return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); -}; - -/* -----[ re-generate code from the AST ]----- */ - -var DOT_CALL_NO_PARENS = array_to_hash([ - "name", - "array", - "object", - "string", - "dot", - "sub", - "call", - "regexp" -]); - -function make_string(str, ascii_only) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){ - switch (s) { - case "\\": return "\\\\"; - case "\b": return "\\b"; - case "\f": return "\\f"; - case "\n": return "\\n"; - case "\r": return "\\r"; - case "\t": return "\\t"; - case "\u2028": return "\\u2028"; - case "\u2029": return "\\u2029"; - case '"': ++dq; return '"'; - case "'": ++sq; return "'"; - } - return s; - }); - if (ascii_only) str = to_ascii(str); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; - else return '"' + str.replace(/\x22/g, '\\"') + '"'; -}; - -function to_ascii(str) { - return str.replace(/[\u0080-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - while (code.length < 4) code = "0" + code; - return "\\u" + code; - }); -}; - -var SPLICE_NEEDS_BRACKETS = array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); - -function gen_code(ast, options) { - options = defaults(options, { - indent_start : 0, - indent_level : 4, - quote_keys : false, - space_colon : false, - beautify : false, - ascii_only : false, - inline_script: false - }); - var beautify = !!options.beautify; - var indentation = 0, - newline = beautify ? "\n" : "", - space = beautify ? " " : ""; - - function encode_string(str) { - var ret = make_string(str, options.ascii_only); - if (options.inline_script) - ret = ret.replace(/<\x2fscript([>/\t\n\f\r ])/gi, "<\\/script$1"); - return ret; - }; - - function make_name(name) { - name = name.toString(); - if (options.ascii_only) - name = to_ascii(name); - return name; - }; - - function indent(line) { - if (line == null) - line = ""; - if (beautify) - line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; - return line; - }; - - function with_indent(cont, incr) { - if (incr == null) incr = 1; - indentation += incr; - try { return cont.apply(null, slice(arguments, 1)); } - finally { indentation -= incr; } - }; - - function add_spaces(a) { - if (beautify) - return a.join(" "); - var b = []; - for (var i = 0; i < a.length; ++i) { - var next = a[i + 1]; - b.push(a[i]); - if (next && - ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || - (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { - b.push(" "); - } - } - return b.join(""); - }; - - function add_commas(a) { - return a.join("," + space); - }; - - function parenthesize(expr) { - var gen = make(expr); - for (var i = 1; i < arguments.length; ++i) { - var el = arguments[i]; - if ((el instanceof Function && el(expr)) || expr[0] == el) - return "(" + gen + ")"; - } - return gen; - }; - - function best_of(a) { - if (a.length == 1) { - return a[0]; - } - if (a.length == 2) { - var b = a[1]; - a = a[0]; - return a.length <= b.length ? a : b; - } - return best_of([ a[0], best_of(a.slice(1)) ]); - }; - - function needs_parens(expr) { - if (expr[0] == "function" || expr[0] == "object") { - // dot/call on a literal function requires the - // function literal itself to be parenthesized - // only if it's the first "thing" in a - // statement. This means that the parent is - // "stat", but it could also be a "seq" and - // we're the first in this "seq" and the - // parent is "stat", and so on. Messy stuff, - // but it worths the trouble. - var a = slice($stack), self = a.pop(), p = a.pop(); - while (p) { - if (p[0] == "stat") return true; - if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || - ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { - self = p; - p = a.pop(); - } else { - return false; - } - } - } - return !HOP(DOT_CALL_NO_PARENS, expr[0]); - }; - - function make_num(num) { - var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; - if (Math.floor(num) === num) { - a.push("0x" + num.toString(16).toLowerCase(), // probably pointless - "0" + num.toString(8)); // same. - if ((m = /^(.*?)(0+)$/.exec(num))) { - a.push(m[1] + "e" + m[2].length); - } - } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { - a.push(m[2] + "e-" + (m[1].length + m[2].length), - str.substr(str.indexOf("."))); - } - return best_of(a); - }; - - var generators = { - "string": encode_string, - "num": make_num, - "name": make_name, - "toplevel": function(statements) { - return make_block_statements(statements) - .join(newline); - }, - "splice": function(statements) { - var parent = $stack[$stack.length - 2][0]; - if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { - // we need block brackets in this case - return make_block.apply(this, arguments); - } else { - return MAP(make_block_statements(statements, true), - function(line, i) { - // the first line is already indented - return i > 0 ? indent(line) : line; - }).join(newline); - } - }, - "block": make_block, - "var": function(defs) { - return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "const": function(defs) { - return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "try": function(tr, ca, fi) { - var out = [ "try", make_block(tr) ]; - if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); - if (fi) out.push("finally", make_block(fi)); - return add_spaces(out); - }, - "throw": function(expr) { - return add_spaces([ "throw", make(expr) ]) + ";"; - }, - "new": function(ctor, args) { - args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; - return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ - var w = ast_walker(), has_call = {}; - try { - w.with_walkers({ - "call": function() { throw has_call }, - "function": function() { return this } - }, function(){ - w.walk(expr); - }); - } catch(ex) { - if (ex === has_call) - return true; - throw ex; - } - }) + args ]); - }, - "switch": function(expr, body) { - return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); - }, - "break": function(label) { - var out = "break"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "continue": function(label) { - var out = "continue"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "conditional": function(co, th, el) { - return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", - parenthesize(th, "seq"), ":", - parenthesize(el, "seq") ]); - }, - "assign": function(op, lvalue, rvalue) { - if (op && op !== true) op += "="; - else op = "="; - return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); - }, - "dot": function(expr) { - var out = make(expr), i = 1; - if (expr[0] == "num") { - if (!/\./.test(expr[1])) - out += "."; - } else if (needs_parens(expr)) - out = "(" + out + ")"; - while (i < arguments.length) - out += "." + make_name(arguments[i++]); - return out; - }, - "call": function(func, args) { - var f = make(func); - if (needs_parens(func)) - f = "(" + f + ")"; - return f + "(" + add_commas(MAP(args, function(expr){ - return parenthesize(expr, "seq"); - })) + ")"; - }, - "function": make_function, - "defun": make_function, - "if": function(co, th, el) { - var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; - if (el) { - out.push("else", make(el)); - } - return add_spaces(out); - }, - "for": function(init, cond, step, block) { - var out = [ "for" ]; - init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); - cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); - step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); - var args = init + cond + step; - if (args == "; ; ") args = ";;"; - out.push("(" + args + ")", make(block)); - return add_spaces(out); - }, - "for-in": function(vvar, key, hash, block) { - return add_spaces([ "for", "(" + - (vvar ? make(vvar).replace(/;+$/, "") : make(key)), - "in", - make(hash) + ")", make(block) ]); - }, - "while": function(condition, block) { - return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); - }, - "do": function(condition, block) { - return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; - }, - "return": function(expr) { - var out = [ "return" ]; - if (expr != null) out.push(make(expr)); - return add_spaces(out) + ";"; - }, - "binary": function(operator, lvalue, rvalue) { - var left = make(lvalue), right = make(rvalue); - // XXX: I'm pretty sure other cases will bite here. - // we need to be smarter. - // adding parens all the time is the safest bet. - if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || - lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { - left = "(" + left + ")"; - } - if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && - !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { - right = "(" + right + ")"; - } - else if (!beautify && options.inline_script && (operator == "<" || operator == "<<") - && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) { - right = " " + right; - } - return add_spaces([ left, operator, right ]); - }, - "unary-prefix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return operator + (is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; - }, - "unary-postfix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return val + operator; - }, - "sub": function(expr, subscript) { - var hash = make(expr); - if (needs_parens(expr)) - hash = "(" + hash + ")"; - return hash + "[" + make(subscript) + "]"; - }, - "object": function(props) { - if (props.length == 0) - return "{}"; - return "{" + newline + with_indent(function(){ - return MAP(props, function(p){ - if (p.length == 3) { - // getter/setter. The name is in p[0], the arg.list in p[1][2], the - // body in p[1][3] and type ("get" / "set") in p[2]. - return indent(make_function(p[0], p[1][2], p[1][3], p[2])); - } - var key = p[0], val = parenthesize(p[1], "seq"); - if (options.quote_keys) { - key = encode_string(key); - } else if ((typeof key == "number" || !beautify && +key + "" == key) - && parseFloat(key) >= 0) { - key = make_num(+key); - } else if (!is_identifier(key)) { - key = encode_string(key); - } - return indent(add_spaces(beautify && options.space_colon - ? [ key, ":", val ] - : [ key + ":", val ])); - }).join("," + newline); - }) + newline + indent("}"); - }, - "regexp": function(rx, mods) { - return "/" + rx + "/" + mods; - }, - "array": function(elements) { - if (elements.length == 0) return "[]"; - return add_spaces([ "[", add_commas(MAP(elements, function(el){ - if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; - return parenthesize(el, "seq"); - })), "]" ]); - }, - "stat": function(stmt) { - return make(stmt).replace(/;*\s*$/, ";"); - }, - "seq": function() { - return add_commas(MAP(slice(arguments), make)); - }, - "label": function(name, block) { - return add_spaces([ make_name(name), ":", make(block) ]); - }, - "with": function(expr, block) { - return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); - }, - "atom": function(name) { - return make_name(name); - } - }; - - // The squeezer replaces "block"-s that contain only a single - // statement with the statement itself; technically, the AST - // is correct, but this can create problems when we output an - // IF having an ELSE clause where the THEN clause ends in an - // IF *without* an ELSE block (then the outer ELSE would refer - // to the inner IF). This function checks for this case and - // adds the block brackets if needed. - function make_then(th) { - if (th[0] == "do") { - // https://github.com/mishoo/UglifyJS/issues/#issue/57 - // IE croaks with "syntax error" on code like this: - // if (foo) do ... while(cond); else ... - // we need block brackets around do/while - return make([ "block", [ th ]]); - } - var b = th; - while (true) { - var type = b[0]; - if (type == "if") { - if (!b[3]) - // no else, we must add the block - return make([ "block", [ th ]]); - b = b[3]; - } - else if (type == "while" || type == "do") b = b[2]; - else if (type == "for" || type == "for-in") b = b[4]; - else break; - } - return make(th); - }; - - function make_function(name, args, body, keyword) { - var out = keyword || "function"; - if (name) { - out += " " + make_name(name); - } - out += "(" + add_commas(MAP(args, make_name)) + ")"; - return add_spaces([ out, make_block(body) ]); - }; - - function make_block_statements(statements, noindent) { - for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { - var stat = statements[i]; - var code = make(stat); - if (code != ";") { - if (!beautify && i == last) { - if ((stat[0] == "while" && empty(stat[2])) || - (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || - (stat[0] == "if" && empty(stat[2]) && !stat[3]) || - (stat[0] == "if" && stat[3] && empty(stat[3]))) { - code = code.replace(/;*\s*$/, ";"); - } else { - code = code.replace(/;+\s*$/, ""); - } - } - a.push(code); - } - } - return noindent ? a : MAP(a, indent); - }; - - function make_switch_block(body) { - var n = body.length; - if (n == 0) return "{}"; - return "{" + newline + MAP(body, function(branch, i){ - var has_body = branch[1].length > 0, code = with_indent(function(){ - return indent(branch[0] - ? add_spaces([ "case", make(branch[0]) + ":" ]) - : "default:"); - }, 0.5) + (has_body ? newline + with_indent(function(){ - return make_block_statements(branch[1]).join(newline); - }) : ""); - if (!beautify && has_body && i < n - 1) - code += ";"; - return code; - }).join(newline) + newline + indent("}"); - }; - - function make_block(statements) { - if (!statements) return ";"; - if (statements.length == 0) return "{}"; - return "{" + newline + with_indent(function(){ - return make_block_statements(statements).join(newline); - }) + newline + indent("}"); - }; - - function make_1vardef(def) { - var name = def[0], val = def[1]; - if (val != null) - name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); - return name; - }; - - var $stack = []; - - function make(node) { - var type = node[0]; - var gen = generators[type]; - if (!gen) - throw new Error("Can't find generator for \"" + type + "\""); - $stack.push(node); - var ret = gen.apply(type, node.slice(1)); - $stack.pop(); - return ret; - }; - - return make(ast); -}; - -/* -----[ Utilities ]----- */ - -function repeat_string(str, i) { - return i < 1 ? "" : new Array(i + 1).join(str); -}; - -function defaults(args, defs) { - var ret = {}; - if (args === true) - args = {}; - for (var i in defs) if (HOP(defs, i)) { - ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; - } - return ret; -}; - -function is_identifier(name) { - return /^[a-z_$][a-z0-9_$]*$/i.test(name) - && name != "this" - && !HOP(KEYWORDS_ATOM, name) - && !HOP(RESERVED_WORDS, name) - && !HOP(KEYWORDS, name); -}; - -function MAP(a, f, o) { - var ret = []; - for (var i = 0; i < a.length; ++i) { - ret.push(f.call(o, a[i], i)); - } - return ret; -}; - -/* -----[ Exports ]----- */ - -return { - parse: parse, - gen_code: gen_code, - tokenizer: tokenizer, - ast_walker: ast_walker -}; - -}; diff --git a/lib/parse-js.js b/lib/parse-js.js deleted file mode 100644 index 749b715b..00000000 --- a/lib/parse-js.js +++ /dev/null @@ -1,1916 +0,0 @@ -/** - * A JavaScript tokenizer / parser / generator, originally written in Lisp. - * Copyright (c) Marijn Haverbeke - * http://marijn.haverbeke.nl/parse-js/ - * - * Ported by to JavaScript by Mihai Bazon - * Copyright (c) 2010, Mihai Bazon - * http://mihai.bazon.net/blog/ - * - * Modifications and adaptions to browser (c) 2011, Juerg Lehni - * http://lehni.org/ - * - * Distributed under the BSD license. - */ - -var parse_js = new function() { - -/* -----[ Tokenizer (constants) ]----- */ - -var KEYWORDS = array_to_hash([ - "break", - "case", - "catch", - "const", - "continue", - "default", - "delete", - "do", - "else", - "finally", - "for", - "function", - "if", - "in", - "instanceof", - "new", - "return", - "switch", - "throw", - "try", - "typeof", - "var", - "void", - "while", - "with" -]); - -var RESERVED_WORDS = array_to_hash([ - "abstract", - "boolean", - "byte", - "char", - "class", - "debugger", - "double", - "enum", - "export", - "extends", - "final", - "float", - "goto", - "implements", - "import", - "int", - "interface", - "long", - "native", - "package", - "private", - "protected", - "public", - "short", - "static", - "super", - "synchronized", - "throws", - "transient", - "volatile" -]); - -var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ - "return", - "new", - "delete", - "throw", - "else", - "case" -]); - -var KEYWORDS_ATOM = array_to_hash([ - "false", - "null", - "true", - "undefined" -]); - -var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); - -var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; -var RE_OCT_NUMBER = /^0[0-7]+$/; -var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - -var OPERATORS = array_to_hash([ - "in", - "instanceof", - "typeof", - "new", - "void", - "delete", - "++", - "--", - "+", - "-", - "!", - "~", - "&", - "|", - "^", - "*", - "/", - "%", - ">>", - "<<", - ">>>", - "<", - ">", - "<=", - ">=", - "==", - "===", - "!=", - "!==", - "?", - "=", - "+=", - "-=", - "/=", - "*=", - "%=", - ">>=", - "<<=", - ">>>=", - "|=", - "^=", - "&=", - "&&", - "||" -]); - -var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t")); - -var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); - -var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); - -var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); - -/* -----[ Tokenizer ]----- */ - -function is_letter(ch) { - ch = ch.charCodeAt(0); - return (ch >= 65 && ch <= 90) || - (ch >= 97 && ch <= 122); -}; - -function is_digit(ch) { - ch = ch.charCodeAt(0); - return ch >= 48 && ch <= 57; -}; - -function is_alphanumeric_char(ch) { - return is_digit(ch) || is_letter(ch); -}; - -function is_identifier_start(ch) { - return ch == "$" || ch == "_" || is_letter(ch); -}; - -function is_identifier_char(ch) { - return is_identifier_start(ch) || is_digit(ch); -}; - -function parse_js_number(num) { - if (RE_HEX_NUMBER.test(num)) { - return parseInt(num.substr(2), 16); - } else if (RE_OCT_NUMBER.test(num)) { - return parseInt(num.substr(1), 8); - } else if (RE_DEC_NUMBER.test(num)) { - return parseFloat(num); - } -}; - -function JS_Parse_Error(message, line, col, pos) { - this.message = message; - this.line = line; - this.col = col; - this.pos = pos; -}; - -JS_Parse_Error.prototype.toString = function() { - return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")"; -}; - -function js_error(message, line, col, pos) { - throw new JS_Parse_Error(message, line, col, pos); -}; - -function is_token(token, type, val) { - return token.type == type && (val == null || token.value == val); -}; - -var EX_EOF = {}; - -function tokenizer($TEXT) { - - var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false, - comments_before : [] - }; - - function peek() { return S.text.charAt(S.pos); }; - - function next(signal_eof) { - var ch = S.text.charAt(S.pos++); - if (signal_eof && !ch) - throw EX_EOF; - if (ch == "\n") { - S.newline_before = true; - ++S.line; - S.col = 0; - } else { - ++S.col; - } - return ch; - }; - - function eof() { - return !S.peek(); - }; - - function find(what, signal_eof) { - var pos = S.text.indexOf(what, S.pos); - if (signal_eof && pos == -1) throw EX_EOF; - return pos; - }; - - function start_token() { - S.tokline = S.line; - S.tokcol = S.col; - S.tokpos = S.pos; - }; - - function token(type, value, is_comment) { - S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || - (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || - (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); - var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - nlb : S.newline_before - }; - if (!is_comment) { - ret.comments_before = S.comments_before; - S.comments_before = []; - } - S.newline_before = false; - return ret; - }; - - function skip_whitespace() { - while (HOP(WHITESPACE_CHARS, peek())) - next(); - }; - - function read_while(pred) { - var ret = "", ch = peek(), i = 0; - while (ch && pred(ch, i++)) { - ret += next(); - ch = peek(); - } - return ret; - }; - - function parse_error(err) { - js_error(err, S.tokline, S.tokcol, S.tokpos); - }; - - function read_num(prefix) { - var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; - var num = read_while(function(ch, i){ - if (ch == "x" || ch == "X") { - if (has_x) return false; - return has_x = true; - } - if (!has_x && (ch == "E" || ch == "e")) { - if (has_e) return false; - return has_e = after_e = true; - } - if (ch == "-") { - if (after_e || (i == 0 && !prefix)) return true; - return false; - } - if (ch == "+") return after_e; - after_e = false; - if (ch == ".") { - if (!has_dot && !has_x) - return has_dot = true; - return false; - } - return is_alphanumeric_char(ch); - }); - if (prefix) - num = prefix + num; - var valid = parse_js_number(num); - if (!isNaN(valid)) { - return token("num", valid); - } else { - parse_error("Invalid syntax: " + num); - } - }; - - function read_escaped_char() { - var ch = next(true); - switch (ch) { - case "n" : return "\n"; - case "r" : return "\r"; - case "t" : return "\t"; - case "b" : return "\b"; - case "v" : return "\v"; - case "f" : return "\f"; - case "0" : return "\0"; - case "x" : return String.fromCharCode(hex_bytes(2)); - case "u" : return String.fromCharCode(hex_bytes(4)); - case "\n": return ""; - default : return ch; - } - }; - - function hex_bytes(n) { - var num = 0; - for (; n > 0; --n) { - var digit = parseInt(next(true), 16); - if (isNaN(digit)) - parse_error("Invalid hex-character pattern in string"); - num = (num << 4) | digit; - } - return num; - }; - - function read_string() { - return with_eof_error("Unterminated string constant", function(){ - var quote = next(), ret = ""; - for (;;) { - var ch = next(true); - if (ch == "\\") ch = read_escaped_char(); - else if (ch == quote) break; - ret += ch; - } - return token("string", ret); - }); - }; - - function read_line_comment() { - next(); - var i = find("\n"), ret; - if (i == -1) { - ret = S.text.substr(S.pos); - S.pos = S.text.length; - } else { - ret = S.text.substring(S.pos, i); - S.pos = i; - } - return token("comment1", ret, true); - }; - - function read_multiline_comment() { - next(); - return with_eof_error("Unterminated multiline comment", function(){ - var i = find("*/", true), - text = S.text.substring(S.pos, i), - tok = token("comment2", text, true); - S.pos = i + 2; - S.line += text.split("\n").length - 1; - S.newline_before = text.indexOf("\n") >= 0; - return tok; - }); - }; - - function read_regexp() { - return with_eof_error("Unterminated regular expression", function(){ - var prev_backslash = false, regexp = "", ch, in_class = false; - while ((ch = next(true))) if (prev_backslash) { - regexp += "\\" + ch; - prev_backslash = false; - } else if (ch == "[") { - in_class = true; - regexp += ch; - } else if (ch == "]" && in_class) { - in_class = false; - regexp += ch; - } else if (ch == "/" && !in_class) { - break; - } else if (ch == "\\") { - prev_backslash = true; - } else { - regexp += ch; - } - var mods = read_while(function(ch){ - return HOP(REGEXP_MODIFIERS, ch); - }); - return token("regexp", [ regexp, mods ]); - }); - }; - - function read_operator(prefix) { - function grow(op) { - if (!peek()) return op; - var bigger = op + peek(); - if (HOP(OPERATORS, bigger)) { - next(); - return grow(bigger); - } else { - return op; - } - }; - return token("operator", grow(prefix || next())); - }; - - function handle_slash() { - next(); - var regex_allowed = S.regex_allowed; - switch (peek()) { - case "/": - S.comments_before.push(read_line_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - case "*": - S.comments_before.push(read_multiline_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - } - return S.regex_allowed ? read_regexp() : read_operator("/"); - }; - - function handle_dot() { - next(); - return is_digit(peek()) - ? read_num(".") - : token("punc", "."); - }; - - function read_word() { - var word = read_while(is_identifier_char); - return !HOP(KEYWORDS, word) - ? token("name", word) - : HOP(OPERATORS, word) - ? token("operator", word) - : HOP(KEYWORDS_ATOM, word) - ? token("atom", word) - : token("keyword", word); - }; - - function with_eof_error(eof_error, cont) { - try { - return cont(); - } catch(ex) { - if (ex === EX_EOF) parse_error(eof_error); - else throw ex; - } - }; - - function next_token(force_regexp) { - if (force_regexp) - return read_regexp(); - skip_whitespace(); - start_token(); - var ch = peek(); - if (!ch) return token("eof"); - if (is_digit(ch)) return read_num(); - if (ch == '"' || ch == "'") return read_string(); - if (HOP(PUNC_CHARS, ch)) return token("punc", next()); - if (ch == ".") return handle_dot(); - if (ch == "/") return handle_slash(); - if (HOP(OPERATOR_CHARS, ch)) return read_operator(); - if (ch == "\\" || is_identifier_start(ch)) return read_word(); - parse_error("Unexpected character '" + ch + "'"); - }; - - next_token.context = function(nc) { - if (nc) S = nc; - return S; - }; - - return next_token; - -}; - -/* -----[ Parser (constants) ]----- */ - -var UNARY_PREFIX = array_to_hash([ - "typeof", - "void", - "delete", - "--", - "++", - "!", - "~", - "-", - "+" -]); - -var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); - -var ASSIGNMENT = (function(a, ret, i){ - while (i < a.length) { - ret[a[i]] = a[i].substr(0, a[i].length - 1); - i++; - } - return ret; -})( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], - { "=": true }, - 0 -); - -var PRECEDENCE = (function(a, ret){ - for (var i = 0, n = 1; i < a.length; ++i, ++n) { - var b = a[i]; - for (var j = 0; j < b.length; ++j) { - ret[b[j]] = n; - } - } - return ret; -})( - [ - ["||"], - ["&&"], - ["|"], - ["^"], - ["&"], - ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], - [">>", "<<", ">>>"], - ["+", "-"], - ["*", "/", "%"] - ], - {} -); - -var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); - -var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); - -/* -----[ Parser ]----- */ - -function NodeWithToken(str, start, end) { - this.name = str; - this.start = start; - this.end = end; -}; - -NodeWithToken.prototype.toString = function() { return this.name; }; - -function parse($TEXT, exigent_mode, embed_tokens) { - - var S = { - input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, - token : null, - prev : null, - peeked : null, - in_function : 0, - in_loop : 0, - labels : [] - }; - - S.token = next(); - - function is(type, value) { - return is_token(S.token, type, value); - }; - - function peek() { return S.peeked || (S.peeked = S.input()); }; - - function next() { - S.prev = S.token; - if (S.peeked) { - S.token = S.peeked; - S.peeked = null; - } else { - S.token = S.input(); - } - return S.token; - }; - - function prev() { - return S.prev; - }; - - function croak(msg, line, col, pos) { - var ctx = S.input.context(); - js_error(msg, - line != null ? line : ctx.tokline, - col != null ? col : ctx.tokcol, - pos != null ? pos : ctx.tokpos); - }; - - function token_error(token, msg) { - croak(msg, token.line, token.col); - }; - - function unexpected(token) { - if (token == null) - token = S.token; - token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); - }; - - function expect_token(type, val) { - if (is(type, val)) { - return next(); - } - token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); - }; - - function expect(punc) { return expect_token("punc", punc); }; - - function can_insert_semicolon() { - return !exigent_mode && ( - S.token.nlb || is("eof") || is("punc", "}") - ); - }; - - function semicolon() { - if (is("punc", ";")) next(); - else if (!can_insert_semicolon()) unexpected(); - }; - - function as() { - return slice(arguments); - }; - - function parenthesised() { - expect("("); - var ex = expression(); - expect(")"); - return ex; - }; - - function add_tokens(str, start, end) { - return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); - }; - - function maybe_embed_tokens(parser) { - if (embed_tokens) return function() { - var start = S.token; - var ast = parser.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - }; - else return parser; - }; - - var statement = maybe_embed_tokens(function() { - if (is("operator", "/")) { - S.peeked = null; - S.token = S.input(true); // force regexp - } - switch (S.token.type) { - case "num": - case "string": - case "regexp": - case "operator": - case "atom": - return simple_statement(); - - case "name": - return is_token(peek(), "punc", ":") - ? labeled_statement(prog1(S.token.value, next, next)) - : simple_statement(); - - case "punc": - switch (S.token.value) { - case "{": - return as("block", block_()); - case "[": - case "(": - return simple_statement(); - case ";": - next(); - return as("block"); - default: - unexpected(); - } - - case "keyword": - switch (prog1(S.token.value, next)) { - case "break": - return break_cont("break"); - - case "continue": - return break_cont("continue"); - - case "debugger": - semicolon(); - return as("debugger"); - - case "do": - return (function(body){ - expect_token("keyword", "while"); - return as("do", prog1(parenthesised, semicolon), body); - })(in_loop(statement)); - - case "for": - return for_(); - - case "function": - return function_(true); - - case "if": - return if_(); - - case "return": - if (S.in_function == 0) - croak("'return' outside of function"); - return as("return", - is("punc", ";") - ? (next(), null) - : can_insert_semicolon() - ? null - : prog1(expression, semicolon)); - - case "switch": - return as("switch", parenthesised(), switch_block_()); - - case "throw": - return as("throw", prog1(expression, semicolon)); - - case "try": - return try_(); - - case "var": - return prog1(var_, semicolon); - - case "const": - return prog1(const_, semicolon); - - case "while": - return as("while", parenthesised(), in_loop(statement)); - - case "with": - return as("with", parenthesised(), statement()); - - default: - unexpected(); - } - } - }); - - function labeled_statement(label) { - S.labels.push(label); - var start = S.token, stat = statement(); - if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) - unexpected(start); - S.labels.pop(); - return as("label", label, stat); - }; - - function simple_statement() { - return as("stat", prog1(expression, semicolon)); - }; - - function break_cont(type) { - var name; - if (!can_insert_semicolon()) { - name = is("name") ? S.token.value : null; - } - if (name != null) { - next(); - if (!member(name, S.labels)) - croak("Label " + name + " without matching loop or statement"); - } - else if (S.in_loop == 0) - croak(type + " not inside a loop or switch"); - semicolon(); - return as(type, name); - }; - - function for_() { - expect("("); - var init = null; - if (!is("punc", ";")) { - init = is("keyword", "var") - ? (next(), var_(true)) - : expression(true, true); - if (is("operator", "in")) - return for_in(init); - } - return regular_for(init); - }; - - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(); - expect(";"); - var step = is("punc", ")") ? null : expression(); - expect(")"); - return as("for", init, test, step, in_loop(statement)); - }; - - function for_in(init) { - var lhs = init[0] == "var" ? as("name", init[1][0]) : init; - next(); - var obj = expression(); - expect(")"); - return as("for-in", init, lhs, obj, in_loop(statement)); - }; - - var function_ = maybe_embed_tokens(function(in_statement) { - var name = is("name") ? prog1(S.token.value, next) : null; - if (in_statement && !name) - unexpected(); - expect("("); - return as(in_statement ? "defun" : "function", - name, - // arguments - (function(first, a){ - while (!is("punc", ")")) { - if (first) first = false; else expect(","); - if (!is("name")) unexpected(); - a.push(S.token.value); - next(); - } - next(); - return a; - })(true, []), - // body - (function(){ - ++S.in_function; - var loop = S.in_loop; - S.in_loop = 0; - var a = block_(); - --S.in_function; - S.in_loop = loop; - return a; - })()); - }); - - function if_() { - var cond = parenthesised(), body = statement(), belse; - if (is("keyword", "else")) { - next(); - belse = statement(); - } - return as("if", cond, body, belse); - }; - - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } - next(); - return a; - }; - - var switch_block_ = curry(in_loop, function(){ - expect("{"); - var a = [], cur = null; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - next(); - cur = []; - a.push([ expression(), cur ]); - expect(":"); - } - else if (is("keyword", "default")) { - next(); - expect(":"); - cur = []; - a.push([ null, cur ]); - } - else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - next(); - return a; - }); - - function try_() { - var body = block_(), bcatch, bfinally; - if (is("keyword", "catch")) { - next(); - expect("("); - if (!is("name")) - croak("Name expected"); - var name = S.token.value; - next(); - expect(")"); - bcatch = [ name, block_() ]; - } - if (is("keyword", "finally")) { - next(); - bfinally = block_(); - } - if (!bcatch && !bfinally) - croak("Missing catch/finally blocks"); - return as("try", body, bcatch, bfinally); - }; - - function vardefs(no_in) { - var a = []; - for (;;) { - if (!is("name")) - unexpected(); - var name = S.token.value; - next(); - if (is("operator", "=")) { - next(); - a.push([ name, expression(false, no_in) ]); - } else { - a.push([ name ]); - } - if (!is("punc", ",")) - break; - next(); - } - return a; - }; - - function var_(no_in) { - return as("var", vardefs(no_in)); - }; - - function const_() { - return as("const", vardefs()); - }; - - function new_() { - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")"); - } else { - args = []; - } - return subscripts(as("new", newexp, args), true); - }; - - var expr_atom = maybe_embed_tokens(function(allow_calls) { - if (is("operator", "new")) { - next(); - return new_(); - } - if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { - return make_unary("unary-prefix", - prog1(S.token.value, next), - expr_atom(allow_calls)); - } - if (is("punc")) { - switch (S.token.value) { - case "(": - next(); - return subscripts(prog1(expression, curry(expect, ")")), allow_calls); - case "[": - next(); - return subscripts(array_(), allow_calls); - case "{": - next(); - return subscripts(object_(), allow_calls); - } - unexpected(); - } - if (is("keyword", "function")) { - next(); - return subscripts(function_(false), allow_calls); - } - if (HOP(ATOMIC_START_TOKEN, S.token.type)) { - var atom = S.token.type == "regexp" - ? as("regexp", S.token.value[0], S.token.value[1]) - : as(S.token.type, S.token.value); - return subscripts(prog1(atom, next), allow_calls); - } - unexpected(); - }); - - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push([ "atom", "undefined" ]); - } else { - a.push(expression(false)); - } - } - next(); - return a; - }; - - function array_() { - return as("array", expr_list("]", !exigent_mode, true)); - }; - - function object_() { - var first = true, a = []; - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!exigent_mode && is("punc", "}")) - // allow trailing comma - break; - var type = S.token.type; - var name = as_property_name(); - if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { - a.push([ as_name(), function_(false), name ]); - } else { - expect(":"); - a.push([ name, expression(false) ]); - } - } - next(); - return as("object", a); - }; - - function as_property_name() { - switch (S.token.type) { - case "num": - case "string": - return prog1(S.token.value, next); - } - return as_name(); - }; - - function as_name() { - switch (S.token.type) { - case "name": - case "operator": - case "keyword": - case "atom": - return prog1(S.token.value, next); - default: - unexpected(); - } - }; - - function subscripts(expr, allow_calls) { - if (is("punc", ".")) { - next(); - return subscripts(as("dot", expr, as_name()), allow_calls); - } - if (is("punc", "[")) { - next(); - return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - return subscripts(as("call", expr, expr_list(")")), true); - } - if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { - return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), - next); - } - return expr; - }; - - function make_unary(tag, op, expr) { - if ((op == "++" || op == "--") && !is_assignable(expr)) - croak("Invalid use of " + op + " operator"); - return as(tag, op, expr); - }; - - function expr_op(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op && op == "in" && no_in) op = null; - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && prec > min_prec) { - next(); - var right = expr_op(expr_atom(true), prec, no_in); - return expr_op(as("binary", op, left, right), min_prec, no_in); - } - return left; - }; - - function expr_ops(no_in) { - return expr_op(expr_atom(true), 0, no_in); - }; - - function maybe_conditional(no_in) { - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return as("conditional", expr, yes, expression(false, no_in)); - } - return expr; - }; - - function is_assignable(expr) { - if (!exigent_mode) return true; - switch (expr[0]) { - case "dot": - case "sub": - case "new": - case "call": - return true; - case "name": - return expr[1] != "this"; - } - }; - - function maybe_assign(no_in) { - var left = maybe_conditional(no_in), val = S.token.value; - if (is("operator") && HOP(ASSIGNMENT, val)) { - if (is_assignable(left)) { - next(); - return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); - } - croak("Invalid assignment"); - } - return left; - }; - - var expression = maybe_embed_tokens(function(commas, no_in) { - if (arguments.length == 0) - commas = true; - var expr = maybe_assign(no_in); - if (commas && is("punc", ",")) { - next(); - return as("seq", expr, expression(true, no_in)); - } - return expr; - }); - - function in_loop(cont) { - try { - ++S.in_loop; - return cont(); - } finally { - --S.in_loop; - } - }; - - return as("toplevel", (function(a){ - while (!is("eof")) - a.push(statement()); - return a; - })([])); - -}; - -/* -----[ Utilities ]----- */ - -function curry(f) { - var args = slice(arguments, 1); - return function() { return f.apply(this, args.concat(slice(arguments))); }; -}; - -function prog1(ret) { - if (ret instanceof Function) - ret = ret(); - for (var i = 1, n = arguments.length; --n > 0; ++i) - arguments[i](); - return ret; -}; - -function array_to_hash(a) { - var ret = {}; - for (var i = 0; i < a.length; ++i) - ret[a[i]] = true; - return ret; -}; - -function slice(a, start) { - return Array.prototype.slice.call(a, start || 0); -}; - -function characters(str) { - return str.split(""); -}; - -function member(name, array) { - for (var i = array.length; --i >= 0;) - if (array[i] === name) - return true; - return false; -}; - -function HOP(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -}; - -/* -----[ helper for AST traversal ]----- */ - -function ast_walker() { - function _vardefs(defs) { - return [ this[0], MAP(defs, function(def){ - var a = [ def[0] ]; - if (def.length > 1) - a[1] = walk(def[1]); - return a; - }) ]; - }; - function _block(statements) { - var out = [ this[0] ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; - }; - var walkers = { - "string": function(str) { - return [ this[0], str ]; - }, - "num": function(num) { - return [ this[0], num ]; - }, - "name": function(name) { - return [ this[0], name ]; - }, - "toplevel": function(statements) { - return [ this[0], MAP(statements, walk) ]; - }, - "block": _block, - "splice": _block, - "var": _vardefs, - "const": _vardefs, - "try": function(t, c, f) { - return [ - this[0], - MAP(t, walk), - c != null ? [ c[0], MAP(c[1], walk) ] : null, - f != null ? MAP(f, walk) : null - ]; - }, - "throw": function(expr) { - return [ this[0], walk(expr) ]; - }, - "new": function(ctor, args) { - return [ this[0], walk(ctor), MAP(args, walk) ]; - }, - "switch": function(expr, body) { - return [ this[0], walk(expr), MAP(body, function(branch){ - return [ branch[0] ? walk(branch[0]) : null, - MAP(branch[1], walk) ]; - }) ]; - }, - "break": function(label) { - return [ this[0], label ]; - }, - "continue": function(label) { - return [ this[0], label ]; - }, - "conditional": function(cond, t, e) { - return [ this[0], walk(cond), walk(t), walk(e) ]; - }, - "assign": function(op, lvalue, rvalue) { - return [ this[0], op, walk(lvalue), walk(rvalue) ]; - }, - "dot": function(expr) { - return [ this[0], walk(expr) ].concat(slice(arguments, 1)); - }, - "call": function(expr, args) { - return [ this[0], walk(expr), MAP(args, walk) ]; - }, - "function": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "defun": function(name, args, body) { - return [ this[0], name, args.slice(), MAP(body, walk) ]; - }, - "if": function(conditional, t, e) { - return [ this[0], walk(conditional), walk(t), walk(e) ]; - }, - "for": function(init, cond, step, block) { - return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; - }, - "for-in": function(vvar, key, hash, block) { - return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; - }, - "while": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "do": function(cond, block) { - return [ this[0], walk(cond), walk(block) ]; - }, - "return": function(expr) { - return [ this[0], walk(expr) ]; - }, - "binary": function(op, left, right) { - return [ this[0], op, walk(left), walk(right) ]; - }, - "unary-prefix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "unary-postfix": function(op, expr) { - return [ this[0], op, walk(expr) ]; - }, - "sub": function(expr, subscript) { - return [ this[0], walk(expr), walk(subscript) ]; - }, - "object": function(props) { - return [ this[0], MAP(props, function(p){ - return p.length == 2 - ? [ p[0], walk(p[1]) ] - : [ p[0], walk(p[1]), p[2] ]; // get/set-ter - }) ]; - }, - "regexp": function(rx, mods) { - return [ this[0], rx, mods ]; - }, - "array": function(elements) { - return [ this[0], MAP(elements, walk) ]; - }, - "stat": function(stat) { - return [ this[0], walk(stat) ]; - }, - "seq": function() { - return [ this[0] ].concat(MAP(slice(arguments), walk)); - }, - "label": function(name, block) { - return [ this[0], name, walk(block) ]; - }, - "with": function(expr, block) { - return [ this[0], walk(expr), walk(block) ]; - }, - "atom": function(name) { - return [ this[0], name ]; - } - }; - - var user = {}; - var stack = []; - function walk(ast) { - if (ast == null) - return null; - try { - stack.push(ast); - var type = ast[0]; - var gen = user[type]; - if (gen) { - var ret = gen.apply(ast, ast.slice(1)); - if (ret != null) - return ret; - } - gen = walkers[type]; - return gen.apply(ast, ast.slice(1)); - } finally { - stack.pop(); - } - }; - - function with_walkers(walkers, cont){ - var save = {}, i; - for (i in walkers) if (HOP(walkers, i)) { - save[i] = user[i]; - user[i] = walkers[i]; - } - var ret = cont(); - for (i in save) if (HOP(save, i)) { - if (!save[i]) delete user[i]; - else user[i] = save[i]; - } - return ret; - }; - - return { - walk: walk, - with_walkers: with_walkers, - parent: function() { - return stack[stack.length - 2]; // last one is current node - }, - stack: function() { - return stack; - } - }; -}; - -function empty(b) { - return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); -}; - -/* -----[ re-generate code from the AST ]----- */ - -var DOT_CALL_NO_PARENS = array_to_hash([ - "name", - "array", - "object", - "string", - "dot", - "sub", - "call", - "regexp" -]); - -function make_string(str) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){ - switch (s) { - case "\\": return "\\\\"; - case "\b": return "\\b"; - case "\f": return "\\f"; - case "\n": return "\\n"; - case "\r": return "\\r"; - case "\t": return "\\t"; - case '"': ++dq; return '"'; - case "'": ++sq; return "'"; - } - return s; - }); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; - else return '"' + str.replace(/\x22/g, '\\"') + '"'; -}; - -var SPLICE_NEEDS_BRACKETS = array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); - -function gen_code(ast, options) { - options = defaults(options, { - indent_start : 0, - indent_level : 4, - quote_keys : false, - space_colon : false, - beautify : false - }); - var beautify = !!options.beautify; - var indentation = 0, - newline = beautify ? "\n" : "", - space = beautify ? " " : ""; - - function make_name(name) { - return name.toString(); - }; - - function indent(line) { - if (line == null) - line = ""; - if (beautify) - line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; - return line; - }; - - function with_indent(cont, incr) { - if (incr == null) incr = 1; - indentation += incr; - try { return cont.apply(null, slice(arguments, 1)); } - finally { indentation -= incr; } - }; - - function add_spaces(a) { - if (beautify) - return a.join(" "); - var b = []; - for (var i = 0; i < a.length; ++i) { - var next = a[i + 1]; - b.push(a[i]); - if (next && - ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || - (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { - b.push(" "); - } - } - return b.join(""); - }; - - function add_commas(a) { - return a.join("," + space); - }; - - function parenthesize(expr) { - var gen = make(expr); - for (var i = 1; i < arguments.length; ++i) { - var el = arguments[i]; - if ((el instanceof Function && el(expr)) || expr[0] == el) - return "(" + gen + ")"; - } - return gen; - }; - - function best_of(a) { - if (a.length == 1) { - return a[0]; - } - if (a.length == 2) { - var b = a[1]; - a = a[0]; - return a.length <= b.length ? a : b; - } - return best_of([ a[0], best_of(a.slice(1)) ]); - }; - - function needs_parens(expr) { - if (expr[0] == "function" || expr[0] == "object") { - // dot/call on a literal function requires the - // function literal itself to be parenthesized - // only if it's the first "thing" in a - // statement. This means that the parent is - // "stat", but it could also be a "seq" and - // we're the first in this "seq" and the - // parent is "stat", and so on. Messy stuff, - // but it worths the trouble. - var a = slice($stack), self = a.pop(), p = a.pop(); - while (p) { - if (p[0] == "stat") return true; - if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || - ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { - self = p; - p = a.pop(); - } else { - return false; - } - } - } - return !HOP(DOT_CALL_NO_PARENS, expr[0]); - }; - - function make_num(num) { - var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; - if (Math.floor(num) === num) { - a.push("0x" + num.toString(16).toLowerCase(), // probably pointless - "0" + num.toString(8)); // same. - if ((m = /^(.*?)(0+)$/.exec(num))) { - a.push(m[1] + "e" + m[2].length); - } - } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { - a.push(m[2] + "e-" + (m[1].length + m[2].length), - str.substr(str.indexOf("."))); - } - return best_of(a); - }; - - var generators = { - "string": make_string, - "num": make_num, - "name": make_name, - "toplevel": function(statements) { - return make_block_statements(statements) - .join(newline); - }, - "splice": function(statements) { - var parent = $stack[$stack.length - 2][0]; - if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { - // we need block brackets in this case - return make_block.apply(this, arguments); - } else { - return MAP(make_block_statements(statements, true), - function(line, i) { - // the first line is already indented - return i > 0 ? indent(line) : line; - }).join(newline); - } - }, - "block": make_block, - "var": function(defs) { - return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "const": function(defs) { - return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; - }, - "try": function(tr, ca, fi) { - var out = [ "try", make_block(tr) ]; - if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); - if (fi) out.push("finally", make_block(fi)); - return add_spaces(out); - }, - "throw": function(expr) { - return add_spaces([ "throw", make(expr) ]) + ";"; - }, - "new": function(ctor, args) { - args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; - return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ - var w = ast_walker(), has_call = {}; - try { - w.with_walkers({ - "call": function() { throw has_call }, - "function": function() { return this } - }, function(){ - w.walk(expr); - }); - } catch(ex) { - if (ex === has_call) - return true; - throw ex; - } - }) + args ]); - }, - "switch": function(expr, body) { - return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); - }, - "break": function(label) { - var out = "break"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "continue": function(label) { - var out = "continue"; - if (label != null) - out += " " + make_name(label); - return out + ";"; - }, - "conditional": function(co, th, el) { - return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", - parenthesize(th, "seq"), ":", - parenthesize(el, "seq") ]); - }, - "assign": function(op, lvalue, rvalue) { - if (op && op !== true) op += "="; - else op = "="; - return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); - }, - "dot": function(expr) { - var out = make(expr), i = 1; - if (expr[0] == "num") { - if (!/\./.test(expr[1])) - out += "."; - } else if (needs_parens(expr)) - out = "(" + out + ")"; - while (i < arguments.length) - out += "." + make_name(arguments[i++]); - return out; - }, - "call": function(func, args) { - var f = make(func); - if (needs_parens(func)) - f = "(" + f + ")"; - return f + "(" + add_commas(MAP(args, function(expr){ - return parenthesize(expr, "seq"); - })) + ")"; - }, - "function": make_function, - "defun": make_function, - "if": function(co, th, el) { - var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; - if (el) { - out.push("else", make(el)); - } - return add_spaces(out); - }, - "for": function(init, cond, step, block) { - var out = [ "for" ]; - init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); - cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); - step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); - var args = init + cond + step; - if (args == "; ; ") args = ";;"; - out.push("(" + args + ")", make(block)); - return add_spaces(out); - }, - "for-in": function(vvar, key, hash, block) { - return add_spaces([ "for", "(" + - (vvar ? make(vvar).replace(/;+$/, "") : make(key)), - "in", - make(hash) + ")", make(block) ]); - }, - "while": function(condition, block) { - return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); - }, - "do": function(condition, block) { - return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; - }, - "return": function(expr) { - var out = [ "return" ]; - if (expr != null) out.push(make(expr)); - return add_spaces(out) + ";"; - }, - "binary": function(operator, lvalue, rvalue) { - var left = make(lvalue), right = make(rvalue); - // XXX: I'm pretty sure other cases will bite here. - // we need to be smarter. - // adding parens all the time is the safest bet. - if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || - lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { - left = "(" + left + ")"; - } - if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && - !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { - right = "(" + right + ")"; - } - return add_spaces([ left, operator, right ]); - }, - "unary-prefix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return operator + (is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; - }, - "unary-postfix": function(operator, expr) { - var val = make(expr); - if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) - val = "(" + val + ")"; - return val + operator; - }, - "sub": function(expr, subscript) { - var hash = make(expr); - if (needs_parens(expr)) - hash = "(" + hash + ")"; - return hash + "[" + make(subscript) + "]"; - }, - "object": function(props) { - if (props.length == 0) - return "{}"; - return "{" + newline + with_indent(function(){ - return MAP(props, function(p){ - if (p.length == 3) { - // getter/setter. The name is in p[0], the arg.list in p[1][2], the - // body in p[1][3] and type ("get" / "set") in p[2]. - return indent(make_function(p[0], p[1][2], p[1][3], p[2])); - } - var key = p[0], val = make(p[1]); - if (options.quote_keys) { - key = make_string(key); - } else if ((typeof key == "number" || !beautify && +key + "" == key) - && parseFloat(key) >= 0) { - key = make_num(+key); - } else if (!is_identifier(key)) { - key = make_string(key); - } - return indent(add_spaces(beautify && options.space_colon - ? [ key, ":", val ] - : [ key + ":", val ])); - }).join("," + newline); - }) + newline + indent("}"); - }, - "regexp": function(rx, mods) { - return "/" + rx + "/" + mods; - }, - "array": function(elements) { - if (elements.length == 0) return "[]"; - return add_spaces([ "[", add_commas(MAP(elements, function(el){ - if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; - return parenthesize(el, "seq"); - })), "]" ]); - }, - "stat": function(stmt) { - return make(stmt).replace(/;*\s*$/, ";"); - }, - "seq": function() { - return add_commas(MAP(slice(arguments), make)); - }, - "label": function(name, block) { - return add_spaces([ make_name(name), ":", make(block) ]); - }, - "with": function(expr, block) { - return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); - }, - "atom": function(name) { - return make_name(name); - } - }; - - // The squeezer replaces "block"-s that contain only a single - // statement with the statement itself; technically, the AST - // is correct, but this can create problems when we output an - // IF having an ELSE clause where the THEN clause ends in an - // IF *without* an ELSE block (then the outer ELSE would refer - // to the inner IF). This function checks for this case and - // adds the block brackets if needed. - function make_then(th) { - if (th[0] == "do") { - // https://github.com/mishoo/UglifyJS/issues/#issue/57 - // IE croaks with "syntax error" on code like this: - // if (foo) do ... while(cond); else ... - // we need block brackets around do/while - return make([ "block", [ th ]]); - } - var b = th; - while (true) { - var type = b[0]; - if (type == "if") { - if (!b[3]) - // no else, we must add the block - return make([ "block", [ th ]]); - b = b[3]; - } - else if (type == "while" || type == "do") b = b[2]; - else if (type == "for" || type == "for-in") b = b[4]; - else break; - } - return make(th); - }; - - function make_function(name, args, body, keyword) { - var out = keyword || "function"; - if (name) { - out += " " + make_name(name); - } - out += "(" + add_commas(MAP(args, make_name)) + ")"; - return add_spaces([ out, make_block(body) ]); - }; - - function make_block_statements(statements, noindent) { - for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { - var stat = statements[i]; - var code = make(stat); - if (code != ";") { - if (!beautify && i == last) { - if ((stat[0] == "while" && empty(stat[2])) || - (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || - (stat[0] == "if" && empty(stat[2]) && !stat[3]) || - (stat[0] == "if" && stat[3] && empty(stat[3]))) { - code = code.replace(/;*\s*$/, ";"); - } else { - code = code.replace(/;+\s*$/, ""); - } - } - a.push(code); - } - } - return noindent ? a : MAP(a, indent); - }; - - function make_switch_block(body) { - var n = body.length; - if (n == 0) return "{}"; - return "{" + newline + MAP(body, function(branch, i){ - var has_body = branch[1].length > 0, code = with_indent(function(){ - return indent(branch[0] - ? add_spaces([ "case", make(branch[0]) + ":" ]) - : "default:"); - }, 0.5) + (has_body ? newline + with_indent(function(){ - return make_block_statements(branch[1]).join(newline); - }) : ""); - if (!beautify && has_body && i < n - 1) - code += ";"; - return code; - }).join(newline) + newline + indent("}"); - }; - - function make_block(statements) { - if (!statements) return ";"; - if (statements.length == 0) return "{}"; - return "{" + newline + with_indent(function(){ - return make_block_statements(statements).join(newline); - }) + newline + indent("}"); - }; - - function make_1vardef(def) { - var name = def[0], val = def[1]; - if (val != null) - name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); - return name; - }; - - var $stack = []; - - function make(node) { - var type = node[0]; - var gen = generators[type]; - if (!gen) - throw new Error("Can't find generator for \"" + type + "\""); - $stack.push(node); - var ret = gen.apply(type, node.slice(1)); - $stack.pop(); - return ret; - }; - - return make(ast); -}; - -/* -----[ Utilities ]----- */ - -function repeat_string(str, i) { - return i < 1 ? "" : new Array(i + 1).join(str); -}; - -function defaults(args, defs) { - var ret = {}; - if (args === true) - args = {}; - for (var i in defs) if (HOP(defs, i)) { - ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; - } - return ret; -}; - -function is_identifier(name) { - return /^[a-z_$][a-z0-9_$]*$/i.test(name) - && name != "this" - && !HOP(KEYWORDS_ATOM, name) - && !HOP(RESERVED_WORDS, name) - && !HOP(KEYWORDS, name); -}; - -function MAP(a, f, o) { - var ret = []; - for (var i = 0; i < a.length; ++i) { - ret.push(f.call(o, a[i], i)); - } - return ret; -}; - -/* -----[ Exports ]----- */ - -return { - parse: parse, - gen_code: gen_code, - tokenizer: tokenizer, - ast_walker: ast_walker -}; - -}; diff --git a/lib/prepro.js b/lib/prepro.js deleted file mode 100644 index c92796a7..00000000 --- a/lib/prepro.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Paper.js - * - * This file is part of Paper.js, a JavaScript Vector Graphics Library, - * based on Scriptographer.org and designed to be largely API compatible. - * http://paperjs.org/ - * http://scriptographer.org/ - * - * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey - * http://lehni.org/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - */ - -// Since loading prepro.js is also used further down to prevent inline scripts -// from executing right away, check that its actual code is only executed once. -if (!window.include) { - // Determine the source of prepro.js, so we can use it to prevent inline - // scripts from loading straight away. - var scripts = document.getElementsByTagName('script'); - var script = scripts[scripts.length - 1]; - var src = script.getAttribute('src'); - var root = src.match(/^(.*\/)/)[1]; - - window.include = function(url) { - url = root + url; - var newRoot = url.match(/^(.*\/)/)[1]; - // Load prepro.js again, just to prevent the setting of newRoot frome - // executing straight away, and delaying it until right before the - // script at 'url' is loaded. - document.write([ - '', - // Set newRoot, so include() from 'url' load from the right place - '', - // Load the actual script - '', - // Set root back to the root before - '' - ].join('')); - } -} diff --git a/lib/stats.js b/lib/stats.js deleted file mode 100644 index 5d85f626..00000000 --- a/lib/stats.js +++ /dev/null @@ -1,10 +0,0 @@ -// stats.js r5 - http://github.com/mrdoob/stats.js -var Stats=function(){function w(d,K,n){var u,f,c;for(f=0;f<30;f++)for(u=0;u<73;u++){c=(u+f*74)*4;d[c]=d[c+4];d[c+1]=d[c+5];d[c+2]=d[c+6]}for(f=0;f<30;f++){c=(73+f*74)*4;if(f'+q+" MS ("+D+"-"+E+")";r.putImageData(F,0,0);J=l;if(l> -z+1E3){o=Math.round(y*1E3/(l-z));A=Math.min(A,o);B=Math.max(B,o);w(C.data,Math.min(30,30-o/100*30),"fps");g.innerHTML=''+o+" FPS ("+A+"-"+B+")";p.putImageData(C,0,0);if(x==3){s=performance.memory.usedJSHeapSize*9.54E-7;G=Math.min(G,s);H=Math.max(H,s);w(I.data,Math.min(30,30-s/2),"mem");k.innerHTML=''+Math.round(s)+" MEM ("+Math.round(G)+"-"+Math.round(H)+")";t.putImageData(I,0,0)}z=l;y=0}}}}; - diff --git a/node.js/index.js b/node.js/index.js deleted file mode 100644 index 243a9d1b..00000000 --- a/node.js/index.js +++ /dev/null @@ -1,58 +0,0 @@ -var fs = require('fs'), - vm = require('vm'), - path = require('path'), - Canvas = require('canvas'); - -__dirname = path.resolve(__dirname, '../src/'); - -// Create the context within which we will run the source files: -var context = vm.createContext({ - options: { - server: true, - version: 'dev' - }, - fs: fs, - // Node Canvas library: https://github.com/learnboost/node-canvas - Canvas: Canvas, - HTMLCanvasElement: Canvas, - Image: Canvas.Image, - // Copy over global variables: - console: console, - require: require, - __dirname: __dirname, - __filename: __filename, - // Used to load and run source files within the same context: - include: function(uri) { - var source = fs.readFileSync(path.resolve(__dirname, uri), 'utf8'); - // For relative includes, we save the current directory and then - // add the uri directory to __dirname: - var oldDirname = __dirname; - __dirname = path.resolve(__dirname, path.dirname(uri)); - vm.runInContext(source, context, uri); - __dirname = oldDirname; - } -}); - -// Load Paper.js library files: -context.include('paper.js'); - -context.Base.each(context, function(val, key) { - if (val && val.prototype instanceof context.Base) { - val._name = key; - // Export all classes through PaperScope: - context.PaperScope.prototype[key] = val; - } -}); -context.PaperScope.prototype['Canvas'] = context.Canvas; - -require.extensions['.pjs'] = function(module, uri) { - var source = context.PaperScript.compile(fs.readFileSync(uri, 'utf8')); - var envVars = 'var __dirname = \'' + path.dirname(uri) + '\';' + - 'var __filename = \'' + uri + '\';'; - vm.runInContext(envVars, context); - var scope = new context.PaperScope(); - context.PaperScript.evaluate(source, scope); - module.exports = scope; -}; - -module.exports = new context.PaperScope(); \ No newline at end of file From a974ec8205dd0303a4cce09f17f003301ad08226 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 30 Sep 2012 21:01:45 -0400 Subject: [PATCH 41/51] Mergin the branches --- build/.gitignore | 3 + build/build.sh | 38 + build/dist.sh | 21 + build/docs.sh | 38 + build/load.sh | 22 + build/parse-js.sh | 20 + build/prepro.js | 174 + build/preprocess.sh | 51 + build/zip.sh | 39 + dist/.gitignore | 3 + dist/docs/classes/CharacterStyle.html | 569 ++ dist/docs/classes/Color.html | 712 ++ dist/docs/classes/CompoundPath.html | 5349 +++++++++++++ dist/docs/classes/Curve.html | 878 +++ dist/docs/classes/CurveLocation.html | 505 ++ dist/docs/classes/Event.html | 73 + dist/docs/classes/Gradient.html | 200 + dist/docs/classes/GradientColor.html | 465 ++ dist/docs/classes/GradientStop.html | 258 + dist/docs/classes/GrayColor.html | 749 ++ dist/docs/classes/Group.html | 3587 +++++++++ dist/docs/classes/HitResult.html | 242 + dist/docs/classes/HsbColor.html | 766 ++ dist/docs/classes/HslColor.html | 730 ++ dist/docs/classes/Item.html | 3289 ++++++++ dist/docs/classes/Key.html | 100 + dist/docs/classes/KeyEvent.html | 220 + dist/docs/classes/Layer.html | 3588 +++++++++ dist/docs/classes/Line.html | 329 + dist/docs/classes/Matrix.html | 1824 +++++ dist/docs/classes/PaperScope.html | 475 ++ dist/docs/classes/PaperScript.html | 137 + dist/docs/classes/ParagraphStyle.html | 92 + dist/docs/classes/Path.html | 6698 ++++++++++++++++ dist/docs/classes/PathItem.html | 4279 ++++++++++ dist/docs/classes/PathStyle.html | 497 ++ dist/docs/classes/PlacedItem.html | 3493 ++++++++ dist/docs/classes/PlacedSymbol.html | 3620 +++++++++ dist/docs/classes/Point.html | 2196 ++++++ dist/docs/classes/PointText.html | 3688 +++++++++ dist/docs/classes/Project.html | 567 ++ dist/docs/classes/Raster.html | 4204 ++++++++++ dist/docs/classes/Rectangle.html | 1380 ++++ dist/docs/classes/RgbColor.html | 765 ++ dist/docs/classes/Segment.html | 544 ++ dist/docs/classes/Size.html | 1247 +++ dist/docs/classes/Symbol.html | 271 + dist/docs/classes/TextItem.html | 3600 +++++++++ dist/docs/classes/Tool.html | 584 ++ dist/docs/classes/ToolEvent.html | 406 + dist/docs/classes/View.html | 538 ++ dist/docs/classes/global.html | 574 ++ dist/docs/classes/index.html | 96 + dist/docs/index.html | 13 + dist/docs/resources/css/assets/bullet.gif | Bin 0 -> 44 bytes dist/docs/resources/css/codemirror.css | 141 + dist/docs/resources/css/paperscript.css | 64 + dist/docs/resources/css/reference.css | 128 + dist/docs/resources/css/style.css | 86 + dist/docs/resources/js/bootstrap.js | 4040 ++++++++++ dist/docs/resources/js/codemirror.js | 1 + dist/docs/resources/js/paper.js | 8761 +++++++++++++++++++++ dist/docs/resources/js/reference.js | 258 + dist/paper.js | 3 + lib/bootstrap.js | 411 + lib/parse-js-min.js | 14 + lib/parse-js-unicode.js | 1997 +++++ lib/parse-js.js | 1916 +++++ lib/prepro.js | 43 + lib/stats.js | 10 + node.js/index.js | 58 + 71 files changed, 82737 insertions(+) create mode 100644 build/.gitignore create mode 100644 build/build.sh create mode 100644 build/dist.sh create mode 100644 build/docs.sh create mode 100644 build/load.sh create mode 100644 build/parse-js.sh create mode 100644 build/prepro.js create mode 100644 build/preprocess.sh create mode 100644 build/zip.sh create mode 100644 dist/.gitignore create mode 100644 dist/docs/classes/CharacterStyle.html create mode 100644 dist/docs/classes/Color.html create mode 100644 dist/docs/classes/CompoundPath.html create mode 100644 dist/docs/classes/Curve.html create mode 100644 dist/docs/classes/CurveLocation.html create mode 100644 dist/docs/classes/Event.html create mode 100644 dist/docs/classes/Gradient.html create mode 100644 dist/docs/classes/GradientColor.html create mode 100644 dist/docs/classes/GradientStop.html create mode 100644 dist/docs/classes/GrayColor.html create mode 100644 dist/docs/classes/Group.html create mode 100644 dist/docs/classes/HitResult.html create mode 100644 dist/docs/classes/HsbColor.html create mode 100644 dist/docs/classes/HslColor.html create mode 100644 dist/docs/classes/Item.html create mode 100644 dist/docs/classes/Key.html create mode 100644 dist/docs/classes/KeyEvent.html create mode 100644 dist/docs/classes/Layer.html create mode 100644 dist/docs/classes/Line.html create mode 100644 dist/docs/classes/Matrix.html create mode 100644 dist/docs/classes/PaperScope.html create mode 100644 dist/docs/classes/PaperScript.html create mode 100644 dist/docs/classes/ParagraphStyle.html create mode 100644 dist/docs/classes/Path.html create mode 100644 dist/docs/classes/PathItem.html create mode 100644 dist/docs/classes/PathStyle.html create mode 100644 dist/docs/classes/PlacedItem.html create mode 100644 dist/docs/classes/PlacedSymbol.html create mode 100644 dist/docs/classes/Point.html create mode 100644 dist/docs/classes/PointText.html create mode 100644 dist/docs/classes/Project.html create mode 100644 dist/docs/classes/Raster.html create mode 100644 dist/docs/classes/Rectangle.html create mode 100644 dist/docs/classes/RgbColor.html create mode 100644 dist/docs/classes/Segment.html create mode 100644 dist/docs/classes/Size.html create mode 100644 dist/docs/classes/Symbol.html create mode 100644 dist/docs/classes/TextItem.html create mode 100644 dist/docs/classes/Tool.html create mode 100644 dist/docs/classes/ToolEvent.html create mode 100644 dist/docs/classes/View.html create mode 100644 dist/docs/classes/global.html create mode 100644 dist/docs/classes/index.html create mode 100644 dist/docs/index.html create mode 100644 dist/docs/resources/css/assets/bullet.gif create mode 100644 dist/docs/resources/css/codemirror.css create mode 100644 dist/docs/resources/css/paperscript.css create mode 100644 dist/docs/resources/css/reference.css create mode 100644 dist/docs/resources/css/style.css create mode 100644 dist/docs/resources/js/bootstrap.js create mode 100644 dist/docs/resources/js/codemirror.js create mode 100644 dist/docs/resources/js/paper.js create mode 100644 dist/docs/resources/js/reference.js create mode 100644 dist/paper.js create mode 100644 lib/bootstrap.js create mode 100644 lib/parse-js-min.js create mode 100644 lib/parse-js-unicode.js create mode 100644 lib/parse-js.js create mode 100644 lib/prepro.js create mode 100644 lib/stats.js create mode 100644 node.js/index.js diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 00000000..baa4f768 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,3 @@ +/scriptographer.sh +/*.tmproj +/sync.sh diff --git a/build/build.sh b/build/build.sh new file mode 100644 index 00000000..e57127be --- /dev/null +++ b/build/build.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +# Usage: +# build.sh MODE +# +# MODE: +# commented Preprocessed but still formated and commented +# stripped Formated but without comments (default) +# compressed Uses UglifyJS to reduce file size + +if [ $# -eq 0 ] +then + MODE="stripped" +else + MODE=$1 +fi + +# Create the dist folder if it does not exist yet. +if [ ! -d ../dist/ ] +then + mkdir ../dist/ +fi + +./preprocess.sh $MODE ../src/paper.js ../dist/paper.js '{ "browser": true }' +#./preprocess.sh $MODE ../src/paper.js ../dist/paper-server.js '{ "server": true }' diff --git a/build/dist.sh b/build/dist.sh new file mode 100644 index 00000000..6283502a --- /dev/null +++ b/build/dist.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +echo "Building paper.js" +./build.sh +echo "Building docs" +./docs.sh +echo "Zipping paperjs.zip" +./zip.sh diff --git a/build/docs.sh b/build/docs.sh new file mode 100644 index 00000000..b55606a0 --- /dev/null +++ b/build/docs.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +# Generate documentation +# +# MODE: +# docs Generates the JS API docs - Default +# serverdocs Generates the website templates for the online JS API docs + +if [ $# -eq 0 ] +then + MODE="docs" +else + MODE=$1 +fi + +cd jsdoc-toolkit +java -jar jsrun.jar app/run.js -c=conf/$MODE.conf -D="renderMode:$MODE" +cd .. + +if [ $MODE = "docs" ] +then + # Build paper.js library for documentation + ./preprocess.sh stripped ../src/paper.js ../dist/docs/resources/js/paper.js\ + '{ "browser": true }' +fi diff --git a/build/load.sh b/build/load.sh new file mode 100644 index 00000000..8ed8a3cc --- /dev/null +++ b/build/load.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +# Generate a paper.js file that uses load.js to directly load the library +# through the seperate source files in the src directory. Very useful during +# development of the library itself. + +echo "// Paper.js loader for development, as produced by the build/load.sh script +document.write(''); +document.write('');" > ../dist/paper.js; \ No newline at end of file diff --git a/build/parse-js.sh b/build/parse-js.sh new file mode 100644 index 00000000..7410b68a --- /dev/null +++ b/build/parse-js.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +# Generate a paper.js file that uses load.js to directly load the library +# through the seperate source files in the src directory. Very useful during +# development of the library itself. + +./preprocess.sh compressed ../lib/parse-js.js ../lib/parse-js-min.js '{}' diff --git a/build/prepro.js b/build/prepro.js new file mode 100644 index 00000000..1ba879dd --- /dev/null +++ b/build/prepro.js @@ -0,0 +1,174 @@ +#! /usr/bin/env node +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +/** + * Prepro.js - A simple preprocesssor for JavaScript that speaks JavaScript, + * written in JavaScript, allowing preprocessing to either happen at build time + * or compile time. Very useful for libraries that are built for distribution, + * but can be also compiled from seperate sources directly for development, + * supporting build time switches. + */ + +// Required libs + +var fs = require('fs'), + path = require('path'); + +// Parse arguments + +var args = process.argv.slice(2), + options = {}, + files = [], + strip = false; + +while (args.length > 0) { + var arg = args.shift(); + switch (arg) { + case '-d': + // Definitions are provided as JSON and supposed to be object literals + var def = JSON.parse(args.shift()); + // Merge new definitions into options object. + for (var key in def) + options[key] = def[key]; + break; + case '-c': + strip = true; + break; + default: + files.push(arg); + } +} + +// Preprocessing + +var code = [], + out = []; + +function include(base, file) { + // Compose a pathname from base and file, which is specified relatively, + // and normalize the new path, to get rid of .. + file = path.normalize(path.join(base, file)); + var content = fs.readFileSync(file).toString(); + content.split(/\r\n|\n|\r/mg).forEach(function(line) { + // See if our line starts with the preprocess prefix. + var match = line.match(/^\s*\/\*#\*\/\s*(.*)$/); + if (match) { + // Check if the preprocessing line is an include statement, and if + // so, handle it straight away + line = match[1]; + if (match = line.match(/^include\(['"]([^;]*)['"]\);?$/)) { + // Pass on the dirname of the current file as the new base + include(path.dirname(file), match[1]); + } else { + // Any other preprocessing code is simply added, for later + // evaluation. + code.push(line); + } + } else { + // Perhaps we need to replace some values? Supported formats are: + // /*#=*/ options.NAME (outside comments) + // *#=* options.NAME (inside comments) + line = line.replace(/\/?\*#=\*\/?\s*options\.([\w]*)/g, + function(all, name) { + return options[name]; + } + ); + // Now add a statement that when evaluated writes out this code line + code.push('out.push(' + JSON.stringify(line) + ');'); + } + }); +} + +// Include all files. Everything else happens from there, through include() +files.forEach(function(file) { + include(path.resolve(), file); +}); + +// Evaluate the resulting code: Calls puts() and writes the result to stdout. +eval(code.join('\n')); + +// Convert the resulting lines to one string again. +var out = out.join('\n'); + +if (strip) { + out = stripComments(out); + // Strip empty lines that contain only white space and line breaks, as they + // are left-overs from comment removal. + out = out.replace(/^[ \t]+(\r\n|\n|\r)/gm, function(all) { + return ''; + }); + // Replace a sequence of more than two line breaks with only two. + out = out.replace(/(\r\n|\n|\r)(\r\n|\n|\r)+/g, function(all, lineBreak) { + return lineBreak + lineBreak; + }); +} + +// Write the result out +process.stdout.write(out); + +/** + * Strips comments out of JavaScript code, based on: + * http://james.padolsey.com/javascript/removing-comments-in-javascript/ +*/ +function stripComments(str) { + str = ('__' + str + '__').split(''); + var singleQuote = false, + doubleQuote = false, + blockComment = false, + lineComment = false, + preserveComment = false; + for (var i = 0, l = str.length; i < l; i++) { + if (singleQuote) { + if (str[i] == "'" && str[i - 1] !== '\\') + singleQuote = false; + } else if (doubleQuote) { + if (str[i] == '"' && str[i - 1] !== '\\') + doubleQuote = false; + } else if (blockComment) { + // Is the block comment closing? + if (str[i] == '*' && str[i + 1] == '/') { + if (!preserveComment) + str[i] = str[i + 1] = ''; + blockComment = preserveComment = false; + } else if (!preserveComment) { + str[i] = ''; + } + } else if (lineComment) { + // One-line comments end with the line-break + if (str[i + 1] == '\n' || str[i + 1] == '\r') + lineComment = false; + str[i] = ''; + } else { + doubleQuote = str[i] == '"'; + singleQuote = str[i] == "'"; + if (!blockComment && str[i] == '/') { + if (str[i + 1] == '*') { + // Do not filter out conditional comments and comments marked + // as protected (/*! */) + preserveComment = str[i + 2] == '@' || str[i + 2] == '!'; + if (!preserveComment) + str[i] = ''; + blockComment = true; + } else if (str[i + 1] == '/') { + str[i] = ''; + lineComment = true; + } + } + } + } + return str.join('').slice(2, -2); +} diff --git a/build/preprocess.sh b/build/preprocess.sh new file mode 100644 index 00000000..860fdd73 --- /dev/null +++ b/build/preprocess.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +# preprocess.sh +# +# A simple code preprocessing wrapper that uses a combination of cpp, jssrip.py +# and sed to preprocess JavaScript files containing C-style preprocess macros +# (#include, #ifdef, etc.). Three options offer control over wether comments +# are preserved or stripped and whitespaces are compressed. +# +# Usage: +# preprocess.sh MODE SOURCE DESTINATION ARGUMENTS +# +# ARGUMENTS: +# e.g. "-DBROWSER" +# +# MODE: +# commented Preprocessed but still formated and commented +# stripped Formated but without comments +# compressed Uses UglifyJS to reduce file size + +VERSION=0.22 +DATE=$(git log -1 --pretty=format:%ad) + +COMMAND="./prepro.js -d '{ \"version\": $VERSION, \"date\": \"$DATE\" }' -d '$4' $2" + +case $1 in + stripped) + eval "$COMMAND -c" > $3 + ;; + commented) + eval $COMMAND > $3 + ;; + compressed) + eval $COMMAND > temp.js + ../../uglifyjs/bin/uglifyjs temp.js --extra --unsafe --reserved-names "$eval,$sign" > $3 + rm temp.js + ;; +esac diff --git a/build/zip.sh b/build/zip.sh new file mode 100644 index 00000000..afc07257 --- /dev/null +++ b/build/zip.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +# Paper.js +# +# This file is part of Paper.js, a JavaScript Vector Graphics Library, +# based on Scriptographer.org and designed to be largely API compatible. +# http://scriptographer.org/ +# +# Copyright (c) 2011, Juerg Lehni & Jonathan Puckey +# http://lehni.org/ & http://jonathanpuckey.com/ +# +# Distributed under the MIT license. See LICENSE file for details. +# +# All rights reserved. + +if [ -f paperjs.zip ] +then + rm paperjs.zip +fi +# Create a temporary folder to copy all files in for zipping +mkdir zip +cd zip +BASE=../.. +# Copy license over +cp $BASE/LICENSE.txt . +# Make library folder and copy paper.js there +mkdir lib +cp $BASE/dist/paper.js lib +# Copy examples over +cp -r $BASE/examples . +# Replace ../../dist/ with ../../lib/ in each example +find examples -type f -print0 | xargs -0 perl -i -pe 's/\.\.\/\.\.\/dist\//\.\.\/\.\.\/lib\//g' +# Copy docs over +cp -r $BASE/dist/docs . +# Zip the whole thing +zip -9 -r $BASE/dist/paperjs.zip * LICENSE.txt -x "*/.DS_Store" +cd .. +# Remove the temporary folder again +rm -fr zip diff --git a/dist/.gitignore b/dist/.gitignore new file mode 100644 index 00000000..61f11ea6 --- /dev/null +++ b/dist/.gitignore @@ -0,0 +1,3 @@ +/paper-server.js +/serverdocs/ +/paperjs.zip diff --git a/dist/docs/classes/CharacterStyle.html b/dist/docs/classes/CharacterStyle.html new file mode 100644 index 00000000..359b7469 --- /dev/null +++ b/dist/docs/classes/CharacterStyle.html @@ -0,0 +1,569 @@ + + + + +CharacterStyle + + + + + + + + + + + +
+

CharacterStyle

+ +

Extends PathStyle

+ +

The CharacterStyle object represents the character style of a text +item (textItem.characterStyle)

+

+Example +

+ + +
var text = new PointText(new Point(50, 50));
+text.content = 'Hello world.';
+text.characterStyle = {
+	fontSize: 50,
+	fillColor: 'black',
+};
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from PathStyle

+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Color.html b/dist/docs/classes/Color.html new file mode 100644 index 00000000..c230d9b0 --- /dev/null +++ b/dist/docs/classes/Color.html @@ -0,0 +1,712 @@ + + + + +Color + + + + + + + + + + + +
+

Color

+ +

All properties and functions that expect color values accept +instances of the different color classes such as RgbColor, +HsbColor and GrayColor, and also accept named colors +and hex values as strings which are then converted to instances of +RgbColor internally.

+

+Example — Named color values: +

+ +
+
Run
+ +
+
+ + +

+Example — Hex color values: +

+ +
+
Run
+ +
+
+ + +
+ + + + +

Operators

+ +
+ + +
+ + +
+ + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +

RGB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Gray Components

+ +
+ + +
+ + +

HSB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

HSL Components

+ +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/CompoundPath.html b/dist/docs/classes/CompoundPath.html new file mode 100644 index 00000000..3719a11c --- /dev/null +++ b/dist/docs/classes/CompoundPath.html @@ -0,0 +1,5349 @@ + + + + +CompoundPath + + + + + + + + + + + +
+

CompoundPath

+ +

Extends PathItem, Item

+ +

A compound path contains two or more paths, holes are drawn +where the paths overlap. All the paths in a compound path take on the +style of the backmost path and can be accessed through its +item.children list.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + + + + +

Methods

+ + +
+ + +
+ +
+ + + + + + +

Methods inherited from PathItem

+ + +
+ + +
+ + +

Postscript Style Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Relative Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Position and Bounding Boxes

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ + +

Event Handlers

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Event Handling

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Curve.html b/dist/docs/classes/Curve.html new file mode 100644 index 00000000..97d51079 --- /dev/null +++ b/dist/docs/classes/Curve.html @@ -0,0 +1,878 @@ + + + + +Curve + + + + + + + + + + + +
+

Curve

+ +

The Curve object represents the parts of a path that are connected by +two following Segment objects. The curves of a path can be accessed +through its path.curves array.

+

While a segment describe the anchor point and its incoming and outgoing +handles, a Curve object describes the curve passing between two such +segments. Curves and segments represent two different ways of looking at the +same thing, but focusing on different aspects. Curves for example offer many +convenient ways to work with parts of the path, finding lengths, positions or +tangents at given offsets.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/CurveLocation.html b/dist/docs/classes/CurveLocation.html new file mode 100644 index 00000000..86dbcaae --- /dev/null +++ b/dist/docs/classes/CurveLocation.html @@ -0,0 +1,505 @@ + + + + +CurveLocation + + + + + + + + + + + +
+

CurveLocation

+ +

CurveLocation objects describe a location on Curve +objects, as defined by the curve parameter, a value between +0 (beginning of the curve) and 1 (end of the curve). If +the curve is part of a Path item, its index inside the +path.curves array is also provided.

+

The class is in use in many places, such as +path.getLocationAt(offset), Path#getNearestLocation(point), etc.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Event.html b/dist/docs/classes/Event.html new file mode 100644 index 00000000..d0848eb9 --- /dev/null +++ b/dist/docs/classes/Event.html @@ -0,0 +1,73 @@ + + + + +Event + + + + + + + + + + + +
+

Event

+ + + +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Gradient.html b/dist/docs/classes/Gradient.html new file mode 100644 index 00000000..f95530ea --- /dev/null +++ b/dist/docs/classes/Gradient.html @@ -0,0 +1,200 @@ + + + + +Gradient + + + + + + + + + + + +
+

Gradient

+ +

The Gradient object.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + +

Operators

+ +
+ + +
+ + +
+ + + +

Properties

+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/GradientColor.html b/dist/docs/classes/GradientColor.html new file mode 100644 index 00000000..76f32a67 --- /dev/null +++ b/dist/docs/classes/GradientColor.html @@ -0,0 +1,465 @@ + + + + +GradientColor + + + + + + + + + + + +
+

GradientColor

+ +

The GradientColor object.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/GradientStop.html b/dist/docs/classes/GradientStop.html new file mode 100644 index 00000000..0e879e34 --- /dev/null +++ b/dist/docs/classes/GradientStop.html @@ -0,0 +1,258 @@ + + + + +GradientStop + + + + + + + + + + + +
+

GradientStop

+ +

The GradientStop object.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/GrayColor.html b/dist/docs/classes/GrayColor.html new file mode 100644 index 00000000..c3987ba6 --- /dev/null +++ b/dist/docs/classes/GrayColor.html @@ -0,0 +1,749 @@ + + + + +GrayColor + + + + + + + + + + + +
+

GrayColor

+ +

Extends Color

+ +

A GrayColor object is used to represent any gray color value.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +

RGB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

HSB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

HSL Components

+ +
+ + +
+ +
+ + + +

Methods inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Group.html b/dist/docs/classes/Group.html new file mode 100644 index 00000000..426e459f --- /dev/null +++ b/dist/docs/classes/Group.html @@ -0,0 +1,3587 @@ + + + + +Group + + + + + + + + + + + +
+

Group

+ +

Extends Item

+ +

A Group is a collection of items. When you transform a Group, its +children are treated as a single unit without changing their relative +positions.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/HitResult.html b/dist/docs/classes/HitResult.html new file mode 100644 index 00000000..78b14184 --- /dev/null +++ b/dist/docs/classes/HitResult.html @@ -0,0 +1,242 @@ + + + + +HitResult + + + + + + + + + + + +
+

HitResult

+ +

A HitResult object contains information about the results of a hit +test. It is returned by item.hitTest(point) and +project.hitTest(point).

+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/HsbColor.html b/dist/docs/classes/HsbColor.html new file mode 100644 index 00000000..b02271d5 --- /dev/null +++ b/dist/docs/classes/HsbColor.html @@ -0,0 +1,766 @@ + + + + +HsbColor + + + + + + + + + + + +
+

HsbColor

+ +

Extends Color

+ +

An HsbColor object is used to represent any HSB color value.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +

RGB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Gray Components

+ +
+ + +
+ + +

HSL Components

+ +
+ + +
+ +
+ + + +

Methods inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/HslColor.html b/dist/docs/classes/HslColor.html new file mode 100644 index 00000000..c22ca01c --- /dev/null +++ b/dist/docs/classes/HslColor.html @@ -0,0 +1,730 @@ + + + + +HslColor + + + + + + + + + + + +
+

HslColor

+ +

Extends Color

+ +

An HslColor object is used to represent any HSL color value.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +

RGB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Gray Components

+ +
+ + +
+ + +
+ + +
+ +
+ + + +

Methods inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Item.html b/dist/docs/classes/Item.html new file mode 100644 index 00000000..43952d74 --- /dev/null +++ b/dist/docs/classes/Item.html @@ -0,0 +1,3289 @@ + + + + +Item + + + + + + + + + + + +
+

Item

+ +

The Item type allows you to access and modify the items in +Paper.js projects. Its functionality is inherited by different project +item types such as Path, CompoundPath, Group, +Layer and Raster. They each add a layer of functionality that +is unique to their type, but share the underlying properties and functions +that they inherit from Item.

+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Key.html b/dist/docs/classes/Key.html new file mode 100644 index 00000000..4f5f511f --- /dev/null +++ b/dist/docs/classes/Key.html @@ -0,0 +1,100 @@ + + + + +Key + + + + + + + + + + + +
+

Key

+ + + +
+ + + + + + + + +

Static Methods

+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/KeyEvent.html b/dist/docs/classes/KeyEvent.html new file mode 100644 index 00000000..3a19161f --- /dev/null +++ b/dist/docs/classes/KeyEvent.html @@ -0,0 +1,220 @@ + + + + +KeyEvent + + + + + + + + + + + +
+

KeyEvent

+ +

Extends Event

+ +

KeyEvent The KeyEvent object is received by the Tool's +keyboard handlers tool.onKeyDown, tool.onKeyUp, +The KeyEvent object is the only parameter passed to these functions +and contains information about the keyboard event.

+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ +
+ + + + + +

Properties inherited from Event

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Layer.html b/dist/docs/classes/Layer.html new file mode 100644 index 00000000..3f626910 --- /dev/null +++ b/dist/docs/classes/Layer.html @@ -0,0 +1,3588 @@ + + + + +Layer + + + + + + + + + + + +
+

Layer

+ +

Extends Item, Group

+ +

The Layer item represents a layer in a Paper.js project.

+

The layer which is currently active can be accessed through +project.activeLayer.

+

An array of all layers in a project can be accessed through +project.layers.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + + + + +

Methods

+ + +
+ + +
+ +
+ + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from Group

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Line.html b/dist/docs/classes/Line.html new file mode 100644 index 00000000..fc195f83 --- /dev/null +++ b/dist/docs/classes/Line.html @@ -0,0 +1,329 @@ + + + + +Line + + + + + + + + + + + +
+

Line

+ +

The Line object represents..

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Matrix.html b/dist/docs/classes/Matrix.html new file mode 100644 index 00000000..844dc516 --- /dev/null +++ b/dist/docs/classes/Matrix.html @@ -0,0 +1,1824 @@ + + + + +Matrix + + + + + + + + + + + +
+

Matrix

+ +

An affine transform performs a linear mapping from 2D coordinates +to other 2D coordinates that preserves the "straightness" and +"parallelness" of lines.

+

Such a coordinate transformation can be represented by a 3 row by 3 +column matrix with an implied last row of [ 0 0 1 ]. This matrix +transforms source coordinates (x,y) into destination coordinates (x',y') +by considering them to be a column vector and multiplying the coordinate +vector by the matrix according to the following process:

+
+     [ x ]   [ a  b  tx ] [ x ]   [ a * x + b * y + tx ]
+     [ y ] = [ c  d  ty ] [ y ] = [ c * x + d * y + ty ]
+     [ 1 ]   [ 0  0  1  ] [ 1 ]   [         1          ]
+
+

This class is optimized for speed and minimizes calculations based on its +knowledge of the underlying matrix (as opposed to say simply performing +matrix multiplication).

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + +

Static Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PaperScope.html b/dist/docs/classes/PaperScope.html new file mode 100644 index 00000000..e32769d1 --- /dev/null +++ b/dist/docs/classes/PaperScope.html @@ -0,0 +1,475 @@ + + + + +PaperScope + + + + + + + + + + + +
+

PaperScope

+ +

The PaperScope class represents the scope associated with a +Paper context. When working with PaperScript, these scopes are automatically +created for us, and through clever scoping the properties and methods of the +active scope seem to become part of the global scope.

+

When working with normal JavaScript code, PaperScope objects need to +be manually created and handled.

+

Paper classes can only be accessed through PaperScope objects. Thus +in PaperScript they are global, while in JavaScript, they are available on +the global paper object. For JavaScript you can use +paperScope.install(scope) to install the Paper classes and objects +on the global scope. Note that when working with more than one scope, this +still works for classes, but not for objects like paperScope.project, +since they are not updated in the injected scope if scopes are switched.

+

The global paper object is simply a reference to the currently active +PaperScope.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + +

Static Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PaperScript.html b/dist/docs/classes/PaperScript.html new file mode 100644 index 00000000..9714c10d --- /dev/null +++ b/dist/docs/classes/PaperScript.html @@ -0,0 +1,137 @@ + + + + +PaperScript + + + + + + + + + + + +
+

PaperScript

+ + + +
+ + + + + + + + +

Static Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/ParagraphStyle.html b/dist/docs/classes/ParagraphStyle.html new file mode 100644 index 00000000..b0b4aa4d --- /dev/null +++ b/dist/docs/classes/ParagraphStyle.html @@ -0,0 +1,92 @@ + + + + +ParagraphStyle + + + + + + + + + + + +
+

ParagraphStyle

+ +

The ParagraphStyle object represents the paragraph style of a text +item (textItem.paragraphStyle).

+

Currently, the ParagraphStyle object may seem a bit empty, with just the +justification property. Yet, we have lots in store for Paper.js +when it comes to typography. Please stay tuned.

+

+Example +

+ + +
var text = new PointText(new Point(0,0));
+text.fillColor = 'black';
+text.content = 'Hello world.';
+text.paragraphStyle.justification = 'center';
+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Path.html b/dist/docs/classes/Path.html new file mode 100644 index 00000000..a55fc047 --- /dev/null +++ b/dist/docs/classes/Path.html @@ -0,0 +1,6698 @@ + + + + +Path + + + + + + + + + + + +
+

Path

+ +

Extends PathItem, Item

+ +

The Path item represents a path in a Paper.js project.

+ +
+ + +

Constructors

+ + +
+ + +
+ +

Shaped Paths

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Positions on Paths and Curves

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +

Methods inherited from PathItem

+ + +
+ + +
+ + +

Postscript Style Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Relative Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PathItem.html b/dist/docs/classes/PathItem.html new file mode 100644 index 00000000..105888d1 --- /dev/null +++ b/dist/docs/classes/PathItem.html @@ -0,0 +1,4279 @@ + + + + +PathItem + + + + + + + + + + + +
+

PathItem

+ +

Extends Item

+ +

The PathItem class is the base for any items that describe paths +and offer standardised methods for drawing and path manipulation, such as +Path and CompoundPath.

+ +
+ + + + + + + + +

Methods

+ + +
+ + +
+ + +

Postscript Style Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Relative Drawing Commands

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PathStyle.html b/dist/docs/classes/PathStyle.html new file mode 100644 index 00000000..2b1ecdf4 --- /dev/null +++ b/dist/docs/classes/PathStyle.html @@ -0,0 +1,497 @@ + + + + +PathStyle + + + + + + + + + + + +
+

PathStyle

+ +

PathStyle is used for changing the visual styles of items +contained within a Paper.js project and is returned by +item.style and project.currentStyle.

+

All properties of PathStyle are also reflected directly in Item, +i.e.: item.fillColor.

+

To set multiple style properties in one go, you can pass an object to +item.style. This is a convenient way to define a style once and +apply it to a series of items:

+

+Example +

+ +
+
Run
+ +
+
+ + +
+ + + + + +

Properties

+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PlacedItem.html b/dist/docs/classes/PlacedItem.html new file mode 100644 index 00000000..959080f6 --- /dev/null +++ b/dist/docs/classes/PlacedItem.html @@ -0,0 +1,3493 @@ + + + + +PlacedItem + + + + + + + + + + + +
+

PlacedItem

+ +

Extends Item

+ +

The PlacedItem class is the base for any items that have a matrix +associated with them, describing their placement in the project, such as +Raster and PlacedSymbol.

+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PlacedSymbol.html b/dist/docs/classes/PlacedSymbol.html new file mode 100644 index 00000000..8780cc5c --- /dev/null +++ b/dist/docs/classes/PlacedSymbol.html @@ -0,0 +1,3620 @@ + + + + +PlacedSymbol + + + + + + + + + + + +
+

PlacedSymbol

+ +

Extends Item, PlacedItem

+ +

A PlacedSymbol represents an instance of a symbol which has been +placed in a Paper.js project.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from PlacedItem

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Point.html b/dist/docs/classes/Point.html new file mode 100644 index 00000000..16e29e6a --- /dev/null +++ b/dist/docs/classes/Point.html @@ -0,0 +1,2196 @@ + + + + +Point + + + + + + + + + + + +
+

Point

+ +

The Point object represents a point in the two dimensional space +of the Paper.js project. It is also used to represent two dimensional +vector objects.

+

+Example — Create a point at x: 10, y: 5 +

+ + +
var point = new Point(10, 5);
+console.log(point.x); // 10
+console.log(point.y); // 5
+ +
+ + +

Constructors

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Operators

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Distance & Length

+ +
+ + +
+ + +
+ + +
+ + +

Angle & Rotation

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Vector Math Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Math Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + +

Static Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/PointText.html b/dist/docs/classes/PointText.html new file mode 100644 index 00000000..a25c35a9 --- /dev/null +++ b/dist/docs/classes/PointText.html @@ -0,0 +1,3688 @@ + + + + +PointText + + + + + + + + + + + +
+

PointText

+ +

Extends Item, TextItem

+ +

A PointText item represents a piece of typography in your Paper.js +project which starts from a certain point and extends by the amount of +characters contained in it.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from TextItem

+ + +
+ + +
+ + +

Style Properties

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Project.html b/dist/docs/classes/Project.html new file mode 100644 index 00000000..d1948071 --- /dev/null +++ b/dist/docs/classes/Project.html @@ -0,0 +1,567 @@ + + + + +Project + + + + + + + + + + + +
+

Project

+ +

A Project object in Paper.js is what usually is referred to as the +document: The top level object that holds all the items contained in the +scene graph. As the term document is already taken in the browser context, +it is called Project.

+

Projects allow the manipluation of the styles that are applied to all newly +created items, give access to the selected items, and will in future versions +offer ways to query for items in the scene graph defining specific +requirements, and means to persist and load from different formats, such as +SVG and PDF.

+

The currently active project can be accessed through the +paperScope.project variable.

+

An array of all open projects is accessible through the +paperScope.projects variable.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Raster.html b/dist/docs/classes/Raster.html new file mode 100644 index 00000000..f54df035 --- /dev/null +++ b/dist/docs/classes/Raster.html @@ -0,0 +1,4204 @@ + + + + +Raster + + + + + + + + + + + +
+

Raster

+ +

Extends Item, PlacedItem

+ +

The Raster item represents an image in a Paper.js project.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Pixels

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Image Data

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Properties inherited from PlacedItem

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Rectangle.html b/dist/docs/classes/Rectangle.html new file mode 100644 index 00000000..34eb81b2 --- /dev/null +++ b/dist/docs/classes/Rectangle.html @@ -0,0 +1,1380 @@ + + + + +Rectangle + + + + + + + + + + + +
+

Rectangle

+ +

A Rectangle specifies an area that is enclosed by it's top-left +point (x, y), its width, and its height. It should not be confused with a +rectangular path, it is not an item.

+ +
+ + +

Constructors

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Operators

+ +
+ + +
+ + +
+ + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Side Positions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Corner and Center Point Positions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +

Geometric Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Boolean Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/RgbColor.html b/dist/docs/classes/RgbColor.html new file mode 100644 index 00000000..a2fcd2cd --- /dev/null +++ b/dist/docs/classes/RgbColor.html @@ -0,0 +1,765 @@ + + + + +RgbColor + + + + + + + + + + + +
+

RgbColor

+ +

Extends Color

+ +

An RgbColor object is used to represent any RGB color value.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +

Gray Components

+ +
+ + +
+ + +

HSB Components

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

HSL Components

+ +
+ + +
+ +
+ + + +

Methods inherited from Color

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Segment.html b/dist/docs/classes/Segment.html new file mode 100644 index 00000000..6075d937 --- /dev/null +++ b/dist/docs/classes/Segment.html @@ -0,0 +1,544 @@ + + + + +Segment + + + + + + + + + + + +
+

Segment

+ +

The Segment object represents the points of a path through which its +Curve objects pass. The segments of a path can be accessed through +its path.segments array.

+

Each segment consists of an anchor point (segment.point) and +optionaly an incoming and an outgoing handle (segment.handleIn and +segment.handleOut), describing the tangents of the two Curve +objects that are connected by this segment.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Sibling Segments

+ +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Size.html b/dist/docs/classes/Size.html new file mode 100644 index 00000000..30c692d1 --- /dev/null +++ b/dist/docs/classes/Size.html @@ -0,0 +1,1247 @@ + + + + +Size + + + + + + + + + + + +
+

Size

+ +

The Size object is used to describe the size of something, through +its width and height properties.

+

+Example — Create a size that is 10pt wide and 5pt high +

+ + +
var size = new Size(10, 5);
+console.log(size.width); // 10
+console.log(size.height); // 5
+ +
+ + +

Constructors

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Operators

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +

Tests

+ +
+ + +
+ + +
+ + +
+ + +

Math Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + +

Static Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Symbol.html b/dist/docs/classes/Symbol.html new file mode 100644 index 00000000..1da24cec --- /dev/null +++ b/dist/docs/classes/Symbol.html @@ -0,0 +1,271 @@ + + + + +Symbol + + + + + + + + + + + +
+

Symbol

+ +

Symbols allow you to place multiple instances of an item in your +project. This can save memory, since all instances of a symbol simply refer +to the original item and it can speed up moving around complex objects, since +internal properties such as segment lists and gradient positions don't need +to be updated with every transformation.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/TextItem.html b/dist/docs/classes/TextItem.html new file mode 100644 index 00000000..9654093b --- /dev/null +++ b/dist/docs/classes/TextItem.html @@ -0,0 +1,3600 @@ + + + + +TextItem + + + + + + + + + + + +
+

TextItem

+ +

Extends Item

+ +

The TextItem type allows you to create typography. Its +functionality is inherited by different text item types such as +PointText, and AreaText (coming soon). They each add a +layer of functionality that is unique to their type, but share the +underlying properties and functions that they inherit from TextItem.

+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +

Style Properties

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + + +

Properties inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Project Hierarchy

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Bounding Rectangles

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Stroke Style

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Fill Style

+ +
+ + +
+ +
+ + + +

Methods inherited from Item

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Hierarchy Tests

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Transform Functions

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/Tool.html b/dist/docs/classes/Tool.html new file mode 100644 index 00000000..8c5f0347 --- /dev/null +++ b/dist/docs/classes/Tool.html @@ -0,0 +1,584 @@ + + + + +Tool + + + + + + + + + + + +
+

Tool

+ +

The Tool object refers to a script that the user can interact with +by using the mouse and keyboard and can be accessed through the global +tool variable. All its properties are also available in the paper +scope.

+

The global tool variable only exists in scripts that contain mouse +handler functions (onMouseMove, onMouseDown, +onMouseDrag, onMouseUp) or a keyboard handler +function (onKeyDown, onKeyUp).

+

+Example +

+ + +
var path;
+
+// Only execute onMouseDrag when the mouse
+// has moved at least 10 points:
+tool.distanceThreshold = 10;
+
+function onMouseDown(event) {
+	// Create a new path every time the mouse is clicked
+	path = new Path();
+	path.add(event.point);
+	path.strokeColor = 'black';
+}
+
+function onMouseDrag(event) {
+	// Add a point to the path every time the mouse is dragged
+	path.add(event.point);
+}
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Mouse Event Handlers

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Keyboard Event Handlers

+ +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/ToolEvent.html b/dist/docs/classes/ToolEvent.html new file mode 100644 index 00000000..cc13b2dd --- /dev/null +++ b/dist/docs/classes/ToolEvent.html @@ -0,0 +1,406 @@ + + + + +ToolEvent + + + + + + + + + + + +
+

ToolEvent

+ +

Extends Event

+ +

ToolEvent The ToolEvent object is received by the Tool's mouse +event handlers tool.onMouseDown, tool.onMouseDrag, +tool.onMouseMove and tool.onMouseUp. The ToolEvent +object is the only parameter passed to these functions and contains +information about the mouse event.

+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ +
+ + + + + +

Properties inherited from Event

+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/View.html b/dist/docs/classes/View.html new file mode 100644 index 00000000..bfcb8e9e --- /dev/null +++ b/dist/docs/classes/View.html @@ -0,0 +1,538 @@ + + + + +View + + + + + + + + + + + +
+

View

+ +

The View object wraps a canvas element and handles drawing and user +interaction through mouse and keyboard for it. It offer means to scroll the +view, find the currently visible bounds in project coordinates, or the +center, both useful for constructing artwork that should appear centered on +screen.

+ +
+ + +

Constructors

+ + +
+ + +
+ +
+ + + + + +

Properties

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Event Handlers

+ +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/global.html b/dist/docs/classes/global.html new file mode 100644 index 00000000..86893a0b --- /dev/null +++ b/dist/docs/classes/global.html @@ -0,0 +1,574 @@ + + + + +_global_ + + + + + + + + + + + +
+

Global Scope

+ + + +
+ + + + + +

Properties

+ + +
+ + +
+ + +

Global PaperScope Properties (for PaperScript)

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

View Event Handlers (for PaperScript)

+ +
+ + +
+ + +
+ + +
+ + +

Mouse Event Handlers (for PaperScript)

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +

Keyboard Event Handlers (for PaperScript)

+ +
+ + +
+ + +
+ + +
+ +
+ + + + +

Methods

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + +
+ + \ No newline at end of file diff --git a/dist/docs/classes/index.html b/dist/docs/classes/index.html new file mode 100644 index 00000000..871e0c3c --- /dev/null +++ b/dist/docs/classes/index.html @@ -0,0 +1,96 @@ + + + + +Paper.js + + + + + + + +
+

Paper.js

+ + + \ No newline at end of file diff --git a/dist/docs/index.html b/dist/docs/index.html new file mode 100644 index 00000000..198c41b4 --- /dev/null +++ b/dist/docs/index.html @@ -0,0 +1,13 @@ + + + + + +Paper.js API + + + + + + + diff --git a/dist/docs/resources/css/assets/bullet.gif b/dist/docs/resources/css/assets/bullet.gif new file mode 100644 index 0000000000000000000000000000000000000000..1789496d2e8f2b05ba41eef2d231489051507b22 GIT binary patch literal 44 tcmZ?wbhEHbWM^PxXkcJ4H8o{mU{L(Y0wft2bU*}1hJlH>g`btd8UTw21o{8~ literal 0 HcmV?d00001 diff --git a/dist/docs/resources/css/codemirror.css b/dist/docs/resources/css/codemirror.css new file mode 100644 index 00000000..98bbf7d3 --- /dev/null +++ b/dist/docs/resources/css/codemirror.css @@ -0,0 +1,141 @@ +.CodeMirror, +.CodeMirror textarea, +.CodeMirror pre { + font-family: Menlo, Consolas, "Vera Mono", monospace; + font-size: 12px; +} + +.CodeMirror { + overflow: auto; + height: 100%; +} + +.CodeMirror-gutter { + position: absolute; + left: 0; + top: 0; + min-width: 30px; + height: 100%; + background-color: #f4f4f4; + border-right: 1px solid #999; +} + +.CodeMirror-gutter-text { + color: #aaa; + text-align: right; + padding: 2px 8px 2px 8px; /* 2px required for CodeMirror-selected */ +} + +.CodeMirror-gutter-text pre { + font-size: 10px; +} + +.CodeMirror-lines { + background: #ffffff; + padding: 2px 0 2px 8px; /* 2px required for CodeMirror-selected */ +} + +.CodeMirror-lines pre.highlight { + background-color: #edf5fc; +} + +/* +.CodeMirror-lines pre:hover { + background-color: #edf5fc; +} + +.CodeMirror-lines pre.highlight:hover { + background-color: #ffffff; +} +*/ + +.CodeMirror pre { + line-height: 16px; + margin: 0; + padding: 0; + background: transparent; + font-family: inherit; +} + +.CodeMirror-cursor { + z-index: 10; + position: absolute; + visibility: hidden; + border-left: 1px solid #7c7c7c !important; + height: 16px; +} + +.CodeMirror-focused .CodeMirror-cursor { + visibility: visible; +} + +span.CodeMirror-selected { + background: #ccc !important; + color: HighlightText !important; + padding: 2px 0 2px 0; +} + +.CodeMirror-focused span.CodeMirror-selected { + background: Highlight !important; +} + +.CodeMirror-matchingbracket { + background: #e3fc8d !important; +} + +.CodeMirror-nonmatchingbracket { + color: #d62a28 !important; +} + +/* JavaScript */ + +span.cm-keyword { + color: #ff7800; +} +span.cm-atom, +span.cm-number { + color: #3b5bb5; +} +span.cm-def, +span.cm-variable-2, +span.cm-variable-3 { + color: #3a4a64; +} +span.cm-variable { + color: #000; +} +span.cm-property { + color: #000; +} +span.cm-operator { + color: #000; +} +span.cm-comment { + color: #8c868f; +} +span.cm-string { + color: #409b1c; +} +span.cm-meta { + color: #555; +} +span.cm-error { + color: #f30; +} +span.cm-qualifier { + color: #555; +} +span.cm-builtin { + color: #30a; +} +span.cm-bracket { + color: #cc7; +} +span.cm-tag { + font-weight: bold; + color: #3b5bb5; +} +span.cm-attribute { + font-style: italic; + color: #3b5bb5; +} diff --git a/dist/docs/resources/css/paperscript.css b/dist/docs/resources/css/paperscript.css new file mode 100644 index 00000000..c296c3c1 --- /dev/null +++ b/dist/docs/resources/css/paperscript.css @@ -0,0 +1,64 @@ +.paperscript .button, +.paperscript .explain { + display: none; + position: relative; /* position (top / right) relative to paperscriptcontainer */ + float: right; /* align right as block */ + font-size: 11px; + line-height: 16px; + padding: 2px 6px; + margin-bottom: -20px; /* move canvas up by 16px (height) + 2 * 2px (padding) */ + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + z-index: 1; + top: 8px; /* margin to top */ +} + +.paperscript .button { + right: 8px; /* margin to right */ + background: #eee; +} + +.paperscript .explain { + display: block; + right: 64px; /* margin to right */ + background: #e3f4fc; + margin-bottom: -36px; /* (height) + 2 * 2px (padding) */ +} + +.paperscript:hover .button { + display: block; +} + +.paperscript .button:hover { + background: #ddd; + cursor: pointer; +} + +.paperscript .source { + overflow: auto; + border: 1px solid #999; +} + +.paperscript .CodeMirror { + margin: 0 !important; /* Override any potential margins again */ +} + +.paperscript .CodeMirror-gutter-text, +.paperscript .CodeMirror-lines { + padding-top: 10px; + padding-bottom: 10px; +} + +.paperscript .canvas { + line-height: 0; /* prevent weird 5px padding under canvas elements */ +} + +.paperscript .canvas.border canvas { + border: 1px solid #999; +} + +.paperscript.split .canvas { + border: 1px solid #999; + border-top: 0; +} diff --git a/dist/docs/resources/css/reference.css b/dist/docs/resources/css/reference.css new file mode 100644 index 00000000..d9e152c3 --- /dev/null +++ b/dist/docs/resources/css/reference.css @@ -0,0 +1,128 @@ +/* These styles are shared with the server version of docs */ + +.reference h1, .reference h2, .reference h3 { + font-size: 13px; + font-weight: normal; + height: 18px; /* -2px so border-bottom aligns with contained links */ + border-bottom: 1px solid; + margin-top: 0; + margin-bottom: 16px; +} + +.reference h3 { + margin-top: 16px; + border-bottom-style: dotted; +} + +.reference a tt { + line-height: 18px; +} + +.reference p { + margin: 0 0 16px 0; +} + +.reference ul { + margin: 0; + padding: 0; + list-style: none; +} + +.reference-list ul, .reference-inherited ul { + margin-left: 16px; +} + +.reference hr { + border: none; + border-bottom: 1px dotted; +} + +.reference-packages { + margin-left: 0px; +} + +.reference-packages h2, .reference-packages h3, .reference-packages hr { + margin: 10px 0 10px 0; +} + +.reference-packages .first h2 { + margin-top: 0; +} + +* html .reference-packages img { + margin-top: 5px; +} + +.reference-packages li { + list-style: none; + list-style-image: none; /* needed for ie 6 */ +} + +.reference-members { + margin-bottom: 16px; +} + +.member-group-text { + margin-bottom: 16px; +} + +.member-description { + border: 1px solid #999; + /* .member-header defines border-top for operator lists */ + border-top: 0; + margin: 16px 0 16px 0; +} + +.member-header { + border-top: 1px solid #999; + padding: 10px; +} + +.member-title { + float: left; + width: 400px; +} + +.member-close { + float: right; +} + +.member-text { + border-top: 1px dashed #999; + padding: 10px 10px 0 10px; + margin-bottom: -6px; /* Compensate margins of p and ul to end up with 10px */ +} + +.reference ul, +.reference .paperscript, +.reference .CodeMirror { + margin-top: -8px; /* Move half way up close to previous paragraph */ + margin-bottom: 16px; +} + +.reference ul { + margin-top: 0; /* Clear the above -10px for ul again */ +} + +.member-link { + text-indent: -30px; + padding-left: 30px; +} + +.reference-inherited ul li { + text-indent: -30px; + padding-left: 30px; +} + +.package-classes { + padding-bottom: 4px; +} + +.package-classes ul { + margin-left: 10px; + margin-bottom: 10px; +} + +.reference h2 a { + font-weight: bold; +} diff --git a/dist/docs/resources/css/style.css b/dist/docs/resources/css/style.css new file mode 100644 index 00000000..e74a2dea --- /dev/null +++ b/dist/docs/resources/css/style.css @@ -0,0 +1,86 @@ +body, select, input, textarea { + font-family: "Lucida Grande", Geneva, Verdana, Arial, sans-serif; +} + +body { + background: #fff; + margin: 16px; + font-size: 13px; + line-height: 20px; + color: #000; + max-width: 540px; +} + +select, input, textarea { + font-size: 11px; + margin: 0; + color: #000; +} + +tt, pre { + font-family: Menlo, Consolas, "Vera Mono", monospace; + font-size: 12px; + line-height: 20px; +} + +a { + color: #000; + text-decoration: none; + border-bottom: 1px solid #000; +} + +img { + border: 0; +} + +a:hover { + background: #e5e5e5; +} + +p { + margin: 0 0 20px 0; +} + +ul { + padding: 0; + margin: 0 0 20px 16px; + list-style: disc outside url(assets/bullet.gif); +} + +ol { + padding: 0; + margin: 0 0 20px 0; +} + +.clear { + clear: both; +} + +.hidden { + display: none; +} + +.reference-packages, .reference-packages a { + color: #009dec; + border-bottom: 0px; +} + +/* Border-bottom color for headers and ruler */ +.reference-packages h2, .reference-packages h3, .reference-packages hr { + border-color: #009dec; +} + +.reference-packages a:hover { + background: #e3f4fc; +} + +.reference h1 { + font-size: 18px; + font-weight: normal; + line-height: 24px; + border: none; +} + +.footer { + margin-top: 20px; +} diff --git a/dist/docs/resources/js/bootstrap.js b/dist/docs/resources/js/bootstrap.js new file mode 100644 index 00000000..59d03a88 --- /dev/null +++ b/dist/docs/resources/js/bootstrap.js @@ -0,0 +1,4040 @@ +new function() { + var fix = !this.__proto__ && [Function, Number, Boolean, String, Array, Date, RegExp]; + if (fix) + for (var i in fix) + fix[i].prototype.__proto__ = fix[i].prototype; + + var has = {}.hasOwnProperty + ? function(obj, name) { + return (!fix || name != '__proto__') && obj.hasOwnProperty(name); + } + : function(obj, name) { + return obj[name] !== (obj.__proto__ || Object.prototype)[name]; + }; + + function inject(dest, src, enumerable, base, preserve, generics) { + + function field(name, dontCheck, generics) { + var val = src[name], func = typeof val == 'function', res = val, prev = dest[name]; + if (generics && func && (!preserve || !generics[name])) generics[name] = function(bind) { + return bind && dest[name].apply(bind, + Array.prototype.slice.call(arguments, 1)); + } + if ((dontCheck || val !== undefined && has(src, name)) && (!preserve || !prev)) { + if (func) { + if (prev && /\bthis\.base\b/.test(val)) { + var fromBase = base && base[name] == prev; + res = (function() { + var tmp = this.base; + this.base = fromBase ? base[name] : prev; + try { return val.apply(this, arguments); } + finally { tmp ? this.base = tmp : delete this.base; } + }).pretend(val); + } + } + dest[name] = res; + } + } + if (src) { + for (var name in src) + if (has(src, name) && !/^(statics|generics|preserve|prototype|constructor|__proto__|toString|valueOf)$/.test(name)) + field(name, true, generics); + field('toString'); + field('valueOf'); + } + } + + function extend(obj) { + function ctor(dont) { + if (fix) this.__proto__ = obj; + if (this.initialize && dont !== ctor.dont) + return this.initialize.apply(this, arguments); + } + ctor.prototype = obj; + ctor.toString = function() { + return (this.prototype.initialize || function() {}).toString(); + } + return ctor; + } + + inject(Function.prototype, { + inject: function(src) { + if (src) { + var proto = this.prototype, base = proto.__proto__ && proto.__proto__.constructor; + inject(proto, src, false, base && base.prototype, src.preserve, src.generics && this); + inject(this, src.statics, true, base, src.preserve); + } + for (var i = 1, l = arguments.length; i < l; i++) + this.inject(arguments[i]); + return this; + }, + + extend: function(src) { + var proto = new this(this.dont), ctor = proto.constructor = extend(proto); + ctor.dont = {}; + inject(ctor, this, true); + return arguments.length ? this.inject.apply(ctor, arguments) : ctor; + }, + + pretend: function(fn) { + this.toString = function() { + return fn.toString(); + } + this.valueOf = function() { + return fn.valueOf(); + } + return this; + } + }); + + function each(obj, iter, bind) { + return obj ? (typeof obj.length == 'number' + ? Array : Hash).prototype.each.call(obj, iter, bind) : bind; + } + + Base = Object.extend({ + has: function(name) { + return has(this, name); + }, + + each: function(iter, bind) { + return each(this, iter, bind); + }, + + inject: function() { + for (var i = 0, l = arguments.length; i < l; i++) + inject(this, arguments[i]); + return this; + }, + + extend: function() { + var res = new (extend(this)); + return res.inject.apply(res, arguments); + }, + + statics: { + has: has, + each: each, + + type: function(obj) { + return (obj || obj === 0) && ( + obj._type || obj.nodeName && ( + obj.nodeType == 1 && 'element' || + obj.nodeType == 3 && 'textnode' || + obj.nodeType == 9 && 'document') + || obj.location && obj.frames && obj.history && 'window' + || typeof obj) || null; + }, + + check: function(obj) { + return !!(obj || obj === 0); + }, + + pick: function() { + for (var i = 0, l = arguments.length; i < l; i++) + if (arguments[i] !== undefined) + return arguments[i]; + return null; + }, + + iterator: function(iter) { + return !iter + ? function(val) { return val } + : typeof iter != 'function' + ? function(val) { return val == iter } + : iter; + }, + + stop: {} + } + }, { + generics: true, + + debug: function() { + return /^(string|number|function|regexp)$/.test(Base.type(this)) ? this + : Base.each(this, function(val, key) { this.push(key + ': ' + val); }, []).join(', '); + }, + + clone: function() { + return Base.each(this, function(val, i) { + this[i] = val; + }, new this.constructor()); + }, + + toQueryString: function() { + return Base.each(this, function(val, key) { + this.push(key + '=' + encodeURIComponent(val)); + }, []).join('&'); + } + }); +} + +$each = Base.each; +$type = Base.type; +$check = Base.check; +$pick = Base.pick; +$stop = $break = Base.stop; + +Enumerable = { + generics: true, + preserve: true, + + findEntry: function(iter, bind) { + var that = this, iter = Base.iterator(iter), ret = null; + Base.each(this, function(val, key) { + var res = iter.call(bind, val, key, that); + if (res) { + ret = { key: key, value: val, result: res }; + throw Base.stop; + } + }); + return ret; + }, + + find: function(iter, bind) { + var entry = this.findEntry(iter, bind); + return entry && entry.result; + }, + + contains: function(iter) { + return !!this.findEntry(iter); + }, + + remove: function(iter, bind) { + var entry = this.findEntry(iter, bind); + if (entry) { + delete this[entry.key]; + return entry.value; + } + }, + + filter: function(iter, bind) { + var that = this; + return Base.each(this, function(val, i) { + if (iter.call(bind, val, i, that)) + this[this.length] = val; + }, []); + }, + + map: function(iter, bind) { + var that = this; + return Base.each(this, function(val, i) { + this[this.length] = iter.call(bind, val, i, that); + }, []); + }, + + every: function(iter, bind) { + var that = this; + return this.find(function(val, i) { + return !iter.call(this, val, i, that); + }, bind || null) == null; + }, + + some: function(iter, bind) { + return this.find(iter, bind || null) != null; + }, + + collect: function(iter, bind) { + var that = this, iter = Base.iterator(iter); + return Base.each(this, function(val, i) { + val = iter.call(bind, val, i, that); + if (val != null) + this[this.length] = val; + }, []); + }, + + max: function(iter, bind) { + var that = this, iter = Base.iterator(iter); + return Base.each(this, function(val, i) { + val = iter.call(bind, val, i, that); + if (val >= (this.max || val)) this.max = val; + }, {}).max; + }, + + min: function(iter, bind) { + var that = this, iter = Base.iterator(iter); + return Base.each(this, function(val, i) { + val = iter.call(bind, val, i, that); + if (val <= (this.min || val)) this.min = val; + }, {}).min; + }, + + pluck: function(prop) { + return this.map(function(val) { + return val[prop]; + }); + }, + + sortBy: function(iter, bind) { + var that = this, iter = Base.iterator(iter); + return this.map(function(val, i) { + return { value: val, compare: iter.call(bind, val, i, that) }; + }, bind).sort(function(left, right) { + var a = left.compare, b = right.compare; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(function(value) { + return value; + }); + } +}; + +Hash = Base.extend(Enumerable, { + generics: true, + + initialize: function(arg) { + if (typeof arg == 'string') { + for (var i = 0, l = arguments.length; i < l; i += 2) + this[arguments[i]] = arguments[i + 1]; + } else { + this.append.apply(this, arguments); + } + return this; + }, + + each: function(iter, bind) { + var bind = bind || this, iter = Base.iterator(iter), has = Base.has; + try { + for (var i in this) + if (has(this, i)) + iter.call(bind, this[i], i, this); + } catch (e) { + if (e !== Base.stop) throw e; + } + return bind; + }, + + append: function() { + for (var i = 0, l = arguments.length; i < l; i++) { + var obj = arguments[i]; + for (var key in obj) + if (Base.has(obj, key)) + this[key] = obj[key]; + } + return this; + }, + + merge: function() { + return Array.each(arguments, function(obj) { + Base.each(obj, function(val, key) { + this[key] = Base.type(this[key]) == 'object' + ? Hash.prototype.merge.call(this[key], val) + : Base.type(val) == 'object' ? Base.clone(val) : val; + }, this); + }, this); + }, + + getKeys: function() { + return Hash.getKeys(this); + }, + + getValues: Enumerable.toArray, + + getSize: function() { + return this.each(function() { + this.size++; + }, { size: 0 }).size; + }, + + statics: { + create: function(obj) { + return arguments.length == 1 && obj.constructor == Hash + ? obj : Hash.prototype.initialize.apply(new Hash(), arguments); + }, + + getKeys: Object.keys || function(obj) { + return Hash.map(function(val, key) { + return key; + }); + } + } +}); + +$H = Hash.create; + +Array.inject({ + generics: true, + preserve: true, + _type: 'array', + + forEach: function(iter, bind) { + for (var i = 0, l = this.length; i < l; i++) + iter.call(bind, this[i], i, this); + }, + + indexOf: function(obj, i) { + i = i || 0; + if (i < 0) i = Math.max(0, this.length + i); + for (var l = this.length; i < l; i++) + if (this[i] == obj) return i; + return -1; + }, + + lastIndexOf: function(obj, i) { + i = i != null ? i : this.length - 1; + if (i < 0) i = Math.max(0, this.length + i); + for (; i >= 0; i--) + if (this[i] == obj) return i; + return -1; + }, + + filter: function(iter, bind) { + var res = []; + for (var i = 0, l = this.length; i < l; i++) { + var val = this[i]; + if (iter.call(bind, val, i, this)) + res[res.length] = val; + } + return res; + }, + + map: function(iter, bind) { + var res = new Array(this.length); + for (var i = 0, l = this.length; i < l; i++) + res[i] = iter.call(bind, this[i], i, this); + return res; + }, + + every: function(iter, bind) { + for (var i = 0, l = this.length; i < l; i++) + if (!iter.call(bind, this[i], i, this)) + return false; + return true; + }, + + some: function(iter, bind) { + for (var i = 0, l = this.length; i < l; i++) + if (iter.call(bind, this[i], i, this)) + return true; + return false; + }, + + reduce: function(fn, value) { + var i = 0; + if (arguments.length < 2 && this.length) value = this[i++]; + for (var l = this.length; i < l; i++) + value = fn.call(null, value, this[i], i, this); + return value; + }, + + statics: { + isArray: function(obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + } + } +}, Enumerable, { + generics: true, + + each: function(iter, bind) { + try { + Array.prototype.forEach.call(this, Base.iterator(iter), bind = bind || this); + } catch (e) { + if (e !== Base.stop) throw e; + } + return bind; + }, + + collect: function(iter, bind) { + var that = this; + return this.each(function(val, i) { + if ((val = iter.call(bind, val, i, that)) != null) + this[this.length] = val; + }, []); + }, + + findEntry: function(iter, bind) { + if (typeof iter != 'function') { + var i = this.indexOf(iter); + return i == -1 ? null : { key: i, value: iter, result: iter }; + } + return Enumerable.findEntry.call(this, iter, bind); + }, + + remove: function(iter, bind) { + var entry = this.findEntry(iter, bind); + if (entry) { + this.splice(entry.key, 1); + return entry.value; + } + }, + + toArray: function() { + return Array.prototype.slice.call(this); + }, + + clone: function() { + return this.toArray(); + }, + + clear: function() { + this.length = 0; + }, + + compact: function() { + return this.filter(function(value) { + return value != null; + }); + }, + + append: function(items) { + for (var i = 0, l = items.length; i < l; i++) + this[this.length++] = items[i]; + return this; + }, + + associate: function(obj) { + if (!obj) + obj = this; + else if (typeof obj == 'function') + obj = this.map(obj); + if (obj.length != null) { + var that = this; + return Base.each(obj, function(name, index) { + this[name] = that[index]; + if (index == that.length) + throw Base.stop; + }, {}); + } else { + obj = Hash.append({}, obj); + return Array.each(this, function(val) { + var type = Base.type(val); + Base.each(obj, function(hint, name) { + if (hint == 'any' || type == hint) { + this[name] = val; + delete obj[name]; + throw Base.stop; + } + }, this); + }, {}); + } + }, + + flatten: function() { + return Array.each(this, function(val) { + if (val != null && val.flatten) this.append(val.flatten()); + else this.push(val); + }, []); + }, + + swap: function(i, j) { + var tmp = this[j]; + this[j] = this[i]; + this[i] = tmp; + return tmp; + }, + + shuffle: function() { + var res = this.clone(); + var i = this.length; + while (i--) res.swap(i, Math.rand(i + 1)); + return res; + }, + + pick: function() { + return this[Math.rand(this.length)]; + }, + + getFirst: function() { + return this[0]; + }, + + getLast: function() { + return this[this.length - 1]; + } +}, new function() { + function combine(subtract) { + return function(items) { + var res = new this.constructor(); + for (var i = this.length - 1; i >= 0; i--) + if (subtract == !Array.find(items, this[i])) + res.push(this[i]); + return res; + } + } + + return { + subtract: combine(true), + + intersect: combine(false) + } +}); + +Array.inject(new function() { + var proto = Array.prototype, fields = ['push','pop','shift','unshift','sort', + 'reverse','join','slice','splice','forEach','indexOf','lastIndexOf', + 'filter','map','every','some','reduce','concat'].each(function(name) { + this[name] = proto[name]; + }, { generics: true, preserve: true }); + + Array.inject(fields); + + Hash.append(fields, proto, { + clear: function() { + for (var i = 0, l = this.length; i < l; i++) + delete this[i]; + this.length = 0; + }, + + concat: function(list) { + return Browser.WEBKIT + ? new Array(this.length + list.length).append(this).append(list) + : Array.concat(this, list); + }, + + toString: proto.join, + + length: 0 + }); + + return { + statics: { + create: function(obj) { + if (obj == null) + return []; + if (obj.toArray) + return obj.toArray(); + if (typeof obj.length == 'number') + return Array.prototype.slice.call(obj); + return [obj]; + }, + + convert: function(obj) { + return Base.type(obj) == 'array' ? obj : Array.create(obj); + }, + + extend: function(src) { + var ret = Base.extend(fields, src); + ret.extend = Function.extend; + return ret; + } + } + }; +}); + +$A = Array.create; + +Function.inject(new function() { + + function timer(set) { + return function(delay, bind, args) { + var func = this.wrap(bind, args); + if (delay === undefined) + return func(); + var timer = set(func, delay); + func.clear = function() { + clearTimeout(timer); + clearInterval(timer); + }; + return func; + }; + } + + return { + generics: true, + preserve: true, + + delay: timer(setTimeout), + periodic: timer(setInterval), + + bind: function(bind) { + var that = this, slice = Array.prototype.slice, + args = arguments.length > 1 ? slice.call(arguments, 1) : null; + return function() { + return that.apply(bind, args ? arguments.length > 0 + ? args.concat(slice.call(arguments)) : args : arguments); + } + }, + + wrap: function(bind, args) { + var that = this; + return function() { + return that.apply(bind, args || arguments); + } + } + } +}); + +Number.inject({ + _type: 'number', + + limit: function(min, max) { + return Math.min(max, Math.max(min, this)); + }, + + times: function(func, bind) { + for (var i = 0; i < this; i++) + func.call(bind, i); + return bind || this; + }, + + toInt: function(base) { + return parseInt(this, base || 10); + }, + + toFloat: function() { + return parseFloat(this); + }, + + toPaddedString: function(length, base, prefix) { + var str = this.toString(base || 10); + return (prefix || '0').times(length - str.length) + str; + } +}); + +String.inject({ + _type: 'string', + + test: function(exp, param) { + return new RegExp(exp, param || '').test(this); + }, + + toArray: function() { + return this ? this.split(/\s+/) : []; + }, + + toInt: Number.prototype.toInt, + + toFloat: Number.prototype.toFloat, + + camelize: function(separator) { + return this.replace(separator ? new RegExp('[' + separator + '](\\w)', 'g') : /-(\w)/g, function(all, chr) { + return chr.toUpperCase(); + }); + }, + + uncamelize: function(separator) { + separator = separator || ' '; + return this.replace(/[a-z][A-Z0-9]|[0-9][a-zA-Z]|[A-Z]{2}[a-z]/g, function(match) { + return match.charAt(0) + separator + match.substring(1); + }); + }, + + hyphenate: function(separator) { + return this.uncamelize(separator || '-').toLowerCase(); + }, + + capitalize: function() { + return this.replace(/\b[a-z]/g, function(match) { + return match.toUpperCase(); + }); + }, + + escapeRegExp: function() { + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + trim: function(exp) { + exp = exp ? '[' + exp + ']' : '\\s'; + return this.replace(new RegExp('^' + exp + '+|' + exp + '+$', 'g'), ''); + }, + + clean: function() { + return this.replace(/\s{2,}/g, ' ').trim(); + }, + + contains: function(string, sep) { + return (sep ? (sep + this + sep).indexOf(sep + string + sep) : this.indexOf(string)) != -1; + }, + + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + + isHtml: function() { + return /^[^<]*(<(.|\s)+>)[^>]*$/.test(this); + } +}); + +RegExp.inject({ + _type: 'regexp' +}); + +Date.inject({ + statics: { + SECOND: 1000, + MINUTE: 60000, + HOUR: 3600000, + DAY: 86400000, + WEEK: 604800000, + MONTH: 2592000000, + YEAR: 31536000000, + + now: Date.now || function() { + return +new Date(); + } + } +}); + +Math.rand = function(first, second) { + return second == undefined + ? Math.rand(0, first) + : Math.floor(Math.random() * (second - first) + first); +} + +Array.inject({ + hexToRgb: function(toArray) { + if (this.length >= 3) { + var rgb = []; + for (var i = 0; i < 3; i++) + rgb.push((this[i].length == 1 ? this[i] + this[i] : this[i]).toInt(16)); + return toArray ? rgb : 'rgb(' + rgb.join(',') + ')'; + } + }, + + rgbToHex: function(toArray) { + if (this.length >= 3) { + if (this.length == 4 && this[3] == 0 && !toArray) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++) { + var bit = (this[i] - 0).toString(16); + hex.push(bit.length == 1 ? '0' + bit : bit); + } + return toArray ? hex : '#' + hex.join(''); + } + }, + + rgbToHsb: function() { + var r = this[0], g = this[1], b = this[2]; + var hue, saturation, brightness; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var delta = max - min; + brightness = max / 255; + saturation = (max != 0) ? delta / max : 0; + if (saturation == 0) { + hue = 0; + } else { + var rr = (max - r) / delta; + var gr = (max - g) / delta; + var br = (max - b) / delta; + if (r == max) hue = br - gr; + else if (g == max) hue = 2 + rr - br; + else hue = 4 + gr - rr; + hue /= 6; + if (hue < 0) hue++; + } + return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)]; + }, + + hsbToRgb: function() { + var br = Math.round(this[2] / 100 * 255); + if (this[1] == 0) { + return [br, br, br]; + } else { + var hue = this[0] % 360; + var f = hue % 60; + var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255); + var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255); + var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255); + switch (Math.floor(hue / 60)) { + case 0: return [br, t, p]; + case 1: return [q, br, p]; + case 2: return [p, br, t]; + case 3: return [p, q, br]; + case 4: return [t, p, br]; + case 5: return [br, p, q]; + } + } + } +}); + +String.inject({ + hexToRgb: function(toArray) { + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return hex && hex.slice(1).hexToRgb(toArray); + }, + + rgbToHex: function(toArray) { + var rgb = this.match(/\d{1,3}/g); + return rgb && rgb.rgbToHex(toArray); + } +}); + +Json = function(JSON) { + var special = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', "'" : "\\'", '\\': '\\\\' }; + return { + encode: JSON + ? function(obj, properties) { + return JSON.stringify(obj, properties || Browser.TRIDENT && function(key, value) { + return key == '__proto__' ? undefined : value; + }); + } + : function(obj, properties) { + if (Base.type(properties) == 'array') { + properties = properties.each(function(val) { + this[val] = true; + }, {}); + } + switch (Base.type(obj)) { + case 'string': + return '"' + obj.replace(/[\x00-\x1f\\"]/g, function(chr) { + return special[chr] || '\\u' + chr.charCodeAt(0).toPaddedString(4, 16); + }) + '"'; + case 'array': + return '[' + obj.collect(function(val) { + return Json.encode(val, properties); + }) + ']'; + case 'object': + case 'hash': + return '{' + Hash.collect(obj, function(val, key) { + if (!properties || properties[key]) { + val = Json.encode(val, properties); + if (val !== undefined) + return Json.encode(key) + ':' + val; + } + }) + '}'; + case 'function': + return undefined; + default: + return obj + ''; + } + return null; + }, + + decode: JSON + ? function(str, secure) { + try { + return JSON.parse(str); + } catch (e) { + return null; + } + } + : function(str, secure) { + try { + return Base.type(str) == 'string' && (str = str.trim()) && + (!secure || /^[\],:{}\s]*$/.test( + str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") + .replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) + ? (new Function('return ' + str))() : null; + } catch (e) { + return null; + } + } + }; +}(this.JSON); + +Browser = new function() { + var name = window.orientation != undefined ? 'ipod' + : (navigator.platform.match(/mac|win|linux|nix/i) || ['other'])[0].toLowerCase(); + var fields = { + PLATFORM: name, + XPATH: !!document.evaluate, + QUERY: !!document.querySelector + }; + fields[name.toUpperCase()] = true; + + function getVersion(prefix, min, max) { + var ver = (new RegExp(prefix + '([\\d.]+)', 'i').exec(navigator.userAgent) || [0, '0'])[1].split('.'); + return (ver.slice(0, min).join('') + '.' + ver.slice(min, max || ver.length).join('')).toFloat(); + } + + var engines = { + presto: function() { + return !window.opera ? false : getVersion('Presto/', 2) || getVersion('Opera[/ ]', 1); + }, + + trident: function() { + return !window.ActiveXObject ? false : getVersion('MSIE ', 1); + }, + + webkit: function() { + return navigator.taintEnabled ? false : getVersion('WebKit/', 1, 2); + }, + + gecko: function() { + return !document.getBoxObjectFor && window.mozInnerScreenX == null ? false : getVersion('rv:', 2); + } + }; + + for (var engine in engines) { + var version = engines[engine](); + if (version) { + fields.ENGINE = engine; + fields.VERSION = version; + engine = engine.toUpperCase(); + fields[engine] = true; + fields[(engine + version).replace(/\./g, '')] = true; + break; + } + } + + fields.log = function() { + if (!Browser.TRIDENT && window.console && console.log) + console.log.apply(console, arguments); + else + (window.console && console.log + || window.opera && opera.postError + || alert)(Array.join(arguments, ' ')); + } + + return fields; +}; + +DomNodes = Array.extend(new function() { + var unique = 0; + return { + initialize: function(nodes) { + this._unique = unique++; + this.append(nodes && nodes.length != null && !nodes.nodeType + ? nodes : arguments); + }, + + push: function() { + this.append(arguments); + return this.length; + }, + + append: function(items) { + for (var i = 0, l = items.length; i < l; i++) { + var el = items[i]; + if ((el = el && (el._wrapper || DomNode.wrap(el))) && el._unique != this._unique) { + el._unique = this._unique; + this[this.length++] = el; + } + } + return this; + }, + + toNode: function() { + return this; + }, + + statics: { + inject: function(src) { + var proto = this.prototype; + this.base(Base.each(src || {}, function(val, key) { + if (typeof val == 'function') { + var func = val, prev = proto[key]; + var count = func.length, prevCount = prev && prev.length; + val = function() { + var args = arguments, values; + if (prev && args.length == prevCount + || (args.length > count && args.length <= prevCount)) + return prev.apply(this, args); + this.each(function(obj) { + var ret = (obj[key] || func).apply(obj, args); + if (ret !== undefined && ret != obj) { + values = values || (DomNode.isNode(ret) + ? new obj._collection() : []); + values.push(ret); + } + }); + return values || this; + } + } + this[key] = val; + }, {})); + for (var i = 1, l = arguments.length; i < l; i++) + this.inject(arguments[i]); + return this; + } + } + }; +}); + +DomNode = Base.extend(new function() { + var nodes = []; + var tags = {}, classes = {}, classCheck, unique = 0; + + function dispose(force) { + for (var i = nodes.length - 1; i >= 0; i--) { + var el = nodes[i]; + if (force || (!el || el != window && el != document && + (!el.parentNode || !el.offsetParent))) { + if (el) { + var obj = el._wrapper; + if (obj && obj.finalize) obj.finalize(); + el._wrapper = el._unique = null; + } + if (!force) nodes.splice(i, 1); + } + } + } + + function inject(src) { + src = src || {}; + (src._methods || []).each(function(name) { + src[name] = function(arg) { + var ret = this.$[name] && this.$[name](arg); + return ret === undefined ? this : ret; + } + }); + (src._properties || []).each(function(name) { + var part = name.capitalize(), prop = name.toLowerCase(); + src['get' + part] = function() { + return this.getProperty(prop); + } + src['set' + part] = function(value) { + return this.setProperty(prop, value); + } + }); + delete src._methods; + delete src._properties; + return Function.inject.call(this, src); + } + + function getConstructor(el) { + var match; + return classCheck && el.className && (match = el.className.match(classCheck)) && match[2] && classes[match[2]] || + el.tagName && tags[el.tagName] || + el.className !== undefined && HtmlElement || + el.nodeType == 1 && DomElement || + el.nodeType == 3 && DomTextNode || + el.nodeType == 9 && (el.documentElement.nodeName.toLowerCase() == 'html' && HtmlDocument || DomDocument) || + el.location && el.frames && el.history && DomWindow || + DomNode; + } + + var dont = {}; + + return { + _type: 'node', + _collection: DomNodes, + _initialize: true, + + initialize: function(el, props, doc) { + if (!el) return null; + if (this._tag && Base.type(el) == 'object') { + props = el; + el = this._tag; + } + if (typeof(el) == 'string') { + el = DomElement.create(el, props, doc); + } else if (el._wrapper) { + return el._wrapper; + } + if (props === dont) { + props = null; + } else { + var ctor = getConstructor(el); + if (ctor != this.constructor) + return new ctor(el, props); + } + this.$ = el; + try { + el._wrapper = this; + nodes[nodes.length] = el; + } catch (e) {} + if (props) this.set(props); + }, + + statics: { + inject: function(src) { + if (src) { + var proto = this.prototype, that = this; + src.statics = Base.each(src, function(val, name) { + if (typeof val == 'function' && !this[name] && !that[name]) { + this[name] = function(el, param1, param2) { + if (el) try { + proto.$ = el.$ || el; + return proto[name](param1, param2); + } finally { + delete proto.$; + } + } + } + }, src.statics || {}); + inject.call(this, src); + delete src.toString; + proto._collection.inject(src); + } + for (var i = 1, l = arguments.length; i < l; i++) + this.inject(arguments[i]); + return this; + }, + + extend: function(src) { + var ret = this.base(); + var init = src.initialize; + if (init) src.initialize = function(el, props) { + var ret = this._initialize && this.base(el, props); + if (ret) return ret; + init.apply(this, arguments); + } + inject.call(ret, src); + if (ret.prototype._collection == this.prototype._collection) + ret.inject = inject; + if (src) { + if (src._tag) + tags[src._tag.toLowerCase()] = tags[src._tag.toUpperCase()] = ret; + if (src._class) { + classes[src._class] = ret; + classCheck = new RegExp('(^|\\s)(' + Base.each(classes, function(val, name) { + this.push(name); + }, []).join('|') + ')(\\s|$)'); + if (!src._lazy && src.initialize) Browser.document.addEvent('domready', function() { + this.getElements('.' + src._class); + }); + } + } + return ret; + }, + + wrap: function(el) { + return el ? typeof el == 'string' + ? DomElement.get(el) + : el._wrapper || el._collection && el || new (getConstructor(el))(el, dont) + : null; + }, + + unwrap: function(el) { + return el && el.$ || el; + }, + + unique: function(el) { + if (!el._unique) { + nodes.push(el); + el._unique = ++unique; + } + }, + + isNode: function(obj) { + return /^(element|node|textnode|document)$/.test( + typeof obj == 'string' ? obj : Base.type(obj)); + }, + + dispose: function() { + dispose(true); + } + } + } +}); + +DomNode.inject(new function() { + var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', + 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer' + ].associate(); + var properties = Hash.append({ + text: Browser.TRIDENT || Browser.WEBKIT && Browser.VERSION < 420 || Browser.PRESTO && Browser.VERSION < 9 + ? function(node) { + return node.$.innerText !== undefined ? 'innerText' : 'nodeValue' + } : 'textContent', + html: 'innerHTML', 'class': 'className', className: 'className', 'for': 'htmlFor' + }, [ + 'value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', + 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', + 'selectedIndex', 'useMap', 'width', 'height' + ].associate(function(name) { + return name.toLowerCase(); + }), bools); + + var clones = { input: 'checked', option: 'selected', textarea: Browser.WEBKIT && Browser.VERSION < 420 ? 'innerHTML' : 'value' }; + + function handle(that, prefix, name, value) { + var ctor = that.__proto__.constructor; + var handlers = ctor.handlers = ctor.handlers || { get: {}, set: {} }; + var list = handlers[prefix]; + var fn = name == 'events' && prefix == 'set' ? that.addEvents : list[name]; + if (fn === undefined) + fn = list[name] = that[prefix + name.capitalize()] || null; + return fn + ? fn[Base.type(value) == 'array' ? 'apply' : 'call'](that, value) + : that[prefix + 'Property'](name, value); + } + + function toNodes(elements) { + var els = Base.type(elements) == 'array' ? elements : Array.create(arguments); + var created = els.find(function(el) { + return !DomNode.isNode(el); + }); + var result = els.toNode(this.getDocument()); + return { + array: result ? (Base.type(result) == 'array' ? result : [result]) : [], + result: created && result + }; + } + + var fields = { + _properties: ['text'], + + set: function(name, value) { + switch (Base.type(name)) { + case 'string': + return handle(this, 'set', name, value); + case 'object': + return Base.each(name, function(value, key) { + handle(this, 'set', key, value); + }, this); + } + return this; + }, + + get: function(name) { + return handle(this, 'get', name); + }, + + getDocument: function() { + return DomNode.wrap(this.$.ownerDocument); + }, + + getWindow: function() { + return this.getDocument().getWindow(); + }, + + getPreviousNode: function() { + return DomNode.wrap(this.$.previousSibling); + }, + + getNextNode: function() { + return DomNode.wrap(this.$.nextSibling); + }, + + getFirstNode: function() { + return DomNode.wrap(this.$.firstChild); + }, + + getLastNode: function() { + return DomNode.wrap(this.$.lastChild); + }, + + getParentNode: function() { + return DomNode.wrap(this.$.parentNode); + }, + + getChildNodes: function() { + return new DomNodes(this.$.childNodes); + }, + + hasChildNodes: function() { + return this.$.hasChildNodes(); + }, + + appendChild: function(el) { + if (el = DomNode.wrap(el)) { + var text = Browser.TRIDENT && el.$.text; + if (text) el.$.text = ''; + this.$.appendChild(el.$); + if (text) el.$.text = text; + } + return this; + }, + + appendChildren: function() { + return Array.flatten(arguments).each(function(el) { + this.appendChild($(DomNode.wrap(el))); + }, this); + }, + + appendText: function(text) { + return this.injectBottom(this.getDocument().createTextNode(text)); + }, + + prependText: function(text) { + return this.injectTop(this.getDocument().createTextNode(text)); + }, + + remove: function() { + if (this.$.parentNode) + this.$.parentNode.removeChild(this.$); + return this; + }, + + removeChild: function(el) { + el = DomNode.wrap(el); + this.$.removeChild(el.$); + return el; + }, + + removeChildren: function() { + var nodes = this.getChildNodes(); + nodes.remove(); + return nodes; + }, + + replaceWith: function(el) { + if (this.$.parentNode) { + el = toNodes.apply(this, arguments); + var els = el.array; + if (els.length > 0) + this.$.parentNode.replaceChild(els[0].$, this.$); + for (var i = els.length - 1; i > 0; i--) + els[i].insertAfter(els[0]); + return el.result; + } + return null; + }, + + wrap: function() { + var el = this.injectBefore.apply(this, arguments), last; + do { + last = el; + el = el.getFirst(); + } while(el); + last.appendChild(this); + return last; + }, + + clone: function(contents) { + var clone = this.$.cloneNode(!!contents); + function clean(left, right) { + if (Browser.TRIDENT) { + left.clearAttributes(); + left.mergeAttributes(right); + left.removeAttribute('_wrapper'); + left.removeAttribute('_unique'); + if (left.options) + for (var l = left.options, r = right.options, i = l.length; i--;) + l[i].selected = r[i].selected; + } + var name = clones[right.tagName.toLowerCase()]; + if (name && right[name]) + left[name] = right[name]; + if (contents) + for (var l = left.childNodes, r = right.childNodes, i = l.length; i--;) + clean(l[i], r[i]); + } + clean(clone, this.$); + return DomNode.wrap(clone); + }, + + hasProperty: function(name) { + var key = properties[name]; + key = key && typeof key == 'function' ? key(this) : key; + return key ? this.$[key] !== undefined : this.$.hasAttribute(name); + }, + + getProperty: function(name) { + var key = properties[name], value; + key = key && typeof key == 'function' ? key(this) : key; + var value = key ? this.$[key] : this.$.getAttribute(name); + return bools[name] ? !!value : value; + }, + + setProperty: function(name, value) { + var key = properties[name], defined = value !== undefined; + key = key && typeof key == 'function' ? key(this) : key; + if (key && bools[name]) value = value || !defined ? true : false; + else if (!defined) return this.removeProperty(name); + key ? this.$[key] = value : this.$.setAttribute(name, value); + return this; + }, + + removeProperty: function(name) { + var key = properties[name], bool = key && bools[name]; + key = key && typeof key == 'function' ? key(this) : key; + key ? this.$[key] = bool ? false : '' : this.$.removeAttribute(name); + return this; + }, + + getProperties: function() { + var props = {}; + for (var i = 0; i < arguments.length; i++) + props[arguments[i]] = this.getProperty(arguments[i]); + return props; + }, + + setProperties: function(src) { + return Base.each(src, function(value, name) { + this.setProperty(name, value); + }, this); + }, + + removeProperties: function() { + return Array.each(arguments, this.removeProperty, this); + } + }; + + var inserters = { + before: function(source, dest) { + if (source && dest && dest.$.parentNode) { + var text = Browser.TRIDENT && dest.$.text; + if (text) dest.$.text = ''; + dest.$.parentNode.insertBefore(source.$, dest.$); + if (text) dest.$.text = text; + } + }, + + after: function(source, dest) { + if (source && dest && dest.$.parentNode) { + var next = dest.$.nextSibling; + if (next) source.insertBefore(next); + else dest.getParent().appendChild(source); + } + }, + + bottom: function(source, dest) { + if (source && dest) + dest.appendChild(source); + }, + + top: function(source, dest) { + if (source && dest) { + var first = dest.$.firstChild; + if (first) source.insertBefore(first); + else dest.appendChild(source); + } + } + }; + + inserters.inside = inserters.bottom; + + Base.each(inserters, function(inserter, name) { + var part = name.capitalize(); + fields['insert' + part] = function(el) { + el = toNodes.apply(this, arguments); + for (var i = 0, list = el.array, l = list.length; i < l; i++) + inserter(i == 0 ? this : this.clone(true), list[i]); + return el.result || this; + } + + fields['inject' + part] = function(el) { + el = toNodes.apply(this, arguments); + for (var i = 0, list = el.array, l = list.length; i < l; i++) + inserter(list[i], this); + return el.result || this; + } + }); + + return fields; +}); + +DomElements = DomNodes.extend(); + +DomElement = DomNode.extend({ + _type: 'element', + _collection: DomElements, + + statics: { + get: function(selector, root) { + return (root && DomNode.wrap(root) || Browser.document).getElement(selector); + }, + + getAll: function(selector, root) { + return (root && DomNode.wrap(root) || Browser.document).getElements(selector); + }, + + create: function(tag, props, doc) { + if (Browser.TRIDENT && props) { + ['name', 'type', 'checked'].each(function(key) { + if (props[key]) { + tag += ' ' + key + '="' + props[key] + '"'; + if (key != 'checked') + delete props[key]; + } + }); + tag = '<' + tag + '>'; + } + return (DomElement.unwrap(doc) || document).createElement(tag); + }, + + isAncestor: function(el, parent) { + return !el ? false : el.ownerDocument == parent ? true + : Browser.WEBKIT && Browser.VERSION < 420 + ? Array.contains(parent.getElementsByTagName(el.tagName), el) + : parent.contains + ? parent != el && parent.contains(el) + : !!(parent.compareDocumentPosition(el) & 16) + } + } +}); + +DomElement.inject(new function() { + function walk(el, walk, start, match, all) { + var elements = all && new el._collection(); + el = el.$[start || walk]; + while (el) { + if (el.nodeType == 1 && (!match || DomElement.match(el, match))) { + if (!all) return DomNode.wrap(el); + elements.push(el); + } + el = el[walk]; + } + return elements; + } + + return { + _properties: ['id'], + + getTag: function() { + return (this.$.tagName || '').toLowerCase(); + }, + + getPrevious: function(match) { + return walk(this, 'previousSibling', null, match); + }, + + getAllPrevious: function(match) { + return walk(this, 'previousSibling', null, match, true); + }, + + getNext: function(match) { + return walk(this, 'nextSibling', null, match); + }, + + getAllNext: function(match) { + return walk(this, 'nextSibling', null, match, true); + }, + + getFirst: function(match) { + return walk(this, 'nextSibling', 'firstChild', match); + }, + + getLast: function(match) { + return walk(this, 'previousSibling', 'lastChild', match); + }, + + hasChild: function(match) { + return DomNode.isNode(match) + ? DomElement.isAncestor(DomElement.unwrap(match), this.$) + : !!this.getFirst(match); + }, + + getParent: function(match) { + return walk(this, 'parentNode', null, match); + }, + + getParents: function(match) { + return walk(this, 'parentNode', null, match, true); + }, + + hasParent: function(match) { + return DomNode.isNode(match) + ? DomElement.isAncestor(this.$, DomElement.unwrap(match)) + : !!this.getParent(match); + }, + + getChildren: function(match) { + return walk(this, 'nextSibling', 'firstChild', match, true); + }, + + hasChildren: function(match) { + return !!this.getChildren(match).length; + }, + + toString: function() { + return (this.$.tagName || this._type).toLowerCase() + + (this.$.id ? '#' + this.$.id : ''); + }, + + toNode: function() { + return this; + } + }; +}); + +$ = DomElement.get; +$$ = DomElement.getAll; + +DomTextNode = DomNode.extend({ + _type: 'textnode' +}); + +DomDocument = DomElement.extend({ + _type: 'document', + + initialize: function() { + if (Browser.TRIDENT && Browser.VERSION < 7) + try { + this.$.execCommand('BackgroundImageCache', false, true); + } catch (e) {} + }, + + createElement: function(tag, props) { + return DomNode.wrap(DomElement.create(tag, props, this.$)).set(props); + }, + + createTextNode: function(text) { + return $(this.$.createTextNode(text)); + }, + + getDocument: function() { + return this; + }, + + getWindow: function() { + return DomNode.wrap(this.$.defaultView || this.$.parentWindow); + }, + + open: function() { + this.$.open(); + }, + + close: function() { + this.$.close(); + }, + + write: function(markup) { + this.$.write(markup); + }, + + writeln: function(markup) { + this.$.writeln(markup); + } +}); + +Window = DomWindow = DomElement.extend({ + _type: 'window', + _initialize: false, + _methods: ['close', 'alert', 'prompt', 'confirm', 'blur', 'focus', 'reload'], + + getDocument: function() { + return DomNode.wrap(this.$.document); + }, + + getWindow: function() { + return this; + }, + + initialize: function(param) { + var win; + if (param.location && param.frames && param.history) { + win = this.base(param) || this; + } else { + if (typeof param == 'string') + param = { url: param }; + (['toolbar','menubar','location','status','resizable','scrollbars']).each(function(key) { + param[key] = param[key] ? 1 : 0; + }); + if (param.width && param.height) { + if (param.left == null) param.left = Math.round( + Math.max(0, (screen.width - param.width) / 2)); + if (param.top == null) param.top = Math.round( + Math.max(0, (screen.height - param.height) / 2 - 40)); + } + var str = Base.each(param, function(val, key) { + if (!/^(focus|confirm|url|name)$/.test(key)) + this.push(key + '=' + (val + 0)); + }, []).join(); + win = this.base(window.open(param.url, param.name.replace(/\s+|\.+|-+/gi, ''), str)) || this; + if (win && param.focus) + win.focus(); + } + return ['location', 'frames', 'history'].each(function(key) { + this[key] = this.$[key]; + }, win); + } +}); + +DomElement.inject(new function() { + function cumulate(name, parent, iter) { + var left = name + 'Left', top = name + 'Top'; + return function(that) { + var cur, next = that, x = 0, y = 0; + do { + cur = next; + x += cur.$[left] || 0; + y += cur.$[top] || 0; + } while((next = DomNode.wrap(cur.$[parent])) && (!iter || iter(cur, next))) + return { x: x, y: y }; + } + } + + function setBounds(fields, offset) { + return function(values) { + var vals = /^(object|array)$/.test(Base.type(values)) ? values : arguments; + if (offset) { + if (vals.x) vals.left = vals.x; + if (vals.y) vals.top = vals.y; + } + var i = 0; + return fields.each(function(name) { + var val = vals.length ? vals[i++] : vals[name]; + if (val != null) this.setStyle(name, val); + }, this); + } + } + + function isBody(that) { + return that.getTag() == 'body'; + } + + var getAbsolute = cumulate('offset', 'offsetParent', Browser.WEBKIT ? function(cur, next) { + return next.$ != document.body || cur.getStyle('position') != 'absolute'; + } : null, true); + + var getPositioned = cumulate('offset', 'offsetParent', function(cur, next) { + return next.$ != document.body && !/^(relative|absolute)$/.test(next.getStyle('position')); + }); + + var getScrollOffset = cumulate('scroll', 'parentNode'); + + var fields = { + + getSize: function() { + return isBody(this) + ? this.getWindow().getSize() + : { width: this.$.offsetWidth, height: this.$.offsetHeight }; + }, + + getOffset: function(relative, scroll) { + if (isBody(this)) + return this.getWindow().getOffset(); + if (relative && !DomNode.isNode(relative)) + return getPositioned(this); + var off = getAbsolute(this); + if (relative) { + var rel = getAbsolute(DomNode.wrap(relative)); + off = { x: off.x - rel.x, y: off.y - rel.y }; + } + if (scroll) { + scroll = this.getScrollOffset(); + off.x -= scroll.x; + off.y -= scroll.y; + } + return off; + }, + + getScrollOffset: function() { + return isBody(this) + ? this.getWindow().getScrollOffset() + : getScrollOffset(this); + }, + + getScrollSize: function() { + return isBody(this) + ? this.getWindow().getScrollSize() + : { width: this.$.scrollWidth, height: this.$.scrollHeight }; + }, + + getBounds: function(relative, scroll) { + if (isBody(this)) + return this.getWindow().getBounds(); + var off = this.getOffset(relative, scroll), + el = this.$; + return { + left: off.x, + top: off.y, + right: off.x + el.offsetWidth, + bottom: off.y + el.offsetHeight, + width: el.offsetWidth, + height: el.offsetHeight + }; + }, + + setBounds: setBounds(['left', 'top', 'width', 'height', 'clip'], true), + + setOffset: setBounds(['left', 'top'], true), + + setSize: setBounds(['width', 'height', 'clip']), + + setScrollOffset: function(x, y) { + if (isBody(this)) { + this.getWindow().setScrollOffset(x, y); + } else { + var off = typeof x == 'object' ? x : { x: x, y: y }; + this.$.scrollLeft = off.x; + this.$.scrollTop = off.y; + } + return this; + }, + + scrollTo: function(x, y) { + return this.setScrollOffset(x, y); + }, + + contains: function(pos) { + var bounds = this.getBounds(); + return pos.x >= bounds.left && pos.x < bounds.right && + pos.y >= bounds.top && pos.y < bounds.bottom; + }, + + isVisible: function(fully) { + var win = this.getWindow(), top = win.getScrollOffset().y, + bottom = top + win.getSize().height, + bounds = this.getBounds(false, true); + return (bounds.height > 0 || bounds.width > 0) + && (bounds.top >= top && bounds.bottom <= bottom + || (fully && bounds.top <= top && bounds.bottom >= bottom) + || !fully && (bounds.top <= top && bounds.bottom >= top + || bounds.top <= bottom && bounds.bottom >= bottom)); + } + }; + + ['left', 'top', 'right', 'bottom', 'width', 'height'].each(function(name) { + var part = name.capitalize(); + fields['get' + part] = function() { + return this.$['offset' + part]; + }; + fields['set' + part] = function(value) { + this.$.style[name] = isNaN(value) ? value : value + 'px'; + }; + }); + + return fields; +}); + +[DomDocument, DomWindow].each(function(ctor) { + ctor.inject(this); +}, { + + getSize: function() { + if (Browser.PRESTO || Browser.WEBKIT) { + var win = this.getWindow().$; + return { width: win.innerWidth, height: win.innerHeight }; + } + var doc = this.getCompatElement(); + return { width: doc.clientWidth, height: doc.clientHeight }; + }, + + getScrollOffset: function() { + var win = this.getWindow().$, doc = this.getCompatElement(); + return { x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop }; + }, + + getScrollSize: function() { + var doc = this.getCompatElement(), min = this.getSize(); + return { width: Math.max(doc.scrollWidth, min.width), height: Math.max(doc.scrollHeight, min.height) }; + }, + + getOffset: function() { + return { x: 0, y: 0 }; + }, + + getBounds: function() { + var size = this.getSize(); + return { + left: 0, top: 0, + right: size.width, bottom: size.height, + width: size.width, height: size.height + }; + }, + + setScrollOffset: function(x, y) { + var off = typeof x == 'object' ? x : { x: x, y: y }; + this.getWindow().$.scrollTo(off.x, off.y); + return this; + }, + + getElementAt: function(pos, exclude) { + var el = this.getDocument().getElement('body'); + while (true) { + var max = -1; + var ch = el.getFirst(); + while (ch) { + if (ch.contains(pos) && ch != exclude) { + var z = ch.$.style.zIndex.toInt() || 0; + if (z >= max) { + el = ch; + max = z; + } + } + ch = ch.getNext(); + } + if (max < 0) break; + } + return el; + }, + + getCompatElement: function() { + var doc = this.getDocument(); + return doc.getElement(!doc.$.compatMode + || doc.$.compatMode == 'CSS1Compat' ? 'html' : 'body').$; + } +}); + +DomEvent = Base.extend(new function() { + var keys = { + '8': 'backspace', + '13': 'enter', + '27': 'escape', + '32': 'space', + '37': 'left', + '38': 'up', + '39': 'right', + '40': 'down', + '46': 'delete' + }; + + function hover(name, type) { + return { + type: type, + listener: function(event) { + if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) + this.fireEvent(name, [event]); + } + } + } + + return { + initialize: function(event) { + this.event = event = event || window.event; + this.type = event.type; + this.target = DomNode.wrap(event.target || event.srcElement); + if (this.target && this.target.$.nodeType == 3) + this.target = this.target.getParentNode(); + this.shift = event.shiftKey; + this.control = event.ctrlKey; + this.alt = event.altKey; + this.meta = event.metaKey; + if (/^(mousewheel|DOMMouseScroll)$/.test(this.type)) { + this.wheel = event.wheelDelta ? + event.wheelDelta / (window.opera ? -120 : 120) : + - (event.detail || 0) / 3; + } else if (/^key/.test(this.type)) { + this.code = event.which || event.keyCode; + this.key = keys[this.code] || String.fromCharCode(this.code).toLowerCase(); + } else if (/^mouse|^click$/.test(this.type)) { + this.page = { + x: event.pageX || event.clientX + document.documentElement.scrollLeft, + y: event.pageY || event.clientY + document.documentElement.scrollTop + }; + this.client = { + x: event.pageX ? event.pageX - window.pageXOffset : event.clientX, + y: event.pageY ? event.pageY - window.pageYOffset : event.clientY + }; + var offset = this.target.getOffset(); + this.offset = { + x: this.page.x - offset.x, + y: this.page.y - offset.y + } + this.rightClick = event.which == 3 || event.button == 2; + if (/^mouse(over|out)$/.test(this.type)) + this.relatedTarget = DomNode.wrap(event.relatedTarget || + this.type == 'mouseout' ? event.toElement : event.fromElement); + } + }, + + stop: function() { + this.stopPropagation(); + this.preventDefault(); + return this; + }, + + stopPropagation: function() { + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + this.stopped = true; + return this; + }, + + preventDefault: function() { + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + }, + + statics: { + events: new Hash({ + mouseenter: hover('mouseenter', 'mouseover'), + + mouseleave: hover('mouseleave', 'mouseout'), + + mousewheel: { type: Browser.GECKO ? 'DOMMouseScroll' : 'mousewheel' }, + + domready: function(func) { + var win = this.getWindow(), doc = this.getDocument(); + if (Browser.loaded) { + func.call(this); + } else if (!doc.onDomReady) { + doc.onDomReady = function() { + if (!Browser.loaded) { + Browser.loaded = true; + doc.fireEvent('domready'); + win.fireEvent('domready'); + } + } + if (Browser.TRIDENT) { + var temp = doc.createElement('div'); + (function() { + try { + temp.$.doScroll('left'); + temp.insertBottom(DomElement.get('body')).setHtml('temp').remove(); + doc.onDomReady(); + } catch (e) { + arguments.callee.delay(50); + } + }).delay(0); + } else if (Browser.WEBKIT && Browser.VERSION < 525) { + (function() { + /^(loaded|complete)$/.test(doc.$.readyState) + ? doc.onDomReady() : arguments.callee.delay(50); + })(); + } else { + win.addEvent('load', doc.onDomReady); + doc.addEvent('DOMContentLoaded', doc.onDomReady); + } + } + } + }), + + add: function(events) { + this.events.append(events); + } + } + }; +}); + +DomElement.inject(new function() { + function callEvent(fire) { + return function(type, args, delay) { + var entries = (this.events || {})[type]; + if (entries) { + var event = args && args[0]; + if (event) + args[0] = event.event ? event : new DomEvent(event); + entries.each(function(entry) { + entry[fire ? 'func' : 'bound'].delay(delay, this, args); + }, this); + } + return !!entries; + } + } + + return { + addEvent: function(type, func) { + this.events = this.events || {}; + var entries = this.events[type] = this.events[type] || []; + if (func && !entries.find(function(entry) { return entry.func == func })) { + var listener = func, name = type, pseudo = DomEvent.events[type]; + if (pseudo) { + if (typeof pseudo == 'function') pseudo = pseudo.call(this, func); + listener = pseudo && pseudo.listener || listener; + name = pseudo && pseudo.type; + } + var that = this, bound = function(event) { + if (event || window.event) + event = event && event.event ? event : new DomEvent(event); + if (listener.call(that, event) === false && event) + event.stop(); + }; + if (name) { + if (this.$.addEventListener) { + this.$.addEventListener(name, bound, false); + } else if (this.$.attachEvent) { + this.$.attachEvent('on' + name, bound); + } + } + entries.push({ func: func, name: name, bound: bound }); + } + return this; + }, + + removeEvent: function(type, func) { + var entries = (this.events || {})[type], entry; + if (func && entries) { + if (entry = entries.remove(function(entry) { return entry.func == func })) { + var name = entry.name, pseudo = DomEvent.events[type]; + if (pseudo && pseudo.remove) pseudo.remove.call(this, func); + if (name) { + if (this.$.removeEventListener) { + this.$.removeEventListener(name, entry.bound, false); + } else if (this.$.detachEvent) { + this.$.detachEvent('on' + name, entry.bound); + } + } + } + } + return this; + }, + + addEvents: function(events) { + return Base.each(events || [], function(fn, type) { + this.addEvent(type, fn); + }, this); + }, + + removeEvents: function(type) { + if (this.events) { + if (type) { + (this.events[type] || []).each(function(fn) { + this.removeEvent(type, fn); + }, this); + delete this.events[type]; + } else { + Base.each(this.events, function(ev, type) { + this.removeEvents(type); + }, this); + this.events = null; + } + } + return this; + }, + + fireEvent: callEvent(true), + + triggerEvent: callEvent(false), + + finalize: function() { + this.removeEvents(); + } + }; +}); + +DomEvent.add(new function() { + var object, last; + + function dragStart(event) { + if (object != this) { + event.type = 'dragstart'; + last = event.page; + this.fireEvent('dragstart', [event]); + if (!event.stopped) { + event.stop(); + var doc = this.getDocument(); + doc.addEvent('mousemove', drag); + doc.addEvent('mouseup', dragEnd); + object = this; + } + } + } + + function drag(event) { + event.type = 'drag'; + event.delta = { + x: event.page.x - last.x, + y: event.page.y - last.y + } + last = event.page; + object.fireEvent('drag', [event]); + event.preventDefault(); + } + + function dragEnd(event) { + if (object) { + event.type = 'dragend'; + object.fireEvent('dragend', [event]); + event.preventDefault(); + var doc = object.getDocument(); + doc.removeEvent('mousemove', drag); + doc.removeEvent('mouseup', dragEnd); + object = null; + } + } + + return { + dragstart: { + type: 'mousedown', + listener: dragStart + }, + + drag: { + type: 'mousedown', + listener: dragStart + }, + + dragend: {} + }; +}); + +DomElement.inject(new function() { + var XPATH= 0, FILTER = 1; + + var methods = [{ + getParam: function(items, separator, context, params) { + var str = context.namespaceURI ? 'xhtml:' + params.tag : params.tag; + if (separator && (separator = DomElement.separators[separator])) + str = separator[XPATH] + str; + for (var i = params.pseudos.length; i--;) { + var pseudo = params.pseudos[i]; + str += pseudo.handler[XPATH](pseudo.argument); + } + if (params.id) str += '[@id="' + params.id + '"]'; + for (var i = params.classes.length; i--;) + str += '[contains(concat(" ", @class, " "), " ' + params.classes[i] + ' ")]'; + for (var i = params.attributes.length; i--;) { + var attribute = params.attributes[i]; + var operator = DomElement.operators[attribute[1]]; + if (operator) str += operator[XPATH](attribute[0], attribute[2]); + else str += '[@' + attribute[0] + ']'; + } + items.push(str); + return items; + }, + + getElements: function(items, elements, context) { + function resolver(prefix) { + return prefix == 'xhtml' ? 'http://www.w3.org/1999/xhtml' : false; + } + var res = (context.ownerDocument || context).evaluate('.//' + items.join(''), context, + resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, l = res.snapshotLength; i < l; i++) + elements.push(res.snapshotItem(i)); + } + }, { + getParam: function(items, separator, context, params, data) { + var found = []; + var tag = params.tag; + if (separator && (separator = DomElement.separators[separator])) { + separator = separator[FILTER]; + var uniques = {}; + function add(item) { + if (!item._unique) + DomNode.unique(item); + if (!uniques[item._unique] && match(item, params, data)) { + uniques[item._unique] = true; + found.push(item); + return true; + } + } + for (var i = 0, l = items.length; i < l; i++) + separator(items[i], params, add); + if (params.clearTag) + params.tag = params.clearTag = null; + return found; + } + if (params.id) { + var el = (context.ownerDocument || context).getElementById(params.id); + params.id = null; + return el && DomElement.isAncestor(el, context) + && match(el, params, data) ? [el] : null; + } else { + if (!items.length) { + items = context.getElementsByTagName(tag); + params.tag = null; + } + for (var i = 0, l = items.length; i < l; i++) + if (match(items[i], params, data)) + found.push(items[i]); + } + return found; + }, + + getElements: function(items, elements, context) { + elements.append(items); + } + }]; + + function parse(selector) { + var params = { tag: '*', id: null, classes: [], attributes: [], pseudos: [] }; + selector.replace(/:([^:(]+)*(?:\((["']?)(.*?)\2\))?|\[([\w-]+)(?:([!*^$~|]?=)(["']?)(.*?)\6)?\]|\.[\w-]+|#[\w-]+|\w+|\*/g, function(part) { + switch (part.charAt(0)) { + case '.': params.classes.push(part.slice(1)); break; + case '#': params.id = part.slice(1); break; + case '[': params.attributes.push([arguments[4], arguments[5], arguments[7]]); break; + case ':': + var handler = DomElement.pseudos[arguments[1]]; + if (!handler) { + params.attributes.push([arguments[1], arguments[3] ? '=' : '', arguments[3]]); + break; + } + params.pseudos.push({ + name: arguments[1], + argument: handler && handler.parser + ? (handler.parser.apply ? handler.parser(arguments[3]) : handler.parser) + : arguments[3], + handler: handler.handler || handler + }); + break; + default: params.tag = part; + } + return ''; + }); + return params; + } + + function match(el, params, data) { + if (params.id && params.id != el.id) + return false; + + if (params.tag && params.tag != '*' && params.tag != (el.tagName || '').toLowerCase()) + return false; + + for (var i = params.classes.length; i--;) + if (!el.className || !el.className.contains(params.classes[i], ' ')) + return false; + + var proto = DomElement.prototype; + for (var i = params.attributes.length; i--;) { + var attribute = params.attributes[i]; + proto.$ = el; + var val = proto.getProperty(attribute[0]); + if (!val) return false; + var operator = DomElement.operators[attribute[1]]; + operator = operator && operator[FILTER]; + if (operator && (!val || !operator(val, attribute[2]))) + return false; + } + + for (var i = params.pseudos.length; i--;) { + var pseudo = params.pseudos[i]; + if (!pseudo.handler[FILTER](el, pseudo.argument, data)) + return false; + } + + return true; + } + + function filter(items, selector, context, elements, data) { + var method = methods[!Browser.XPATH || items.length || + typeof selector == 'string' && selector.contains('option[') + ? FILTER : XPATH]; + var separators = []; + selector = selector.trim().replace(/\s*([+>~\s])[a-zA-Z#.*\s]/g, function(match) { + if (match.charAt(2)) match = match.trim(); + separators.push(match.charAt(0)); + return ':)' + match.charAt(1); + }).split(':)'); + for (var i = 0, l = selector.length; i < l; i++) { + var params = parse(selector[i]); + if (!params) return elements; + var next = method.getParam(items, separators[i - 1], context, params, data); + if (!next) break; + items = next; + } + method.getElements(items, elements, context); + return elements; + } + + return { + + getElements: function(selectors, nowrap) { + var elements = nowrap ? [] : new this._collection(); + selectors = !selectors ? ['*'] : typeof selectors == 'string' + ? selectors.split(',') + : selectors.length != null ? selectors : [selectors]; + for (var i = 0, l = selectors.length; i < l; i++) { + var selector = selectors[i]; + if (Base.type(selector) == 'element') elements.push(selector); + else filter([], selector, this.$, elements, {}); + } + return elements; + }, + + getElement: function(selector) { + var el, type = Base.type(selector), match; + if (type == 'window') { + el = selector; + } else { + if (type == 'string' && (match = selector.match(/^#?([\w-]+)$/))) + el = this.getDocument().$.getElementById(match[1]); + else if (DomNode.isNode(type)) + el = DomElement.unwrap(selector); + if (el && el != this.$ && !DomElement.isAncestor(el, this.$)) + el = null; + if (!el) + el = this.getElements(selector, true)[0]; + } + return DomNode.wrap(el); + }, + + hasElement: function(selector) { + return !!this.getElement(selector); + }, + + match: function(selector) { + return !selector || match(this.$, parse(selector), {}); + }, + + filter: function(elements, selector) { + return filter(elements, selector, this.$, new this._collection(), {}); + }, + + statics: { + match: function(el, selector) { + return !selector || match(DomElement.unwrap(el), parse(selector), {}); + } + } + }; +}); + +DomElement.separators = { + '~': [ + '/following-sibling::', + function(item, params, add) { + while (item = item.nextSibling) + if (item.nodeType == 1 && add(item)) + break; + } + ], + + '+': [ + '/following-sibling::*[1]/self::', + function(item, params, add) { + while (item = item.nextSibling) { + if (item.nodeType == 1) { + add(item); + break; + } + } + } + ], + + '>': [ + '/', + function(item, params, add) { + var children = item.childNodes; + for (var i = 0, l = children.length; i < l; i++) + if (children[i].nodeType == 1) + add(children[i]); + } + ], + + ' ': [ + '//', + function(item, params, add) { + var children = item.getElementsByTagName(params.tag); + params.clearTag = true; + for (var i = 0, l = children.length; i < l; i++) + add(children[i]); + } + ] +}; + +DomElement.operators = new function() { + function contains(sep) { + return [ + function(a, v) { + return '[contains(' + (sep ? 'concat("' + sep + '", @' + a + ', "' + sep + '")' : '@' + a) + ', "' + sep + v + sep + '")]'; + }, + function(a, v) { + return a.contains(v, sep); + } + ] + } + + return { + '=': [ + function(a, v) { + return '[@' + a + '="' + v + '"]'; + }, + function(a, v) { + return a == v; + } + ], + + '^=': [ + function(a, v) { + return '[starts-with(@' + a + ', "' + v + '")]'; + }, + function(a, v) { + return a.substring(0, v.length) == v; + } + ], + + '$=': [ + function(a, v) { + return '[substring(@' + a + ', string-length(@' + a + ') - ' + v.length + ' + 1) = "' + v + '"]'; + }, + function(a, v) { + return a.substring(a.length - v.length) == v; + } + ], + + '!=': [ + function(a, v) { + return '[@' + a + '!="' + v + '"]'; + }, + function(a, v) { + return a != v; + } + ], + + '*=': contains(''), + + '|=': contains('-'), + + '~=': contains(' ') + }; +}; + +DomElement.pseudos = new function() { + var nthChild = [ + function(argument) { + switch (argument.special) { + case 'n': return '[count(preceding-sibling::*) mod ' + argument.a + ' = ' + argument.b + ']'; + case 'first': return '[count(preceding-sibling::*) = 0]'; + case 'last': return '[count(following-sibling::*) = 0]'; + case 'only': return '[not(preceding-sibling::* or following-sibling::*)]'; + case 'index': return '[count(preceding-sibling::*) = ' + argument.a + ']'; + } + }, + function(el, argument, data) { + var count = 0; + switch (argument.special) { + case 'n': + data.indices = data.indices || {}; + if (!data.indices[el._unique]) { + var children = el.parentNode.childNodes; + for (var i = 0, l = children.length; i < l; i++) { + var child = children[i]; + if (child.nodeType == 1) { + if (!child._unique) + DomNode.unique(item); + data.indices[child._unique] = count++; + } + } + } + return data.indices[el._unique] % argument.a == argument.b; + case 'first': + while (el = el.previousSibling) + if (el.nodeType == 1) + return false; + return true; + case 'last': + while (el = el.nextSibling) + if (el.nodeType == 1) + return false; + return true; + case 'only': + var prev = el; + while(prev = prev.previousSibling) + if (prev.nodeType == 1) + return false; + var next = el; + while (next = next.nextSibling) + if (next.nodeType == 1) + return false; + return true; + case 'index': + while (el = el.previousSibling) + if (el.nodeType == 1 && ++count > argument.a) + return false; + return true; + } + return false; + } + ]; + + function contains(caseless) { + var abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + return [ + function(argument) { + return '[contains(' + (caseless ? 'translate(text(), "' + abc + + '", "' + abc.toLowerCase() + '")' : 'text()') + ', "' + + (caseless && argument ? argument.toLowerCase() : argument) + '")]'; + }, + function(el, argument) { + if (caseless && argument) argument = argument.toLowerCase(); + var nodes = el.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) { + var child = nodes[i]; + if (child.nodeName && child.nodeType == 3 && + (caseless ? child.nodeValue.toLowerCase() : child.nodeValue).contains(argument)) + return true; + } + return false; + } + ]; + } + + return { + 'nth-child': { + parser: function(argument) { + var match = argument ? argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/) : [null, 1, 'n', 0]; + if (!match) return null; + var i = parseInt(match[1]), + a = isNaN(i) ? 1 : i, + special = match[2], + b = parseInt(match[3]) || 0; + if (a != 0) { + b--; + while (b < 1) b += a; + while (b >= a) b -= a; + } else { + a = b; + special = 'index'; + } + switch (special) { + case 'n': return { a: a, b: b, special: 'n' }; + case 'odd': return { a: 2, b: 0, special: 'n' }; + case 'even': return { a: 2, b: 1, special: 'n' }; + case 'first': return { special: 'first' }; + case 'last': return { special: 'last' }; + case 'only': return { special: 'only' }; + default: return { a: a - 1, special: 'index' }; + } + }, + handler: nthChild + }, + + 'even': { + parser: { a: 2, b: 1, special: 'n' }, + handler: nthChild + }, + + 'odd': { + parser: { a: 2, b: 0, special: 'n' }, + handler: nthChild + }, + + 'first-child': { + parser: { special: 'first' }, + handler: nthChild + }, + + 'last-child': { + parser: { special: 'last' }, + handler: nthChild + }, + + 'only-child': { + parser: { special: 'only' }, + handler: nthChild + }, + + 'enabled': [ + function() { + return '[not(@disabled)]'; + }, + function(el) { + return !el.disabled; + } + ], + + 'empty': [ + function() { + return '[not(node())]'; + }, + function(el) { + return !(el.innerText || el.textContent || '').length; + } + ], + + 'contains': contains(false), + + 'contains-caseless': contains(true) + }; +}; + +HtmlElements = DomElements.extend(); + +HtmlElement = DomElement.extend({ + _collection: HtmlElements +}); + +HtmlElement.inject({ + _properties: ['html'], + + getClass: function() { + return this.$.className; + }, + + setClass: function(cls) { + this.$.className = cls; + }, + + modifyClass: function(name, add) { + if (!this.hasClass(name) ^ !add) + this.$.className = (add ? this.$.className + ' ' + name : + this.$.className.replace(name, '')).clean(); + return this; + }, + + addClass: function(name) { + return this.modifyClass(name, true); + }, + + removeClass: function(name) { + return this.modifyClass(name, false); + }, + + toggleClass: function(name) { + return this.modifyClass(name, !this.hasClass(name)); + }, + + hasClass: function(name) { + return this.$.className.contains(name, ' '); + } +}); + +Array.inject({ + toNode: function(doc) { + doc = DomNode.wrap(doc || document); + var elements = new HtmlElements(); + for (var i = 0; i < this.length;) { + var value = this[i++], element = null, type = Base.type(value); + if (type == 'string') { + var props = /^(object|hash)$/.test(Base.type(this[i])) && this[i++]; + element = value.isHtml() + ? value.toNode(doc).set(props) + : doc.createElement(value, props); + if (Base.type(this[i]) == 'array') + element.injectBottom(this[i++].toNode(doc)); + } else if (DomNode.isNode(type)) { + element = value; + } else if (value && value.toNode) { + element = value.toNode(doc); + } + if (element) + elements[Base.type(element) == 'array' ? 'append' : 'push'](element); + } + return elements.length == 1 ? elements[0] : elements; + } +}); + +String.inject({ + toNode: function(doc) { + var doc = doc || document, elements; + if (this.isHtml()) { + var str = this.trim().toLowerCase(); + var div = DomElement.unwrap(doc).createElement('div'); + + var wrap = + !str.indexOf('', ''] || + !str.indexOf('', ''] || + (!str.indexOf('', ''] || + !str.indexOf('', ''] || + (!str.indexOf('', ''] || + !str.indexOf('', ''] || + [0,'','']; + + div.innerHTML = wrap[1] + this + wrap[2]; + while (wrap[0]--) + div = div.firstChild; + if (Browser.TRIDENT) { + var els = []; + if (!str.indexOf('' && str.indexOf('= 0 ; --i) { + var el = els[i]; + if (el.nodeName.toLowerCase() == 'tbody' && !el.childNodes.length) + el.parentNode.removeChild(el); + } + } + elements = new HtmlElements(div.childNodes); + } else { + elements = DomNode.wrap(doc).getElements(this); + } + return elements.length == 1 ? elements[0] : elements; + } +}); + +HtmlDocument = DomDocument.extend({ + _collection: HtmlElements +}); + +HtmlElement.inject(new function() { + var styles = { + all: { + width: '@px', height: '@px', left: '@px', top: '@px', right: '@px', bottom: '@px', + color: 'rgb(@, @, @)', backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', + fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', textIndent: '@px', + margin: '@px @px @px @px', padding: '@px @px @px @px', + border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', + borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', + borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', + clip: 'rect(@px, @px, @px, @px)', opacity: '@' + }, + part: { + 'border': {}, 'borderWidth': {}, 'borderStyle': {}, 'borderColor': {}, + 'margin': {}, 'padding': {} + } + }; + + ['Top', 'Right', 'Bottom', 'Left'].each(function(dir) { + ['margin', 'padding'].each(function(style) { + var sd = style + dir; + styles.part[style][sd] = styles.all[sd] = '@px'; + }); + var bd = 'border' + dir; + styles.part.border[bd] = styles.all[bd] = '@px @ rgb(@, @, @)'; + var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; + styles.part[bd] = {}; + styles.part.borderWidth[bdw] = styles.part[bd][bdw] = '@px'; + styles.part.borderStyle[bds] = styles.part[bd][bds] = '@'; + styles.part.borderColor[bdc] = styles.part[bd][bdc] = 'rgb(@, @, @)'; + }); + + Base.each(styles.all, function(val, name) { + this[name] = val.split(' '); + }); + + var fields = { + + getComputedStyle: function(name) { + if (this.$.currentStyle) return this.$.currentStyle[name.camelize()]; + var style = this.getWindow().$.getComputedStyle(this.$, null); + return style ? style.getPropertyValue(name.hyphenate()) : null; + }, + + getStyle: function(name) { + if (name === undefined) return this.getStyles(); + if (name == 'opacity') { + var op = this.opacity; + return op || op == 0 ? op : this.getVisibility() ? 1 : 0; + } + var el = this.$; + name = name.camelize(); + var style = el.style[name]; + if (!Base.check(style)) { + if (styles.part[name]) { + style = Hash.map(styles.part[name], function(val, key) { + return this.getStyle(key); + }, this); + return style.every(function(val) { + return val == style[0]; + }) ? style[0] : style.join(' '); + } + style = this.getComputedStyle(name); + } + if (name == 'visibility') + return /^(visible|inherit(|ed))$/.test(style); + var color = style && style.match(/rgb[a]?\([\d\s,]+\)/); + if (color) return style.replace(color[0], color[0].rgbToHex()); + if (Browser.PRESTO || Browser.TRIDENT && isNaN(parseInt(style))) { + if (/^(width|height)$/.test(name)) { + var size = 0; + (name == 'width' ? ['left', 'right'] : ['top', 'bottom']).each(function(val) { + size += this.getStyle('border-' + val + '-width').toInt() + this.getStyle('padding-' + val).toInt(); + }, this); + return this.$['offset' + name.capitalize()] - size + 'px'; + } + if (Browser.PRESTO && /px/.test(style)) return style; + if (/border(.+)[wW]idth|margin|padding/.test(name)) return '0px'; + } + return style; + }, + + setStyle: function(name, value) { + if (value === undefined) return this.setStyles(name); + var el = this.$; + switch (name) { + case 'float': + name = Browser.TRIDENT ? 'styleFloat' : 'cssFloat'; + break; + case 'clip': + if (value == true) + value = [0, el.offsetWidth, el.offsetHeight, 0]; + break; + default: + name = name.camelize(); + } + var type = Base.type(value); + if (value != undefined && type != 'string') { + var parts = styles.all[name] || ['@'], index = 0; + value = (type == 'array' ? value.flatten() : [value]).map(function(val) { + var part = parts[index++]; + if (!part) + throw Base.stop; + return Base.type(val) == 'number' ? part.replace('@', name == 'opacity' ? val : Math.round(val)) : val; + }).join(' '); + } + switch (name) { + case 'visibility': + if (!isNaN(value)) value = !!value.toInt() + ''; + value = value == 'true' && 'visible' || value == 'false' && 'hidden' || value; + break; + case 'opacity': + this.opacity = value = parseFloat(value); + this.setStyle('visibility', !!value); + if (!value) value = 1; + if (!el.currentStyle || !el.currentStyle.hasLayout) el.style.zoom = 1; + if (Browser.TRIDENT) el.style.filter = value > 0 && value < 1 ? 'alpha(opacity=' + value * 100 + ')' : ''; + el.style.opacity = value; + return this; + } + el.style[name] = value; + return this; + }, + + getStyles: function() { + return arguments.length ? Array.each(arguments, function(name) { + this[name] = that.getStyle(name); + }, {}) : this.$.style.cssText; + }, + + setStyles: function(styles) { + switch (Base.type(styles)) { + case 'object': + Base.each(styles, function(style, name) { + if (style !== undefined) + this.setStyle(name, style); + }, this); + break; + case 'string': + this.$.style.cssText = styles; + } + return this; + } + }; + + ['opacity', 'color', 'background', 'visibility', 'clip', 'zIndex', + 'border', 'margin', 'padding', 'display'].each(function(name) { + var part = name.capitalize(); + fields['get' + part] = function() { + return this.getStyle(name); + }; + fields['set' + part] = function(value) { + return this.setStyle(name, arguments.length > 1 + ? Array.create(arguments) : value); + }; + }); + + return fields; +}); + +HtmlElement.inject({ + + getFormElements: function() { + return this.getElements(['input', 'select', 'textarea']); + }, + + getValue: function(name) { + var el = this.getElement(name); + return el && el.getValue && el.getValue(); + }, + + setValue: function(name, val) { + var el = this.getElement(name); + if (!el) el = this.injectTop('input', { type: 'hidden', id: name, name: name }); + return el.setValue(val); + }, + + getValues: function() { + return this.getFormElements().each(function(el) { + var name = el.getName(), value = el.getValue(); + if (name && value !== undefined && !el.getDisabled()) + this[name] = value; + }, new Hash()); + }, + + setValues: function(values) { + return Base.each(values, function(val, name) { + this.setValue(name, val); + }, this); + }, + + toQueryString: function() { + return Base.toQueryString(this.getValues()); + } +}); + +HtmlForm = HtmlElement.extend({ + _tag: 'form', + _properties: ['action', 'method', 'target'], + _methods: ['submit'], + + blur: function() { + return this.getFormElements().each(function(el) { + el.blur(); + }, this); + }, + + enable: function(enable) { + return this.getFormElements().each(function(el) { + el.enable(enable); + }, this); + } +}); + +HtmlFormElement = HtmlElement.extend({ + _properties: ['name', 'disabled'], + _methods: ['focus', 'blur'], + + enable: function(enable) { + var disabled = !enable && enable !== undefined; + if (disabled) this.$.blur(); + this.$.disabled = disabled; + return this; + } +}); + +HtmlInput = HtmlFormElement.extend({ + _tag: 'input', + _properties: ['type', 'checked', 'defaultChecked', 'readOnly', 'maxLength'], + _methods: ['click'], + + getValue: function() { + if (this.$.checked && /^(checkbox|radio)$/.test(this.$.type) || + /^(hidden|text|password|button|search)$/.test(this.$.type)) + return this.$.value; + }, + + setValue: function(val) { + if (/^(checkbox|radio)$/.test(this.$.type)) this.$.checked = this.$.value == val; + else this.$.value = val != null ? val : ''; + return this; + } +}); + +HtmlTextArea = HtmlFormElement.extend({ + _tag: 'textarea', + _properties: ['value'] +}); + +HtmlSelect = HtmlFormElement.extend({ + _tag: 'select', + _properties: ['type', 'selectedIndex'], + + getOptions: function() { + return this.getElements('option'); + }, + + getSelected: function() { + return this.getElements('option[selected]'); + }, + + setSelected: function(values) { + this.$.selectedIndex = -1; + if (values) { + Array.each(values.length != null ? values : [values], function(val) { + val = DomElement.unwrap(val); + if (val != null) + this.getElements('option[value="' + (val.value || val) + '"]').setProperty('selected', true); + }, this); + } + return this; + }, + + getValue: function() { + return this.getSelected().getProperty('value'); + }, + + setValue: function(values) { + return this.setSelected(values); + } +}); + +HtmlOption = HtmlFormElement.extend({ + _tag: 'option', + _properties: ['text', 'value', 'selected', 'defaultSelected', 'index'] +}); + +HtmlFormElement.inject({ + setSelection: function(start, end) { + var sel = end == undefined ? start : { start: start, end: end }; + this.focus(); + if (this.$.setSelectionRange) { + this.$.setSelectionRange(sel.start, sel.end); + } else { + var value = this.getValue(); + var len = value.substring(sel.start, sel.end).replace(/\r/g, '').length; + var pos = value.substring(0, sel.start).replace(/\r/g, '').length; + var range = this.$.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos + len); + range.moveStart('character', pos); + range.select(); + } + return this; + }, + + getSelection: function() { + if (this.$.selectionStart !== undefined) { + return { start: this.$.selectionStart, end: this.$.selectionEnd }; + } else { + this.focus(); + var pos = { start: 0, end: 0 }; + var range = this.getDocument().$.selection.createRange(); + var dup = range.duplicate(); + if (this.$.type == 'text') { + pos.start = 0 - dup.moveStart('character', -100000); + pos.end = pos.start + range.text.length; + } else { + var value = this.getValue(); + dup.moveToElementText(this.$); + dup.setEndPoint('StartToEnd', range); + pos.end = value.length - dup.text.length; + dup.setEndPoint('StartToStart', range); + pos.start = value.length - dup.text.length; + } + return pos; + } + }, + + getSelectedText: function() { + var range = this.getSelection(); + return this.getValue().substring(range.start, range.end); + }, + + replaceSelectedText: function(value, select) { + var range = this.getSelection(), current = this.getValue(); + var top = this.$.scrollTop, height = this.$.scrollHeight; + this.setValue(current.substring(0, range.start) + value + current.substring(range.end, current.length)); + if (top != null) + this.$.scrollTop = top + this.$.scrollHeight - height; + return select || select == undefined + ? this.setSelection(range.start, range.start + value.length) + : this.setCaret(range.start + value.length); + }, + + getCaret: function() { + return this.getSelection().start; + }, + + setCaret: function(pos) { + return this.setSelection(pos, pos); + } +}); + +HtmlImage = HtmlElement.extend({ + _tag: 'img', + _properties: ['src', 'alt', 'title'] +}); + +$document = Browser.document = DomNode.wrap(document); +$window = Browser.window = DomNode.wrap(window).addEvent('unload', DomNode.dispose); + +Chain = { + chain: function(fn) { + (this._chain = this._chain || []).push(fn); + return this; + }, + + callChain: function() { + if (this._chain && this._chain.length) + this._chain.shift().apply(this, arguments); + return this; + }, + + clearChain: function() { + this._chain = []; + return this; + } +}; + +Callback = { + addEvent: function(type, fn) { + var ref = this.events = this.events || {}; + ref = ref[type] = ref[type] || []; + if (!ref.find(function(val) { return val == fn })) ref.push(fn); + return this; + }, + + addEvents: function(events) { + return Base.each((events || []), function(fn, type) { + this.addEvent(type, fn); + }, this); + }, + + fireEvent: function(type, args, delay) { + return (this.events && this.events[type] || []).each(function(fn) { + fn.delay(delay, this, args); + }, this); + }, + + removeEvent: function(type, fn) { + if (this.events && this.events[type]) + this.events[type].remove(function(val) { return fn == val; }); + return this; + }, + + setOptions: function(opts) { + return (this.options = Hash.create(this.options, opts)).each(function(val, i) { + if (typeof val == 'function' && (i = i.match(/^on([A-Z]\w*)/))) + this.addEvent(i[1].toLowerCase(), val); + }, this); + }, + + statics: { + inject: function() { + var proto = this.prototype, options = proto.options; + this.base.apply(this, arguments); + if (proto.options != options) + proto.options = Hash.merge({}, options, proto.options); + return this; + } + } +}; + +Request = Base.extend(Chain, Callback, new function() { + var unique = 0; + + function createRequest(that) { + if (!that.transport) + that.transport = window.XMLHttpRequest && new XMLHttpRequest() + || Browser.TRIDENT && new ActiveXObject('Microsoft.XMLHTTP'); + } + + function createFrame(that) { + var id = 'request_' + unique++, load = that.onFrameLoad.bind(that); + var div = DomElement.get('body').injectBottom('div', { + styles: { + position: 'absolute', width: 0, height: 0, top: 0, marginLeft: '-10000px' + } + }, [ + 'iframe', { + name: id, id: id, events: { load: load, readystatechange: load } + } + ] + ); + that.frame = { + id: id, div: div, + iframe: window.frames[id] || document.getElementById(id), + element: DomElement.get(id) + }; + div.offsetWidth; + } + + return { + options: { + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }, + method: 'post', + async: true, + urlEncoded: true, + encoding: 'utf-8', + emulation: true, + secure: false + }, + + initialize: function() { + var params = Array.associate(arguments, { url: 'string', options: 'object', handler: 'function' }); + this.setOptions(params.options); + if (params.handler) + this.addEvent('complete', params.handler); + if (this.options.update) + this.options.type = 'html'; + this.headers = new Hash(this.options.headers); + if (this.options.type == 'json') { + this.setHeader('Accept', 'application/json'); + this.setHeader('X-Request', 'JSON'); + } + if (this.options.urlEncoded && /^(post|put)$/.test(this.options.method)) { + this.setHeader('Content-Type', 'application/x-www-form-urlencoded' + + (this.options.encoding ? '; charset=' + this.options.encoding : '')); + } + this.headers.append(this.options.headers); + }, + + onStateChange: function() { + if (this.transport.readyState == 4 && this.running) { + this.running = false; + this.status = 0; + try { + this.status = this.transport.status; + delete this.transport.onreadystatechange; + } catch (e) {} + if (!this.status || this.status >= 200 && this.status < 300) { + this.success(this.transport.responseText, this.transport.responseXML); + } else { + this.fireEvent('complete').fireEvent('failure'); + } + } + }, + + onFrameLoad: function() { + var frame = this.frame && this.frame.iframe, loc = frame && frame.location, + doc = frame && (frame.contentDocument || frame.contentWindow || frame).document; + if (this.running && frame && loc && (!loc.href || loc.href.indexOf(this.url) != -1) + && /^(loaded|complete|undefined)$/.test(doc.readyState)) { + this.running = false; + var html = this.options.type == 'html', area = !html + && doc.getElementsByTagName('textarea')[0]; + var text = doc && (area && area.value || doc.body + && (html && doc.body.innerHTML || doc.body.textContent + || doc.body.innerText)) || ''; + this.frame.element.setProperty('src', ''); + this.success(text); + if (!this.options.link) { + var div = this.frame.div; + div.insertBottom(DomElement.get('body')); + div.remove.delay(5000, div); + this.frame = null; + } + } + }, + + success: function(text, xml) { + var args; + switch (this.options.type) { + case 'html': + var match = text.match(/]*>([\u0000-\uffff]*?)<\/body>/i); + var stripped = this.stripScripts(match ? match[1] : text); + if (this.options.update) + DomElement.get(this.options.update).setHtml(stripped.html); + if (this.options.evalScripts) + this.executeScript(stripped.script); + args = [ stripped.html, text ]; + break; + case 'json': + args = [ Json.decode(text, this.options.secure), text ]; + break; + default: + args = [ this.processScripts(text), xml ] + } + this.fireEvent('complete', args) + .fireEvent('success', args) + .callChain(); + }, + + stripScripts: function(html) { + var script = ''; + html = html.replace(/]*>([\u0000-\uffff]*?)<\/script>/gi, function() { + script += arguments[1] + '\n'; + return ''; + }); + return { html: html, script: script }; + }, + + processScripts: function(text) { + if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) { + this.executeScript(text); + return text; + } else { + var stripped = this.stripScripts(text); + if (this.options.evalScripts) + this.executeScript(stripped.script); + return stripped.html; + } + }, + + executeScript: function(script) { + if (window.execScript) { + window.execScript(script); + } else { + DomElement.get('head').injectBottom('script', { + type: 'text/javascript', text: script + }).remove(); + } + }, + + setHeader: function(name, value) { + this.headers[name] = value; + return this; + }, + + getHeader: function(name) { + try { + if (this.transport) + return this.transport.getResponseHeader(name); + } catch (e) {} + return null; + }, + + send: function() { + var params = Array.associate(arguments, { url: 'string', options: 'object', handler: 'function' }); + var opts = params.options ? Hash.merge(params.options, this.options) : this.options; + if (params.handler) + this.addEvent('complete', function() { + params.handler.apply(this, arguments); + this.removeEvent('complete', arguments.callee); + }); + if (this.running) { + switch (opts.link) { + case 'cancel': + this.cancel(); + break; + case 'chain': + this.chain(this.send.wrap(this, arguments)); + default: + return this; + } + } + var data = opts.data || ''; + var url = params.url || opts.url; + switch (Base.type(data)) { + case 'element': + data = DomNode.wrap(data); + if (data.getTag() != 'form' || !data.hasElement('input[type=file]')) + data = data.toQueryString(); + break; + case 'object': + data = Base.toQueryString(data); + break; + default: + data = data.toString(); + } + var string = typeof data == 'string', method = opts.method; + if (opts.emulation && /^(put|delete)$/.test(method)) { + if (string) data += '&_method=' + method; + else data.setValue('_method', method); + method = 'post'; + } + if (string && !this.options.iframe) { + createRequest(this); + if (!this.transport) { + if (!this.frame) + createFrame(this); + method = 'get'; + } + } else if (!this.frame) { + createFrame(this); + } + if (string && data && method == 'get') { + url += (url.contains('?') ? '&' : '?') + data; + data = null; + } + this.running = true; + this.url = url; + if (this.frame) { + var form = !string && data; + if (form) { + form.set({ + target: this.frame.id, action: url, method: method, + enctype: method == 'get' + ? 'application/x-www-form-urlencoded' + : 'multipart/form-data', + 'accept-charset': opts.encoding || '' + }).submit(); + } else { + this.frame.element.setProperty('src', url); + } + } else if (this.transport) { + try { + this.transport.open(method.toUpperCase(), url, opts.async); + this.transport.onreadystatechange = this.onStateChange.bind(this); + new Hash(this.headers, opts.headers).each(function(header, name) { + try{ + this.transport.setRequestHeader(name, header); + } catch (e) { + this.fireEvent('exception', [e, name, header]); + } + }, this); + this.fireEvent('request'); + this.transport.send(data); + if (!opts.async) + this.onStateChange(); + } catch (e) { + this.fireEvent('failure', [e]); + } + } + return this; + }, + + cancel: function() { + if (this.running) { + this.running = false; + if (this.transport) { + this.transport.abort(); + this.transport.onreadystatechange = null; + this.transport = null; + } else if (this.frame) { + this.frame.div.remove(); + this.frame = null; + } + this.fireEvent('cancel'); + } + return this; + } + }; +}); + +HtmlForm.inject({ + send: function(url) { + if (!this.sender) + this.sender = new Request({ link: 'cancel' }); + this.sender.send({ + url: url || this.getProperty('action'), + data: this, method: this.getProperty('method') || 'post' + }); + } +}); + +HtmlElement.inject({ + load: function() { + if (!this.loader) + this.loader = new Request({ link: 'cancel', update: this, method: 'get' }); + this.loader.send(Array.associate(arguments, { data: 'object', url: 'string' })); + return this; + } +}); + +Asset = new function() { + function getProperties(props) { + return props ? Hash.create(props).each(function(val, key) { + if (/^on/.test(key)) delete this[key]; + }) : {}; + } + + function createMultiple(type, sources, options) { + var props = getProperties(options), count = 0; + options = options || {}; + return sources.each(function(src) { + props.onLoad = function() { + if (options.onProgress) + options.onProgress(src); + if (++count == sources.length && options.onComplete) + options.onComplete(); + } + this.push(Asset[type](src, props)); + }, new HtmlElements()); + } + + return { + script: function(src, props) { + var script = DomElement.get('head').injectBottom('script', Hash.merge({ + events: { + load: props.onLoad && function() { + if (!this.loaded) { + this.loaded = true; + props.onLoad.call(this); + } + }, + readystatechange: function() { + if (/loaded|complete/.test(this.$.readyState)) + this.fireEvent('load'); + } + }, + src: src + }, getProperties(props))); + if (Browser.WEBKIT && Browser.VERSION < 420) + new Request({ url: src, method: 'get' }).addEvent('success', function() { + script.fireEvent('load', [], 1); + }).send(); + return script; + }, + + stylesheet: function(src, props) { + return new HtmlElement('link', new Hash({ + rel: 'stylesheet', media: 'screen', type: 'text/css', href: src + }, props)).insertInside(DomElement.get('head')); + }, + + image: function(src, props) { + props = props || {}; + var image = new Image(); + image.src = src; + var element = new HtmlElement('img', { src: src }); + ['load', 'abort', 'error'].each(function(type) { + var name = 'on' + type.capitalize(); + if (props[name]) element.addEvent(type, function() { + this.removeEvent(type, arguments.callee); + props[name].call(this); + }); + }); + if (image.width && image.height) + element.fireEvent('load', [], 1); + return element.setProperties(getProperties(props)); + }, + + scripts: function(sources, options) { + return createMultiple('script', sources, options); + }, + + stylesheets: function(sources, options) { + return createMultiple('stylesheet', sources, options); + }, + + images: function(sources, options) { + return createMultiple('image', sources, options); + } + } +}; + +Cookie = { + set: function(name, value, expires, path) { + document.cookie = name + '=' + encodeURIComponent(value) + (expires ? ';expires=' + + expires.toGMTString() : '') + ';path=' + (path || '/'); + }, + get: function(name) { + var res = document.cookie.match('(?:^|;)\\s*' + name + '=([^;]*)'); + if (res) return decodeURIComponent(res[1]); + }, + + remove: function(name) { + this.set(name, '', -1); + } +}; + +Fx = Base.extend(Chain, Callback, { + options: { + fps: 50, + unit: false, + duration: 500, + wait: true, + transition: function(p) { + return -(Math.cos(Math.PI * p) - 1) / 2; + } + }, + + initialize: function(element, options) { + this.element = DomElement.get(element); + this.setOptions(options); + }, + + step: function() { + var time = Date.now(); + if (time < this.time + this.options.duration) { + this.delta = this.options.transition((time - this.time) / this.options.duration); + this.update(this.get()); + } else { + this.stop(true); + this.update(this.to); + this.fireEvent('complete', [this.element]).callChain(); + } + }, + + set: function(to) { + this.update(to); + this.fireEvent('set', [this.element]); + return this; + }, + + get: function() { + return this.compute(this.from, this.to); + }, + + compute: function(from, to) { + return (to - from) * this.delta + from; + }, + + start: function(from, to) { + if (!this.options.wait) this.stop(); + else if (this.timer) return this; + this.from = from; + this.to = to; + this.time = Date.now(); + if (!this.slave) { + this.timer = this.step.periodic(Math.round(1000 / this.options.fps), this); + this.fireEvent('start', [this.element]); + } + this.step(); + return this; + }, + + stop: function(end) { + if (this.timer) { + this.timer = this.timer.clear(); + if (!end) this.fireEvent('cancel', [this.element]).clearChain(); + } + return this; + } +}); + +Fx.Scroll = Fx.extend({ + options: { + offset: { x: 0, y: 0 }, + wheelStops: true + }, + + initialize: function(element, options) { + this.base(element, options); + if (this.options.wheelStops) { + var stop = this.stop.bind(this), stopper = this.element; + this.addEvent('start', function() { + stopper.addEvent('mousewheel', stop); + }, true); + this.addEvent('complete', function() { + stopper.removeEvent('mousewheel', stop); + }, true); + } + }, + + update: function(x, y) { + var now = Array.flatten(arguments); + this.element.setScrollOffset(now[0], now[1]); + }, + + get: function() { + var now = []; + for (var i = 0; i < 2; i++) + now.push(this.compute(this.from[i], this.to[i])); + return now; + }, + + start: function(x, y) { + var offsetSize = this.element.getSize(), + scrollSize = this.element.getScrollSize(), + scroll = this.element.getScrollOffset(), + values = { x: x, y: y }, + lookup = { x: 'width', y: 'height' }; + for (var i in values) { + var s = lookup[i]; + var max = scrollSize[s] - offsetSize[s]; + if (Base.check(values[i])) + values[i] = Base.type(values[i]) == 'number' + ? values[i].limit(0, max) : max; + else values[i] = scroll[i]; + values[i] += this.options.offset[i]; + } + return this.base([scroll.x, scroll.y], [values.x, values.y]); + }, + + toTop: function() { + return this.start(false, 0); + }, + + toLeft: function() { + return this.start(0, false); + }, + + toRight: function() { + return this.start('right', false); + }, + + toBottom: function() { + return this.start(false, 'bottom'); + }, + + toElement: function(el, options) { + var el = DomElement.get(el), offset = el.getOffset(), + current = el.getWindow().getScrollOffset(); + return this.start( + !options || options.x ? offset.x : current.x, + !options || options.y ? offset.y : current.y); + } +}); + +Fx.SmoothScroll = Fx.Scroll.extend({ + initialize: function(options, context) { + context = DomElement.get(context || document); + var doc = context.getDocument(), win = context.getWindow(); + this.base(doc, options); + var links = this.options.links ? $$(this.options.links) : $$('a', context); + var loc = win.location.href.match(/^[^#]*/)[0] + '#'; + links.each(function(link) { + if (link.$.href.indexOf(loc) != 0) return; + var hash = link.$.href.substring(loc.length); + var anchor = hash && DomElement.get('#' + hash, context); + if (anchor) { + link.addEvent('click', function(event) { + this.toElement(anchor); + var props = anchor.getProperties('name', 'id'); + anchor.removeProperties('name', 'id'); + win.location.hash = hash; + anchor.setProperties(props); + event.stop(); + }.bind(this)); + } + }, this); + } +}); + +Fx.CSS = new function() { + + var parsers = new Hash({ + color: { + match: function(value) { + if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); + return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; + }, + + compute: function(from, to, fx) { + return from.map(function(value, i) { + return Math.round(fx.compute(value, to[i])); + }); + }, + + get: function(value) { + return value.map(Number); + } + }, + + number: { + match: function(value) { + return parseFloat(value); + }, + + compute: function(from, to, fx) { + return fx.compute(from, to); + }, + + get: function(value, unit) { + return (unit) ? value + unit : value; + } + } + }); + + return { + start: function(element, property, values) { + values = Array.convert(values); + if (!Base.check(values[1])) + values = [ element.getStyle(property), values[0] ]; + var parsed = values.map(Fx.CSS.set); + return { from: parsed[0], to: parsed[1] }; + }, + + set: function(value) { + return Array.convert(value).map(function(val) { + val = val + ''; + var res = parsers.find(function(parser, key) { + var value = parser.match(val); + if (Base.check(value)) return { value: value, parser: parser }; + }) || { + value: val, + parser: { + compute: function(from, to) { + return to; + } + } + }; + return res; + }); + }, + + compute: function(from, to, fx) { + return from.map(function(obj, i) { + return { + value: obj.parser.compute(obj.value, to[i].value, fx), + parser: obj.parser + }; + }); + }, + + get: function(now, unit) { + return now.reduce(function(prev, cur) { + var get = cur.parser.get; + return prev.concat(get ? get(cur.value, unit) : cur.value); + }, []); + } + } +}; + +Fx.Style = Fx.extend({ + initialize: function(element, property, options) { + this.base(element, options); + this.property = property; + }, + + hide: function() { + return this.set(0); + }, + + get: function() { + return Fx.CSS.compute(this.from, this.to, this); + }, + + set: function(to) { + return this.base(Fx.CSS.set(to)); + }, + + start: function(from, to) { + if (this.timer && this.options.wait) return this; + var parsed = Fx.CSS.start(this.element, this.property, [from, to]); + return this.base(parsed.from, parsed.to); + }, + + update: function(val) { + this.element.setStyle(this.property, Fx.CSS.get(val, this.options.unit)); + } +}); + +HtmlElement.inject({ + effect: function(prop, opts) { + return new Fx.Style(this, prop, opts); + } +}); + +Fx.Styles = Fx.extend({ + get: function() { + var that = this; + return Base.each(this.from, function(from, key) { + this[key] = Fx.CSS.compute(from, that.to[key], that); + }, {}); + }, + + set: function(to) { + return this.base(Base.each(to, function(val, key) { + this[key] = Fx.CSS.set(val); + }, {})); + }, + + start: function(obj) { + if (this.timer && this.options.wait) return this; + var from = {}, to = {}; + Base.each(obj, function(val, key) { + var parsed = Fx.CSS.start(this.element, key, val); + from[key] = parsed.from; + to[key] = parsed.to; + }, this); + return this.base(from, to); + }, + + update: function(val) { + Base.each(val, function(val, key) { + this.element.setStyle(key, Fx.CSS.get(val, this.options.unit)); + }, this); + } + +}); + +HtmlElement.inject({ + effects: function(opts) { + return new Fx.Styles(this, opts); + } +}); + +Fx.Elements = Fx.extend({ + initialize: function(elements, options) { + this.base(null, options); + this.elements = DomElement.getAll(elements); + }, + + start: function(obj) { + if (this.timer && this.options.wait) return this; + this.effects = {}; + + function start(that, key, val) { + var fx = that.effects[key] = new Fx.Styles(that.elements[key], that.options); + fx.slave = true; + fx.start(val); + } + + Base.each(obj, function(val, key) { + if (key == '*') { + this.elements.each(function(el, key) { + start(this, key, val); + }, this); + } else if (isNaN(parseInt(key))) { + var els = DomElement.getAll(key); + this.elements.append(els); + els.each(function(el) { + start(this, this.elements.indexOf(el), val); + }, this); + } else { + start(this, key, val); + } + }, this); + return this.base(); + }, + + set: function(to) { + }, + + update: function(to) { + Base.each(this.effects, function(fx) { + fx.step(); + }); + } +}); + +Fx.Transitions = new Base().inject({ + inject: function(src) { + return this.base(Base.each(src, function(func, name) { + func.In = func; + + func.Out = function(pos) { + return 1 - func(1 - pos); + } + + func.InOut = function(pos) { + return pos <= 0.5 ? func(2 * pos) / 2 : (2 - func(2 * (1 - pos))) / 2; + } + })); + }, + + Linear: function(p) { + return p; + } +}); + +Fx.Transitions.inject({ + Pow: function(p, x) { + return Math.pow(p, x[0] || 6); + }, + + Expo: function(p) { + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p) { + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p) { + return 1 - Math.sin((1 - p) * Math.PI / 2); + }, + + Back: function(p, x) { + x = x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p) { + var value; + for (var a = 0, b = 1; 1; a += b, b /= 2) { + if (p >= (7 - 4 * a) / 11) { + value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b; + break; + } + } + return value; + }, + + Elastic: function(p, x) { + return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); + } + +}); + +Fx.Transitions.inject(['Quad', 'Cubic', 'Quart', 'Quint'].each(function(name, i) { + this[name] = function(p) { + return Math.pow(p, i + 2); + } +}, {})); + diff --git a/dist/docs/resources/js/codemirror.js b/dist/docs/resources/js/codemirror.js new file mode 100644 index 00000000..0c1c6427 --- /dev/null +++ b/dist/docs/resources/js/codemirror.js @@ -0,0 +1 @@ +var CodeMirror=function(){function O(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c=0&&d>=0;--c,--d)if(a.charAt(c)!=b.charAt(d))break;return d+1}function M(a){L.innerText=L.textContent=a;return L.innerHTML}function K(a){return{line:a.line,ch:a.ch}}function J(a,b){return a.linea&&d.push(h.slice(a-f,Math.min(h.length,b-f)),c[e+1]),i>=a&&(g=1)):g==1&&(i>b?d.push(h.slice(0,b-f),c[e+1]):d.push(h,c[e+1])),f=i}}function h(a,b){this.styles=b||[a,null],this.stateAfter=null,this.text=a,this.marked=this.gutterMarker=this.className=null}function g(a){this.pos=this.start=0,this.string=a}function f(a,b,c){return a.startState?a.startState(b,c):!0}function e(a,b){if(b===!0)return b;if(a.copyState)return a.copyState(b);var c={};for(var d in b){var e=b[d];e instanceof Array&&(e=e.concat([])),c[d]=e}return c}function a(b,c){function cV(a,b,c){this.atOccurrence=!1,c==null&&(c=typeof a=="string"&&a==a.toLowerCase()),b&&typeof b=="object"?b=cj(b):b={line:0,ch:0},this.pos={from:b,to:b};if(typeof a!="string")this.matches=function(b,c){if(b){var d=ba[c.line].text.slice(0,c.ch),e=d.match(a),f=0;while(e){var g=d.indexOf(e[0]);f+=g,d=d.slice(g+1);var h=d.match(a);if(h)e=h;else break;f++}}else var d=ba[c.line].text.slice(c.ch),e=d.match(a),f=e&&c.ch+d.indexOf(e[0]);if(e)return{from:{line:c.line,ch:f},to:{line:c.line,ch:f+e[0].length},match:e}};else{c&&(a=a.toLowerCase());var d=c?function(a){return a.toLowerCase()}:function(a){return a},e=a.split("\n");e.length==1?this.matches=function(b,c){var e=d(ba[c.line].text),f=a.length,g;if(b?c.ch>=f&&(g=e.lastIndexOf(a,c.ch-f))!=-1:(g=e.indexOf(a,c.ch))!=-1)return{from:{line:c.line,ch:g},to:{line:c.line,ch:g+f}}}:this.matches=function(a,b){var c=b.line,f=a?e.length-1:0,g=e[f],h=d(ba[c].text),i=a?h.indexOf(g)+g.length:h.lastIndexOf(g);if(!(a?i>=b.ch||i!=g.length:i<=b.ch||i!=h.length-g.length))for(;;){if(a?!c:c==ba.length-1)return;h=d(ba[c+=a?-1:1].text),g=e[a?--f:++f];if(f>0&&f=ba.length)continue;var d=cM(c),h=d&&ba[d-1].stateAfter;h?h=e(_,h):h=f(_);var i=0,j=_.compareStates;for(var k=d,l=ba.length;ka){bb.push(k),cQ(g.workDelay),bj.push({from:c,to:k+1});return}var o=m.highlight(_,h);m.stateAfter=e(_,h);if(j){if(n&&j(n,h))break}else if(o||!n)i=0;else if(++i>3)break}bj.push({from:c,to:k+1})}b&&g.onHighlightComplete&&g.onHighlightComplete(by)}function cO(a,b){var c=cN(a);for(var d=a;de;--d){if(d==0)return 0;var f=ba[d-1];if(f.stateAfter)return d;var g=f.indentation();if(c==null||b>g)c=d,b=g}return c}function cL(a){function p(a,b,c){if(!!a.text){var d=a.styles,e=g?0:a.text.length-1,f;for(var i=g?0:d.length-2,j=g?d.length:-2;i!=j;i+=2*h){var k=d[i];if(d[i+1]!=null&&d[i+1]!=m){e+=h*k.length;continue}for(var l=g?0:k.length-1,p=g?k.length:-1;l!=p;l+=h,e+=h)if(e>=b&&e"==g)n.push(f);else{if(n.pop()!=q.charAt(0))return{pos:e,match:!1};if(!n.length)return{pos:e,match:!0}}}}}}var b=be.inverted?be.from:be.to,c=ba[b.line],d=b.ch-1,e=d>=0&&cK[c.text.charAt(d)]||cK[c.text.charAt(++d)];if(!!e){var f=e.charAt(0),g=e.charAt(1)==">",h=g?1:-1,i=c.styles;for(var j=d+1,k=0,l=i.length;kF.clientWidth||e-c.top>F.clientHeight))return null;var f=G(V,!0),g=bn+Math.floor((e-f.top)/cE());return cj({line:g,ch:cB(ci(g),d-f.left)})}function cG(){return V.offsetLeft}function cF(){return V.offsetTop}function cE(){var a=X.childNodes.length;if(a)return X.offsetHeight/a||1;M.innerHTML="
x
";return M.firstChild.offsetHeight||1}function cD(a){var b=cC(a,!0),c=G(V);return{x:c.left+b.x,y:c.top+b.y,yBot:c.top+b.yBot}}function cC(a,b){var c=cE(),d=a.line-(b?bn:0);return{x:cA(a.line,a.ch),y:d*c,yBot:(d+1)*c}}function cB(a,b){function e(a){M.innerHTML="
"+c.getHTML(null,null,!1,a)+"
";return M.firstChild.firstChild.offsetWidth}if(b<=0)return 0;var c=ba[a],d=c.text,f=0,g=0,h=d.length,i,j=Math.min(h,Math.ceil(b/cz("x")));for(;;){var k=e(j);if(k<=b&&ji)return h;j=Math.floor(h*.8),k=e(j),kb-g?f:h;var l=Math.ceil((f+h)/2),m=e(l);m>b?(h=l,i=m):(f=l,g=m)}}function cA(a,b){if(b==0)return 0;M.innerHTML="
"+ba[a].getHTML(null,null,!1,b)+"
";return M.firstChild.firstChild.offsetWidth}function cz(a){M.innerHTML="
x
",M.firstChild.firstChild.firstChild.nodeValue=a;return M.firstChild.firstChild.offsetWidth||10}function cy(a){if(typeof a=="number"){var b=a;a=ba[a];if(!a)return null}else{var b=O(ba,a);if(b==-1)return null}var c=a.gutterMarker;return{line:b,text:a.text,markerText:c&&c.text,markerClass:c&&c.style}}function cx(a,b){if(typeof a=="number"){var c=a;a=ba[ci(a)]}else{var c=O(ba,a);if(c==-1)return null}a.className!=b&&(a.className=b,bj.push({from:c,to:c+1}));return a}function cw(a){typeof a=="number"&&(a=ba[ci(a)]),a.gutterMarker=null,cd()}function cv(a,b,c){typeof a=="number"&&(a=ba[ci(a)]),a.gutterMarker={text:b,style:c},cd();return a}function cu(a,b,c){function e(a,b,c,e){var a=ba[a],f=a.addMark(b,c,e);f.line=a,d.push(f)}a=cj(a),b=cj(b);var d=[];if(a.line==b.line)e(a.line,a.ch,b.ch,c);else{e(a.line,a.ch,null,c);for(var f=a.line+1,g=b.line;f-1&&(a==null&&(a=f),b=f)}a!=null&&bj.push({from:a,to:b+1})}}function ct(){var a=g.gutter||g.lineNumbers;T.style.display=a?"":"none",a?cd():X.parentNode.style.marginLeft=0}function cs(){_=a.getMode(g,g.mode);for(var b=0,c=ba.length;b0&&/\w/.test(b.charAt(c-1)))--c;while(d=ba.length)return{line:ba.length-1,ch:ba[ba.length-1].text.length};var b=a.ch,c=ba[a.line].text.length;return b==null||b>c?{line:a.line,ch:c}:b<0?{line:a.line,ch:0}:a}function ci(a){return Math.max(0,Math.min(a,ba.length-1))}function ch(a,b,c){var d=cj({line:a,ch:b||0});(c?cf:cg)(d,d)}function cg(a,b,c,d){if(!I(be.from,a)||!I(be.to,b)){if(J(b,a)){var e=b;b=a,a=e}I(a,b)?be.inverted=!1:I(a,be.to)?be.inverted=!1:I(b,be.from)&&(be.inverted=!0),c==null&&(c=be.from.line,d=be.to.line),I(a,b)?I(be.from,be.to)||bj.push({from:c,to:d+1}):I(be.from,be.to)?bj.push({from:a.line,to:b.line+1}):(I(a,be.from)||(a.line':"
",f,"
")}T.style.display="none",U.innerHTML=c.join("");var h=String(ba.length).length,i=U.firstChild,j=H(i),k="";while(j.length+k.length0;--k)X.removeChild(j?j.previousSibling:X.lastChild);else if(i){for(var k=Math.max(0,i);k>0;--k)X.insertBefore(n.createElement("pre"),j);for(var k=Math.max(0,-i);k>0;--k)X.removeChild(j?j.previousSibling:X.lastChild)}var l=X.childNodes[h.domStart+d],m=b=h.from;for(var k=h.from;kj.from&&f.push({from:j.from,to:e.from,domStart:j.domStart}),e.to=m)break;if(j.domStart>o||j.from>q)n.push({from:q,to:j.from,domSize:j.domStart-o,domStart:o}),r+=j.from-q;q=j.to,o=j.domStart+(j.to-j.from)}if(o!=p||q!=m)r+=Math.abs(m-q),n.push({from:q,to:m,domSize:p-o,domStart:o});if(!n.length)return;X.style.display="none",r>(k.to-k.from)*.3?cb(l=Math.max(k.from-10,0),m=Math.min(k.to+7,ba.length)):cc(n),X.style.display="";var s=l!=bn||m!=bo||bp!=F.clientHeight;bn=l,bo=m,S.style.top=l*cE()+"px",s&&(bp=F.clientHeight,L.style.height=ba.length*cE()+2*cF()+"px",cd()),bu==null&&(bu=cz(bt)),bu>F.clientWidth?(V.style.width=bu+"px",L.style.width="",L.style.width=F.scrollWidth+"px"):V.style.width=L.style.width="";if(X.childNodes.length!=bo-bn)throw new Error("BAD PATCH! "+JSON.stringify(n)+" size="+(bo-bn)+" nodes="+X.childNodes.length);ce()}}function b_(){var a=cE(),b=F.scrollTop-cF();return{from:Math.min(ba.length,Math.max(0,Math.floor(b/a))),to:Math.min(ba.length,Math.ceil((b+F.clientHeight)/a))}}function b$(a,b,c,d){var e=cG(),f=cF(),h=cE();b+=f,d+=f,a+=e,c+=e;var i=F.clientHeight,j=F.scrollTop,k=!1,l=!0;bj+i&&(F.scrollTop=d+h-i,k=!0);var m=F.clientWidth,n=F.scrollLeft;am+n&&(F.scrollLeft=c+10-m,k=!0,c>L.clientWidth&&(l=!1)),k&&g.onScroll&&g.onScroll(by);return l}function bZ(){var a=cC(be.inverted?be.from:be.to);return b$(a.x,a.y,a.x,a.yBot)}function bY(){g.readOnly!="nocursor"&&E.focus()}function bX(){var a=[],b=Math.max(0,be.from.line-1),c=Math.min(ba.length,be.to.line+2);for(var d=b;d=a)return{line:c,ch:a-d};++c,d=e+1}}if(!bm&&!!bd){var a=!1,b=E.value,c=Q(E);if(!c)return!1;var a=br.text!=b,d=bg,e=a||c.start!=br.start||c.end!=(d?br.start:br.end);if(!e&&!d)return!1;if(a){bf=bg=null;if(g.readOnly){bi=!0;return"changed"}}var h=f(c.start,br.from),i=f(c.end,br.from);if(d){var j=c.start==d.anchor?i:h,k=bf?be.to:c.start==d.anchor?h:i;(be.inverted=J(j,k))?(h=j,i=k):(bg=null,h=k,i=j)}h.line==i.line&&h.line==be.from.line&&h.line==be.to.line&&!bf&&(bi=!1);if(a){var l=0,m=b.length,n=Math.min(m,br.text.length),o,p=br.from,q=-1;while(l-1?l-q:l,s=br.to-1,t=br.text.length;for(;;){o=br.text.charAt(t);if(b.charAt(m)!=o){++m,++t;break}o=="\n"&&s--;if(t<=l||m<=l)break;--m,--t}var q=br.text.lastIndexOf("\n",t-1),u=q==-1?t:t-q-1;bJ({line:p,ch:r},{line:s,ch:u},P(b.slice(l,m)),h,i);if(p!=s||h.line!=p)bi=!0}else cg(h,i);br.text=b,br.start=c.start,br.end=c.end;return a?"changed":e?"moved":!1}}function bV(a){function c(){cR();var d=bW();d=="moved"&&a&&(C[a]=!0),!d&&!b?(b=!0,Y.set(80,c)):(bT=!1,bU()),cS()}var b=!1;bT=!0,Y.set(20,c)}function bU(){bT||Y.set(2e3,function(){cR(),bW(),bd&&bU(),cS()})}function bS(){return bR(be.from,be.to)}function bR(a,b){var c=a.line,d=b.line;if(c==d)return ba[c].text.slice(a.ch,b.ch);var e=[ba[c].text.slice(a.ch)];for(var f=c+1;fg&&(bt=o,g=o.length,bu=null,f=!1)}if(f){g=0,bt="",bu=null;for(var i=0,n=ba.length;ig&&(g=o.length,bt=o)}}var p=[],q=c.length-j-1;for(var i=0,o=bb.length;ib.line&&p.push(r+q)}c.length<5?(cO(a.line,a.line+c.length),p.push(a.line+c.length)):p.push(a.line),bb=p,cQ(100),bj.push({from:a.line,to:b.line+1,diff:q}),bk={from:a,to:b,text:c},cg(d,e,s(be.from.line),s(be.to.line)),L.style.height=ba.length*cE()+2*cF()+"px"}function bM(){bK(bc.undone,bc.done)}function bL(){bK(bc.done,bc.undone)}function bK(a,b){var c=a.pop();if(c){var d=[],e=c.start+c.added;for(var f=c.start;fg.undoDepth)bc.done.shift()}bN(a,b,c,d,e)}function bI(){bd&&(g.onBlur&&g.onBlur(by),bd=!1,y.className=y.className.replace(" CodeMirror-focused","")),clearInterval($),setTimeout(function(){bd||(bf=null)},150)}function bH(){g.readOnly!="nocursor"&&(bd||(g.onFocus&&g.onFocus(by),bd=!0,y.className.search(/\bCodeMirror-focused\b/)==-1&&(y.className+=" CodeMirror-focused"),bm||bX()),bU(),cJ())}function bG(a){if(!g.onKeyEvent||!g.onKeyEvent(by,l(a))){if(g.electricChars&&_.electricChars){var b=String.fromCharCode(a.charCode==null?a.keyCode:a.charCode);_.electricChars.indexOf(b)>-1&&setTimeout(cU(function(){cr(be.to.line,"smart")}),50)}var c=a.keyCode;c==13?(g.readOnly||cp(),m(a)):!a.ctrlKey&&!a.altKey&&!a.metaKey&&c==9&&g.tabMode!="default"?m(a):bV(bq)}}function bF(a){if(!g.onKeyEvent||!g.onKeyEvent(by,l(a)))bg&&(bg=null,bi=!0),a.keyCode==16&&(bf=null)}function bE(a){bd||bH();var b=a.keyCode;x&&b==27&&(a.returnValue=!1);var c=(B?a.metaKey:a.ctrlKey)&&!a.altKey,d=a.ctrlKey||a.altKey||a.metaKey;b==16||a.shiftKey?bf=bf||(be.inverted?be.to:be.from):bf=null;if(!g.onKeyEvent||!g.onKeyEvent(by,l(a))){if(b==33||b==34){ck(b==34);return m(a)}if(c&&(b==36||b==35||B&&(b==38||b==40))){cl(b==36||b==38);return m(a)}if(c&&b==65){cm();return m(a)}if(!g.readOnly){if(!d&&b==13)return;if(!d&&b==9&&cq(a.shiftKey))return m(a);if(c&&b==90){bL();return m(a)}if(c&&(a.shiftKey&&b==90||b==89)){bM();return m(a)}}bq=(c?"c":"")+b;if(be.inverted&&C.hasOwnProperty(bq)){var e=Q(E);e&&(bg={anchor:e.start},R(E,e.start,e.start))}bV(bq)}}function bD(a){a.preventDefault();var b=cH(a,!0),c=a.dataTransfer.files;if(!!b&&!g.readOnly)if(c&&c.length&&window.FileReader&&window.File){function d(a,c){var d=new FileReader;d.onload=function(){f[c]=d.result,++h==e&&bO(f.join(""),cj(b),cj(b))},d.readAsText(a)}var e=c.length,f=Array(e),h=0;for(var i=0;i=c.to||b.line=0&&a
'+'
'+'
'+'
'+'
'+'
'+'
 
'+"
"+"
",b.appendChild?b.appendChild(y):b(y);var D=y.firstChild,E=D.firstChild,F=y.lastChild,L=F.firstChild,M=L.firstChild,S=M.nextSibling,T=S.firstChild,U=T.firstChild,V=T.nextSibling.firstChild,W=V.firstChild,X=W.nextSibling;g.tabindex!=null&&(E.tabindex=g.tabindex),!g.gutter&&!g.lineNumbers&&(T.style.display="none");var Y=new u,Z=new u,$,_,ba=[new h("")],bb,bc=new j,bd;cs();var be={from:{line:0,ch:0},to:{line:0,ch:0},inverted:!1},bf,bg,bh,bi,bj,bk,bl,bm,bn=0,bo=0,bp=0,bq=null,br,bs,bt="",bu;cU(function(){bz(g.value||""),bi=!1})(),t(F,"mousedown",cU(bB)),w||t(F,"contextmenu",cI),t(L,"dblclick",cU(bC)),t(F,"scroll",function(){ca([]),g.onScroll&&g.onScroll(by)}),t(window,"resize",function(){ca(!0)}),t(E,"keyup",cU(bF)),t(E,"keydown",cU(bE)),t(E,"keypress",cU(bG)),t(E,"focus",bH),t(E,"blur",bI),t(F,"dragenter",o),t(F,"dragover",o),t(F,"drop",cU(bD)),t(F,"paste",function(){bY(),bV()}),t(E,"paste",function(){bV()}),t(E,"cut",function(){bV()});var bv;try{bv=n.activeElement==E}catch(bw){}bv?setTimeout(bH,20):bI();var by={getValue:bA,setValue:cU(bz),getSelection:bS,replaceSelection:cU(bP),focus:function(){bY(),bH(),bV()},setOption:function(a,b){g[a]=b,a=="lineNumbers"||a=="gutter"?ct():a=="mode"||a=="indentUnit"?cs():a=="readOnly"&&b=="nocursor"?E.blur():a=="theme"&&(F.className=F.className.replace(/cm-s-\w+/,"cm-s-"+b))},getOption:function(a){return g[a]},undo:cU(bL),redo:cU(bM),indentLine:cU(function(a,b){bx(a)&&cr(a,b==null?"smart":b?"add":"subtract")}),historySize:function(){return{undo:bc.done.length,redo:bc.undone.length}},matchBrackets:cU(function(){cL(!0)}),getTokenAt:function(a){a=cj(a);return ba[a.line].getTokenAt(_,cN(a.line),a.ch)},getStateAfter:function(a){a=ci(a==null?ba.length-1:a);return cN(a+1)},cursorCoords:function(a){a==null&&(a=be.inverted);return cD(a?be.from:be.to)},charCoords:function(a){return cD(cj(a))},coordsChar:function(a){var b=G(V),c=ci(Math.min(ba.length-1,bn+Math.floor((a.y-b.top)/cE())));return cj({line:c,ch:cB(ci(c),a.x-b.left)})},getSearchCursor:function(a,b,c){return new cV(a,b,c)},markText:cU(function(a,b,c){return cU(cu(a,b,c))}),setMarker:cv,clearMarker:cw,setLineClass:cU(cx),lineInfo:cy,addWidget:function(a,b,c,d){a=cC(cj(a));var e=a.yBot,f=a.x;b.style.position="absolute",L.appendChild(b),b.style.left=f+"px";if(d=="over")e=a.y;else if(d=="near"){var g=Math.max(F.offsetHeight,ba.length*cE()),h=Math.max(L.clientWidth,V.clientWidth)-cG();a.yBot+b.offsetHeight>g&&a.y>b.offsetHeight&&(e=a.y-b.offsetHeight),f+b.offsetWidth>h&&(f=h-b.offsetWidth)}b.style.top=e+cF()+"px",b.style.left=f+cG()+"px",c&&b$(f,e,f+b.offsetWidth,e+b.offsetHeight)},lineCount:function(){return ba.length},getCursor:function(a){a==null&&(a=be.inverted);return K(a?be.from:be.to)},somethingSelected:function(){return!I(be.from,be.to)},setCursor:cU(function(a,b){b==null&&typeof a.line=="number"?ch(a.line,a.ch):ch(a,b)}),setSelection:cU(function(a,b){cg(cj(a),cj(b||a))}),getLine:function(a){if(bx(a))return ba[a].text},setLine:cU(function(a,b){bx(a)&&bO(b,{line:a,ch:0},{line:a,ch:ba[a].text.length})}),removeLine:cU(function(a){bx(a)&&bO("",{line:a,ch:0},cj({line:a+1,ch:0}))}),replaceRange:cU(bO),getRange:function(a,b){return bR(cj(a),cj(b))},operation:function(a){return cU(a)()},refresh:function(){ca(!0)},getInputField:function(){return E},getWrapperElement:function(){return y},getScrollerElement:function(){return F},getGutterElement:function(){return T}},bT=!1,cK={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},cT=0;cV.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(a){function d(a){var c={line:a,ch:0};b.pos={from:c,to:c},b.atOccurrence=!1;return!1}var b=this,c=cj(a?this.pos.from:this.pos.to);for(;;){if(this.pos=this.matches(a,c)){this.atOccurrence=!0;return this.pos.match||!0}if(a){if(!c.line)return d(0);c={line:c.line-1,ch:ba[c.line-1].text.length}}else{if(c.line==ba.length-1)return d(ba.length);c={line:c.line+1,ch:0}}}},from:function(){if(this.atOccurrence)return K(this.pos.from)},to:function(){if(this.atOccurrence)return K(this.pos.to)},replace:function(a){var b=this;this.atOccurrence&&cU(function(){b.pos.to=bO(a,b.pos.from,b.pos.to)})()}};for(var cW in d)d.propertyIsEnumerable(cW)&&!by.propertyIsEnumerable(cW)&&(by[cW]=d[cW]);return by}a.defaults={value:"",mode:null,theme:"default",indentUnit:2,indentWithTabs:!1,tabMode:"classic",enterMode:"indent",electricChars:!0,onKeyEvent:null,lineNumbers:!1,gutter:!1,firstLineNumber:1,readOnly:!1,onChange:null,onCursorActivity:null,onGutterClick:null,onHighlightComplete:null,onFocus:null,onBlur:null,onScroll:null,matchBrackets:!1,workTime:100,workDelay:200,undoDepth:40,tabindex:null,document:window.document};var b={},c={};a.defineMode=function(c,d){!a.defaults.mode&&c!="null"&&(a.defaults.mode=c),b[c]=d},a.defineMIME=function(a,b){c[a]=b},a.getMode=function(d,e){typeof e=="string"&&c.hasOwnProperty(e)&&(e=c[e]);if(typeof e=="string")var f=e,g={};else if(e!=null)var f=e.name,g=e;var h=b[f];if(!h){window.console&&console.warn("No mode "+f+" found, falling back to plain text.");return a.getMode(d,"text/plain")}return h(d,g||{})},a.listModes=function(){var a=[];for(var c in b)b.propertyIsEnumerable(c)&&a.push(c);return a},a.listMIMEs=function(){var a=[];for(var b in c)c.propertyIsEnumerable(b)&&a.push(b);return a};var d={};a.defineExtension=function(a,b){d[a]=b},a.fromTextArea=function(b,c){function d(){b.value=h.getValue()}c||(c={}),c.value=b.value,!c.tabindex&&b.tabindex&&(c.tabindex=b.tabindex);if(b.form){var e=t(b.form,"submit",d,!0);if(typeof b.form.submit=="function"){var f=b.form.submit;function g(){d(),b.form.submit=f,b.form.submit(),b.form.submit=g}b.form.submit=g}}b.style.display="none";var h=a(function(a){b.parentNode.insertBefore(a,b.nextSibling)},c);h.save=d,h.toTextArea=function(){d(),b.parentNode.removeChild(h.getWrapperElement()),b.style.display="",b.form&&(e(),typeof b.form.submit=="function"&&(b.form.submit=f))};return h},a.startState=f,a.copyState=e,g.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)},next:function(){if(this.posb},eatSpace:function(){var a=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);if(b>-1){this.pos=b;return!0}},backUp:function(a){this.pos-=a},column:function(){return E(this.string,this.start)},indentation:function(){return E(this.string)},match:function(a,b,c){if(typeof a!="string"){var e=this.string.slice(this.pos).match(a);e&&b!==!1&&(this.pos+=e[0].length);return e}function d(a){return c?a.toLowerCase():a}if(d(this.string).indexOf(d(a),this.pos)==this.pos){b!==!1&&(this.pos+=a.length);return!0}},current:function(){return this.string.slice(this.start,this.pos)}},a.StringStream=g,h.prototype={replace:function(a,b,c){var d=[],e=this.marked;i(0,a,this.styles,d),c&&d.push(c,null),i(b,this.text.length,this.styles,d),this.styles=d,this.text=this.text.slice(0,a)+c+this.text.slice(b),this.stateAfter=null;if(e){var f=c.length-(b-a),g=this.text.length;function h(a){return a<=Math.min(b,b+f)?a:a+f}for(var j=0;j=g?l=!0:(k.from=h(k.from),k.to!=null&&(k.to=h(k.to)));if(l||k.from>=k.to)e.splice(j,1),j--}}},split:function(a,b){var c=[b,null];i(a,this.text.length,this.styles,c);return new h(b+this.text.slice(a),c)},addMark:function(a,b,c){var d=this.marked,e={from:a,to:b,style:c};this.marked==null&&(this.marked=[]),this.marked.push(e),this.marked.sort(function(a,b){return a.from-b.from});return e},removeMark:function(a){var b=this.marked;if(!!b)for(var c=0;c5e3){d[e++]=this.text.slice(c.pos),d[e++]=null;break}}d.length!=e&&(d.length=e,f=!0),e&&d[e-2]!=i&&(f=!0);return f||d.length<5&&this.text.length<10},getTokenAt:function(a,b,c){var d=this.text,e=new g(d);while(e.pos',M(a),""):e.push(M(a)))}var e=[];c&&e.push(this.className?'
':"
");var g=this.styles,h=this.text,i=this.marked;a==b&&(a=null);var j=h.length;d!=null&&(j=Math.min(d,j));if(!h&&d==null)f(" ",a!=null&&b==null?"CodeMirror-selected":null);else if(!i&&a==null)for(var k=0,l=0;lj&&(m=m.slice(0,j-l)),l+=n,f(m,"cm-"+g[k+1])}else{var o=0,k=0,p="",q,r=0,s=-1,t=null;function u(){i&&(s+=1,t=so)v=a;else if(b==null||b>o)w=" CodeMirror-selected",b!=null&&(v=Math.min(v,b));while(t&&t.to!=null&&t.to<=o)u();t&&(t.from>o?v=Math.min(v,t.from):(w+=" "+t.style,t.to!=null&&(v=Math.min(v,t.to))));for(;;){var x=o+p.length,y=q;w&&(y=q?q+w:w),f(x>v?p.slice(0,v-o):p,y);if(x>=v){p=p.slice(v-o),o=v;break}o=x,p=g[k++],q="cm-"+g[k++]}}a!=null&&b==null&&f(" ","CodeMirror-selected")}c&&e.push("
");return e.join("")}},j.prototype={addChange:function(a,b,c){this.undone.length=0;var d=+(new Date),e=this.done[this.done.length-1];if(d-this.time>400||!e||e.start>a+b||e.start+e.added=0;--g)e.old.unshift(c[g]);e.added+=e.start-a,e.start=a}else e.start-1&&(z="\r\n")})();var A=8,B=/Mac/.test(navigator.platform),C={};for(var D=35;D<=40;++D)C[D]=C["c"+D]=!0;var L=document.createElement("div");a.htmlEscape=M;var P,Q,R;"\n\nb".split(/\n/).length!=3?P=function(a){var b=0,c,d=[];while((c=a.indexOf("\n",b))>-1)d.push(a.slice(b,a.charAt(c-1)=="\r"?c-1:c)),b=c+1;d.push(a.slice(b));return d}:P=function(a){return a.split(/\r?\n/)},a.splitLines=P,window.getSelection?(Q=function(a){try{return{start:a.selectionStart,end:a.selectionEnd}}catch(b){return null}},y?R=function(a,b,c){b==c?a.setSelectionRange(b,c):(a.setSelectionRange(b,c-1),window.getSelection().modify("extend","forward","character"))}:R=function(a,b,c){try{a.setSelectionRange(b,c)}catch(d){}}):(Q=function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){return null}if(!b||b.parentElement()!=a)return null;var d=a.value,e=d.length,f=a.createTextRange();f.moveToBookmark(b.getBookmark());var g=a.createTextRange();g.collapse(!1);if(f.compareEndPoints("StartToEnd",g)>-1)return{start:e,end:e};var h=-f.moveStart("character",-e);for(var i=d.indexOf("\r");i>-1&&i-1)return{start:h,end:e};var j=-f.moveEnd("character",-e);for(var i=d.indexOf("\r");i>-1&&i-1&&h-1&&h=0;a--)s.cc.push(arguments[a])}function r(a,b,c,e,f){var g=a.cc;s.state=a,s.stream=f,s.marked=null,s.cc=g,a.lexical.hasOwnProperty("align")||(a.lexical.align=!0);for(;;){var h=g.length?g.pop():d?D:C;if(h(c,e)){while(g.length&&g[g.length-1].lex)g.pop()();if(s.marked)return s.marked;if(c=="variable"&&q(a,e))return"variable-2";return b}}}function q(a,b){for(var c=a.localVars;c;c=c.next)if(c.name==b)return!0}function p(a,b,c,d,e,f){this.indented=a,this.column=b,this.type=c,this.prev=e,this.info=f,d!=null&&(this.align=d)}function n(a,b){var c=!1,d;while(d=a.next()){if(d=="/"&&c){b.tokenize=l;break}c=d=="*"}return k("comment","comment")}function m(a){return function(b,c){h(b,a)||(c.tokenize=l);return k("string","string")}}function l(a,b){var c=a.next();if(c=='"'||c=="'")return g(a,b,m(c));if(/[\[\]{}\(\),;\:\.]/.test(c))return k(c);if(c=="0"&&a.eat(/x/i)){a.eatWhile(/[\da-f]/i);return k("number","number")}if(/\d/.test(c)){a.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);return k("number","number")}if(c=="/"){if(a.eat("*"))return g(a,b,n);if(a.eat("/")){a.skipToEnd();return k("comment","comment")}if(b.reAllowed){h(a,"/"),a.eatWhile(/[gimy]/);return k("regexp","string")}a.eatWhile(f);return k("operator",null,a.current())}if(f.test(c)){a.eatWhile(f);return k("operator",null,a.current())}a.eatWhile(/[\w\$_]/);var d=a.current(),i=e.propertyIsEnumerable(d)&&e[d];return i?k(i.type,i.style,d):k("variable","variable",d)}function k(a,b,c){i=a,j=c;return b}function h(a,b){var c=!1,d;while((d=a.next())!=null){if(d==b&&!c)return!1;c=!c&&d=="\\"}return c}function g(a,b,c){b.tokenize=c;return c(a,b)}var c=a.indentUnit,d=b.json,e=function(){function a(a){return{type:a,style:"keyword"}}var b=a("keyword a"),c=a("keyword b"),d=a("keyword c"),e=a("operator"),f={type:"atom",style:"atom"};return{"if":b,"while":b,"with":b,"else":c,"do":c,"try":c,"finally":c,"return":d,"break":d,"continue":d,"new":d,"delete":d,"throw":d,"var":a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),"case":a("case"),"default":a("default"),"in":e,"typeof":e,"instanceof":e,"true":f,"false":f,"null":f,"undefined":f,NaN:f,Infinity:f}}(),f=/[+\-*&%=<>!?|]/,i,j,o={atom:!0,number:!0,variable:!0,string:!0,regexp:!0},s={state:null,column:null,marked:null,cc:null},w={name:"this",next:{name:"arguments"}};A.lex=!0;return{startState:function(a){return{tokenize:l,reAllowed:!0,cc:[],lexical:new p((a||0)-c,0,"block",!1),localVars:null,context:null,indented:0}},token:function(a,b){a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation());if(a.eatSpace())return null;var c=b.tokenize(a,b);if(i=="comment")return c;b.reAllowed=i=="operator"||i=="keyword c"||i.match(/^[\[{}\(,;:]$/);return r(b,c,i,j,a)},indent:function(a,b){if(a.tokenize!=l)return 0;var d=b&&b.charAt(0),e=a.lexical,f=e.type,g=d==f;return f=="vardef"?e.indented+4:f=="form"&&d=="{"?e.indented:f=="stat"||f=="form"?e.indented+c:e.info=="switch"&&!g?e.indented+(/^(?:case|default)\b/.test(b)?c:2*c):e.align?e.column+(g?0:1):e.indented+(g?0:c)},electricChars:":{}"}}),CodeMirror.defineMIME("text/javascript","javascript"),CodeMirror.defineMIME("application/json",{name:"javascript",json:!0}),CodeMirror.defineMode("xml",function(a,b){function w(a){return a=="string"?o(w):n()}function v(a){if(a=="word"&&d.allowUnquoted){m="string";return o()}if(a=="string")return o(w);return n()}function u(a){if(a=="word"){m="attribute";return o(u)}if(a=="equals")return o(v,u);return n()}function t(a){return function(b){a&&(m="error");if(b=="endTag")return o();return n()}}function s(a){return function(b){if(b=="selfcloseTag"||b=="endTag"&&d.autoSelfClosers.hasOwnProperty(l.tagName.toLowerCase()))return o();if(b=="endTag"){p(l.tagName,a);return o()}return o()}}function r(a){if(a=="openTag"){l.tagName=f;return o(u,s(l.startOfLine))}if(a=="closeTag"){var b=!1;l.context?(b=l.context.tagName!=f,q()):b=!0,b&&(m="error");return o(t(b))}if(a=="string"){(!l.context||l.context.name!="!cdata")&&p("!cdata"),l.tokenize==h&&q();return o()}return o()}function q(){l.context&&(l.context=l.context.prev)}function p(a,b){var c=d.doNotIndent.hasOwnProperty(a)||l.context&&l.context.noIndent;l.context={prev:l.context,tagName:a,indent:l.indented,startOfLine:b,noIndent:c}}function o(){n.apply(null,arguments);return!0}function n(){for(var a=arguments.length-1;a>=0;a--)l.cc.push(arguments[a])}function k(a,b){return function(c,d){while(!c.eol()){if(c.match(b)){d.tokenize=h;break}c.next()}return a}}function j(a){return function(b,c){while(!b.eol())if(b.next()==a){c.tokenize=i;break}return"string"}}function i(a,b){var c=a.next();if(c==">"||c=="/"&&a.eat(">")){b.tokenize=h,g=c==">"?"endTag":"selfcloseTag";return"tag"}if(c=="="){g="equals";return null}if(/[\'\"]/.test(c)){b.tokenize=j(c);return b.tokenize(a,b)}a.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);return"word"}function h(a,b){function c(c){b.tokenize=c;return c(a,b)}var d=a.next();if(d=="<"){if(a.eat("!")){if(a.eat("["))return a.match("CDATA[")?c(k("atom","]]>")):null;if(a.match("--"))return c(k("comment","-->"));if(a.match("DOCTYPE",!0,!0)){a.eatWhile(/[\w\._\-]/);return c(k("meta",">"))}return null}if(a.eat("?")){a.eatWhile(/[\w\._\-]/),b.tokenize=k("meta","?>");return"meta"}g=a.eat("/")?"closeTag":"openTag",a.eatSpace(),f="";var e;while(e=a.eat(/[^\s\u00a0=<>\"\'\/?]/))f+=e;b.tokenize=i;return"tag"}if(d=="&"){a.eatWhile(/[^;]/),a.eat(";");return"atom"}a.eatWhile(/[^&<]/);return null}var c=a.indentUnit,d=b.htmlMode?{autoSelfClosers:{br:!0,img:!0,hr:!0,link:!0,input:!0,meta:!0,col:!0,frame:!0,base:!0,area:!0},doNotIndent:{pre:!0,"!cdata":!0},allowUnquoted:!0}:{autoSelfClosers:{},doNotIndent:{"!cdata":!0},allowUnquoted:!1},e=b.alignCDATA,f,g,l,m;return{startState:function(){return{tokenize:h,cc:[],indented:0,startOfLine:!0,tagName:null,context:null}},token:function(a,b){a.sol()&&(b.startOfLine=!0,b.indented=a.indentation());if(a.eatSpace())return null;m=g=f=null;var c=b.tokenize(a,b);if((c||g)&&c!="comment"){l=b;for(;;){var d=b.cc.pop()||r;if(d(g||c))break}}b.startOfLine=!1;return m||c},indent:function(a,b){var d=a.context;if(d&&d.noIndent)return 0;if(e&&/=2&&f==">"){b.tokenize=e;break}c=f=="-"?c+1:0}return d("comment","comment")}function f(a,b){var c=!1,f;while((f=a.next())!=null){if(c&&f=="/"){b.tokenize=e;break}c=f=="*"}return d("comment","comment")}function e(a,b){var c=a.next();if(c=="@"){a.eatWhile(/\w/);return d("meta",a.current())}if(c=="/"&&a.eat("*")){b.tokenize=f;return f(a,b)}if(c=="<"&&a.eat("!")){b.tokenize=g;return g(a,b)}if(c=="=")d(null,"compare");else{if(c!="~"&&c!="|"||!a.eat("=")){if(c=='"'||c=="'"){b.tokenize=h(c);return b.tokenize(a,b)}if(c=="#"){a.eatWhile(/\w/);return d("atom","hash")}if(c=="!"){a.match(/^\s*\w*/);return d("keyword","important")}if(/\d/.test(c)){a.eatWhile(/[\w.%]/);return d("number","unit")}if(/[,.+>*\/]/.test(c))return d(null,"select-op");if(/[;{}:\[\]]/.test(c))return d(null,c);a.eatWhile(/[\w\\\-_]/);return d("variable","variable")}return d(null,"compare")}}function d(a,b){c=b;return a}var b=a.indentUnit,c;return{startState:function(a){return{tokenize:e,baseIndent:a||0,stack:[]}},token:function(a,b){if(a.eatSpace())return null;var d=b.tokenize(a,b),e=b.stack[b.stack.length-1];if(c=="hash"&&e=="rule")d="atom";else if(d=="variable")if(e=="rule")d="number";else if(!e||e=="@media{")d="tag";e=="rule"&&/^[\{\};]$/.test(c)&&b.stack.pop(),c=="{"?e=="@media"?b.stack[b.stack.length-1]="@media{":b.stack.push("{"):c=="}"?b.stack.pop():c=="@media"?b.stack.push("@media"):e=="{"&&c!="comment"&&b.stack.push("rule");return d},indent:function(a,c){var d=a.stack.length;/^\}/.test(c)&&(d-=a.stack[a.stack.length-1]=="rule"?2:1);return a.baseIndent+d*b},electricChars:"}"}}),CodeMirror.defineMIME("text/css","css"),CodeMirror.defineMode("htmlmixed",function(a,b){function i(a,b){if(a.match(/^<\/\s*style\s*>/i,!1)){b.token=f,b.localState=null,b.mode="html";return f(a,b)}return g(a,/<\/\s*style\s*>/,e.token(a,b.localState))}function h(a,b){if(a.match(/^<\/\s*script\s*>/i,!1)){b.token=f,b.curState=null,b.mode="html";return f(a,b)}return g(a,/<\/\s*script\s*>/,d.token(a,b.localState))}function g(a,b,c){var d=a.current(),e=d.search(b);e>-1&&a.backUp(d.length-e);return c}function f(a,b){var f=c.token(a,b.htmlState);f=="tag"&&a.current()==">"&&b.htmlState.context&&(/^script$/i.test(b.htmlState.context.tagName)?(b.token=h,b.localState=d.startState(c.indent(b.htmlState,"")),b.mode="javascript"):/^style$/i.test(b.htmlState.context.tagName)&&(b.token=i,b.localState=e.startState(c.indent(b.htmlState,"")),b.mode="css"));return f}var c=CodeMirror.getMode(a,{name:"xml",htmlMode:!0}),d=CodeMirror.getMode(a,"javascript"),e=CodeMirror.getMode(a,"css");return{startState:function(){var a=c.startState();return{token:f,localState:null,mode:"html",htmlState:a}},copyState:function(a){if(a.localState)var b=CodeMirror.copyState(a.token==i?e:d,a.localState);return{token:a.token,localState:b,mode:a.mode,htmlState:CodeMirror.copyState(c,a.htmlState)}},token:function(a,b){return b.token(a,b)},indent:function(a,b){return a.token==f||/^\s*<\//.test(b)?c.indent(a.htmlState,b):a.token==h?d.indent(a.localState,b):e.indent(a.localState,b)},electricChars:"/{}:"}}),CodeMirror.defineMIME("text/html","htmlmixed") \ No newline at end of file diff --git a/dist/docs/resources/js/paper.js b/dist/docs/resources/js/paper.js new file mode 100644 index 00000000..23c5f1a6 --- /dev/null +++ b/dist/docs/resources/js/paper.js @@ -0,0 +1,8761 @@ +/*! + * Paper.js v0.22 + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + * + * Date: Wed Sep 26 16:04:23 2012 -0400 + * + *** + * + * Bootstrap.js JavaScript Framework. + * http://bootstrapjs.org/ + * + * Copyright (c) 2006 - 2011 Juerg Lehni + * http://lehni.org/ + * + * Distributed under the MIT license. + * + *** + * + * Parse-js + * + * A JavaScript tokenizer / parser / generator, originally written in Lisp. + * Copyright (c) Marijn Haverbeke + * http://marijn.haverbeke.nl/parse-js/ + * + * Ported by to JavaScript by Mihai Bazon + * Copyright (c) 2010, Mihai Bazon + * http://mihai.bazon.net/blog/ + * + * Modifications and adaptions to browser (c) 2011, Juerg Lehni + * http://lehni.org/ + * + * Distributed under the BSD license. + */ + +var paper = new function() { + +var Base = new function() { + var fix = !this.__proto__, + hidden = /^(statics|generics|preserve|enumerable|prototype|__proto__|toString|valueOf)$/, + proto = Object.prototype, + has = fix + ? function(name) { + return name !== '__proto__' && this.hasOwnProperty(name); + } + : proto.hasOwnProperty, + toString = proto.toString, + proto = Array.prototype, + isArray = Array.isArray = Array.isArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }, + slice = proto.slice, + forEach = proto.forEach || function(iter, bind) { + for (var i = 0, l = this.length; i < l; i++) + iter.call(bind, this[i], i, this); + }, + forIn = function(iter, bind) { + for (var i in this) + if (this.hasOwnProperty(i)) + iter.call(bind, this[i], i, this); + }, + _define = Object.defineProperty, + _describe = Object.getOwnPropertyDescriptor; + + function define(obj, name, desc) { + if (_define) { + try { + delete obj[name]; + return _define(obj, name, desc); + } catch (e) {} + } + if ((desc.get || desc.set) && obj.__defineGetter__) { + desc.get && obj.__defineGetter__(name, desc.get); + desc.set && obj.__defineSetter__(name, desc.set); + } else { + obj[name] = desc.value; + } + return obj; + } + + function describe(obj, name) { + if (_describe) { + try { + return _describe(obj, name); + } catch (e) {} + } + var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); + return get + ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, + configurable: true } + : has.call(obj, name) + ? { value: obj[name], enumerable: true, configurable: true, + writable: true } + : null; + } + + function inject(dest, src, enumerable, base, preserve, generics) { + var beans, bean; + + function field(name, val, dontCheck, generics) { + var val = val || (val = describe(src, name)) + && (val.get ? val : val.value), + func = typeof val === 'function', + res = val, + prev = preserve || func + ? (val && val.get ? name in dest : dest[name]) : null; + if (generics && func && (!preserve || !generics[name])) { + generics[name] = function(bind) { + return bind && dest[name].apply(bind, + slice.call(arguments, 1)); + } + } + if ((dontCheck || val !== undefined && has.call(src, name)) + && (!preserve || !prev)) { + if (func) { + if (prev && /\bthis\.base\b/.test(val)) { + var fromBase = base && base[name] == prev; + res = function() { + var tmp = describe(this, 'base'); + define(this, 'base', { value: fromBase + ? base[name] : prev, configurable: true }); + try { + return val.apply(this, arguments); + } finally { + tmp ? define(this, 'base', tmp) + : delete this.base; + } + }; + res.toString = function() { + return val.toString(); + } + res.valueOf = function() { + return val.valueOf(); + } + } + if (beans && val.length == 0 + && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) + beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); + } + if (!res || func || !res.get) + res = { value: res, writable: true }; + if ((describe(dest, name) + || { configurable: true }).configurable) { + res.configurable = true; + res.enumerable = enumerable; + } + define(dest, name, res); + } + } + if (src) { + beans = []; + for (var name in src) + if (has.call(src, name) && !hidden.test(name)) + field(name, null, true, generics); + field('toString'); + field('valueOf'); + for (var i = 0, l = beans && beans.length; i < l; i++) + try { + var bean = beans[i], part = bean[1]; + field(bean[0], { + get: dest['get' + part] || dest['is' + part], + set: dest['set' + part] + }, true); + } catch (e) {} + } + return dest; + } + + function extend(obj) { + var ctor = function(dont) { + if (fix) define(this, '__proto__', { value: obj }); + if (this.initialize && dont !== ctor.dont) + return this.initialize.apply(this, arguments); + } + ctor.prototype = obj; + ctor.toString = function() { + return (this.prototype.initialize || function() {}).toString(); + } + return ctor; + } + + function iterator(iter) { + return !iter + ? function(val) { return val } + : typeof iter !== 'function' + ? function(val) { return val == iter } + : iter; + } + + function each(obj, iter, bind, asArray) { + try { + if (obj) + (asArray || asArray === undefined && isArray(obj) + ? forEach : forIn).call(obj, iterator(iter), + bind = bind || obj); + } catch (e) { + if (e !== Base.stop) throw e; + } + return bind; + } + + function clone(obj) { + return each(obj, function(val, i) { + this[i] = val; + }, new obj.constructor()); + } + + return inject(function() {}, { + inject: function(src) { + if (src) { + var proto = this.prototype, + base = proto.__proto__ && proto.__proto__.constructor, + statics = src.statics == true ? src : src.statics; + if (statics != src) + inject(proto, src, src.enumerable, base && base.prototype, + src.preserve, src.generics && this); + inject(this, statics, true, base, src.preserve); + } + for (var i = 1, l = arguments.length; i < l; i++) + this.inject(arguments[i]); + return this; + }, + + extend: function(src) { + var proto = new this(this.dont), + ctor = extend(proto); + define(proto, 'constructor', + { value: ctor, writable: true, configurable: true }); + ctor.dont = {}; + inject(ctor, this, true); + return arguments.length ? this.inject.apply(ctor, arguments) : ctor; + } + }, true).inject({ + has: has, + each: each, + + inject: function() { + for (var i = 0, l = arguments.length; i < l; i++) + inject(this, arguments[i]); + return this; + }, + + extend: function() { + var res = new (extend(this)); + return res.inject.apply(res, arguments); + }, + + each: function(iter, bind) { + return each(this, iter, bind); + }, + + clone: function() { + return clone(this); + }, + + statics: { + each: each, + clone: clone, + define: define, + describe: describe, + iterator: iterator, + + has: function(obj, name) { + return has.call(obj, name); + }, + + type: function(obj) { + return (obj || obj === 0) && (obj._type || typeof obj) || null; + }, + + check: function(obj) { + return !!(obj || obj === 0); + }, + + pick: function() { + for (var i = 0, l = arguments.length; i < l; i++) + if (arguments[i] !== undefined) + return arguments[i]; + return null; + }, + + stop: {} + } + }); +} + +this.Base = Base.inject({ + generics: true, + + clone: function() { + return new this.constructor(this); + }, + + toString: function() { + return '{ ' + Base.each(this, function(value, key) { + if (key.charAt(0) != '_') { + var type = typeof value; + this.push(key + ': ' + (type === 'number' + ? Base.formatNumber(value) + : type === 'string' ? "'" + value + "'" : value)); + } + }, []).join(', ') + ' }'; + }, + + statics: { + read: function(list, start, length) { + var start = start || 0, + length = length || list.length - start; + var obj = list[start]; + if (obj instanceof this + || this.prototype._readNull && obj == null && length <= 1) + return obj; + obj = new this(this.dont); + return obj.initialize.apply(obj, start > 0 || length < list.length + ? Array.prototype.slice.call(list, start, start + length) + : list) || obj; + }, + + readAll: function(list, start) { + var res = [], entry; + for (var i = start || 0, l = list.length; i < l; i++) { + res.push(Array.isArray(entry = list[i]) + ? this.read(entry, 0) + : this.read(list, i, 1)); + } + return res; + }, + + splice: function(list, items, index, remove) { + var amount = items && items.length, + append = index === undefined; + index = append ? list.length : index; + for (var i = 0; i < amount; i++) + items[i]._index = index + i; + if (append) { + list.push.apply(list, items); + return []; + } else { + var args = [index, remove]; + if (items) + args.push.apply(args, items); + var removed = list.splice.apply(list, args); + for (var i = 0, l = removed.length; i < l; i++) + delete removed[i]._index; + for (var i = index + amount, l = list.length; i < l; i++) + list[i]._index = i; + return removed; + } + }, + + merge: function() { + return Base.each(arguments, function(hash) { + Base.each(hash, function(value, key) { + this[key] = value; + }, this); + }, new Base(), true); + }, + + capitalize: function(str) { + return str.replace(/\b[a-z]/g, function(match) { + return match.toUpperCase(); + }); + }, + + camelize: function(str) { + return str.replace(/-(\w)/g, function(all, chr) { + return chr.toUpperCase(); + }); + }, + + hyphenate: function(str) { + return str.replace(/[a-z][A-Z0-9]|[0-9][a-zA-Z]|[A-Z]{2}[a-z]/g, + function(match) { + return match.charAt(0) + '-' + match.substring(1); + } + ).toLowerCase(); + }, + + formatNumber: function(num) { + return (Math.round(num * 100000) / 100000).toString(); + } + } +}); + +var PaperScope = this.PaperScope = Base.extend({ + + initialize: function(script) { + paper = this; + this.project = null; + this.projects = []; + this.tools = []; + this._id = script && (script.getAttribute('id') || script.src) + || ('paperscope-' + (PaperScope._id++)); + if (script) + script.setAttribute('id', this._id); + PaperScope._scopes[this._id] = this; + }, + + version: 0.22, + + getView: function() { + return this.project.view; + }, + + getTool: function() { + if (!this._tool) + this._tool = new Tool(); + return this._tool; + }, + + evaluate: function(code) { + var res = PaperScript.evaluate(code, this); + View.updateFocus(); + return res; + }, + + install: function(scope) { + var that = this; + Base.each(['project', 'view', 'tool'], function(key) { + Base.define(scope, key, { + configurable: true, + writable: true, + get: function() { + return that[key]; + } + }); + }); + for (var key in this) { + if (!/^(version|_id|load)/.test(key) && !(key in scope)) + scope[key] = this[key]; + } + }, + + setup: function(canvas) { + paper = this; + this.project = new Project(canvas); + }, + + clear: function() { + for (var i = this.projects.length - 1; i >= 0; i--) + this.projects[i].remove(); + for (var i = this.tools.length - 1; i >= 0; i--) + this.tools[i].remove(); + }, + + remove: function() { + this.clear(); + delete PaperScope._scopes[this._id]; + }, + + statics: { + _scopes: {}, + _id: 0, + + get: function(id) { + if (typeof id === 'object') + id = id.getAttribute('id'); + return this._scopes[id] || null; + } + } +}); + +var PaperScopeItem = Base.extend({ + + initialize: function(activate) { + this._scope = paper; + this._index = this._scope[this._list].push(this) - 1; + if (activate || !this._scope[this._reference]) + this.activate(); + }, + + activate: function() { + if (!this._scope) + return false; + this._scope[this._reference] = this; + return true; + }, + + remove: function() { + if (this._index == null) + return false; + Base.splice(this._scope[this._list], null, this._index, 1); + if (this._scope[this._reference] == this) + this._scope[this._reference] = null; + this._scope = null; + return true; + } +}); + +var Callback = { + attach: function(type, func) { + if (typeof type !== 'string') { + return Base.each(type, function(value, key) { + this.attach(key, value); + }, this); + } + var entry = this._eventTypes[type]; + if (!entry) + return this; + var handlers = this._handlers = this._handlers || {}; + handlers = handlers[type] = handlers[type] || []; + if (handlers.indexOf(func) == -1) { + handlers.push(func); + if (entry.install && handlers.length == 1) + entry.install.call(this, type); + } + return this; + }, + + detach: function(type, func) { + if (typeof type !== 'string') { + return Base.each(type, function(value, key) { + this.detach(key, value); + }, this); + } + var entry = this._eventTypes[type], + handlers = this._handlers && this._handlers[type], + index; + if (entry && handlers) { + if (!func || (index = handlers.indexOf(func)) != -1 + && handlers.length == 1) { + if (entry.uninstall) + entry.uninstall.call(this, type); + delete this._handlers[type]; + } else if (index != -1) { + handlers.splice(index, 1); + } + } + return this; + }, + + fire: function(type, event) { + var handlers = this._handlers && this._handlers[type]; + if (!handlers) + return false; + Base.each(handlers, function(func) { + if (func.call(this, event) === false && event && event.stop) + event.stop(); + }, this); + return true; + }, + + responds: function(type) { + return !!(this._handlers && this._handlers[type]); + }, + + statics: { + inject: function() { + for (var i = 0, l = arguments.length; i < l; i++) { + var src = arguments[i], + events = src._events; + if (events) { + var types = {}; + Base.each(events, function(entry, key) { + var isString = typeof entry === 'string', + name = isString ? entry : key, + part = Base.capitalize(name), + type = name.substring(2).toLowerCase(); + types[type] = isString ? {} : entry; + name = '_' + name; + src['get' + part] = function() { + return this[name]; + }; + src['set' + part] = function(func) { + if (func) { + this.attach(type, func); + } else if (this[name]) { + this.detach(type, this[name]); + } + this[name] = func; + }; + }); + src._eventTypes = types; + } + this.base(src); + } + return this; + } + } +}; + +var Point = this.Point = Base.extend({ + initialize: function(arg0, arg1) { + if (arg1 !== undefined) { + this.x = arg0; + this.y = arg1; + } else if (arg0 !== undefined) { + if (arg0 == null) { + this.x = this.y = 0; + } else if (arg0.x !== undefined) { + this.x = arg0.x; + this.y = arg0.y; + } else if (arg0.width !== undefined) { + this.x = arg0.width; + this.y = arg0.height; + } else if (Array.isArray(arg0)) { + this.x = arg0[0]; + this.y = arg0.length > 1 ? arg0[1] : arg0[0]; + } else if (arg0.angle !== undefined) { + this.x = arg0.length; + this.y = 0; + this.setAngle(arg0.angle); + } else if (typeof arg0 === 'number') { + this.x = this.y = arg0; + } else { + this.x = this.y = 0; + } + } else { + this.x = this.y = 0; + } + }, + + set: function(x, y) { + this.x = x; + this.y = y; + return this; + }, + + clone: function() { + return Point.create(this.x, this.y); + }, + + toString: function() { + var format = Base.formatNumber; + return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }'; + }, + + add: function(point) { + point = Point.read(arguments); + return Point.create(this.x + point.x, this.y + point.y); + }, + + subtract: function(point) { + point = Point.read(arguments); + return Point.create(this.x - point.x, this.y - point.y); + }, + + multiply: function(point) { + point = Point.read(arguments); + return Point.create(this.x * point.x, this.y * point.y); + }, + + divide: function(point) { + point = Point.read(arguments); + return Point.create(this.x / point.x, this.y / point.y); + }, + + modulo: function(point) { + point = Point.read(arguments); + return Point.create(this.x % point.x, this.y % point.y); + }, + + negate: function() { + return Point.create(-this.x, -this.y); + }, + + transform: function(matrix) { + return matrix ? matrix._transformPoint(this) : this; + }, + + getDistance: function(point, squared) { + point = Point.read(arguments); + var x = point.x - this.x, + y = point.y - this.y, + d = x * x + y * y; + return squared ? d : Math.sqrt(d); + }, + + getLength: function() { + var l = this.x * this.x + this.y * this.y; + return (arguments.length && arguments[0]) ? l : Math.sqrt(l); + }, + + setLength: function(length) { + if (this.isZero()) { + var angle = this._angle || 0; + this.set( + Math.cos(angle) * length, + Math.sin(angle) * length + ); + } else { + var scale = length / this.getLength(); + if (scale == 0) + this.getAngle(); + this.set( + this.x * scale, + this.y * scale + ); + } + return this; + }, + + normalize: function(length) { + if (length === undefined) + length = 1; + var current = this.getLength(), + scale = current != 0 ? length / current : 0, + point = Point.create(this.x * scale, this.y * scale); + point._angle = this._angle; + return point; + }, + + getAngle: function() { + return this.getAngleInRadians(arguments[0]) * 180 / Math.PI; + }, + + setAngle: function(angle) { + angle = this._angle = angle * Math.PI / 180; + if (!this.isZero()) { + var length = this.getLength(); + this.set( + Math.cos(angle) * length, + Math.sin(angle) * length + ); + } + return this; + }, + + getAngleInRadians: function() { + if (arguments[0] === undefined) { + if (this._angle == null) + this._angle = Math.atan2(this.y, this.x); + return this._angle; + } else { + var point = Point.read(arguments), + div = this.getLength() * point.getLength(); + if (div == 0) { + return NaN; + } else { + return Math.acos(this.dot(point) / div); + } + } + }, + + getAngleInDegrees: function() { + return this.getAngle(arguments[0]); + }, + + getQuadrant: function() { + return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; + }, + + getDirectedAngle: function(point) { + point = Point.read(arguments); + return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; + }, + + rotate: function(angle, center) { + angle = angle * Math.PI / 180; + var point = center ? this.subtract(center) : this, + s = Math.sin(angle), + c = Math.cos(angle); + point = Point.create( + point.x * c - point.y * s, + point.y * c + point.x * s + ); + return center ? point.add(center) : point; + }, + + equals: function(point) { + point = Point.read(arguments); + return this.x == point.x && this.y == point.y; + }, + + isInside: function(rect) { + return rect.contains(this); + }, + + isClose: function(point, tolerance) { + return this.getDistance(point) < tolerance; + }, + + isColinear: function(point) { + return this.cross(point) < Numerical.TOLERANCE; + }, + + isOrthogonal: function(point) { + return this.dot(point) < Numerical.TOLERANCE; + }, + + isZero: function() { + return this.x == 0 && this.y == 0; + }, + + isNaN: function() { + return isNaN(this.x) || isNaN(this.y); + }, + + dot: function(point) { + point = Point.read(arguments); + return this.x * point.x + this.y * point.y; + }, + + cross: function(point) { + point = Point.read(arguments); + return this.x * point.y - this.y * point.x; + }, + + project: function(point) { + point = Point.read(arguments); + if (point.isZero()) { + return Point.create(0, 0); + } else { + var scale = this.dot(point) / point.dot(point); + return Point.create( + point.x * scale, + point.y * scale + ); + } + }, + + statics: { + create: function(x, y) { + var point = new Point(Point.dont); + point.x = x; + point.y = y; + return point; + }, + + min: function(point1, point2) { + point1 = Point.read(arguments, 0, 1); + point2 = Point.read(arguments, 1, 1); + return Point.create( + Math.min(point1.x, point2.x), + Math.min(point1.y, point2.y) + ); + }, + + max: function(point1, point2) { + point1 = Point.read(arguments, 0, 1); + point2 = Point.read(arguments, 1, 1); + return Point.create( + Math.max(point1.x, point2.x), + Math.max(point1.y, point2.y) + ); + }, + + random: function() { + return Point.create(Math.random(), Math.random()); + } + } +}, new function() { + + return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { + var op = Math[name]; + this[name] = function() { + return Point.create(op(this.x), op(this.y)); + }; + }, {}); +}); + +var LinkedPoint = Point.extend({ + set: function(x, y, dontNotify) { + this._x = x; + this._y = y; + if (!dontNotify) + this._owner[this._setter](this); + return this; + }, + + getX: function() { + return this._x; + }, + + setX: function(x) { + this._x = x; + this._owner[this._setter](this); + }, + + getY: function() { + return this._y; + }, + + setY: function(y) { + this._y = y; + this._owner[this._setter](this); + }, + + statics: { + create: function(owner, setter, x, y, dontLink) { + if (dontLink) + return Point.create(x, y); + var point = new LinkedPoint(LinkedPoint.dont); + point._x = x; + point._y = y; + point._owner = owner; + point._setter = setter; + return point; + } + } +}); + +var Size = this.Size = Base.extend({ + initialize: function(arg0, arg1) { + if (arg1 !== undefined) { + this.width = arg0; + this.height = arg1; + } else if (arg0 !== undefined) { + if (arg0 == null) { + this.width = this.height = 0; + } else if (arg0.width !== undefined) { + this.width = arg0.width; + this.height = arg0.height; + } else if (arg0.x !== undefined) { + this.width = arg0.x; + this.height = arg0.y; + } else if (Array.isArray(arg0)) { + this.width = arg0[0]; + this.height = arg0.length > 1 ? arg0[1] : arg0[0]; + } else if (typeof arg0 === 'number') { + this.width = this.height = arg0; + } else { + this.width = this.height = 0; + } + } else { + this.width = this.height = 0; + } + }, + + toString: function() { + var format = Base.formatNumber; + return '{ width: ' + format(this.width) + + ', height: ' + format(this.height) + ' }'; + }, + + set: function(width, height) { + this.width = width; + this.height = height; + return this; + }, + + clone: function() { + return Size.create(this.width, this.height); + }, + + add: function(size) { + size = Size.read(arguments); + return Size.create(this.width + size.width, this.height + size.height); + }, + + subtract: function(size) { + size = Size.read(arguments); + return Size.create(this.width - size.width, this.height - size.height); + }, + + multiply: function(size) { + size = Size.read(arguments); + return Size.create(this.width * size.width, this.height * size.height); + }, + + divide: function(size) { + size = Size.read(arguments); + return Size.create(this.width / size.width, this.height / size.height); + }, + + modulo: function(size) { + size = Size.read(arguments); + return Size.create(this.width % size.width, this.height % size.height); + }, + + negate: function() { + return Size.create(-this.width, -this.height); + }, + + equals: function(size) { + size = Size.read(arguments); + return this.width == size.width && this.height == size.height; + }, + + isZero: function() { + return this.width == 0 && this.height == 0; + }, + + isNaN: function() { + return isNaN(this.width) || isNaN(this.height); + }, + + statics: { + create: function(width, height) { + return new Size(Size.dont).set(width, height); + }, + + min: function(size1, size2) { + return Size.create( + Math.min(size1.width, size2.width), + Math.min(size1.height, size2.height)); + }, + + max: function(size1, size2) { + return Size.create( + Math.max(size1.width, size2.width), + Math.max(size1.height, size2.height)); + }, + + random: function() { + return Size.create(Math.random(), Math.random()); + } + } +}, new function() { + + return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { + var op = Math[name]; + this[name] = function() { + return Size.create(op(this.width), op(this.height)); + }; + }, {}); +}); + +var LinkedSize = Size.extend({ + set: function(width, height, dontNotify) { + this._width = width; + this._height = height; + if (!dontNotify) + this._owner[this._setter](this); + return this; + }, + + getWidth: function() { + return this._width; + }, + + setWidth: function(width) { + this._width = width; + this._owner[this._setter](this); + }, + + getHeight: function() { + return this._height; + }, + + setHeight: function(height) { + this._height = height; + this._owner[this._setter](this); + }, + + statics: { + create: function(owner, setter, width, height, dontLink) { + if (dontLink) + return Size.create(width, height); + var size = new LinkedSize(LinkedSize.dont); + size._width = width; + size._height = height; + size._owner = owner; + size._setter = setter; + return size; + } + } +}); + +var Rectangle = this.Rectangle = Base.extend({ + initialize: function(arg0, arg1, arg2, arg3) { + if (arguments.length == 4) { + this.x = arg0; + this.y = arg1; + this.width = arg2; + this.height = arg3; + } else if (arguments.length == 2) { + if (arg1 && arg1.x !== undefined) { + var point1 = Point.read(arguments, 0, 1); + var point2 = Point.read(arguments, 1, 1); + this.x = point1.x; + this.y = point1.y; + this.width = point2.x - point1.x; + this.height = point2.y - point1.y; + if (this.width < 0) { + this.x = point2.x; + this.width = -this.width; + } + if (this.height < 0) { + this.y = point2.y; + this.height = -this.height; + } + } else { + var point = Point.read(arguments, 0, 1); + var size = Size.read(arguments, 1, 1); + this.x = point.x; + this.y = point.y; + this.width = size.width; + this.height = size.height; + } + } else if (arg0) { + this.x = arg0.x || 0; + this.y = arg0.y || 0; + this.width = arg0.width || 0; + this.height = arg0.height || 0; + } else { + this.x = this.y = this.width = this.height = 0; + } + }, + + set: function(x, y, width, height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + return this; + }, + + getPoint: function() { + return LinkedPoint.create(this, 'setPoint', this.x, this.y, + arguments[0]); + }, + + setPoint: function(point) { + point = Point.read(arguments); + this.x = point.x; + this.y = point.y; + return this; + }, + + getSize: function() { + return LinkedSize.create(this, 'setSize', this.width, this.height, + arguments[0]); + }, + + setSize: function(size) { + size = Size.read(arguments); + this.width = size.width; + this.height = size.height; + return this; + }, + + getLeft: function() { + return this.x; + }, + + setLeft: function(left) { + this.width -= left - this.x; + this.x = left; + return this; + }, + + getTop: function() { + return this.y; + }, + + setTop: function(top) { + this.height -= top - this.y; + this.y = top; + return this; + }, + + getRight: function() { + return this.x + this.width; + }, + + setRight: function(right) { + this.width = right - this.x; + return this; + }, + + getBottom: function() { + return this.y + this.height; + }, + + setBottom: function(bottom) { + this.height = bottom - this.y; + return this; + }, + + getCenterX: function() { + return this.x + this.width * 0.5; + }, + + setCenterX: function(x) { + this.x = x - this.width * 0.5; + return this; + }, + + getCenterY: function() { + return this.y + this.height * 0.5; + }, + + setCenterY: function(y) { + this.y = y - this.height * 0.5; + return this; + }, + + getCenter: function() { + return LinkedPoint.create(this, 'setCenter', + this.getCenterX(), this.getCenterY(), arguments[0]); + }, + + setCenter: function(point) { + point = Point.read(arguments); + return this.setCenterX(point.x).setCenterY(point.y); + }, + + equals: function(rect) { + rect = Rectangle.read(arguments); + return this.x == rect.x && this.y == rect.y + && this.width == rect.width && this.height == rect.height; + }, + + isEmpty: function() { + return this.width == 0 || this.height == 0; + }, + + toString: function() { + var format = Base.formatNumber; + return '{ x: ' + format(this.x) + + ', y: ' + format(this.y) + + ', width: ' + format(this.width) + + ', height: ' + format(this.height) + + ' }'; + }, + + contains: function(arg) { + return arg && arg.width !== undefined + || (Array.isArray(arg) ? arg : arguments).length == 4 + ? this._containsRectangle(Rectangle.read(arguments)) + : this._containsPoint(Point.read(arguments)); + }, + + _containsPoint: function(point) { + var x = point.x, + y = point.y; + return x >= this.x && y >= this.y + && x <= this.x + this.width + && y <= this.y + this.height; + }, + + _containsRectangle: function(rect) { + var x = rect.x, + y = rect.y; + return x >= this.x && y >= this.y + && x + rect.width <= this.x + this.width + && y + rect.height <= this.y + this.height; + }, + + intersects: function(rect) { + rect = Rectangle.read(arguments); + return rect.x + rect.width > this.x + && rect.y + rect.height > this.y + && rect.x < this.x + this.width + && rect.y < this.y + this.height; + }, + + intersect: function(rect) { + rect = Rectangle.read(arguments); + var x1 = Math.max(this.x, rect.x), + y1 = Math.max(this.y, rect.y), + x2 = Math.min(this.x + this.width, rect.x + rect.width), + y2 = Math.min(this.y + this.height, rect.y + rect.height); + return Rectangle.create(x1, y1, x2 - x1, y2 - y1); + }, + + unite: function(rect) { + rect = Rectangle.read(arguments); + var x1 = Math.min(this.x, rect.x), + y1 = Math.min(this.y, rect.y), + x2 = Math.max(this.x + this.width, rect.x + rect.width), + y2 = Math.max(this.y + this.height, rect.y + rect.height); + return Rectangle.create(x1, y1, x2 - x1, y2 - y1); + }, + + include: function(point) { + point = Point.read(arguments); + var x1 = Math.min(this.x, point.x), + y1 = Math.min(this.y, point.y), + x2 = Math.max(this.x + this.width, point.x), + y2 = Math.max(this.y + this.height, point.y); + return Rectangle.create(x1, y1, x2 - x1, y2 - y1); + }, + + expand: function(hor, ver) { + if (ver === undefined) + ver = hor; + return Rectangle.create(this.x - hor / 2, this.y - ver / 2, + this.width + hor, this.height + ver); + }, + + scale: function(hor, ver) { + return this.expand(this.width * hor - this.width, + this.height * (ver === undefined ? hor : ver) - this.height); + }, + + statics: { + create: function(x, y, width, height) { + return new Rectangle(Rectangle.dont).set(x, y, width, height); + } + } +}, new function() { + return Base.each([ + ['Top', 'Left'], ['Top', 'Right'], + ['Bottom', 'Left'], ['Bottom', 'Right'], + ['Left', 'Center'], ['Top', 'Center'], + ['Right', 'Center'], ['Bottom', 'Center'] + ], + function(parts, index) { + var part = parts.join(''); + var xFirst = /^[RL]/.test(part); + if (index >= 4) + parts[1] += xFirst ? 'Y' : 'X'; + var x = parts[xFirst ? 0 : 1], + y = parts[xFirst ? 1 : 0], + getX = 'get' + x, + getY = 'get' + y, + setX = 'set' + x, + setY = 'set' + y, + get = 'get' + part, + set = 'set' + part; + this[get] = function() { + return LinkedPoint.create(this, set, + this[getX](), this[getY](), arguments[0]); + }; + this[set] = function(point) { + point = Point.read(arguments); + return this[setX](point.x)[setY](point.y); + }; + }, {}); +}); + +var LinkedRectangle = Rectangle.extend({ + set: function(x, y, width, height, dontNotify) { + this._x = x; + this._y = y; + this._width = width; + this._height = height; + if (!dontNotify) + this._owner[this._setter](this); + return this; + }, + + statics: { + create: function(owner, setter, x, y, width, height) { + var rect = new LinkedRectangle(LinkedRectangle.dont).set( + x, y, width, height, true); + rect._owner = owner; + rect._setter = setter; + return rect; + } + } +}, new function() { + var proto = Rectangle.prototype; + + return Base.each(['x', 'y', 'width', 'height'], function(key) { + var part = Base.capitalize(key); + var internal = '_' + key; + this['get' + part] = function() { + return this[internal]; + }; + + this['set' + part] = function(value) { + this[internal] = value; + if (!this._dontNotify) + this._owner[this._setter](this); + }; + }, Base.each(['Point', 'Size', 'Center', + 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', + 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', + 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], + function(key) { + var name = 'set' + key; + this[name] = function(value) { + this._dontNotify = true; + proto[name].apply(this, arguments); + delete this._dontNotify; + this._owner[this._setter](this); + return this; + }; + }, {}) + ); +}); + +var Matrix = this.Matrix = Base.extend({ + initialize: function(arg) { + var count = arguments.length, + ok = true; + if (count == 6) { + this.set.apply(this, arguments); + } else if (count == 1) { + if (arg instanceof Matrix) { + this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty); + } else if (Array.isArray(arg)) { + this.set.apply(this, arg); + } else { + ok = false; + } + } else if (count == 0) { + this.setIdentity(); + } else { + ok = false; + } + if (!ok) + throw new Error('Unsupported matrix parameters'); + }, + + clone: function() { + return Matrix.create(this._a, this._c, this._b, this._d, + this._tx, this._ty); + }, + + set: function(a, c, b, d, tx, ty) { + this._a = a; + this._c = c; + this._b = b; + this._d = d; + this._tx = tx; + this._ty = ty; + return this; + }, + + setIdentity: function() { + this._a = this._d = 1; + this._c = this._b = this._tx = this._ty = 0; + return this; + }, + + scale: function( hor, ver, center) { + if (arguments.length < 2 || typeof ver === 'object') { + center = Point.read(arguments, 1); + ver = hor; + } else { + center = Point.read(arguments, 2); + } + if (center) + this.translate(center); + this._a *= hor; + this._c *= hor; + this._b *= ver; + this._d *= ver; + if (center) + this.translate(center.negate()); + return this; + }, + + translate: function(point) { + point = Point.read(arguments); + var x = point.x, y = point.y; + this._tx += x * this._a + y * this._b; + this._ty += x * this._c + y * this._d; + return this; + }, + + rotate: function(angle, center) { + return this.concatenate( + Matrix.getRotateInstance.apply(Matrix, arguments)); + }, + + shear: function( hor, ver, center) { + if (arguments.length < 2 || typeof ver === 'object') { + center = Point.read(arguments, 1); + ver = hor; + } else { + center = Point.read(arguments, 2); + } + if (center) + this.translate(center); + var a = this._a, + c = this._c; + this._a += ver * this._b; + this._c += ver * this._d; + this._b += hor * a; + this._d += hor * c; + if (center) + this.translate(center.negate()); + return this; + }, + + toString: function() { + var format = Base.formatNumber; + return '[[' + [format(this._a), format(this._b), + format(this._tx)].join(', ') + '], [' + + [format(this._c), format(this._d), + format(this._ty)].join(', ') + ']]'; + }, + + getValues: function() { + return [ this._a, this._c, this._b, this._d, this._tx, this._ty ]; + }, + + concatenate: function(mx) { + var a = this._a, + b = this._b, + c = this._c, + d = this._d; + this._a = mx._a * a + mx._c * b; + this._b = mx._b * a + mx._d * b; + this._c = mx._a * c + mx._c * d; + this._d = mx._b * c + mx._d * d; + this._tx += mx._tx * a + mx._ty * b; + this._ty += mx._tx * c + mx._ty * d; + return this; + }, + + preConcatenate: function(mx) { + var a = this._a, + b = this._b, + c = this._c, + d = this._d, + tx = this._tx, + ty = this._ty; + this._a = mx._a * a + mx._b * c; + this._b = mx._a * b + mx._b * d; + this._c = mx._c * a + mx._d * c; + this._d = mx._c * b + mx._d * d; + this._tx = mx._a * tx + mx._b * ty + mx._tx; + this._ty = mx._c * tx + mx._d * ty + mx._ty; + return this; + }, + + transform: function( src, srcOff, dst, dstOff, numPts) { + return arguments.length < 5 + ? this._transformPoint(Point.read(arguments)) + : this._transformCoordinates(src, srcOff, dst, dstOff, numPts); + }, + + _transformPoint: function(point, dest, dontNotify) { + var x = point.x, + y = point.y; + if (!dest) + dest = new Point(Point.dont); + return dest.set( + x * this._a + y * this._b + this._tx, + x * this._c + y * this._d + this._ty, + dontNotify + ); + }, + + _transformCoordinates: function(src, srcOff, dst, dstOff, numPts) { + var i = srcOff, j = dstOff, + srcEnd = srcOff + 2 * numPts; + while (i < srcEnd) { + var x = src[i++]; + var y = src[i++]; + dst[j++] = x * this._a + y * this._b + this._tx; + dst[j++] = x * this._c + y * this._d + this._ty; + } + return dst; + }, + + _transformCorners: function(rect) { + var x1 = rect.x, + y1 = rect.y, + x2 = x1 + rect.width, + y2 = y1 + rect.height, + coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; + return this._transformCoordinates(coords, 0, coords, 0, 4); + }, + + _transformBounds: function(bounds, dest, dontNotify) { + var coords = this._transformCorners(bounds), + min = coords.slice(0, 2), + max = coords.slice(0); + for (var i = 2; i < 8; i++) { + var val = coords[i], + j = i & 1; + if (val < min[j]) + min[j] = val; + else if (val > max[j]) + max[j] = val; + } + if (!dest) + dest = new Rectangle(Rectangle.dont); + return dest.set(min[0], min[1], max[0] - min[0], max[1] - min[1], + dontNotify); + }, + + inverseTransform: function(point) { + return this._inverseTransform(Point.read(arguments)); + }, + + _getDeterminant: function() { + var det = this._a * this._d - this._b * this._c; + return isFinite(det) && Math.abs(det) > Numerical.EPSILON + && isFinite(this._tx) && isFinite(this._ty) + ? det : null; + }, + + _inverseTransform: function(point, dest, dontNotify) { + var det = this._getDeterminant(); + if (!det) + return null; + var x = point.x - this._tx, + y = point.y - this._ty; + if (!dest) + dest = new Point(Point.dont); + return dest.set( + (x * this._d - y * this._b) / det, + (y * this._a - x * this._c) / det, + dontNotify + ); + }, + + getTranslation: function() { + return Point.create(this._tx, this._ty); + }, + + getScaling: function() { + var hor = Math.sqrt(this._a * this._a + this._c * this._c), + ver = Math.sqrt(this._b * this._b + this._d * this._d); + return Point.create(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); + }, + + getRotation: function() { + var angle1 = -Math.atan2(this._b, this._d), + angle2 = Math.atan2(this._c, this._a); + return Math.abs(angle1 - angle2) < Numerical.TOLERANCE + ? angle1 * 180 / Math.PI : undefined; + }, + + equals: function(mx) { + return this._a == mx._a && this._b == mx._b && this._c == mx._c + && this._d == mx._d && this._tx == mx._tx && this._ty == mx._ty; + }, + + isIdentity: function() { + return this._a == 1 && this._c == 0 && this._b == 0 && this._d == 1 + && this._tx == 0 && this._ty == 0; + }, + + isInvertible: function() { + return !!this._getDeterminant(); + }, + + isSingular: function() { + return !this._getDeterminant(); + }, + + createInverse: function() { + var det = this._getDeterminant(); + return det && Matrix.create( + this._d / det, + -this._c / det, + -this._b / det, + this._a / det, + (this._b * this._ty - this._d * this._tx) / det, + (this._c * this._tx - this._a * this._ty) / det); + }, + + createShiftless: function() { + return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); + }, + + setToScale: function(hor, ver) { + return this.set(hor, 0, 0, ver, 0, 0); + }, + + setToTranslation: function(delta) { + delta = Point.read(arguments); + return this.set(1, 0, 0, 1, delta.x, delta.y); + }, + + setToShear: function(hor, ver) { + return this.set(1, ver, hor, 1, 0, 0); + }, + + setToRotation: function(angle, center) { + center = Point.read(arguments, 1); + angle = angle * Math.PI / 180; + var x = center.x, + y = center.y, + cos = Math.cos(angle), + sin = Math.sin(angle); + return this.set(cos, sin, -sin, cos, + x - x * cos + y * sin, + y - x * sin - y * cos); + }, + + applyToContext: function(ctx, reset) { + ctx[reset ? 'setTransform' : 'transform']( + this._a, this._c, this._b, this._d, this._tx, this._ty); + return this; + }, + + statics: { + create: function(a, c, b, d, tx, ty) { + return new Matrix(Matrix.dont).set(a, c, b, d, tx, ty); + }, + + getScaleInstance: function(hor, ver) { + var mx = new Matrix(); + return mx.setToScale.apply(mx, arguments); + }, + + getTranslateInstance: function(delta) { + var mx = new Matrix(); + return mx.setToTranslation.apply(mx, arguments); + }, + + getShearInstance: function(hor, ver, center) { + var mx = new Matrix(); + return mx.setToShear.apply(mx, arguments); + }, + + getRotateInstance: function(angle, center) { + var mx = new Matrix(); + return mx.setToRotation.apply(mx, arguments); + } + } +}, new function() { + return Base.each({ + scaleX: '_a', + scaleY: '_d', + translateX: '_tx', + translateY: '_ty', + shearX: '_b', + shearY: '_c' + }, function(prop, name) { + name = Base.capitalize(name); + this['get' + name] = function() { + return this[prop]; + }; + this['set' + name] = function(value) { + this[prop] = value; + }; + }, {}); +}); + +var Line = this.Line = Base.extend({ + initialize: function(point1, point2, infinite) { + point1 = Point.read(arguments, 0, 1); + point2 = Point.read(arguments, 1, 1); + if (arguments.length == 3) { + this.point = point1; + this.vector = point2.subtract(point1); + this.infinite = infinite; + } else { + this.point = point1; + this.vector = point2; + this.infinite = true; + } + }, + + intersect: function(line) { + var cross = this.vector.cross(line.vector); + if (Math.abs(cross) <= Numerical.EPSILON) + return null; + var v = line.point.subtract(this.point), + t1 = v.cross(line.vector) / cross, + t2 = v.cross(this.vector) / cross; + return (this.infinite || 0 <= t1 && t1 <= 1) + && (line.infinite || 0 <= t2 && t2 <= 1) + ? this.point.add(this.vector.multiply(t1)) : null; + }, + + getSide: function(point) { + var v1 = this.vector, + v2 = point.subtract(this.point), + ccw = v2.cross(v1); + if (ccw == 0) { + ccw = v2.dot(v1); + if (ccw > 0) { + ccw = v2.subtract(v1).dot(v1); + if (ccw < 0) + ccw = 0; + } + } + return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; + }, + + getDistance: function(point) { + var m = this.vector.y / this.vector.x, + b = this.point.y - (m * this.point.x); + var dist = Math.abs(point.y - (m * point.x) - b) / Math.sqrt(m * m + 1); + return this.infinite ? dist : Math.min(dist, + point.getDistance(this.point), + point.getDistance(this.point.add(this.vector))); + } +}); + +var Project = this.Project = PaperScopeItem.extend({ + _list: 'projects', + _reference: 'project', + + initialize: function(view) { + this.base(true); + this._currentStyle = new PathStyle(); + this._selectedItems = {}; + this._selectedItemCount = 0; + this.layers = []; + this.symbols = []; + this.activeLayer = new Layer(); + if (view) + this.view = view instanceof View ? view : View.create(view); + }, + + _needsRedraw: function() { + if (this.view) + this.view._redrawNeeded = true; + }, + + remove: function() { + if (!this.base()) + return false; + if (this.view) + this.view.remove(); + return true; + }, + + getCurrentStyle: function() { + return this._currentStyle; + }, + + setCurrentStyle: function(style) { + this._currentStyle.initialize(style); + }, + + getIndex: function() { + return this._index; + }, + + getSelectedItems: function() { + var items = []; + Base.each(this._selectedItems, function(item) { + items.push(item); + }); + return items; + }, + + _updateSelection: function(item) { + if (item._selected) { + this._selectedItemCount++; + this._selectedItems[item._id] = item; + } else { + this._selectedItemCount--; + delete this._selectedItems[item._id]; + } + }, + + selectAll: function() { + for (var i = 0, l = this.layers.length; i < l; i++) + this.layers[i].setSelected(true); + }, + + deselectAll: function() { + for (var i in this._selectedItems) + this._selectedItems[i].setSelected(false); + }, + + hitTest: function(point, options) { + options = HitResult.getOptions(point, options); + point = options.point; + for (var i = this.layers.length - 1; i >= 0; i--) { + var res = this.layers[i].hitTest(point, options); + if (res) return res; + } + return null; + }, + + draw: function(ctx, matrix) { + ctx.save(); + if (!matrix.isIdentity()) + matrix.applyToContext(ctx); + var param = { offset: new Point(0, 0) }; + for (var i = 0, l = this.layers.length; i < l; i++) + Item.draw(this.layers[i], ctx, param); + ctx.restore(); + + if (this._selectedItemCount > 0) { + ctx.save(); + ctx.strokeWidth = 1; + ctx.strokeStyle = ctx.fillStyle = '#009dec'; + var matrices = {}; + function getGlobalMatrix(item, mx, cached) { + var cache = cached && matrices[item._id]; + if (cache) { + mx.concatenate(cache); + return mx; + } + if (item._parent) { + getGlobalMatrix(item._parent, mx, true); + if (!item._matrix.isIdentity()) + mx.concatenate(item._matrix); + } else { + mx.initialize(item._matrix); + } + if (cached) + matrices[item._id] = mx.clone(); + return mx; + } + for (var id in this._selectedItems) { + var item = this._selectedItems[id]; + item.drawSelected(ctx, getGlobalMatrix(item, matrix.clone())); + } + ctx.restore(); + } + } +}); + +var Symbol = this.Symbol = Base.extend({ + initialize: function(item) { + this.project = paper.project; + this.project.symbols.push(this); + this.setDefinition(item); + this._instances = {}; + }, + + _changed: function(flags) { + Base.each(this._instances, function(item) { + item._changed(flags); + }); + }, + + getDefinition: function() { + return this._definition; + }, + + setDefinition: function(item) { + if (item._parentSymbol) + item = item.clone(); + if (this._definition) + delete this._definition._parentSymbol; + this._definition = item; + item.remove(); + item.setPosition(new Point()); + item._parentSymbol = this; + this._changed(Change.GEOMETRY); + }, + + place: function(position) { + return new PlacedSymbol(this, position); + }, + + clone: function() { + return new Symbol(this._definition.clone()); + } +}); + +var ChangeFlag = { + APPEARANCE: 1, + HIERARCHY: 2, + GEOMETRY: 4, + STROKE: 8, + STYLE: 16, + ATTRIBUTE: 32, + CONTENT: 64, + PIXELS: 128, + CLIPPING: 256 +}; + +var Change = { + HIERARCHY: ChangeFlag.HIERARCHY | ChangeFlag.APPEARANCE, + GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, + STROKE: ChangeFlag.STROKE | ChangeFlag.STYLE | ChangeFlag.APPEARANCE, + STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE, + ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE, + CONTENT: ChangeFlag.CONTENT | ChangeFlag.APPEARANCE, + PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE +}; + +var Item = this.Item = Base.extend(Callback, { + _events: new function() { + + var mouseFlags = { + mousedown: { + mousedown: 1, + mousedrag: 1, + click: 1, + doubleclick: 1 + }, + mouseup: { + mouseup: 1, + mousedrag: 1, + click: 1, + doubleclick: 1 + }, + mousemove: { + mousedrag: 1, + mousemove: 1, + mouseenter: 1, + mouseleave: 1 + } + }; + + var mouseEvent = { + install: function(type) { + var counters = this._project.view._eventCounters; + if (counters) { + for (var key in mouseFlags) { + counters[key] = (counters[key] || 0) + + (mouseFlags[key][type] || 0); + } + } + }, + uninstall: function(type) { + var counters = this._project.view._eventCounters; + if (counters) { + for (var key in mouseFlags) + counters[key] -= mouseFlags[key][type] || 0; + } + } + }; + + var onFrameItems = []; + function onFrame(event) { + for (var i = 0, l = onFrameItems.length; i < l; i++) + onFrameItems[i].fire('frame', event); + } + + return Base.each(['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick', + 'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave'], + function(name) { + this[name] = mouseEvent; + }, { + onFrame: { + install: function() { + if (!onFrameItems.length) + this._project.view.attach('frame', onFrame); + onFrameItems.push(this); + }, + uninstall: function() { + onFrameItems.splice(onFrameItems.indexOf(this), 1); + if (!onFrameItems.length) + this._project.view.detach('frame', onFrame); + } + } + }); + }, + + initialize: function(pointOrMatrix) { + this._id = ++Item._id; + if (!this._project) + paper.project.activeLayer.addChild(this); + if (!this._style) + this._style = PathStyle.create(this); + this.setStyle(this._project.getCurrentStyle()); + this._matrix = pointOrMatrix !== undefined + ? pointOrMatrix instanceof Matrix + ? pointOrMatrix.clone() + : new Matrix().translate(Point.read(arguments, 0)) + : new Matrix(); + }, + + _changed: function(flags) { + if (flags & ChangeFlag.GEOMETRY) { + delete this._bounds; + delete this._position; + } + if (this._parent + && (flags & (ChangeFlag.GEOMETRY | ChangeFlag.STROKE))) { + this._parent._clearBoundsCache(); + } + if (flags & ChangeFlag.HIERARCHY) { + this._clearBoundsCache(); + } + if (flags & ChangeFlag.APPEARANCE) { + this._project._needsRedraw(); + } + if (this._parentSymbol) + this._parentSymbol._changed(flags); + if (this._project._changes) { + var entry = this._project._changesById[this._id]; + if (entry) { + entry.flags |= flags; + } else { + entry = { item: this, flags: flags }; + this._project._changesById[this._id] = entry; + this._project._changes.push(entry); + } + } + }, + + getId: function() { + return this._id; + }, + + getName: function() { + return this._name; + }, + + setName: function(name) { + + if (this._name) + this._removeFromNamed(); + this._name = name || undefined; + if (name && this._parent) { + var children = this._parent._children, + namedChildren = this._parent._namedChildren; + (namedChildren[name] = namedChildren[name] || []).push(this); + children[name] = this; + } + this._changed(ChangeFlag.ATTRIBUTE); + }, + + statics: { + _id: 0 + } +}, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], + function(name) { + var part = Base.capitalize(name), + name = '_' + name; + this['get' + part] = function() { + return this[name]; + }; + this['set' + part] = function(value) { + if (value != this[name]) { + this[name] = value; + this._changed(name === '_locked' + ? ChangeFlag.ATTRIBUTE : Change.ATTRIBUTE); + } + }; +}, {}), { + + _locked: false, + + _visible: true, + + _blendMode: 'normal', + + _opacity: 1, + + _guide: false, + + isSelected: function() { + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) + if (this._children[i].isSelected()) + return true; + } + return this._selected; + }, + + setSelected: function(selected ) { + if (this._children && !arguments[1]) { + for (var i = 0, l = this._children.length; i < l; i++) + this._children[i].setSelected(selected); + } else if ((selected = !!selected) != this._selected) { + this._selected = selected; + this._project._updateSelection(this); + this._changed(Change.ATTRIBUTE); + } + }, + + _selected: false, + + isFullySelected: function() { + if (this._children && this._selected) { + for (var i = 0, l = this._children.length; i < l; i++) + if (!this._children[i].isFullySelected()) + return false; + return true; + } + return this._selected; + }, + + setFullySelected: function(selected) { + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) + this._children[i].setFullySelected(selected); + } + this.setSelected(selected, true); + }, + + isClipMask: function() { + return this._clipMask; + }, + + setClipMask: function(clipMask) { + if (this._clipMask != (clipMask = !!clipMask)) { + this._clipMask = clipMask; + if (clipMask) { + this.setFillColor(null); + this.setStrokeColor(null); + } + this._changed(Change.ATTRIBUTE); + if (this._parent) + this._parent._changed(ChangeFlag.CLIPPING); + } + }, + + _clipMask: false, + + getPosition: function() { + var pos = this._position + || (this._position = this.getBounds().getCenter(true)); + return arguments[0] ? pos + : LinkedPoint.create(this, 'setPosition', pos.x, pos.y); + }, + + setPosition: function(point) { + this.translate(Point.read(arguments).subtract(this.getPosition(true))); + }, + + getMatrix: function() { + return this._matrix; + }, + + setMatrix: function(matrix) { + this._matrix.initialize(matrix); + this._changed(Change.GEOMETRY); + } +}, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds'], +function(name) { + this['get' + Base.capitalize(name)] = function() { + var type = this._boundsType, + bounds = this._getCachedBounds( + typeof type == 'string' ? type : type && type[name] || name, + arguments[0]); + return name == 'bounds' ? LinkedRectangle.create(this, 'setBounds', + bounds.x, bounds.y, bounds.width, bounds.height) : bounds; + }; +}, { + _getCachedBounds: function(type, matrix, cacheItem) { + var cache = (!matrix || matrix.equals(this._matrix)) && type; + if (cacheItem && this._parent) { + var id = cacheItem._id, + ref = this._parent._boundsCache + = this._parent._boundsCache || { + ids: {}, + list: [] + }; + if (!ref.ids[id]) { + ref.list.push(cacheItem); + ref.ids[id] = cacheItem; + } + } + if (cache && this._bounds && this._bounds[cache]) + return this._bounds[cache]; + var identity = this._matrix.isIdentity(); + matrix = !matrix || matrix.isIdentity() + ? identity ? null : this._matrix + : identity ? matrix : matrix.clone().concatenate(this._matrix); + var bounds = this._getBounds(type, matrix, cache ? this : cacheItem); + if (cache) { + if (!this._bounds) + this._bounds = {}; + this._bounds[cache] = bounds.clone(); + } + return bounds; + }, + + _clearBoundsCache: function() { + if (this._boundsCache) { + for (var i = 0, list = this._boundsCache.list, l = list.length; + i < l; i++) { + var item = list[i]; + delete item._bounds; + if (item != this && item._boundsCache) + item._clearBoundsCache(); + } + delete this._boundsCache; + } + }, + + _getBounds: function(type, matrix, cacheItem) { + var children = this._children; + if (!children || children.length == 0) + return new Rectangle(); + var x1 = Infinity, + x2 = -x1, + y1 = x1, + y2 = x2; + for (var i = 0, l = children.length; i < l; i++) { + var child = children[i]; + if (child._visible) { + var rect = child._getCachedBounds(type, matrix, cacheItem); + x1 = Math.min(rect.x, x1); + y1 = Math.min(rect.y, y1); + x2 = Math.max(rect.x + rect.width, x2); + y2 = Math.max(rect.y + rect.height, y2); + } + } + return Rectangle.create(x1, y1, x2 - x1, y2 - y1); + }, + + setBounds: function(rect) { + rect = Rectangle.read(arguments); + var bounds = this.getBounds(), + matrix = new Matrix(), + center = rect.getCenter(); + matrix.translate(center); + if (rect.width != bounds.width || rect.height != bounds.height) { + matrix.scale( + bounds.width != 0 ? rect.width / bounds.width : 1, + bounds.height != 0 ? rect.height / bounds.height : 1); + } + center = bounds.getCenter(); + matrix.translate(-center.x, -center.y); + this.transform(matrix); + } + +}), { + getProject: function() { + return this._project; + }, + + _setProject: function(project) { + if (this._project != project) { + this._project = project; + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) { + this._children[i]._setProject(project); + } + } + } + }, + + getLayer: function() { + var parent = this; + while (parent = parent._parent) { + if (parent instanceof Layer) + return parent; + } + return null; + }, + + getParent: function() { + return this._parent; + }, + + getChildren: function() { + return this._children; + }, + + setChildren: function(items) { + this.removeChildren(); + this.addChildren(items); + }, + + getFirstChild: function() { + return this._children && this._children[0] || null; + }, + + getLastChild: function() { + return this._children && this._children[this._children.length - 1] + || null; + }, + + getNextSibling: function() { + return this._parent && this._parent._children[this._index + 1] || null; + }, + + getPreviousSibling: function() { + return this._parent && this._parent._children[this._index - 1] || null; + }, + + getIndex: function() { + return this._index; + }, + + clone: function() { + return this._clone(new this.constructor()); + }, + + _clone: function(copy) { + copy.setStyle(this._style); + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) + copy.addChild(this._children[i].clone()); + } + var keys = ['_locked', '_visible', '_blendMode', '_opacity', + '_clipMask', '_guide']; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (this.hasOwnProperty(key)) + copy[key] = this[key]; + } + copy._matrix.initialize(this._matrix); + copy.setSelected(this._selected); + if (this._name) + copy.setName(this._name); + return copy; + }, + + copyTo: function(itemOrProject) { + var copy = this.clone(); + if (itemOrProject.layers) { + itemOrProject.activeLayer.addChild(copy); + } else { + itemOrProject.addChild(copy); + } + return copy; + }, + + rasterize: function(resolution) { + var bounds = this.getStrokeBounds(), + scale = (resolution || 72) / 72, + canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), + ctx = canvas.getContext('2d'), + matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); + matrix.applyToContext(ctx); + this.draw(ctx, {}); + var raster = new Raster(canvas); + raster.setBounds(bounds); + return raster; + }, + + hitTest: function(point, options) { + options = HitResult.getOptions(point, options); + point = options.point = this._matrix._inverseTransform(options.point); + if (!this._children && !this.getRoughBounds() + .expand(options.tolerance)._containsPoint(point)) + return null; + if ((options.center || options.bounds) && + !(this instanceof Layer && !this._parent)) { + var bounds = this.getBounds(), + that = this, + points = ['TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', + 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], + res; + function checkBounds(type, part) { + var pt = bounds['get' + part](); + if (point.getDistance(pt) < options.tolerance) + return new HitResult(type, that, + { name: Base.hyphenate(part), point: pt }); + } + if (options.center && (res = checkBounds('center', 'Center'))) + return res; + if (options.bounds) { + for (var i = 0; i < 8; i++) + if (res = checkBounds('bounds', points[i])) + return res; + } + } + + return this._children || !(options.guides && !this._guide + || options.selected && !this._selected) + ? this._hitTest(point, options) : null; + }, + + _hitTest: function(point, options) { + if (this._children) { + for (var i = this._children.length - 1; i >= 0; i--) { + var res = this._children[i].hitTest(point, options); + if (res) return res; + } + } + }, + + addChild: function(item) { + return this.insertChild(undefined, item); + }, + + insertChild: function(index, item) { + if (this._children) { + item._remove(false, true); + Base.splice(this._children, [item], index, 0); + item._parent = this; + item._setProject(this._project); + if (item._name) + item.setName(item._name); + this._changed(Change.HIERARCHY); + return true; + } + return false; + }, + + addChildren: function(items) { + for (var i = 0, l = items && items.length; i < l; i++) + this.insertChild(undefined, items[i]); + }, + + insertChildren: function(index, items) { + for (var i = 0, l = items && items.length; i < l; i++) { + if (this.insertChild(index, items[i])) + index++; + } + }, + + insertAbove: function(item) { + var index = item._index; + if (item._parent == this._parent && index < this._index) + index++; + return item._parent.insertChild(index, this); + }, + + insertBelow: function(item) { + var index = item._index; + if (item._parent == this._parent && index > this._index) + index--; + return item._parent.insertChild(index, this); + }, + + appendTop: function(item) { + return this.addChild(item); + }, + + appendBottom: function(item) { + return this.insertChild(0, item); + }, + + moveAbove: function(item) { + return this.insertAbove(item); + }, + + moveBelow: function(item) { + return this.insertBelow(item); + }, + + _removeFromNamed: function() { + var children = this._parent._children, + namedChildren = this._parent._namedChildren, + name = this._name, + namedArray = namedChildren[name], + index = namedArray ? namedArray.indexOf(this) : -1; + if (index == -1) + return; + if (children[name] == this) + delete children[name]; + namedArray.splice(index, 1); + if (namedArray.length) { + children[name] = namedArray[namedArray.length - 1]; + } else { + delete namedChildren[name]; + } + }, + + _remove: function(deselect, notify) { + if (this._parent) { + if (deselect) + this.setSelected(false); + if (this._name) + this._removeFromNamed(); + if (this._index != null) + Base.splice(this._parent._children, null, this._index, 1); + if (notify) + this._parent._changed(Change.HIERARCHY); + this._parent = null; + return true; + } + return false; + }, + + remove: function() { + return this._remove(true, true); + }, + + removeChildren: function(from, to) { + if (!this._children) + return null; + from = from || 0; + to = Base.pick(to, this._children.length); + var removed = Base.splice(this._children, null, from, to - from); + for (var i = removed.length - 1; i >= 0; i--) + removed[i]._remove(true, false); + if (removed.length > 0) + this._changed(Change.HIERARCHY); + return removed; + }, + + reverseChildren: function() { + if (this._children) { + this._children.reverse(); + for (var i = 0, l = this._children.length; i < l; i++) + this._children[i]._index = i; + this._changed(Change.HIERARCHY); + } + }, + + isEditable: function() { + var item = this; + while (item) { + if (!item._visible || item._locked) + return false; + item = item._parent; + } + return true; + }, + + _getOrder: function(item) { + function getList(item) { + var list = []; + do { + list.unshift(item); + } while (item = item._parent) + return list; + } + var list1 = getList(this), + list2 = getList(item); + for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { + if (list1[i] != list2[i]) { + return list1[i]._index < list2[i]._index ? 1 : -1; + } + } + return 0; + }, + + hasChildren: function() { + return this._children && this._children.length > 0; + }, + + isAbove: function(item) { + return this._getOrder(item) == -1; + }, + + isBelow: function(item) { + return this._getOrder(item) == 1; + }, + + isParent: function(item) { + return this._parent == item; + }, + + isChild: function(item) { + return item && item._parent == this; + }, + + isDescendant: function(item) { + var parent = this; + while (parent = parent._parent) { + if (parent == item) + return true; + } + return false; + }, + + isAncestor: function(item) { + return item ? item.isDescendant(this) : false; + }, + + isGroupedWith: function(item) { + var parent = this._parent; + while (parent) { + if (parent._parent + && (parent instanceof Group || parent instanceof CompoundPath) + && item.isDescendant(parent)) + return true; + parent = parent._parent; + } + return false; + }, + + scale: function(hor, ver , center, apply) { + if (arguments.length < 2 || typeof ver === 'object') { + apply = center; + center = ver; + ver = hor; + } + return this.transform(new Matrix().scale(hor, ver, + center || this.getPosition(true)), apply); + }, + + translate: function(delta, apply) { + var mx = new Matrix(); + return this.transform(mx.translate.apply(mx, arguments), apply); + }, + + rotate: function(angle, center, apply) { + return this.transform(new Matrix().rotate(angle, + center || this.getPosition(true)), apply); + }, + + shear: function(hor, ver, center, apply) { + if (arguments.length < 2 || typeof ver === 'object') { + apply = center; + center = ver; + ver = hor; + } + return this.transform(new Matrix().shear(hor, ver, + center || this.getPosition(true)), apply); + }, + + transform: function(matrix, apply) { + var bounds = this._bounds, + position = this._position; + this._matrix.preConcatenate(matrix); + if (this._transform) + this._transform(matrix); + if (apply) + this.apply(); + this._changed(Change.GEOMETRY); + if (bounds && matrix.getRotation() % 90 === 0) { + for (var key in bounds) { + var rect = bounds[key]; + matrix._transformBounds(rect, rect); + } + var type = this._boundsType, + rect = bounds[type && type.bounds || 'bounds']; + if (rect) + this._position = rect.getCenter(true); + this._bounds = bounds; + } else if (position) { + this._position = matrix._transformPoint(position, position); + } + return this; + }, + + apply: function() { + if (this._apply(this._matrix)) { + this._matrix.setIdentity(); + } + }, + + _apply: function(matrix) { + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) { + var child = this._children[i]; + child.transform(matrix); + child.apply(); + } + return true; + } + }, + + fitBounds: function(rectangle, fill) { + rectangle = Rectangle.read(arguments); + var bounds = this.getBounds(), + itemRatio = bounds.height / bounds.width, + rectRatio = rectangle.height / rectangle.width, + scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) + ? rectangle.width / bounds.width + : rectangle.height / bounds.height, + newBounds = new Rectangle(new Point(), + Size.create(bounds.width * scale, bounds.height * scale)); + newBounds.setCenter(rectangle.getCenter()); + this.setBounds(newBounds); + }, + + toString: function() { + return (this.constructor._name || 'Item') + (this._name + ? " '" + this._name + "'" + : ' @' + this._id); + }, + + _setStyles: function(ctx) { + var style = this._style, + width = style._strokeWidth, + join = style._strokeJoin, + cap = style._strokeCap, + limit = style._miterLimit, + fillColor = style._fillColor, + strokeColor = style._strokeColor; + if (width != null) ctx.lineWidth = width; + if (join) ctx.lineJoin = join; + if (cap) ctx.lineCap = cap; + if (limit) ctx.miterLimit = limit; + if (fillColor) ctx.fillStyle = fillColor.getCanvasStyle(ctx); + if (strokeColor) ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); + if (!fillColor || !strokeColor) + ctx.globalAlpha = this._opacity; + }, + + statics: { + drawSelectedBounds: function(bounds, ctx, matrix) { + var coords = matrix._transformCorners(bounds); + ctx.beginPath(); + for (var i = 0; i < 8; i++) + ctx[i == 0 ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); + ctx.closePath(); + ctx.stroke(); + for (var i = 0; i < 8; i++) { + ctx.beginPath(); + ctx.rect(coords[i] - 2, coords[++i] - 2, 4, 4); + ctx.fill(); + } + }, + + draw: function(item, ctx, param) { + if (!item._visible || item._opacity == 0) + return; + var tempCanvas, parentCtx, + itemOffset, prevOffset; + if (item._blendMode !== 'normal' || item._opacity < 1 + && !(item._segments + && (!item.getFillColor() || !item.getStrokeColor()))) { + var bounds = item.getStrokeBounds(); + if (!bounds.width || !bounds.height) + return; + prevOffset = param.offset; + parentCtx = ctx; + itemOffset = param.offset = bounds.getTopLeft().floor(); + tempCanvas = CanvasProvider.getCanvas( + bounds.getSize().ceil().add(Size.create(1, 1))); + ctx = tempCanvas.getContext('2d'); + } + if (!param.clipping) + ctx.save(); + if (tempCanvas) + ctx.translate(-itemOffset.x, -itemOffset.y); + item._matrix.applyToContext(ctx); + item.draw(ctx, param); + if (!param.clipping) + ctx.restore(); + if (tempCanvas) { + param.offset = prevOffset; + if (item._blendMode !== 'normal') { + BlendMode.process(item._blendMode, ctx, parentCtx, + item._opacity, itemOffset.subtract(prevOffset)); + } else { + parentCtx.save(); + parentCtx.globalAlpha = item._opacity; + parentCtx.drawImage(tempCanvas, itemOffset.x, itemOffset.y); + parentCtx.restore(); + } + CanvasProvider.returnCanvas(tempCanvas); + } + } + } +}, Base.each(['down', 'drag', 'up', 'move'], function(name) { + this['removeOn' + Base.capitalize(name)] = function() { + var hash = {}; + hash[name] = true; + return this.removeOn(hash); + }; +}, { + + removeOn: function(obj) { + for (var name in obj) { + if (obj[name]) { + var key = 'mouse' + name, + sets = Tool._removeSets = Tool._removeSets || {}; + sets[key] = sets[key] || {}; + sets[key][this._id] = this; + } + } + return this; + } +})); + +var Group = this.Group = Item.extend({ + initialize: function(items) { + this.base(); + this._children = []; + this._namedChildren = {}; + this.addChildren(!items || !Array.isArray(items) + || typeof items[0] !== 'object' ? arguments : items); + }, + + _changed: function(flags) { + Item.prototype._changed.call(this, flags); + if (flags & (ChangeFlag.HIERARCHY | ChangeFlag.CLIPPING)) { + delete this._clipItem; + } + }, + + _getClipItem: function() { + if (this._clipItem !== undefined) + return this._clipItem; + for (var i = 0, l = this._children.length; i < l; i++) { + var child = this._children[i]; + if (child._clipMask) + return this._clipItem = child; + } + return this._clipItem = null; + }, + + isClipped: function() { + return !!this._getClipItem(); + }, + + setClipped: function(clipped) { + var child = this.getFirstChild(); + if (child) + child.setClipMask(clipped); + return this; + }, + + draw: function(ctx, param) { + var clipItem = this._getClipItem(); + if (clipItem) { + param.clipping = true; + Item.draw(clipItem, ctx, param); + delete param.clipping; + } + for (var i = 0, l = this._children.length; i < l; i++) { + var item = this._children[i]; + if (item != clipItem) + Item.draw(item, ctx, param); + } + } +}); + +var Layer = this.Layer = Group.extend({ + initialize: function(items) { + this._project = paper.project; + this._index = this._project.layers.push(this) - 1; + this.base.apply(this, arguments); + this.activate(); + }, + + _remove: function(deselect, notify) { + if (this._parent) + return this.base(deselect, notify); + if (this._index != null) { + if (deselect) + this.setSelected(false); + Base.splice(this._project.layers, null, this._index, 1); + this._project._needsRedraw(); + return true; + } + return false; + }, + + getNextSibling: function() { + return this._parent ? this.base() + : this._project.layers[this._index + 1] || null; + }, + + getPreviousSibling: function() { + return this._parent ? this.base() + : this._project.layers[this._index - 1] || null; + }, + + activate: function() { + this._project.activeLayer = this; + } +}, new function () { + function insert(above) { + return function(item) { + if (item instanceof Layer && !item._parent + && this._remove(false, true)) { + Base.splice(item._project.layers, [this], + item._index + (above ? 1 : -1), 0); + this._setProject(item._project); + return true; + } + return this.base(item); + }; + } + + return { + insertAbove: insert(true), + + insertBelow: insert(false) + }; +}); + +var PlacedItem = this.PlacedItem = Item.extend({ + _boundsType: { bounds: 'strokeBounds' } +}); + +var Raster = this.Raster = PlacedItem.extend({ + _boundsType: 'bounds', + + initialize: function(object, pointOrMatrix) { + this.base(pointOrMatrix); + if (object.getContext) { + this.setCanvas(object); + } else { + if (typeof object === 'string') + object = document.getElementById(object); + this.setImage(object); + } + }, + + clone: function() { + var image = this._image; + if (!image) { + image = CanvasProvider.getCanvas(this._size); + image.getContext('2d').drawImage(this._canvas, 0, 0); + } + var copy = new Raster(image); + return this._clone(copy); + }, + + getSize: function() { + return this._size; + }, + + setSize: function() { + var size = Size.read(arguments), + image = this.getImage(); + this.setCanvas(CanvasProvider.getCanvas(size)); + this.getContext(true).drawImage(image, 0, 0, size.width, size.height); + }, + + getWidth: function() { + return this._size.width; + }, + + getHeight: function() { + return this._size.height; + }, + + getPpi: function() { + var matrix = this._matrix, + orig = new Point(0, 0).transform(matrix), + u = new Point(1, 0).transform(matrix).subtract(orig), + v = new Point(0, 1).transform(matrix).subtract(orig); + return Size.create( + 72 / u.getLength(), + 72 / v.getLength() + ); + }, + + getContext: function() { + if (!this._context) + this._context = this.getCanvas().getContext('2d'); + if (arguments[0]) + this._changed(Change.PIXELS); + return this._context; + }, + + setContext: function(context) { + this._context = context; + }, + + getCanvas: function() { + if (!this._canvas) { + this._canvas = CanvasProvider.getCanvas(this._size); + if (this._image) + this.getContext(true).drawImage(this._image, 0, 0); + } + return this._canvas; + }, + + setCanvas: function(canvas) { + if (this._canvas) + CanvasProvider.returnCanvas(this._canvas); + this._canvas = canvas; + this._size = Size.create(canvas.width, canvas.height); + this._image = null; + this._context = null; + this._changed(Change.GEOMETRY | Change.PIXELS); + }, + + getImage: function() { + return this._image || this.getCanvas(); + }, + + setImage: function(image) { + if (this._canvas) + CanvasProvider.returnCanvas(this._canvas); + this._image = image; + this._size = Size.create(image.naturalWidth, image.naturalHeight); + this._canvas = null; + this._context = null; + this._changed(Change.GEOMETRY); + }, + + getSubImage: function(rect) { + rect = Rectangle.read(arguments); + var canvas = CanvasProvider.getCanvas(rect.getSize()); + canvas.getContext('2d').drawImage(this.getCanvas(), rect.x, rect.y, + canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); + return canvas; + }, + + drawImage: function(image, point) { + point = Point.read(arguments, 1); + this.getContext(true).drawImage(image, point.x, point.y); + }, + + getAverageColor: function(object) { + var bounds, path; + if (!object) { + bounds = this.getBounds(); + } else if (object instanceof PathItem) { + path = object; + bounds = object.getBounds(); + } else if (object.width) { + bounds = new Rectangle(object); + } else if (object.x) { + bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1); + } + var sampleSize = 32, + width = Math.min(bounds.width, sampleSize), + height = Math.min(bounds.height, sampleSize); + var ctx = Raster._sampleContext; + if (!ctx) { + ctx = Raster._sampleContext = CanvasProvider.getCanvas( + new Size(sampleSize)).getContext('2d'); + } else { + ctx.clearRect(0, 0, sampleSize, sampleSize); + } + ctx.save(); + ctx.scale(width / bounds.width, height / bounds.height); + ctx.translate(-bounds.x, -bounds.y); + if (path) + path.draw(ctx, { clip: true }); + this._matrix.applyToContext(ctx); + ctx.drawImage(this._canvas || this._image, + -this._size.width / 2, -this._size.height / 2); + ctx.restore(); + var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), + Math.ceil(height)).data, + channels = [0, 0, 0], + total = 0; + for (var i = 0, l = pixels.length; i < l; i += 4) { + var alpha = pixels[i + 3]; + total += alpha; + alpha /= 255; + channels[0] += pixels[i] * alpha; + channels[1] += pixels[i + 1] * alpha; + channels[2] += pixels[i + 2] * alpha; + } + for (var i = 0; i < 3; i++) + channels[i] /= total; + return total ? Color.read(channels) : null; + }, + + getPixel: function(point) { + point = Point.read(arguments); + var pixels = this.getContext().getImageData(point.x, point.y, 1, 1).data, + channels = new Array(4); + for (var i = 0; i < 4; i++) + channels[i] = pixels[i] / 255; + return RgbColor.read(channels); + }, + + setPixel: function(point, color) { + var hasPoint = arguments.length == 2; + point = Point.read(arguments, 0, hasPoint ? 1 : 2); + color = Color.read(arguments, hasPoint ? 1 : 2); + var ctx = this.getContext(true), + imageData = ctx.createImageData(1, 1), + alpha = color.getAlpha(); + imageData.data[0] = color.getRed() * 255; + imageData.data[1] = color.getGreen() * 255; + imageData.data[2] = color.getBlue() * 255; + imageData.data[3] = alpha != null ? alpha * 255 : 255; + ctx.putImageData(imageData, point.x, point.y); + }, + + createData: function(size) { + size = Size.read(arguments); + return this.getContext().createImageData(size.width, size.height); + }, + + getData: function(rect) { + rect = Rectangle.read(arguments); + if (rect.isEmpty()) + rect = new Rectangle(this.getSize()); + return this.getContext().getImageData(rect.x, rect.y, + rect.width, rect.height); + }, + + setData: function(data, point) { + point = Point.read(arguments, 1); + this.getContext(true).putImageData(data, point.x, point.y); + }, + + _getBounds: function(type, matrix) { + var rect = new Rectangle(this._size).setCenter(0, 0); + return matrix ? matrix._transformBounds(rect) : rect; + }, + + _hitTest: function(point, options) { + if (point.isInside(this._getBounds())) { + var that = this; + return new HitResult('pixel', that, { + offset: point.add(that._size.divide(2)).round(), + getColor: function() { + return that.getPixel(this.offset); + } + }); + } + }, + + draw: function(ctx, param) { + ctx.drawImage(this._canvas || this._image, + -this._size.width / 2, -this._size.height / 2); + }, + + drawSelected: function(ctx, matrix) { + Item.drawSelectedBounds(new Rectangle(this._size).setCenter(0, 0), ctx, + matrix); + } +}); + +var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend({ + initialize: function(symbol, pointOrMatrix) { + this.base(pointOrMatrix); + this.setSymbol(symbol instanceof Symbol ? symbol : new Symbol(symbol)); + }, + + getSymbol: function() { + return this._symbol; + }, + + setSymbol: function(symbol) { + if (this._symbol) + delete this._symbol._instances[this._id]; + this._symbol = symbol; + symbol._instances[this._id] = this; + }, + + clone: function() { + return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone())); + }, + + _getBounds: function(type, matrix) { + return this.symbol._definition._getCachedBounds(type, matrix); + }, + + draw: function(ctx, param) { + Item.draw(this.symbol._definition, ctx, param); + }, + + drawSelected: function(ctx, matrix) { + Item.drawSelectedBounds(this.symbol._definition.getBounds(), ctx, + matrix); + } + +}); + +HitResult = Base.extend({ + initialize: function(type, item, values) { + this.type = type; + this.item = item; + if (values) + this.inject(values); + }, + + statics: { + getOptions: function(point, options) { + return options && options._merged ? options : Base.merge({ + point: Point.read(arguments, 0, 1), + type: null, + tolerance: 2, + fill: !options, + stroke: !options, + segments: !options, + handles: false, + ends: false, + center: false, + bounds: false, + guides: false, + selected: false, + _merged: true + }, options); + } + } +}); + +var Segment = this.Segment = Base.extend({ + initialize: function(arg0, arg1, arg2, arg3, arg4, arg5) { + var count = arguments.length, + createPoint = SegmentPoint.create, + point, handleIn, handleOut; + if (count == 0) { + } else if (count == 1) { + if (arg0.point) { + point = arg0.point; + handleIn = arg0.handleIn; + handleOut = arg0.handleOut; + } else { + point = arg0; + } + } else if (count < 6) { + if (count == 2 && arg1.x === undefined) { + point = [ arg0, arg1 ]; + } else { + point = arg0; + handleIn = arg1; + handleOut = arg2; + } + } else if (count == 6) { + point = [ arg0, arg1 ]; + handleIn = [ arg2, arg3 ]; + handleOut = [ arg4, arg5 ]; + } + createPoint(this, '_point', point); + createPoint(this, '_handleIn', handleIn); + createPoint(this, '_handleOut', handleOut); + }, + + _changed: function(point) { + if (!this._path) + return; + var curve = this._path._curves && this.getCurve(), other; + if (curve) { + curve._changed(); + if (other = (curve[point == this._point + || point == this._handleIn && curve._segment1 == this + ? 'getPrevious' : 'getNext']())) { + other._changed(); + } + } + this._path._changed(Change.GEOMETRY); + }, + + getPoint: function() { + return this._point; + }, + + setPoint: function(point) { + point = Point.read(arguments); + this._point.set(point.x, point.y); + }, + + getHandleIn: function() { + return this._handleIn; + }, + + setHandleIn: function(point) { + point = Point.read(arguments); + this._handleIn.set(point.x, point.y); + }, + + getHandleOut: function() { + return this._handleOut; + }, + + setHandleOut: function(point) { + point = Point.read(arguments); + this._handleOut.set(point.x, point.y); + }, + + _isSelected: function(point) { + var state = this._selectionState; + return point == this._point ? !!(state & SelectionState.POINT) + : point == this._handleIn ? !!(state & SelectionState.HANDLE_IN) + : point == this._handleOut ? !!(state & SelectionState.HANDLE_OUT) + : false; + }, + + _setSelected: function(point, selected) { + var path = this._path, + selected = !!selected, + state = this._selectionState || 0, + selection = [ + !!(state & SelectionState.POINT), + !!(state & SelectionState.HANDLE_IN), + !!(state & SelectionState.HANDLE_OUT) + ]; + if (point == this._point) { + if (selected) { + selection[1] = selection[2] = false; + } else { + var previous = this.getPrevious(), + next = this.getNext(); + selection[1] = previous && (previous._point.isSelected() + || previous._handleOut.isSelected()); + selection[2] = next && (next._point.isSelected() + || next._handleIn.isSelected()); + } + selection[0] = selected; + } else { + var index = point == this._handleIn ? 1 : 2; + if (selection[index] != selected) { + if (selected) + selection[0] = false; + selection[index] = selected; + path._changed(Change.ATTRIBUTE); + } + } + this._selectionState = (selection[0] ? SelectionState.POINT : 0) + | (selection[1] ? SelectionState.HANDLE_IN : 0) + | (selection[2] ? SelectionState.HANDLE_OUT : 0); + if (path && state != this._selectionState) + path._updateSelection(this, state, this._selectionState); + }, + + isSelected: function() { + return this._isSelected(this._point); + }, + + setSelected: function(selected) { + this._setSelected(this._point, selected); + }, + + getIndex: function() { + return this._index !== undefined ? this._index : null; + }, + + getPath: function() { + return this._path || null; + }, + + getCurve: function() { + if (this._path) { + var index = this._index; + if (!this._path._closed && index == this._path._segments.length - 1) + index--; + return this._path.getCurves()[index] || null; + } + return null; + }, + + getNext: function() { + var segments = this._path && this._path._segments; + return segments && (segments[this._index + 1] + || this._path._closed && segments[0]) || null; + }, + + getPrevious: function() { + var segments = this._path && this._path._segments; + return segments && (segments[this._index - 1] + || this._path._closed && segments[segments.length - 1]) || null; + }, + + reverse: function() { + return new Segment(this._point, this._handleOut, this._handleIn); + }, + + remove: function() { + return this._path ? !!this._path.removeSegment(this._index) : false; + }, + + clone: function() { + return new Segment(this._point, this._handleIn, this._handleOut); + }, + + equals: function(segment) { + return segment == this || segment + && this._point.equals(segment._point) + && this._handleIn.equals(segment._handleIn) + && this._handleOut.equals(segment._handleOut); + }, + + toString: function() { + var parts = [ 'point: ' + this._point ]; + if (!this._handleIn.isZero()) + parts.push('handleIn: ' + this._handleIn); + if (!this._handleOut.isZero()) + parts.push('handleOut: ' + this._handleOut); + return '{ ' + parts.join(', ') + ' }'; + }, + + _transformCoordinates: function(matrix, coords, change) { + var point = this._point, + handleIn = !change || !this._handleIn.isZero() + ? this._handleIn : null, + handleOut = !change || !this._handleOut.isZero() + ? this._handleOut : null, + x = point._x, + y = point._y, + i = 2; + coords[0] = x; + coords[1] = y; + if (handleIn) { + coords[i++] = handleIn._x + x; + coords[i++] = handleIn._y + y; + } + if (handleOut) { + coords[i++] = handleOut._x + x; + coords[i++] = handleOut._y + y; + } + if (!matrix) + return; + matrix._transformCoordinates(coords, 0, coords, 0, i / 2); + x = coords[0]; + y = coords[1]; + if (change) { + point._x = x; + point._y = y; + i = 2; + if (handleIn) { + handleIn._x = coords[i++] - x; + handleIn._y = coords[i++] - y; + } + if (handleOut) { + handleOut._x = coords[i++] - x; + handleOut._y = coords[i++] - y; + } + } else { + if (!handleIn) { + coords[i++] = x; + coords[i++] = y; + } + if (!handleOut) { + coords[i++] = x; + coords[i++] = y; + } + } + } +}); + +var SegmentPoint = Point.extend({ + set: function(x, y) { + this._x = x; + this._y = y; + this._owner._changed(this); + return this; + }, + + getX: function() { + return this._x; + }, + + setX: function(x) { + this._x = x; + this._owner._changed(this); + }, + + getY: function() { + return this._y; + }, + + setY: function(y) { + this._y = y; + this._owner._changed(this); + }, + + isZero: function() { + return this._x == 0 && this._y == 0; + }, + + setSelected: function(selected) { + this._owner._setSelected(this, selected); + }, + + isSelected: function() { + return this._owner._isSelected(this); + }, + + statics: { + create: function(segment, key, pt) { + var point = new SegmentPoint(SegmentPoint.dont), + x, y, selected; + if (!pt) { + x = y = 0; + } else if ((x = pt[0]) !== undefined) { + y = pt[1]; + } else { + if ((x = pt.x) === undefined) { + pt = Point.read(arguments, 2, 1); + x = pt.x; + } + y = pt.y; + selected = pt.selected; + } + point._x = x; + point._y = y; + point._owner = segment; + segment[key] = point; + if (selected) + point.setSelected(true); + return point; + } + } +}); + +var SelectionState = { + HANDLE_IN: 1, + HANDLE_OUT: 2, + POINT: 4 +}; + +var Curve = this.Curve = Base.extend({ + initialize: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { + var count = arguments.length; + if (count == 0) { + this._segment1 = new Segment(); + this._segment2 = new Segment(); + } else if (count == 1) { + this._segment1 = new Segment(arg0.segment1); + this._segment2 = new Segment(arg0.segment2); + } else if (count == 2) { + this._segment1 = new Segment(arg0); + this._segment2 = new Segment(arg1); + } else if (count == 4) { + this._segment1 = new Segment(arg0, null, arg1); + this._segment2 = new Segment(arg3, arg2, null); + } else if (count == 8) { + var p1 = Point.create(arg0, arg1), + p2 = Point.create(arg6, arg7); + this._segment1 = new Segment(p1, null, + Point.create(arg2, arg3).subtract(p1)); + this._segment2 = new Segment(p2, + Point.create(arg4, arg5).subtract(p2), null); + } + }, + + _changed: function() { + delete this._length; + }, + + getPoint1: function() { + return this._segment1._point; + }, + + setPoint1: function(point) { + point = Point.read(arguments); + this._segment1._point.set(point.x, point.y); + }, + + getPoint2: function() { + return this._segment2._point; + }, + + setPoint2: function(point) { + point = Point.read(arguments); + this._segment2._point.set(point.x, point.y); + }, + + getHandle1: function() { + return this._segment1._handleOut; + }, + + setHandle1: function(point) { + point = Point.read(arguments); + this._segment1._handleOut.set(point.x, point.y); + }, + + getHandle2: function() { + return this._segment2._handleIn; + }, + + setHandle2: function(point) { + point = Point.read(arguments); + this._segment2._handleIn.set(point.x, point.y); + }, + + getSegment1: function() { + return this._segment1; + }, + + getSegment2: function() { + return this._segment2; + }, + + getPath: function() { + return this._path; + }, + + getIndex: function() { + return this._segment1._index; + }, + + getNext: function() { + var curves = this._path && this._path._curves; + return curves && (curves[this._segment1._index + 1] + || this._path._closed && curves[0]) || null; + }, + + getPrevious: function() { + var curves = this._path && this._path._curves; + return curves && (curves[this._segment1._index - 1] + || this._path._closed && curves[curves.length - 1]) || null; + }, + + isSelected: function() { + return this.getHandle1().isSelected() && this.getHandle2().isSelected(); + }, + + setSelected: function(selected) { + this.getHandle1().setSelected(selected); + this.getHandle2().setSelected(selected); + }, + + getValues: function() { + return Curve.getValues(this._segment1, this._segment2); + }, + + getPoints: function() { + var coords = this.getValues(), + points = []; + for (var i = 0; i < 8; i += 2) + points.push(Point.create(coords[i], coords[i + 1])); + return points; + }, + + getLength: function() { + var from = arguments[0], + to = arguments[1]; + fullLength = arguments.length == 0 || from == 0 && to == 1; + if (fullLength && this._length != null) + return this._length; + var length = Curve.getLength(this.getValues(), from, to); + if (fullLength) + this._length = length; + return length; + }, + + getPart: function(from, to) { + return new Curve(Curve.getPart(this.getValues(), from, to)); + }, + + isLinear: function() { + return this._segment1._handleOut.isZero() + && this._segment2._handleIn.isZero(); + }, + + getParameterAt: function(offset, start) { + return Curve.getParameterAt(this.getValues(), offset, + start !== undefined ? start : offset < 0 ? 1 : 0); + }, + + getPoint: function(parameter) { + return Curve.evaluate(this.getValues(), parameter, 0); + }, + + getTangent: function(parameter) { + return Curve.evaluate(this.getValues(), parameter, 1); + }, + + getNormal: function(parameter) { + return Curve.evaluate(this.getValues(), parameter, 2); + }, + + getParameter: function(point) { + point = Point.read(point); + return Curve.getParameter(this.getValues(), point.x, point.y); + }, + + getCrossings: function(point, roots) { + var vals = this.getValues(), + num = Curve.solveCubic(vals, 1, point.y, roots), + crossings = 0; + for (var i = 0; i < num; i++) { + var t = roots[i]; + if (t >= 0 && t < 1 && Curve.evaluate(vals, t, 0).x > point.x) { + if (t < Numerical.TOLERANCE && Curve.evaluate( + this.getPrevious().getValues(), 1, 1).y + * Curve.evaluate(vals, t, 1).y >= 0) + continue; + crossings++; + } + } + return crossings; + }, + + reverse: function() { + return new Curve(this._segment2.reverse(), this._segment1.reverse()); + }, + + clone: function() { + return new Curve(this._segment1, this._segment2); + }, + + toString: function() { + var parts = [ 'point1: ' + this._segment1._point ]; + if (!this._segment1._handleOut.isZero()) + parts.push('handle1: ' + this._segment1._handleOut); + if (!this._segment2._handleIn.isZero()) + parts.push('handle2: ' + this._segment2._handleIn); + parts.push('point2: ' + this._segment2._point); + return '{ ' + parts.join(', ') + ' }'; + }, + + statics: { + create: function(path, segment1, segment2) { + var curve = new Curve(Curve.dont); + curve._path = path; + curve._segment1 = segment1; + curve._segment2 = segment2; + return curve; + }, + + getValues: function(segment1, segment2) { + var p1 = segment1._point, + h1 = segment1._handleOut, + h2 = segment2._handleIn, + p2 = segment2._point; + return [ + p1._x, p1._y, + p1._x + h1._x, p1._y + h1._y, + p2._x + h2._x, p2._y + h2._y, + p2._x, p2._y + ]; + }, + + evaluate: function(v, t, type) { + var p1x = v[0], p1y = v[1], + c1x = v[2], c1y = v[3], + c2x = v[4], c2y = v[5], + p2x = v[6], p2y = v[7], + x, y; + + if (type == 0 && (t == 0 || t == 1)) { + x = t == 0 ? p1x : p2x; + y = t == 0 ? p1y : p2y; + } else { + var tMin = Numerical.TOLERANCE; + if (t < tMin && c1x == p1x && c1y == p1y) + t = tMin; + else if (t > 1 - tMin && c2x == p2x && c2y == p2y) + t = 1 - tMin; + var cx = 3 * (c1x - p1x), + bx = 3 * (c2x - c1x) - cx, + ax = p2x - p1x - cx - bx, + + cy = 3 * (c1y - p1y), + by = 3 * (c2y - c1y) - cy, + ay = p2y - p1y - cy - by; + + switch (type) { + case 0: + x = ((ax * t + bx) * t + cx) * t + p1x; + y = ((ay * t + by) * t + cy) * t + p1y; + break; + case 1: + case 2: + x = (3 * ax * t + 2 * bx) * t + cx; + y = (3 * ay * t + 2 * by) * t + cy; + break; + } + } + return type == 2 ? new Point(y, -x) : new Point(x, y); + }, + + subdivide: function(v, t) { + var p1x = v[0], p1y = v[1], + c1x = v[2], c1y = v[3], + c2x = v[4], c2y = v[5], + p2x = v[6], p2y = v[7]; + if (t === undefined) + t = 0.5; + var u = 1 - t, + p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y, + p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y, + p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y, + p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y, + p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y, + p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y; + return [ + [p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], + [p8x, p8y, p7x, p7y, p5x, p5y, p2x, p2y] + ]; + }, + + solveCubic: function (v, coord, val, roots) { + var p1 = v[coord], + c1 = v[coord + 2], + c2 = v[coord + 4], + p2 = v[coord + 6], + c = 3 * (c1 - p1), + b = 3 * (c2 - c1) - c, + a = p2 - p1 - c - b; + return Numerical.solveCubic(a, b, c, p1 - val, roots, + Numerical.TOLERANCE); + }, + + getParameter: function(v, x, y) { + var txs = [], + tys = [], + sx = Curve.solveCubic(v, 0, x, txs), + sy = Curve.solveCubic(v, 1, y, tys), + tx, ty; + for (var cx = 0; sx == -1 || cx < sx;) { + if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) { + for (var cy = 0; sy == -1 || cy < sy;) { + if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) { + if (sx == -1) tx = ty; + else if (sy == -1) ty = tx; + if (Math.abs(tx - ty) < Numerical.TOLERANCE) + return (tx + ty) * 0.5; + } + } + if (sx == -1) + break; + } + } + return null; + }, + + getPart: function(v, from, to) { + if (from > 0) + v = Curve.subdivide(v, from)[1]; + if (to < 1) + v = Curve.subdivide(v, (to - from) / (1 - from))[0]; + return v; + }, + + isFlatEnough: function(v) { + var p1x = v[0], p1y = v[1], + c1x = v[2], c1y = v[3], + c2x = v[4], c2y = v[5], + p2x = v[6], p2y = v[7], + ux = 3 * c1x - 2 * p1x - p2x, + uy = 3 * c1y - 2 * p1y - p2y, + vx = 3 * c2x - 2 * p2x - p1x, + vy = 3 * c2y - 2 * p2y - p1y; + return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy) < 1; + } + } +}, new function() { + + function getLengthIntegrand(v) { + var p1x = v[0], p1y = v[1], + c1x = v[2], c1y = v[3], + c2x = v[4], c2y = v[5], + p2x = v[6], p2y = v[7], + + ax = 9 * (c1x - c2x) + 3 * (p2x - p1x), + bx = 6 * (p1x + c2x) - 12 * c1x, + cx = 3 * (c1x - p1x), + + ay = 9 * (c1y - c2y) + 3 * (p2y - p1y), + by = 6 * (p1y + c2y) - 12 * c1y, + cy = 3 * (c1y - p1y); + + return function(t) { + var dx = (ax * t + bx) * t + cx, + dy = (ay * t + by) * t + cy; + return Math.sqrt(dx * dx + dy * dy); + }; + } + + function getIterations(a, b) { + return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); + } + + return { + statics: true, + + getLength: function(v, a, b) { + if (a === undefined) + a = 0; + if (b === undefined) + b = 1; + if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) { + var dx = v[6] - v[0], + dy = v[7] - v[1]; + return (b - a) * Math.sqrt(dx * dx + dy * dy); + } + var ds = getLengthIntegrand(v); + return Numerical.integrate(ds, a, b, getIterations(a, b)); + }, + + getParameterAt: function(v, offset, start) { + if (offset == 0) + return start; + var forward = offset > 0, + a = forward ? start : 0, + b = forward ? 1 : start, + offset = Math.abs(offset), + ds = getLengthIntegrand(v), + rangeLength = Numerical.integrate(ds, a, b, + getIterations(a, b)); + if (offset >= rangeLength) + return forward ? b : a; + var guess = offset / rangeLength, + length = 0; + function f(t) { + var count = getIterations(start, t); + length += start < t + ? Numerical.integrate(ds, start, t, count) + : -Numerical.integrate(ds, t, start, count); + start = t; + return length - offset; + } + return Numerical.findRoot(f, ds, + forward ? a + guess : b - guess, + a, b, 16, Numerical.TOLERANCE); + } + }; +}, new function() { + + var maxDepth = 32, + epsilon = Math.pow(2, -maxDepth - 1); + + var zCubic = [ + [1.0, 0.6, 0.3, 0.1], + [0.4, 0.6, 0.6, 0.4], + [0.1, 0.3, 0.6, 1.0] + ]; + + var xAxis = new Line(new Point(0, 0), new Point(1, 0)); + + function toBezierForm(v, point) { + var n = 3, + degree = 5, + c = [], + d = [], + cd = [], + w = []; + for(var i = 0; i <= n; i++) { + c[i] = v[i].subtract(point); + if (i < n) + d[i] = v[i + 1].subtract(v[i]).multiply(n); + } + + for (var row = 0; row < n; row++) { + cd[row] = []; + for (var column = 0; column <= n; column++) + cd[row][column] = d[row].dot(c[column]); + } + + for (var i = 0; i <= degree; i++) + w[i] = new Point(i / degree, 0); + + for (k = 0; k <= degree; k++) { + var lb = Math.max(0, k - n + 1), + ub = Math.min(k, n); + for (var i = lb; i <= ub; i++) { + var j = k - i; + w[k].y += cd[j][i] * zCubic[j][i]; + } + } + + return w; + } + + function findRoots(w, depth) { + switch (countCrossings(w)) { + case 0: + return []; + case 1: + if (depth >= maxDepth) + return [0.5 * (w[0].x + w[5].x)]; + if (isFlatEnough(w)) { + var line = new Line(w[0], w[5], true); + return [ line.vector.getLength(true) <= Numerical.EPSILON + ? line.point.x + : xAxis.intersect(line).x ]; + } + } + + var p = [[]], + left = [], + right = []; + for (var j = 0; j <= 5; j++) + p[0][j] = new Point(w[j]); + + for (var i = 1; i <= 5; i++) { + p[i] = []; + for (var j = 0 ; j <= 5 - i; j++) + p[i][j] = p[i - 1][j].add(p[i - 1][j + 1]).multiply(0.5); + } + for (var j = 0; j <= 5; j++) { + left[j] = p[j][0]; + right[j] = p[5 - j][j]; + } + + return findRoots(left, depth + 1).concat(findRoots(right, depth + 1)); + } + + function countCrossings(v) { + var crossings = 0, + prevSign = null; + for (var i = 0, l = v.length; i < l; i++) { + var sign = v[i].y < 0 ? -1 : 1; + if (prevSign != null && sign != prevSign) + crossings++; + prevSign = sign; + } + return crossings; + } + + function isFlatEnough(v) { + + var n = v.length - 1, + a = v[0].y - v[n].y, + b = v[n].x - v[0].x, + c = v[0].x * v[n].y - v[n].x * v[0].y, + maxAbove = 0, + maxBelow = 0; + for (var i = 1; i < n; i++) { + var val = a * v[i].x + b * v[i].y + c, + dist = val * val; + if (val < 0 && dist > maxBelow) { + maxBelow = dist; + } else if (dist > maxAbove) { + maxAbove = dist; + } + } + return Math.abs((maxAbove + maxBelow) / (2 * a * (a * a + b * b))) + < epsilon; + } + + return { + getNearestLocation: function(point) { + var w = toBezierForm(this.getPoints(), point); + var roots = findRoots(w, 0).concat([0, 1]); + var minDist = Infinity, + minT, + minPoint; + for (var i = 0; i < roots.length; i++) { + var pt = this.getPoint(roots[i]), + dist = point.getDistance(pt, true); + if (dist < minDist) { + minDist = dist; + minT = roots[i]; + minPoint = pt; + } + } + return new CurveLocation(this, minT, minPoint, Math.sqrt(minDist)); + }, + + getNearestPoint: function(point) { + return this.getNearestLocation(point).getPoint(); + } + }; +}); + +CurveLocation = Base.extend({ + initialize: function(curve, parameter, point, distance) { + this._curve = curve; + this._parameter = parameter; + this._point = point; + this._distance = distance; + }, + + getSegment: function() { + if (!this._segment) { + var curve = this._curve, + parameter = this.getParameter(); + if (parameter == 0) { + this._segment = curve._segment1; + } else if (parameter == 1) { + this._segment = curve._segment2; + } else if (parameter == null) { + return null; + } else { + this._segment = curve.getLength(0, parameter) + < curve.getLength(parameter, 1) + ? curve._segment1 + : curve._segment2; + } + } + return this._segment; + }, + + getCurve: function() { + return this._curve; + }, + + getPath: function() { + return this._curve && this._curve._path; + }, + + getIndex: function() { + return this._curve && this._curve.getIndex(); + }, + + getOffset: function() { + var path = this._curve && this._curve._path; + return path && path._getOffset(this); + }, + + getCurveOffset: function() { + var parameter = this.getParameter(); + return parameter != null && this._curve + && this._curve.getLength(0, parameter); + }, + + getParameter: function() { + if (this._parameter == null && this._curve && this._point) + this._parameter = this._curve.getParameterAt(this._point); + return this._parameter; + }, + + getPoint: function() { + if (!this._point && this._curve && this._parameter != null) + this._point = this._curve.getPoint(this._parameter); + return this._point; + }, + + getTangent: function() { + var parameter = this.getParameter(); + return parameter != null && this._curve + && this._curve.getTangent(parameter); + }, + + getNormal: function() { + var parameter = this.getParameter(); + return parameter != null && this._curve + && this._curve.getNormal(parameter); + }, + + getDistance: function() { + return this._distance; + }, + + toString: function() { + var parts = [], + point = this.getPoint(); + if (point) + parts.push('point: ' + point); + var index = this.getIndex(); + if (index != null) + parts.push('index: ' + index); + var parameter = this.getParameter(); + if (parameter != null) + parts.push('parameter: ' + Base.formatNumber(parameter)); + if (this._distance != null) + parts.push('distance: ' + Base.formatNumber(this._distance)); + return '{ ' + parts.join(', ') + ' }'; + } +}); + +var PathItem = this.PathItem = Item.extend({ + +}); + +var Path = this.Path = PathItem.extend({ + initialize: function(segments) { + this.base(); + this._closed = false; + this._selectedSegmentState = 0; + this.setSegments(!segments || !Array.isArray(segments) + || typeof segments[0] !== 'object' ? arguments : segments); + }, + + clone: function() { + var copy = this._clone(new Path(this._segments)); + copy._closed = this._closed; + if (this._clockwise !== undefined) + copy._clockwise = this._clockwise; + return copy; + }, + + _changed: function(flags) { + Item.prototype._changed.call(this, flags); + if (flags & ChangeFlag.GEOMETRY) { + delete this._length; + delete this._clockwise; + if (this._curves != null) { + for (var i = 0, l = this._curves.length; i < l; i++) { + this._curves[i]._changed(Change.GEOMETRY); + } + } + } else if (flags & ChangeFlag.STROKE) { + delete this._bounds; + } + }, + + getSegments: function() { + return this._segments; + }, + + setSegments: function(segments) { + if (!this._segments) { + this._segments = []; + } else { + this._selectedSegmentState = 0; + this._segments.length = 0; + if (this._curves) + delete this._curves; + } + this._add(Segment.readAll(segments)); + }, + + getFirstSegment: function() { + return this._segments[0]; + }, + + getLastSegment: function() { + return this._segments[this._segments.length - 1]; + }, + + getCurves: function() { + if (!this._curves) { + var segments = this._segments, + length = segments.length; + if (!this._closed && length > 0) + length--; + this._curves = new Array(length); + for (var i = 0; i < length; i++) + this._curves[i] = Curve.create(this, segments[i], + segments[i + 1] || segments[0]); + } + return this._curves; + }, + + getFirstCurve: function() { + return this.getCurves()[0]; + }, + + getLastCurve: function() { + var curves = this.getCurves(); + return curves[curves.length - 1]; + }, + + getClosed: function() { + return this._closed; + }, + + setClosed: function(closed) { + if (this._closed != (closed = !!closed)) { + this._closed = closed; + if (this._curves) { + var length = this._segments.length, + i; + if (!closed && length > 0) + length--; + this._curves.length = length; + if (closed) + this._curves[i = length - 1] = Curve.create(this, + this._segments[i], this._segments[0]); + } + this._changed(Change.GEOMETRY); + } + }, + + transform: function(matrix) { + return this.base(matrix, true); + }, + + getMatrix: function() { + return null; + }, + + setMatrix: function(matrix) { + }, + + _apply: function(matrix) { + var coords = new Array(6); + for (var i = 0, l = this._segments.length; i < l; i++) { + this._segments[i]._transformCoordinates(matrix, coords, true); + } + var style = this._style, + fillColor = style._fillColor, + strokeColor = style._strokeColor; + if (fillColor && fillColor.transform) + fillColor.transform(matrix); + if (strokeColor && strokeColor.transform) + strokeColor.transform(matrix); + return true; + }, + + _add: function(segs, index) { + var segments = this._segments, + curves = this._curves, + amount = segs.length, + append = index == null, + index = append ? segments.length : index, + fullySelected = this.isFullySelected(); + for (var i = 0; i < amount; i++) { + var segment = segs[i]; + if (segment._path) { + segment = segs[i] = new Segment(segment); + } + segment._path = this; + segment._index = index + i; + if (fullySelected) + segment._selectionState = SelectionState.POINT; + if (segment._selectionState) + this._updateSelection(segment, 0, segment._selectionState); + } + if (append) { + segments.push.apply(segments, segs); + } else { + segments.splice.apply(segments, [index, 0].concat(segs)); + for (var i = index + amount, l = segments.length; i < l; i++) { + segments[i]._index = i; + } + } + if (curves && --index >= 0) { + curves.splice(index, 0, Curve.create(this, segments[index], + segments[index + 1])); + var curve = curves[index + amount]; + if (curve) { + curve._segment1 = segments[index + amount]; + } + } + this._changed(Change.GEOMETRY); + return segs; + }, + + add: function(segment1 ) { + return arguments.length > 1 && typeof segment1 !== 'number' + ? this._add(Segment.readAll(arguments)) + : this._add([ Segment.read(arguments) ])[0]; + }, + + insert: function(index, segment1 ) { + return arguments.length > 2 && typeof segment1 !== 'number' + ? this._add(Segment.readAll(arguments, 1), index) + : this._add([ Segment.read(arguments, 1) ], index)[0]; + }, + + addSegment: function(segment) { + return this._add([ Segment.read(arguments) ])[0]; + }, + + insertSegment: function(index, segment) { + return this._add([ Segment.read(arguments, 1) ], index)[0]; + }, + + addSegments: function(segments) { + return this._add(Segment.readAll(segments)); + }, + + insertSegments: function(index, segments) { + return this._add(Segment.readAll(segments), index); + }, + + removeSegment: function(index) { + var segments = this.removeSegments(index, index + 1); + return segments[0] || null; + }, + + removeSegments: function(from, to) { + from = from || 0; + to = Base.pick(to, this._segments.length); + var segments = this._segments, + curves = this._curves, + last = to >= segments.length, + removed = segments.splice(from, to - from), + amount = removed.length; + if (!amount) + return removed; + for (var i = 0; i < amount; i++) { + var segment = removed[i]; + if (segment._selectionState) + this._updateSelection(segment, segment._selectionState, 0); + removed._index = removed._path = undefined; + } + for (var i = from, l = segments.length; i < l; i++) + segments[i]._index = i; + if (curves) { + curves.splice(from, amount); + var curve; + if (curve = curves[from - 1]) + curve._segment2 = segments[from]; + if (curve = curves[from]) + curve._segment1 = segments[from]; + if (last && this._closed && (curve = curves[curves.length - 1])) + curve._segment2 = segments[0]; + } + this._changed(Change.GEOMETRY); + return removed; + }, + + isFullySelected: function() { + return this._selected && this._selectedSegmentState + == this._segments.length * SelectionState.POINT; + }, + + setFullySelected: function(selected) { + var length = this._segments.length; + this._selectedSegmentState = selected + ? length * SelectionState.POINT : 0; + for (var i = 0; i < length; i++) + this._segments[i]._selectionState = selected + ? SelectionState.POINT : 0; + this.setSelected(selected); + }, + + _updateSelection: function(segment, oldState, newState) { + segment._selectionState = newState; + var total = this._selectedSegmentState += newState - oldState; + if (total > 0) + this.setSelected(true); + }, + + flatten: function(maxDistance) { + var flattener = new PathFlattener(this), + pos = 0, + step = flattener.length / Math.ceil(flattener.length / maxDistance), + end = flattener.length + (this._closed ? -step : step) / 2; + var segments = []; + while (pos <= end) { + segments.push(new Segment(flattener.evaluate(pos, 0))); + pos += step; + } + this.setSegments(segments); + }, + + simplify: function(tolerance) { + if (this._segments.length > 2) { + var fitter = new PathFitter(this, tolerance || 2.5); + this.setSegments(fitter.fit()); + } + }, + + isClockwise: function() { + if (this._clockwise !== undefined) + return this._clockwise; + var sum = 0, + xPre, yPre; + function edge(x, y) { + if (xPre !== undefined) + sum += (xPre - x) * (y + yPre); + xPre = x; + yPre = y; + } + for (var i = 0, l = this._segments.length; i < l; i++) { + var seg1 = this._segments[i], + seg2 = this._segments[i + 1 < l ? i + 1 : 0], + point1 = seg1._point, + handle1 = seg1._handleOut, + handle2 = seg2._handleIn, + point2 = seg2._point; + edge(point1._x, point1._y); + edge(point1._x + handle1._x, point1._y + handle1._y); + edge(point2._x + handle2._x, point2._y + handle2._y); + edge(point2._x, point2._y); + } + return sum > 0; + }, + + setClockwise: function(clockwise) { + if (this.isClockwise() != (clockwise = !!clockwise)) { + this.reverse(); + this._clockwise = clockwise; + } + }, + + reverse: function() { + this._segments.reverse(); + for (var i = 0, l = this._segments.length; i < l; i++) { + var segment = this._segments[i]; + var handleIn = segment._handleIn; + segment._handleIn = segment._handleOut; + segment._handleOut = handleIn; + segment._index = i; + } + if (this._clockwise !== undefined) + this._clockwise = !this._clockwise; + }, + + join: function(path) { + if (path) { + var segments = path._segments, + last1 = this.getLastSegment(), + last2 = path.getLastSegment(); + if (last1._point.equals(last2._point)) + path.reverse(); + var first2 = path.getFirstSegment(); + if (last1._point.equals(first2._point)) { + last1.setHandleOut(first2._handleOut); + this._add(segments.slice(1)); + } else { + var first1 = this.getFirstSegment(); + if (first1._point.equals(first2._point)) + path.reverse(); + last2 = path.getLastSegment(); + if (first1._point.equals(last2._point)) { + first1.setHandleIn(last2._handleIn); + this._add(segments.slice(0, segments.length - 1), 0); + } else { + this._add(segments.slice(0)); + } + } + path.remove(); + var first1 = this.getFirstSegment(); + last1 = this.getLastSegment(); + if (last1._point.equals(first1._point)) { + first1.setHandleIn(last1._handleIn); + last1.remove(); + this.setClosed(true); + } + this._changed(Change.GEOMETRY); + return true; + } + return false; + }, + + getLength: function() { + if (this._length == null) { + var curves = this.getCurves(); + this._length = 0; + for (var i = 0, l = curves.length; i < l; i++) + this._length += curves[i].getLength(); + } + return this._length; + }, + + _getOffset: function(location) { + var index = location && location.getIndex(); + if (index != null) { + var curves = this.getCurves(), + offset = 0; + for (var i = 0; i < index; i++) + offset += curves[i].getLength(); + var curve = curves[index]; + return offset + curve.getLength(0, location.getParameter()); + } + return null; + }, + + getLocation: function(point) { + var curves = this.getCurves(); + for (var i = 0, l = curves.length; i < l; i++) { + var curve = curves[i]; + var t = curve.getParameter(point); + if (t != null) + return new CurveLocation(curve, t); + } + return null; + }, + + getLocationAt: function(offset, isParameter) { + var curves = this.getCurves(), + length = 0; + if (isParameter) { + var index = ~~offset; + return new CurveLocation(curves[index], offset - index); + } + for (var i = 0, l = curves.length; i < l; i++) { + var start = length, + curve = curves[i]; + length += curve.getLength(); + if (length >= offset) { + return new CurveLocation(curve, + curve.getParameterAt(offset - start)); + } + } + if (offset <= this.getLength()) + return new CurveLocation(curves[curves.length - 1], 1); + return null; + }, + + getPointAt: function(offset, isParameter) { + var loc = this.getLocationAt(offset, isParameter); + return loc && loc.getPoint(); + }, + + getTangentAt: function(offset, isParameter) { + var loc = this.getLocationAt(offset, isParameter); + return loc && loc.getTangent(); + }, + + getNormalAt: function(offset, isParameter) { + var loc = this.getLocationAt(offset, isParameter); + return loc && loc.getNormal(); + }, + + getNearestLocation: function(point) { + var curves = this.getCurves(), + minDist = Infinity, + minLoc = null; + for (var i = 0, l = curves.length; i < l; i++) { + var loc = curves[i].getNearestLocation(point); + if (loc._distance < minDist) { + minDist = loc._distance; + minLoc = loc; + } + } + return minLoc; + }, + + getNearestPoint: function(point) { + return this.getNearestLocation(point).getPoint(); + }, + + contains: function(point) { + point = Point.read(arguments); + if (!this._closed || !this.getRoughBounds()._containsPoint(point)) + return false; + var curves = this.getCurves(), + crossings = 0, + roots = []; + for (var i = 0, l = curves.length; i < l; i++) + crossings += curves[i].getCrossings(point, roots); + return (crossings & 1) == 1; + }, + + _hitTest: function(point, options) { + var style = this._style, + tolerance = options.tolerance || 0, + radius = (options.stroke && style._strokeColor + ? style._strokeWidth / 2 : 0) + tolerance, + loc, + res; + var coords = [], + that = this; + function checkPoint(seg, pt, name) { + if (point.getDistance(pt) < tolerance) + return new HitResult(name, that, { segment: seg, point: pt }); + } + function checkSegment(seg, ends) { + var point = seg._point; + return (ends || options.segments) + && checkPoint(seg, point, 'segment') + || (!ends && options.handles) && ( + checkPoint(seg, point.add(seg._handleIn), 'handle-in') || + checkPoint(seg, point.add(seg._handleOut), 'handle-out')); + } + if (options.ends && !options.segments && !this._closed) { + if (res = checkSegment(this.getFirstSegment(), true) + || checkSegment(this.getLastSegment(), true)) + return res; + } else if (options.segments || options.handles) { + for (var i = 0, l = this._segments.length; i < l; i++) { + if (res = checkSegment(this._segments[i])) + return res; + } + } + if (options.stroke && radius > 0) + loc = this.getNearestLocation(point); + if (!(loc && loc._distance <= radius) && options.fill + && style._fillColor && this.contains(point)) + return new HitResult('fill', this); + if (!loc && options.stroke && radius > 0) + loc = this.getNearestLocation(point); + if (loc && loc._distance <= radius) + return options.stroke + ? new HitResult('stroke', this, { location: loc }) + : new HitResult('fill', this); + } + +}, new function() { + + function drawHandles(ctx, segments, matrix) { + var coords = new Array(6); + for (var i = 0, l = segments.length; i < l; i++) { + var segment = segments[i]; + segment._transformCoordinates(matrix, coords, false); + var state = segment._selectionState, + selected = state & SelectionState.POINT, + pX = coords[0], + pY = coords[1]; + + function drawHandle(index) { + var hX = coords[index], + hY = coords[index + 1]; + if (pX != hX || pY != hY) { + ctx.beginPath(); + ctx.moveTo(pX, pY); + ctx.lineTo(hX, hY); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(hX, hY, 1.75, 0, Math.PI * 2, true); + ctx.fill(); + } + } + + if (selected || (state & SelectionState.HANDLE_IN)) + drawHandle(2); + if (selected || (state & SelectionState.HANDLE_OUT)) + drawHandle(4); + ctx.save(); + ctx.beginPath(); + ctx.rect(pX - 2, pY - 2, 4, 4); + ctx.fill(); + if (!selected) { + ctx.beginPath(); + ctx.rect(pX - 1, pY - 1, 2, 2); + ctx.fillStyle = '#ffffff'; + ctx.fill(); + } + ctx.restore(); + } + } + + function drawSegments(ctx, path, matrix) { + var segments = path._segments, + length = segments.length, + coords = new Array(6), + first = true, + pX, pY, + inX, inY, + outX, outY; + + function drawSegment(i) { + var segment = segments[i]; + if (matrix) { + segment._transformCoordinates(matrix, coords, false); + pX = coords[0]; + pY = coords[1]; + } else { + var point = segment._point; + pX = point._x; + pY = point._y; + } + if (first) { + ctx.moveTo(pX, pY); + first = false; + } else { + if (matrix) { + inX = coords[2]; + inY = coords[3]; + } else { + var handle = segment._handleIn; + inX = pX + handle._x; + inY = pY + handle._y; + } + if (inX == pX && inY == pY && outX == pX && outY == pY) { + ctx.lineTo(pX, pY); + } else { + ctx.bezierCurveTo(outX, outY, inX, inY, pX, pY); + } + } + if (matrix) { + outX = coords[4]; + outY = coords[5]; + } else { + var handle = segment._handleOut; + outX = pX + handle._x; + outY = pY + handle._y; + } + } + + for (var i = 0; i < length; i++) + drawSegment(i); + if (path._closed && length > 1) + drawSegment(0); + } + + return { + draw: function(ctx, param) { + if (!param.compound) + ctx.beginPath(); + + var style = this._style, + fillColor = style._fillColor, + strokeColor = style._strokeColor, + dashArray = style._dashArray, + hasDash = strokeColor && dashArray && dashArray.length; + + if (param.compound || this._clipMask || fillColor + || strokeColor && !hasDash) { + drawSegments(ctx, this); + } + + if (this._closed) + ctx.closePath(); + + if (this._clipMask) { + ctx.clip(); + } else if (!param.compound && (fillColor || strokeColor)) { + ctx.save(); + this._setStyles(ctx); + if (fillColor) + ctx.fill(); + if (strokeColor) { + if (hasDash) { + ctx.beginPath(); + var flattener = new PathFlattener(this), + from = style._dashOffset, to, + i = 0; + while (from < flattener.length) { + to = from + dashArray[(i++) % dashArray.length]; + flattener.drawPart(ctx, from, to); + from = to + dashArray[(i++) % dashArray.length]; + } + } + ctx.stroke(); + } + ctx.restore(); + } + }, + + drawSelected: function(ctx, matrix) { + ctx.beginPath(); + drawSegments(ctx, this, matrix); + ctx.stroke(); + drawHandles(ctx, this._segments, matrix); + } + }; +}, new function() { + + function getFirstControlPoints(rhs) { + var n = rhs.length, + x = [], + tmp = [], + b = 2; + x[0] = rhs[0] / b; + for (var i = 1; i < n; i++) { + tmp[i] = 1 / b; + b = (i < n - 1 ? 4 : 2) - tmp[i]; + x[i] = (rhs[i] - x[i - 1]) / b; + } + for (var i = 1; i < n; i++) { + x[n - i - 1] -= tmp[n - i] * x[n - i]; + } + return x; + }; + + return { + smooth: function() { + var segments = this._segments, + size = segments.length, + n = size, + overlap; + + if (size <= 2) + return; + + if (this._closed) { + overlap = Math.min(size, 4); + n += Math.min(size, overlap) * 2; + } else { + overlap = 0; + } + var knots = []; + for (var i = 0; i < size; i++) + knots[i + overlap] = segments[i]._point; + if (this._closed) { + for (var i = 0; i < overlap; i++) { + knots[i] = segments[i + size - overlap]._point; + knots[i + size + overlap] = segments[i]._point; + } + } else { + n--; + } + var rhs = []; + + for (var i = 1; i < n - 1; i++) + rhs[i] = 4 * knots[i]._x + 2 * knots[i + 1]._x; + rhs[0] = knots[0]._x + 2 * knots[1]._x; + rhs[n - 1] = 3 * knots[n - 1]._x; + var x = getFirstControlPoints(rhs); + + for (var i = 1; i < n - 1; i++) + rhs[i] = 4 * knots[i]._y + 2 * knots[i + 1]._y; + rhs[0] = knots[0]._y + 2 * knots[1]._y; + rhs[n - 1] = 3 * knots[n - 1]._y; + var y = getFirstControlPoints(rhs); + + if (this._closed) { + for (var i = 0, j = size; i < overlap; i++, j++) { + var f1 = (i / overlap); + var f2 = 1 - f1; + x[j] = x[i] * f1 + x[j] * f2; + y[j] = y[i] * f1 + y[j] * f2; + var ie = i + overlap, je = j + overlap; + x[je] = x[ie] * f2 + x[je] * f1; + y[je] = y[ie] * f2 + y[je] * f1; + } + n--; + } + var handleIn = null; + for (var i = overlap; i <= n - overlap; i++) { + var segment = segments[i - overlap]; + if (handleIn) + segment.setHandleIn(handleIn.subtract(segment._point)); + if (i < n) { + segment.setHandleOut( + Point.create(x[i], y[i]).subtract(segment._point)); + if (i < n - 1) + handleIn = Point.create( + 2 * knots[i + 1]._x - x[i + 1], + 2 * knots[i + 1]._y - y[i + 1]); + else + handleIn = Point.create( + (knots[n]._x + x[n - 1]) / 2, + (knots[n]._y + y[n - 1]) / 2); + } + } + if (this._closed && handleIn) { + var segment = this._segments[0]; + segment.setHandleIn(handleIn.subtract(segment._point)); + } + } + }; +}, new function() { + function getCurrentSegment(that) { + var segments = that._segments; + if (segments.length == 0) + throw new Error('Use a moveTo() command first'); + return segments[segments.length - 1]; + } + + return { + moveTo: function(point) { + if (!this._segments.length) + this._add([ new Segment(Point.read(arguments)) ]); + }, + + moveBy: function(point) { + throw new Error('moveBy() is unsupported on Path items.'); + }, + + lineTo: function(point) { + this._add([ new Segment(Point.read(arguments)) ]); + }, + + cubicCurveTo: function(handle1, handle2, to) { + handle1 = Point.read(arguments, 0, 1); + handle2 = Point.read(arguments, 1, 1); + to = Point.read(arguments, 2, 1); + var current = getCurrentSegment(this); + current.setHandleOut(handle1.subtract(current._point)); + this._add([ new Segment(to, handle2.subtract(to)) ]); + }, + + quadraticCurveTo: function(handle, to) { + handle = Point.read(arguments, 0, 1); + to = Point.read(arguments, 1, 1); + var current = getCurrentSegment(this)._point; + this.cubicCurveTo( + handle.add(current.subtract(handle).multiply(1/3)), + handle.add(to.subtract(handle).multiply(1/3)), + to + ); + }, + + curveTo: function(through, to, parameter) { + through = Point.read(arguments, 0, 1); + to = Point.read(arguments, 1, 1); + var t = Base.pick(parameter, 0.5), + t1 = 1 - t, + current = getCurrentSegment(this)._point, + handle = through.subtract(current.multiply(t1 * t1)) + .subtract(to.multiply(t * t)).divide(2 * t * t1); + if (handle.isNaN()) + throw new Error( + 'Cannot put a curve through points with parameter = ' + t); + this.quadraticCurveTo(handle, to); + }, + + arcTo: function(to, clockwise ) { + var current = getCurrentSegment(this), + from = current._point, + through; + if (clockwise === undefined) + clockwise = true; + if (typeof clockwise === 'boolean') { + to = Point.read(arguments, 0, 1); + var middle = from.add(to).divide(2), + through = middle.add(middle.subtract(from).rotate( + clockwise ? -90 : 90)); + } else { + through = Point.read(arguments, 0, 1); + to = Point.read(arguments, 1, 1); + } + var l1 = new Line(from.add(through).divide(2), + through.subtract(from).rotate(90)), + l2 = new Line(through.add(to).divide(2), + to.subtract(through).rotate(90)), + center = l1.intersect(l2), + line = new Line(from, to, true), + throughSide = line.getSide(through); + if (!center) { + if (!throughSide) + return this.lineTo(to); + throw new Error("Cannot put an arc through the given points: " + + [from, through, to]); + } + var vector = from.subtract(center), + radius = vector.getLength(), + extent = vector.getDirectedAngle(to.subtract(center)), + centerSide = line.getSide(center); + if (centerSide == 0) { + extent = throughSide * Math.abs(extent); + } else if (throughSide == centerSide) { + extent -= 360 * (extent < 0 ? -1 : 1); + } + var ext = Math.abs(extent), + count = ext >= 360 ? 4 : Math.ceil(ext / 90), + inc = extent / count, + half = inc * Math.PI / 360, + z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), + segments = []; + for (var i = 0; i <= count; i++) { + var pt = i < count ? center.add(vector) : to; + var out = i < count ? vector.rotate(90).multiply(z) : null; + if (i == 0) { + current.setHandleOut(out); + } else { + segments.push( + new Segment(pt, vector.rotate(-90).multiply(z), out)); + } + vector = vector.rotate(inc); + } + this._add(segments); + }, + + lineBy: function(vector) { + vector = Point.read(arguments); + var current = getCurrentSegment(this); + this.lineTo(current._point.add(vector)); + }, + + curveBy: function(throughVector, toVector, parameter) { + throughVector = Point.read(throughVector); + toVector = Point.read(toVector); + var current = getCurrentSegment(this)._point; + this.curveTo(current.add(throughVector), current.add(toVector), + parameter); + }, + + arcBy: function(throughVector, toVector) { + throughVector = Point.read(throughVector); + toVector = Point.read(toVector); + var current = getCurrentSegment(this)._point; + this.arcBy(current.add(throughVector), current.add(toVector)); + }, + + closePath: function() { + this.setClosed(true); + } + }; +}, new function() { + function getBounds(matrix, strokePadding) { + var segments = this._segments, + first = segments[0]; + if (!first) + return null; + var coords = new Array(6), + prevCoords = new Array(6); + first._transformCoordinates(matrix, prevCoords, false); + var min = prevCoords.slice(0, 2), + max = min.slice(0), + tMin = Numerical.TOLERANCE, + tMax = 1 - tMin; + function processSegment(segment) { + segment._transformCoordinates(matrix, coords, false); + + for (var i = 0; i < 2; i++) { + var v0 = prevCoords[i], + v1 = prevCoords[i + 4], + v2 = coords[i + 2], + v3 = coords[i]; + + function add(value, t) { + var padding = 0; + if (value == null) { + var u = 1 - t; + value = u * u * u * v0 + + 3 * u * u * t * v1 + + 3 * u * t * t * v2 + + t * t * t * v3; + padding = strokePadding ? strokePadding[i] : 0; + } + var left = value - padding, + right = value + padding; + if (left < min[i]) + min[i] = left; + if (right > max[i]) + max[i] = right; + + } + add(v3, null); + + var a = 3 * (v1 - v2) - v0 + v3, + b = 2 * (v0 + v2) - 4 * v1, + c = v1 - v0; + + if (a == 0) { + if (b == 0) + continue; + var t = -c / b; + if (tMin < t && t < tMax) + add(null, t); + continue; + } + + var q = b * b - 4 * a * c; + if (q < 0) + continue; + var sqrt = Math.sqrt(q), + f = -0.5 / a, + t1 = (b - sqrt) * f, + t2 = (b + sqrt) * f; + if (tMin < t1 && t1 < tMax) + add(null, t1); + if (tMin < t2 && t2 < tMax) + add(null, t2); + } + var tmp = prevCoords; + prevCoords = coords; + coords = tmp; + } + for (var i = 1, l = segments.length; i < l; i++) + processSegment(segments[i]); + if (this._closed) + processSegment(first); + return Rectangle.create(min[0], min[1], + max[0] - min[0], max[1] - min[1]); + } + + function getPenPadding(radius, matrix) { + if (!matrix) + return [radius, radius]; + var mx = matrix.createShiftless(), + hor = mx.transform(Point.create(radius, 0)), + ver = mx.transform(Point.create(0, radius)), + phi = hor.getAngleInRadians(), + a = hor.getLength(), + b = ver.getLength(); + var sin = Math.sin(phi), + cos = Math.cos(phi), + tan = Math.tan(phi), + tx = -Math.atan(b * tan / a), + ty = Math.atan(b / (tan * a)); + return [Math.abs(a * Math.cos(tx) * cos - b * Math.sin(tx) * sin), + Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)]; + } + + function getStrokeBounds(matrix) { + var style = this._style; + if (!style._strokeColor || !style._strokeWidth) + return getBounds.call(this, matrix); + var width = style._strokeWidth, + radius = width / 2, + padding = getPenPadding(radius, matrix), + join = style._strokeJoin, + cap = style._strokeCap, + miter = style._miterLimit * width / 2, + segments = this._segments, + length = segments.length, + bounds = getBounds.call(this, matrix, padding); + var joinBounds = new Rectangle(new Size(padding).multiply(2)); + + function add(point) { + bounds = bounds.include(matrix + ? matrix._transformPoint(point, point) : point); + } + + function addBevelJoin(curve, t) { + var point = curve.getPoint(t), + normal = curve.getNormal(t).normalize(radius); + add(point.add(normal)); + add(point.subtract(normal)); + } + + function addJoin(segment, join) { + if (join === 'round' || !segment._handleIn.isZero() + && !segment._handleOut.isZero()) { + bounds = bounds.unite(joinBounds.setCenter(matrix + ? matrix._transformPoint(segment._point) : segment._point)); + } else if (join == 'bevel') { + var curve = segment.getCurve(); + addBevelJoin(curve, 0); + addBevelJoin(curve.getPrevious(), 1); + } else if (join == 'miter') { + var curve2 = segment.getCurve(), + curve1 = curve2.getPrevious(), + point = curve2.getPoint(0), + normal1 = curve1.getNormal(1).normalize(radius), + normal2 = curve2.getNormal(0).normalize(radius), + line1 = new Line(point.subtract(normal1), + Point.create(-normal1.y, normal1.x)), + line2 = new Line(point.subtract(normal2), + Point.create(-normal2.y, normal2.x)), + corner = line1.intersect(line2); + if (!corner || point.getDistance(corner) > miter) { + addJoin(segment, 'bevel'); + } else { + add(corner); + } + } + } + + function addCap(segment, cap, t) { + switch (cap) { + case 'round': + return addJoin(segment, cap); + case 'butt': + case 'square': + var curve = segment.getCurve(), + point = curve.getPoint(t), + normal = curve.getNormal(t).normalize(radius); + if (cap === 'square') + point = point.add(normal.rotate(t == 0 ? -90 : 90)); + add(point.add(normal)); + add(point.subtract(normal)); + break; + } + } + + for (var i = 1, l = length - (this._closed ? 0 : 1); i < l; i++) { + addJoin(segments[i], join); + } + if (this._closed) { + addJoin(segments[0], join); + } else { + addCap(segments[0], cap, 0); + addCap(segments[length - 1], cap, 1); + } + return bounds; + } + + function getHandleBounds(matrix, stroke, join) { + var coords = new Array(6), + x1 = Infinity, + x2 = -x1, + y1 = x1, + y2 = x2; + stroke = stroke / 2 || 0; + join = join / 2 || 0; + for (var i = 0, l = this._segments.length; i < l; i++) { + var segment = this._segments[i]; + segment._transformCoordinates(matrix, coords, false); + for (var j = 0; j < 6; j += 2) { + var padding = j == 0 ? join : stroke, + x = coords[j], + y = coords[j + 1], + xn = x - padding, + xx = x + padding, + yn = y - padding, + yx = y + padding; + if (xn < x1) x1 = xn; + if (xx > x2) x2 = xx; + if (yn < y1) y1 = yn; + if (yx > y2) y2 = yx; + } + } + return Rectangle.create(x1, y1, x2 - x1, y2 - y1); + } + + function getRoughBounds(matrix) { + var style = this._style, + width = style._strokeWidth; + return getHandleBounds.call(this, matrix, width, + style._strokeJoin == 'miter' + ? width * style._miterLimit + : width); + } + + var get = { + bounds: getBounds, + strokeBounds: getStrokeBounds, + handleBounds: getHandleBounds, + roughBounds: getRoughBounds + }; + + return { + _getBounds: function(type, matrix) { + return get[type].call(this, matrix); + } + }; +}); + +Path.inject({ statics: new function() { + var kappa = 2 / 3 * (Math.sqrt(2) - 1); + + var ovalSegments = [ + new Segment([0, 0.5], [0, kappa ], [0, -kappa]), + new Segment([0.5, 0], [-kappa, 0], [kappa, 0 ]), + new Segment([1, 0.5], [0, -kappa], [0, kappa ]), + new Segment([0.5, 1], [kappa, 0 ], [-kappa, 0]) + ]; + + return { + Line: function() { + var step = Math.floor(arguments.length / 2); + return new Path( + Segment.read(arguments, 0, step), + Segment.read(arguments, step, step) + ); + }, + + Rectangle: function(rect) { + rect = Rectangle.read(arguments); + var left = rect.x, + top = rect.y, + right = left + rect.width, + bottom = top + rect.height, + path = new Path(); + path._add([ + new Segment(Point.create(left, bottom)), + new Segment(Point.create(left, top)), + new Segment(Point.create(right, top)), + new Segment(Point.create(right, bottom)) + ]); + path._closed = true; + return path; + }, + + RoundRectangle: function(rect, size) { + if (arguments.length == 2) { + rect = Rectangle.read(arguments, 0, 1); + size = Size.read(arguments, 1, 1); + } else if (arguments.length == 6) { + rect = Rectangle.read(arguments, 0, 4); + size = Size.read(arguments, 4, 2); + } + size = Size.min(size, rect.getSize(true).divide(2)); + var path = new Path(), + uSize = size.multiply(kappa * 2), + bl = rect.getBottomLeft(true), + tl = rect.getTopLeft(true), + tr = rect.getTopRight(true), + br = rect.getBottomRight(true); + path._add([ + new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]), + new Segment(bl.subtract(0, size.height), [0, uSize.height], null), + + new Segment(tl.add(0, size.height), null, [0, -uSize.height]), + new Segment(tl.add(size.width, 0), [-uSize.width, 0], null), + + new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]), + new Segment(tr.add(0, size.height), [0, -uSize.height], null), + + new Segment(br.subtract(0, size.height), null, [0, uSize.height]), + new Segment(br.subtract(size.width, 0), [uSize.width, 0], null) + ]); + path._closed = true; + return path; + }, + + Oval: function(rect) { + rect = Rectangle.read(arguments); + var path = new Path(), + point = rect.getPoint(true), + size = rect.getSize(true), + segments = new Array(4); + for (var i = 0; i < 4; i++) { + var segment = ovalSegments[i]; + segments[i] = new Segment( + segment._point.multiply(size).add(point), + segment._handleIn.multiply(size), + segment._handleOut.multiply(size) + ); + } + path._add(segments); + path._closed = true; + return path; + }, + + Circle: function(center, radius) { + if (arguments.length == 3) { + center = Point.read(arguments, 0, 2); + radius = arguments[2]; + } else { + center = Point.read(arguments, 0, 1); + } + return Path.Oval(new Rectangle(center.subtract(radius), + Size.create(radius * 2, radius * 2))); + }, + + Arc: function(from, through, to) { + var path = new Path(); + path.moveTo(from); + path.arcTo(through, to); + return path; + }, + + RegularPolygon: function(center, numSides, radius) { + center = Point.read(arguments, 0, 1); + var path = new Path(), + step = 360 / numSides, + three = !(numSides % 3), + vector = new Point(0, three ? -radius : radius), + offset = three ? -1 : 0.5, + segments = new Array(numSides); + for (var i = 0; i < numSides; i++) { + segments[i] = new Segment(center.add( + vector.rotate((i + offset) * step))); + } + path._add(segments); + path._closed = true; + return path; + }, + + Star: function(center, numPoints, radius1, radius2) { + center = Point.read(arguments, 0, 1); + numPoints *= 2; + var path = new Path(), + step = 360 / numPoints, + vector = new Point(0, -1), + segments = new Array(numPoints); + for (var i = 0; i < numPoints; i++) { + segments[i] = new Segment(center.add( + vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); + } + path._add(segments); + path._closed = true; + return path; + } + }; +}}); + +var CompoundPath = this.CompoundPath = PathItem.extend({ + initialize: function(paths) { + this.base(); + this._children = []; + this._namedChildren = {}; + var items = !paths || !Array.isArray(paths) + || typeof paths[0] !== 'object' ? arguments : paths; + this.addChildren(items); + }, + + insertChild: function(index, item) { + this.base(index, item); + if (item._clockwise === undefined) + item.setClockwise(item._index == 0); + }, + + simplify: function() { + if (this._children.length == 1) { + var child = this._children[0]; + child.insertAbove(this); + this.remove(); + return child; + } + return this; + }, + + smooth: function() { + for (var i = 0, l = this._children.length; i < l; i++) + this._children[i].smooth(); + }, + + draw: function(ctx, param) { + var children = this._children; + if (children.length == 0) + return; + var firstChild = children[0], + style = firstChild._style; + ctx.beginPath(); + param.compound = true; + for (var i = 0, l = children.length; i < l; i++) + Item.draw(children[i], ctx, param); + firstChild._setStyles(ctx); + if (style._fillColor) + ctx.fill(); + if (style._strokeColor) + ctx.stroke(); + param.compound = false; + } +}, new function() { + function getCurrentPath(that) { + if (!that._children.length) + throw new Error('Use a moveTo() command first'); + return that._children[that._children.length - 1]; + } + + var fields = { + moveTo: function(point) { + var path = new Path(); + this.addChild(path); + path.moveTo.apply(path, arguments); + }, + + moveBy: function(point) { + this.moveTo(getCurrentPath(this).getLastSegment()._point.add( + Point.read(arguments))); + }, + + closePath: function() { + getCurrentPath(this).setClosed(true); + } + }; + + Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', + 'arcTo', 'lineBy', 'curveBy', 'arcBy'], function(key) { + fields[key] = function() { + var path = getCurrentPath(this); + path[key].apply(path, arguments); + }; + }); + + return fields; +}); + +var PathFlattener = Base.extend({ + initialize: function(path) { + this.curves = []; + this.parts = []; + this.length = 0; + this.index = 0; + + var segments = path._segments, + segment1 = segments[0], + segment2, + that = this; + + function addCurve(segment1, segment2) { + var curve = Curve.getValues(segment1, segment2); + that.curves.push(curve); + that._computeParts(curve, segment1._index, 0, 1); + } + + for (var i = 1, l = segments.length; i < l; i++) { + segment2 = segments[i]; + addCurve(segment1, segment2); + segment1 = segment2; + } + if (path._closed) + addCurve(segment2, segments[0]); + }, + + _computeParts: function(curve, index, minT, maxT) { + if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough(curve)) { + var curves = Curve.subdivide(curve); + var halfT = (minT + maxT) / 2; + this._computeParts(curves[0], index, minT, halfT); + this._computeParts(curves[1], index, halfT, maxT); + } else { + var x = curve[6] - curve[0], + y = curve[7] - curve[1], + dist = Math.sqrt(x * x + y * y); + if (dist > Numerical.TOLERANCE) { + this.length += dist; + this.parts.push({ + offset: this.length, + value: maxT, + index: index + }); + } + } + }, + + getParameterAt: function(offset) { + var i, j = this.index; + for (;;) { + i = j; + if (j == 0 || this.parts[--j].offset < offset) + break; + } + for (var l = this.parts.length; i < l; i++) { + var part = this.parts[i]; + if (part.offset >= offset) { + this.index = i; + var prev = this.parts[i - 1]; + var prevVal = prev && prev.index == part.index ? prev.value : 0, + prevLen = prev ? prev.offset : 0; + return { + value: prevVal + (part.value - prevVal) + * (offset - prevLen) / (part.offset - prevLen), + index: part.index + }; + } + } + var part = this.parts[this.parts.length - 1]; + return { + value: 1, + index: part.index + }; + }, + + evaluate: function(offset, type) { + var param = this.getParameterAt(offset); + return Curve.evaluate(this.curves[param.index], param.value, type); + }, + + drawPart: function(ctx, from, to) { + from = this.getParameterAt(from); + to = this.getParameterAt(to); + for (var i = from.index; i <= to.index; i++) { + var curve = Curve.getPart(this.curves[i], + i == from.index ? from.value : 0, + i == to.index ? to.value : 1); + if (i == from.index) + ctx.moveTo(curve[0], curve[1]); + ctx.bezierCurveTo.apply(ctx, curve.slice(2)); + } + } +}); + +var PathFitter = Base.extend({ + initialize: function(path, error) { + this.points = []; + var segments = path._segments, + prev; + for (var i = 0, l = segments.length; i < l; i++) { + var point = segments[i].point.clone(); + if (!prev || !prev.equals(point)) { + this.points.push(point); + prev = point; + } + } + this.error = error; + }, + + fit: function() { + this.segments = [new Segment(this.points[0])]; + this.fitCubic(0, this.points.length - 1, + this.points[1].subtract(this.points[0]).normalize(), + this.points[this.points.length - 2].subtract( + this.points[this.points.length - 1]).normalize()); + return this.segments; + }, + + fitCubic: function(first, last, tan1, tan2) { + if (last - first == 1) { + var pt1 = this.points[first], + pt2 = this.points[last], + dist = pt1.getDistance(pt2) / 3; + this.addCurve([pt1, pt1.add(tan1.normalize(dist)), + pt2.add(tan2.normalize(dist)), pt2]); + return; + } + var uPrime = this.chordLengthParameterize(first, last), + maxError = Math.max(this.error, this.error * this.error), + error, + split; + for (var i = 0; i <= 4; i++) { + var curve = this.generateBezier(first, last, uPrime, tan1, tan2); + var max = this.findMaxError(first, last, curve, uPrime); + if (max.error < this.error) { + this.addCurve(curve); + return; + } + split = max.index; + if (max.error >= maxError) + break; + this.reparameterize(first, last, uPrime, curve); + maxError = max.error; + } + var V1 = this.points[split - 1].subtract(this.points[split]), + V2 = this.points[split].subtract(this.points[split + 1]), + tanCenter = V1.add(V2).divide(2).normalize(); + this.fitCubic(first, split, tan1, tanCenter); + this.fitCubic(split, last, tanCenter.negate(), tan2); + }, + + addCurve: function(curve) { + var prev = this.segments[this.segments.length - 1]; + prev.setHandleOut(curve[1].subtract(curve[0])); + this.segments.push( + new Segment(curve[3], curve[2].subtract(curve[3]))); + }, + + generateBezier: function(first, last, uPrime, tan1, tan2) { + var epsilon = Numerical.EPSILON, + pt1 = this.points[first], + pt2 = this.points[last], + C = [[0, 0], [0, 0]], + X = [0, 0]; + + for (var i = 0, l = last - first + 1; i < l; i++) { + var u = uPrime[i], + t = 1 - u, + b = 3 * u * t, + b0 = t * t * t, + b1 = b * t, + b2 = b * u, + b3 = u * u * u, + a1 = tan1.normalize(b1), + a2 = tan2.normalize(b2), + tmp = this.points[first + i] + .subtract(pt1.multiply(b0 + b1)) + .subtract(pt2.multiply(b2 + b3)); + C[0][0] += a1.dot(a1); + C[0][1] += a1.dot(a2); + C[1][0] = C[0][1]; + C[1][1] += a2.dot(a2); + X[0] += a1.dot(tmp); + X[1] += a2.dot(tmp); + } + + var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], + alpha1, alpha2; + if (Math.abs(detC0C1) > epsilon) { + var detC0X = C[0][0] * X[1] - C[1][0] * X[0], + detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; + alpha1 = detXC1 / detC0C1; + alpha2 = detC0X / detC0C1; + } else { + var c0 = C[0][0] + C[0][1], + c1 = C[1][0] + C[1][1]; + if (Math.abs(c0) > epsilon) { + alpha1 = alpha2 = X[0] / c0; + } else if (Math.abs(c1) > epsilon) { + alpha1 = alpha2 = X[1] / c1; + } else { + alpha1 = alpha2 = 0.; + } + } + + var segLength = pt2.getDistance(pt1); + epsilon *= segLength; + if (alpha1 < epsilon || alpha2 < epsilon) { + alpha1 = alpha2 = segLength / 3; + } + + return [pt1, pt1.add(tan1.normalize(alpha1)), + pt2.add(tan2.normalize(alpha2)), pt2]; + }, + + reparameterize: function(first, last, u, curve) { + for (var i = first; i <= last; i++) { + u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); + } + }, + + findRoot: function(curve, point, u) { + var curve1 = [], + curve2 = []; + for (var i = 0; i <= 2; i++) { + curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); + } + for (var i = 0; i <= 1; i++) { + curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); + } + var pt = this.evaluate(3, curve, u), + pt1 = this.evaluate(2, curve1, u), + pt2 = this.evaluate(1, curve2, u), + diff = pt.subtract(point), + df = pt1.dot(pt1) + diff.dot(pt2); + if (Math.abs(df) < Numerical.TOLERANCE) + return u; + return u - diff.dot(pt1) / df; + }, + + evaluate: function(degree, curve, t) { + var tmp = curve.slice(); + for (var i = 1; i <= degree; i++) { + for (var j = 0; j <= degree - i; j++) { + tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); + } + } + return tmp[0]; + }, + + chordLengthParameterize: function(first, last) { + var u = [0]; + for (var i = first + 1; i <= last; i++) { + u[i - first] = u[i - first - 1] + + this.points[i].getDistance(this.points[i - 1]); + } + for (var i = 1, m = last - first; i <= m; i++) { + u[i] /= u[m]; + } + return u; + }, + + findMaxError: function(first, last, curve, u) { + var index = Math.floor((last - first + 1) / 2), + maxDist = 0; + for (var i = first + 1; i < last; i++) { + var P = this.evaluate(3, curve, u[i - first]); + var v = P.subtract(this.points[i]); + var dist = v.x * v.x + v.y * v.y; + if (dist >= maxDist) { + maxDist = dist; + index = i; + } + } + return { + error: maxDist, + index: index + }; + } +}); + +var TextItem = this.TextItem = Item.extend({ + _boundsType: 'bounds', + + initialize: function(pointOrMatrix) { + this._style = CharacterStyle.create(this); + this._paragraphStyle = ParagraphStyle.create(this); + this.base(pointOrMatrix); + this.setParagraphStyle(); + this._content = ''; + this._lines = []; + }, + + _clone: function(copy) { + copy.setContent(this._content); + copy.setParagraphStyle(this._paragraphStyle); + return this.base(copy); + }, + + getContent: function() { + return this._content; + }, + + setContent: function(content) { + this._content = '' + content; + this._lines = this._content.split(/\r\n|\n|\r/mg); + this._changed(Change.CONTENT); + }, + + getCharacterStyle: function() { + return this.getStyle(); + }, + + setCharacterStyle: function(style) { + this.setStyle(style); + } + +}); + +var PointText = this.PointText = TextItem.extend({ + initialize: function(pointOrMatrix) { + this.base(pointOrMatrix); + this._point = this._matrix.getTranslation(); + }, + + clone: function() { + return this._clone(new PointText(this._matrix)); + }, + + getPoint: function() { + return LinkedPoint.create(this, 'setPoint', + this._point.x, this._point.y); + }, + + setPoint: function(point) { + this.translate(Point.read(arguments).subtract(this._point)); + }, + + _transform: function(matrix) { + matrix._transformPoint(this._point, this._point); + }, + + draw: function(ctx) { + if (!this._content) + return; + this._setStyles(ctx); + var style = this._style, + leading = this.getLeading(), + lines = this._lines; + ctx.font = style.getFontStyle(); + ctx.textAlign = this.getJustification(); + for (var i = 0, l = lines.length; i < l; i++) { + var line = lines[i]; + if (style._fillColor) + ctx.fillText(line, 0, 0); + if (style._strokeColor) + ctx.strokeText(line, 0, 0); + ctx.translate(0, leading); + } + } +}, new function() { + var context = null; + + return { + _getBounds: function(type, matrix) { + if (!context) + context = CanvasProvider.getCanvas( + Size.create(1, 1)).getContext('2d'); + var justification = this.getJustification(), + x = 0; + context.font = this._style.getFontStyle(); + var width = 0; + for (var i = 0, l = this._lines.length; i < l; i++) + width = Math.max(width, context.measureText( + this._lines[i]).width); + if (justification !== 'left') + x -= width / (justification === 'center' ? 2: 1); + var leading = this.getLeading(), + count = this._lines.length, + bounds = Rectangle.create(x, + count ? leading / 4 + (count - 1) * leading : 0, + width, -count * leading); + return matrix ? matrix._transformBounds(bounds, bounds) : bounds; + } + }; +}); + +var ExportSVG = this.ExportSVG = Base.extend({ + initialize: function() { + this.NS = 'http://www.w3.org/2000/svg'; + this.svgObj = document.createElementNS(this.NS, 'svg'); + }, + + exportProject: function(project) { + var layerArray = project.layers; + var layer; + for (var i = 0; i < layerArray.length; ++i) { + layer = layerArray[i]; + this.svgObj.appendChild(this.exportLayer(layer)); + } + return this.svgObj; + }, + + exportLayer: function(layer) { + return this.exportGroup(layer); + }, + + exportGroup: function(group) { + var svgG = document.createElementNS(this.NS, 'g'); + var curChild; + + for (var i in group.children) { + curChild = group.children[i]; + if (curChild.children) { + svgG.appendChild(this.exportGroup(curChild)); + } else { + svgG.appendChild(this.exportPath(curChild)); + } + } + + return svgG; + }, + + exportPath: function(path) { + var svgEle; + + var segArray = path.getSegments(); + var pointArray = new Array(); + var handleInArray = new Array(); + var handleOutArray = new Array(); + for (i = 0; i < segArray.length; i++) { + console.log(segArray[i].toString()); + pointArray[i] = segArray[i].getPoint(); + handleInArray[i] = segArray[i].getHandleIn(); + handleOutArray[i] = segArray[i].getHandleOut(); + } + if(path.content){ + type = 'text'; + } else { + var type = this._checkType(path, segArray, pointArray, handleInArray, handleOutArray); + } + switch (type) { + case 'rect': + svgEle = document.createElementNS(this.NS, 'rect'); + svgEle.setAttribute('x', pointArray[1].getX()); + svgEle.setAttribute('y', pointArray[1].getY()); + svgEle.setAttribute('width', pointArray[1].getDistance(pointArray[2], true)); + svgEle.setAttribute('height', pointArray[0].getDistance(pointArray[1], true)); + break; + case 'roundRect': + var rx = pointArray[4].getX() - pointArray[3].getX(); + var ry = pointArray[3].getY() - pointArray[4].getY(); + svgEle = document.createElementNS(this.NS, 'rect'); + svgEle.setAttribute('x', pointArray[3].getX()); + svgEle.setAttribute('y', pointArray[4].getY()); + svgEle.setAttribute('rx', rx); + svgEle.setAttribute('ry', ry); + svgEle.setAttribute('width', pointArray[1].getDistance(pointArray[6], true)); + svgEle.setAttribute('height',pointArray[0].getDistance(pointArray[3], true)); + break; + case'line': + svgEle = document.createElementNS(this.NS, 'line'); + svgEle.setAttribute('x1', pointArray[0].getX()); + svgEle.setAttribute('y1', pointArray[0].getY()); + svgEle.setAttribute('x2', pointArray[pointArray.length - 1].getX()); + svgEle.setAttribute('y2', pointArray[pointArray.length - 1].getY()); + break; + case 'circle': + svgEle = document.createElementNS(this.NS, 'circle'); + var radius = (pointArray[2].getX() - pointArray[0].getX()) /2; + var cx = pointArray[0].getX() + radius; + svgEle.setAttribute('cx', cx); + svgEle.setAttribute('cy', pointArray[0].getY()); + svgEle.setAttribute('r', radius); + break; + case 'ellipse': + svgEle = document.createElementNS(this.NS, 'ellipse'); + var radiusX = (pointArray[2].getX() - pointArray[0].getX()) / 2; + var radiusY = (pointArray[3].getY() - pointArray[1].getY()) /2; + var cx = pointArray[0].getX() + radiusX; + svgEle.setAttribute('cx', cx); + svgEle.setAttribute('cy', pointArray[0].getY()); + svgEle.setAttribute('rx', radiusX); + svgEle.setAttribute('ry', radiusY); + break; + case 'polyline': + svgEle = document.createElementNS(this.NS, 'polyline'); + var pointString; + for(i = 0; i < pointArray.length; ++i) { + pointString += pointArray[i].getX() + ", " + pointArray[i].getY(); + } + svgEle.setAttribute('points', pointString); + break; + case 'polygon': + svgEle = document.createElementNS(this.NS, 'polygon'); + var pointString; + for(i = 0; i < pointArray.length; ++i) { + pointString += pointArray[i].getX() + ", " + pointArray[i].getY(); + } + svgEle.setAttribute('points', pointString); + break; + case 'text': + svgEle = document.createElementNS(this.NS, 'text'); + svgEle.setAttribute('x', path.getPosition().getX()); + svgEle.setAttribute('y', path.getPosition().getY()); + svgEle.appendChild(path.getContent()); + default: + svgEle = document.createElementNS(this.NS, 'path'); + svgEle = this.pathSetup(path); + break; + } + + if (path.strokeColor != undefined) { + svgEle.setAttribute('stroke', path.strokeColor.toCssString()); + } + + if (path.fillColor != undefined) { + svgEle.setAttribute('fill', path.fillColor.toCssString()); + } + + if(path.strokeWidth != undefined){ + svgEle.setAttribute('stroke-width', path.strokeWidth); + } + + if(path.name != undefined) { + svgEle.setAttribute('name', path.name); + } + return svgEle; + }, + + pathSetup: function(path) { + var svgPath = document.createElementNS(this.NS, 'path'); + var segArray = path.getSegments(); + var pointArray = new Array(); + var hIArray = new Array(); + var hOArray = new Array(); + for (i = 0; i < segArray.length; i++) { + pointArray[i] = segArray[i].getPoint(); + hIArray[i] = segArray[i].getHandleIn(); + hOArray[i] = segArray[i].getHandleOut(); + } + var pointString = ''; + var x1; + var x2; + var y1; + var y2; + var handleOut1; + var handleIn2; + pointString += 'M' + pointArray[0].getX() + ',' + pointArray[0].getY(); + for (i = 0; i < pointArray.length-1; i++) { + console.log(pointArray[i].getX()); + console.log(pointArray[i].getY()); + x1 = pointArray[i].getX(); + y1 = pointArray[i].getY(); + x2 = pointArray[i + 1].getX(); + y2 = pointArray[i + 1].getY(); + handleOut1 = hOArray[i]; + handleIn2 = hIArray[i+1]; + if(handleOut1.getX() == 0 && handleOut1.getY() == 0 && handleIn2.getX() == 0 && handleIn2.getY() ==0) { + pointString+= 'L' + x2 + ',' + y2 + ' '; + } else { + pointString+= 'c' + (handleOut1.getX()) + ',' + (handleOut1.getY()) + ' '; + pointString+= (x2 - x1 + handleIn2.getX()) + ',' + (y2 - y1 + handleIn2.getY()) + ' '; + pointString+= (x2 - x1) + ',' + (y2-y1) + ' '; + } + } + if (path.getClosed()) + { + pointString += 'z'; + } + svgPath.setAttribute('d',pointString); + return svgPath; + }, + + _checkType: function(path, segArray, pointArray, handleInArray, handleOutArray) { + var type; + var dPoint12; + var dPoint34; + var curves = false; + var segHandleIn; + var segHandleOut; + for( var i in segArray){ + segHandleIn = segArray[i].getHandleIn(); + segHandleOut = segArray[i].getHandleOut(); + curves = segHandleIn.getX() != 0 || segHandleIn.getY() != 0 ? true : curves; + curves = segHandleOut.getX() != 0 || segHandleOut.getY() != 0 ? true : curves; + } + if(curves){ + dPoint12 = pointArray[0].getDistance(pointArray[3], true); + dPoint34 = pointArray[4].getDistance(pointArray[7], true); + if(segArray.length == 8 && dPoint12 === dPoint34) { + type = 'roundRect'; + } else if(segArray.length == 4) { + var checkPointValues = true; + for(i = 0; i < pointArray.length && checkPointValues == true; i++) { + if(handleInArray[i].getX() != 0 || handleInArray[i].getY() != 0 && Math.abs(handleInArray[i].getX()) === Math.abs(handleOutArray[i].getX()) && Math.abs(handleInArray[i].getY()) === Math.abs(handleOutArray[i].getY())) { + checkPointValues = true; + } else { + checkPointValues = false; + } + } + if(checkPointValues == true && handleInArray[3].getY() === handleOutArray[0].getX() && handleOutArray[3].getY() === handleInArray[0].getX()) { + type = 'circle'; + } else { + type = 'ellipse'; + } + } + } else if(!curves) { + dPoint12 = pointArray[0].getDistance(pointArray[1], true); + dPoint34 = pointArray[2].getDistance(pointArray[3], true); + if(segArray.length == 4 && dPoint12 == dPoint34) { + type = 'rect'; + } else if(segArray.length >= 3) { + if(path.getClosed()) { + type = 'polygon'; + } else { + type = 'polyline'; + } + } else { + type = 'line'; + } + } else { + type = 'NULL"; + } + } +}); + +/** + * Imports svg into items with groups + * Stetson Alpha - Paper.js + * + */ + +var ImportSVG = this.ImportSVG = Base.extend({ + /** + * Takes the svg dom obj and parses the data + * to create a layer with groups (if needed) with + * items inside. Should support nested groups. + * + * takes in a svg object (xml dom) + * returns Paper.js Layer + */ + importSVG: function(svg) + { + var layer = new Layer(); + groups = this.importGroup(svg); + layer.addChild(groups); + + return layer; + }, + + /** + * Creates a Paper.js Group by parsing + * a specific svg g node + * + * takes in a svg object (xml dom) + * returns Paper.js Group + */ + importGroup: function(svg) + { + var group = new Group(); + var child; + for (var i in svg.childNodes) { + child = svg.childNodes[i]; + if (child.nodeType != 1) { + continue; + } + item = this.importPath(child); + group.addChild(item); + } + return group; + }, + + /** + * Creates a Paper.js Path by parsing + * a specific svg node (rect, path, circle, polygon, etc) + * and creating the right path object based on the svg type. + * + * takes in a svg object (xml dom) + * returns Paper.js Item + */ + importPath: function(svg) + { + switch (svg.nodeName.toLowerCase()) { + case 'line': + item = this._importLine(svg); + break; + case 'rect': + item = this._importRectangle(svg); + break; + case 'ellipse': + item = this._importOval(svg); + break; + case 'g': + item = this.importGroup(svg); + break; + case 'text': + item = this._importText(svg); + break; + default: + break; + } + return item; + }, + + /** + * Creates a Path.Circle Paper.js item + * + * takes a svg circle node (xml dom) + * returns Paper.js Path.Circle item + */ + _importCircle: function(svgCircle) + { + var cx = svgCircle.cx.baseVal.value || 0; + var cy = svgCircle.cy.baseVal.value || 0; + var r = svgCircle.r.baseVal.value || 0; + var center = new Point(cx, cy); + var circle = new Path.Circle(center, r); + + return circle; + }, + + /** + * Creates a Path.Oval Paper.js item + * + * takes a svg ellipse node (xml dom) + * returns Paper.js Path.Oval item + */ + _importOval: function(svgOval) + { + var cx = svgOval.cx.baseVal.value || 0; + var cy = svgOval.cy.baseVal.value || 0; + var rx = svgOval.rx.baseVal.value || 0; + var ry = svgOval.ry.baseVal.value || 0; + + var center = new Point(cx, cy); + var offset = new Point(rx, ry); + var topLeft = center.subtract(offset); + var bottomRight = center.add(offset); + + var rect = new Rectangle(topLeft, bottomRight); + var oval = new Path.Oval(rect); + + return oval; + }, + + /** + * Creates a "rectangle" Paper.js item + * + * takes a svg rect node (xml dom) + * returns either a + * - Path.Rectangle item + * - Path.RoundRectangle item (if the rectangle has rounded corners) + */ + _importRectangle: function(svgRectangle) + { + var x = svgRectangle.x.baseVal.value || 0; + var y = svgRectangle.y.baseVal.value || 0; + var rx = svgRectangle.rx.baseVal.value || 0; + var ry = svgRectangle.ry.baseVal.value || 0; + var width = svgRectangle.width.baseVal.value || 0; + var height = svgRectangle.height.baseVal.value || 0; + + var topLeft = new Point(x, y); + var size = new Size(width, height); + var rectangle = new Rectangle(topLeft, size); + + if (rx > 0 || ry > 0) { + var cornerSize = new Size(rx, ry); + rectangle = new Path.RoundRectangle(rectangle, cornerSize); + } else { + rectangle = new Path.Rectangle(rectangle); + } + + return rectangle; + }, + + /** + * Creates a Path.Line Paper.js item + * + * takes a svg line node (xml dom) + * returns a Path.Line item + */ + _importLine: function(svgLine) + { + var x1 = svgLine.x1.baseVal.value || 0; + var y1 = svgLine.y1.baseVal.value || 0; + var x2 = svgLine.x2.baseVal.value || 0; + var y2 = svgLine.y2.baseVal.value || 0; + + var from = new Point(x1, y1); + var to = new Point(x2, y2); + var line = new Path.Line(from, to); + + return line; + }, + + /** + * Creates a PointText Paper.js item + * + * takes a svg text node (xml dom) + * returns a PointText item + */ + _importText: function(svgText) + { + //TODO: Extend this for multiple values + var x = svgText.x.baseVal.getItem(0).value || 0; + var y = svgText.y.baseVal.getItem(0).value || 0; + //END:Todo + var dx; //character kerning + var dy; //character baseline + var rotate; //character rotation + var textLength; //the width of the containing box + var lengthAdjust; // + var textContent = svgText.textContent || ""; + var topLeft = new Point(x, y); + var text = new PointText(topLeft); + text.content = textContent; + return text; + } +}); + +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +/** + * @name Style + * + * @class Internal base-class for all style objects, e.g. PathStyle, + * CharacterStyle, PargraphStyle. + * + * @private + */ +var Style = Item.extend({ + initialize: function(style) { + // If the passed style object is also a Style, clone its clonable + // fields rather than simply copying them. + var clone = style instanceof Style; + // Note: This relies on bean getters and setters that get implicetly + // called when getting from style[key] and setting on this[key]. + return Base.each(this._defaults, function(value, key) { + value = style && style[key] || value; + this[key] = value && clone && value.clone + ? value.clone() : value; + }, this); + }, + + statics: { + create: function(item) { + var style = new this(this.dont); + style._item = item; + return style; + }, + + extend: function(src) { + // Inject style getters and setters into the 'owning' class, which + // redirect calls to the linked style objects through their internal + // property on the instances of that class, as defined by _style. + var styleKey = '_' + src._style, + stylePart = Base.capitalize(src._style), + flags = src._flags || {}, + owner = {}; + + // Define accessor on owner class for this style: + owner['get' + stylePart] = function() { + return this[styleKey]; + }; + + owner['set' + stylePart] = function(style) { + this[styleKey].initialize(style); + }; + + Base.each(src._defaults, function(value, key) { + var isColor = !!key.match(/Color$/), + part = Base.capitalize(key), + set = 'set' + part, + get = 'get' + part; + // Simply extend src with these getters and setters, to be + // injected into this class using this.base() further down. + src[set] = function(value) { + var children = this._item && this._item._children; + value = isColor ? Color.read(arguments) : value; + if (children) { + for (var i = 0, l = children.length; i < l; i++) + children[i][styleKey][set](value); + } else { + var old = this['_' + key]; + if (old != value && !(old && old.equals + && old.equals(value))) { + this['_' + key] = value; + if (isColor) { + if (old) + old._removeOwner(this._item); + if (value) + value._addOwner(this._item); + } + // Notify the item of the style change STYLE is + // always set, additional flags come from _flags, + // as used for STROKE: + if (this._item) + this._item._changed(flags[key] || Change.STYLE); + } + } + return this; + }; + src[get] = function() { + var children = this._item && this._item._children, + style; + // If this item has children, walk through all of them and + // see if they all have the same style. + if (!children) + return this['_' + key]; + for (var i = 0, l = children.length; i < l; i++) { + var childStyle = children[i][styleKey][get](); + if (!style) { + style = childStyle; + } else if (style != childStyle && !(style + && style.equals && style.equals(childStyle))) { + // If there is another item with a different + // style, the style is not defined: + // PORT: Change this in Scriptographer + // (currently returns null) + return undefined; + } + } + return style; + }; + // Style-getters and setters for owner class: + owner[set] = function(value) { + this[styleKey][set](value); + return this; + }; + owner[get] = function() { + return this[styleKey][get](); + }; + }); + src._owner.inject(owner); + // Pass on to base() + return this.base.apply(this, arguments); + } + } +}); + +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +/** + * @name PathStyle + * + * @class PathStyle is used for changing the visual styles of items + * contained within a Paper.js project and is returned by + * {@link Item#style} and {@link Project#currentStyle}. + * + * All properties of PathStyle are also reflected directly in {@link Item}, + * i.e.: {@link Item#fillColor}. + * + * To set multiple style properties in one go, you can pass an object to + * {@link Item#style}. This is a convenient way to define a style once and + * apply it to a series of items: + * + * @classexample {@paperscript} + * var circleStyle = { + * fillColor: new RgbColor(1, 0, 0), + * strokeColor: 'black', + * strokeWidth: 5 + * }; + * + * var path = new Path.Circle(new Point(80, 50), 30); + * path.style = circleStyle; + */ +var PathStyle = this.PathStyle = Style.extend(/** @lends PathStyle# */{ + _owner: Item, + _style: 'style', + // windingRule / resolution / fillOverprint / strokeOverprint are currently + // not supported. + _defaults: { + fillColor: undefined, + strokeColor: undefined, + strokeWidth: 1, + strokeCap: 'butt', + strokeJoin: 'miter', + miterLimit: 10, + dashOffset: 0, + dashArray: [] + }, + _flags: { + strokeWidth: Change.STROKE, + strokeCap: Change.STROKE, + strokeJoin: Change.STROKE, + miterLimit: Change.STROKE + } + + // DOCS: why isn't the example code showing up? + +}); + +var ParagraphStyle = this.ParagraphStyle = Style.extend({ + _owner: TextItem, + _style: 'paragraphStyle', + _defaults: { + justification: 'left' + }, + _flags: { + justification: Change.GEOMETRY + } + +}); + +var CharacterStyle = this.CharacterStyle = PathStyle.extend({ + _owner: TextItem, + _style: 'style', + _defaults: Base.merge(PathStyle.prototype._defaults, { + fillColor: 'black', + fontSize: 12, + leading: null, + font: 'sans-serif' + }), + _flags: { + fontSize: Change.GEOMETRY, + leading: Change.GEOMETRY, + font: Change.GEOMETRY + } + +}, { + getLeading: function() { + var leading = this.base(); + return leading != null ? leading : this.getFontSize() * 1.2; + }, + + getFontStyle: function() { + return this._fontSize + 'px ' + this._font; + } +}); + +var Color = this.Color = Base.extend(new function() { + + var components = { + gray: ['gray'], + rgb: ['red', 'green', 'blue'], + hsb: ['hue', 'saturation', 'brightness'], + hsl: ['hue', 'saturation', 'lightness'] + }; + + var colorCache = {}, + colorContext; + + function nameToRgbColor(name) { + var color = colorCache[name]; + if (color) + return color.clone(); + if (!colorContext) { + var canvas = CanvasProvider.getCanvas(Size.create(1, 1)); + colorContext = canvas.getContext('2d'); + colorContext.globalCompositeOperation = 'copy'; + } + colorContext.fillStyle = 'rgba(0,0,0,0)'; + colorContext.fillStyle = name; + colorContext.fillRect(0, 0, 1, 1); + var data = colorContext.getImageData(0, 0, 1, 1).data, + rgb = [data[0] / 255, data[1] / 255, data[2] / 255]; + return (colorCache[name] = RgbColor.read(rgb)).clone(); + } + + function hexToRgbColor(string) { + var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + if (hex.length >= 4) { + var rgb = new Array(3); + for (var i = 0; i < 3; i++) { + var channel = hex[i + 1]; + rgb[i] = parseInt(channel.length == 1 + ? channel + channel : channel, 16) / 255; + } + return RgbColor.read(rgb); + } + } + + var hsbIndices = [ + [0, 3, 1], + [2, 0, 1], + [1, 0, 3], + [1, 2, 0], + [3, 1, 0], + [0, 1, 2] + ]; + + var converters = { + 'rgb-hsb': function(color) { + var r = color._red, + g = color._green, + b = color._blue, + max = Math.max(r, g, b), + min = Math.min(r, g, b), + delta = max - min, + h = delta == 0 ? 0 + : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) + : max == g ? (b - r) / delta + 2 + : (r - g) / delta + 4) * 60, + s = max == 0 ? 0 : delta / max, + v = max; + return new HsbColor(h, s, v, color._alpha); + }, + + 'hsb-rgb': function(color) { + var h = (color._hue / 60) % 6, + s = color._saturation, + b = color._brightness, + i = Math.floor(h), + f = h - i, + i = hsbIndices[i], + v = [ + b, + b * (1 - s), + b * (1 - s * f), + b * (1 - s * (1 - f)) + ]; + return new RgbColor(v[i[0]], v[i[1]], v[i[2]], color._alpha); + }, + + 'rgb-hsl': function(color) { + var r = color._red, + g = color._green, + b = color._blue, + max = Math.max(r, g, b), + min = Math.min(r, g, b), + delta = max - min, + achromatic = delta == 0, + h = achromatic ? 0 + : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) + : max == g ? (b - r) / delta + 2 + : (r - g) / delta + 4) * 60, + l = (max + min) / 2, + s = achromatic ? 0 : l < 0.5 + ? delta / (max + min) + : delta / (2 - max - min); + return new HslColor(h, s, l, color._alpha); + }, + + 'hsl-rgb': function(color) { + var s = color._saturation, + h = color._hue / 360, + l = color._lightness, + t1, t2, c; + if (s == 0) + return new RgbColor(l, l, l, color._alpha); + var t3s = [ h + 1 / 3, h, h - 1 / 3 ], + t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, + t1 = 2 * l - t2, + c = []; + for (var i = 0; i < 3; i++) { + var t3 = t3s[i]; + if (t3 < 0) t3 += 1; + if (t3 > 1) t3 -= 1; + c[i] = 6 * t3 < 1 + ? t1 + (t2 - t1) * 6 * t3 + : 2 * t3 < 1 + ? t2 + : 3 * t3 < 2 + ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 + : t1; + } + return new RgbColor(c[0], c[1], c[2], color._alpha); + }, + + 'rgb-gray': function(color) { + return new GrayColor(1 - (color._red * 0.2989 + color._green * 0.587 + + color._blue * 0.114), color._alpha); + }, + + 'gray-rgb': function(color) { + var comp = 1 - color._gray; + return new RgbColor(comp, comp, comp, color._alpha); + }, + + 'gray-hsb': function(color) { + return new HsbColor(0, 0, 1 - color._gray, color._alpha); + }, + + 'gray-hsl': function(color) { + return new HslColor(0, 0, 1 - color._gray, color._alpha); + } + }; + + var fields = { + _readNull: true, + + initialize: function(arg) { + var isArray = Array.isArray(arg), + type = this._colorType; + if (typeof arg === 'object' && !isArray) { + if (!type) { + return arg.red !== undefined + ? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha) + : arg.gray !== undefined + ? new GrayColor(arg.gray, arg.alpha) + : arg.lightness !== undefined + ? new HslColor(arg.hue, arg.saturation, arg.lightness, + arg.alpha) + : arg.hue !== undefined + ? new HsbColor(arg.hue, arg.saturation, arg.brightness, + arg.alpha) + : new RgbColor(); + } else { + return Color.read(arguments).convert(type); + } + } else if (typeof arg === 'string') { + var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i) + ? hexToRgbColor(arg) + : nameToRgbColor(arg); + return type + ? rgbColor.convert(type) + : rgbColor; + } else { + var components = isArray ? arg + : Array.prototype.slice.call(arguments); + if (!type) { + if (components.length >= 3) + return new RgbColor(components); + return new GrayColor(components); + } else { + Base.each(this._components, + function(name, i) { + var value = components[i]; + this['_' + name] = value !== undefined + ? value : null; + }, + this); + } + } + }, + + clone: function() { + var ctor = this.constructor, + copy = new ctor(ctor.dont), + components = this._components; + for (var i = 0, l = components.length; i < l; i++) { + var key = '_' + components[i]; + copy[key] = this[key]; + } + return copy; + }, + + convert: function(type) { + var converter; + return this._colorType == type + ? this.clone() + : (converter = converters[this._colorType + '-' + type]) + ? converter(this) + : converters['rgb-' + type]( + converters[this._colorType + '-rgb'](this)); + }, + + statics: { + extend: function(src) { + if (src._colorType) { + var comps = components[src._colorType]; + src._components = comps.concat(['alpha']); + Base.each(comps, function(name) { + var isHue = name === 'hue', + part = Base.capitalize(name), + name = '_' + name; + this['get' + part] = function() { + return this[name]; + }; + this['set' + part] = function(value) { + this[name] = isHue + ? ((value % 360) + 360) % 360 + : Math.min(Math.max(value, 0), 1); + this._changed(); + return this; + }; + }, src); + } + return this.base(src); + } + } + }; + + Base.each(components, function(comps, type) { + Base.each(comps, function(component) { + var part = Base.capitalize(component); + fields['get' + part] = function() { + return this.convert(type)[component]; + }; + fields['set' + part] = function(value) { + var color = this.convert(type); + color[component] = value; + color = color.convert(this._colorType); + for (var i = 0, l = this._components.length; i < l; i++) { + var key = this._components[i]; + this[key] = color[key]; + } + }; + }); + }); + + return fields; +}, { + + _changed: function() { + this._cssString = null; + for (var i = 0, l = this._owners && this._owners.length; i < l; i++) + this._owners[i]._changed(Change.STYLE); + }, + + _addOwner: function(item) { + if (!this._owners) + this._owners = []; + this._owners.push(item); + }, + + _removeOwner: function(item) { + var index = this._owners ? this._owners.indexOf(item) : -1; + if (index != -1) { + this._owners.splice(index, 1); + if (this._owners.length == 0) + delete this._owners; + } + }, + + getType: function() { + return this._colorType; + }, + + getComponents: function() { + var length = this._components.length; + var comps = new Array(length); + for (var i = 0; i < length; i++) + comps[i] = this['_' + this._components[i]]; + return comps; + }, + + getAlpha: function() { + return this._alpha != null ? this._alpha : 1; + }, + + setAlpha: function(alpha) { + this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); + this._changed(); + return this; + }, + + hasAlpha: function() { + return this._alpha != null; + }, + + equals: function(color) { + if (color && color._colorType === this._colorType) { + for (var i = 0, l = this._components.length; i < l; i++) { + var component = '_' + this._components[i]; + if (this[component] !== color[component]) + return false; + } + return true; + } + return false; + }, + + toString: function() { + var parts = [], + format = Base.formatNumber; + for (var i = 0, l = this._components.length; i < l; i++) { + var component = this._components[i], + value = this['_' + component]; + if (component === 'alpha' && value == null) + value = 1; + parts.push(component + ': ' + format(value)); + } + return '{ ' + parts.join(', ') + ' }'; + }, + + toCssString: function() { + if (!this._cssString) { + var color = this.convert('rgb'), + alpha = color.getAlpha(), + components = [ + Math.round(color._red * 255), + Math.round(color._green * 255), + Math.round(color._blue * 255), + alpha != null ? alpha : 1 + ]; + this._cssString = 'rgba(' + components.join(', ') + ')'; + } + return this._cssString; + }, + + getCanvasStyle: function() { + return this.toCssString(); + } + +}); + +var GrayColor = this.GrayColor = Color.extend({ + + _colorType: 'gray' +}); + +var RgbColor = this.RgbColor = this.RGBColor = Color.extend({ + + _colorType: 'rgb' +}); + +var HsbColor = this.HsbColor = this.HSBColor = Color.extend({ + + _colorType: 'hsb' +}); + +var HslColor = this.HslColor = this.HSLColor = Color.extend({ + + _colorType: 'hsl' +}); + +var GradientColor = this.GradientColor = Color.extend({ + + initialize: function(gradient, origin, destination, hilite) { + this.gradient = gradient || new Gradient(); + this.gradient._addOwner(this); + this.setOrigin(origin); + this.setDestination(destination); + if (hilite) + this.setHilite(hilite); + }, + + clone: function() { + return new GradientColor(this.gradient, this._origin, this._destination, + this._hilite); + }, + + getOrigin: function() { + return this._origin; + }, + + setOrigin: function(origin) { + origin = Point.read(arguments).clone(); + this._origin = origin; + if (this._destination) + this._radius = this._destination.getDistance(this._origin); + this._changed(); + return this; + }, + + getDestination: function() { + return this._destination; + }, + + setDestination: function(destination) { + destination = Point.read(arguments).clone(); + this._destination = destination; + this._radius = this._destination.getDistance(this._origin); + this._changed(); + return this; + }, + + getHilite: function() { + return this._hilite; + }, + + setHilite: function(hilite) { + hilite = Point.read(arguments).clone(); + var vector = hilite.subtract(this._origin); + if (vector.getLength() > this._radius) { + this._hilite = this._origin.add( + vector.normalize(this._radius - 0.1)); + } else { + this._hilite = hilite; + } + this._changed(); + return this; + }, + + getCanvasStyle: function(ctx) { + var gradient; + if (this.gradient.type === 'linear') { + gradient = ctx.createLinearGradient(this._origin.x, this._origin.y, + this._destination.x, this._destination.y); + } else { + var origin = this._hilite || this._origin; + gradient = ctx.createRadialGradient(origin.x, origin.y, + 0, this._origin.x, this._origin.y, this._radius); + } + for (var i = 0, l = this.gradient._stops.length; i < l; i++) { + var stop = this.gradient._stops[i]; + gradient.addColorStop(stop._rampPoint, stop._color.toCssString()); + } + return gradient; + }, + + equals: function(color) { + return color == this || color && color._colorType === this._colorType + && this.gradient.equals(color.gradient) + && this._origin.equals(color._origin) + && this._destination.equals(color._destination); + }, + + transform: function(matrix) { + matrix._transformPoint(this._origin, this._origin, true); + matrix._transformPoint(this._destination, this._destination, true); + if (this._hilite) + matrix._transformPoint(this._hilite, this._hilite, true); + this._radius = this._destination.getDistance(this._origin); + } +}); + +var Gradient = this.Gradient = Base.extend({ + initialize: function(stops, type) { + this.setStops(stops || ['white', 'black']); + this.type = type || 'linear'; + }, + + _changed: function() { + for (var i = 0, l = this._owners && this._owners.length; i < l; i++) + this._owners[i]._changed(); + }, + + _addOwner: function(color) { + if (!this._owners) + this._owners = []; + this._owners.push(color); + }, + + _removeOwner: function(color) { + var index = this._owners ? this._owners.indexOf(color) : -1; + if (index != -1) { + this._owners.splice(index, 1); + if (this._owners.length == 0) + delete this._owners; + } + }, + + clone: function() { + var stops = []; + for (var i = 0, l = this._stops.length; i < l; i++) + stops[i] = this._stops[i].clone(); + return new Gradient(stops, this.type); + }, + + getStops: function() { + return this._stops; + }, + + setStops: function(stops) { + if (this.stops) { + for (var i = 0, l = this._stops.length; i < l; i++) { + this._stops[i]._removeOwner(this); + } + } + if (stops.length < 2) + throw new Error( + 'Gradient stop list needs to contain at least two stops.'); + this._stops = GradientStop.readAll(stops); + for (var i = 0, l = this._stops.length; i < l; i++) { + var stop = this._stops[i]; + stop._addOwner(this); + if (stop._defaultRamp) + stop.setRampPoint(i / (l - 1)); + } + this._changed(); + }, + + equals: function(gradient) { + if (gradient.type != this.type) + return false; + if (this._stops.length == gradient._stops.length) { + for (var i = 0, l = this._stops.length; i < l; i++) { + if (!this._stops[i].equals(gradient._stops[i])) + return false; + } + return true; + } + return false; + } +}); + +var GradientStop = this.GradientStop = Base.extend({ + initialize: function(arg0, arg1) { + if (arg1 === undefined && Array.isArray(arg0)) { + this.setColor(arg0[0]); + this.setRampPoint(arg0[1]); + } else if (arg0.color) { + this.setColor(arg0.color); + this.setRampPoint(arg0.rampPoint); + } else { + this.setColor(arg0); + this.setRampPoint(arg1); + } + }, + + clone: function() { + return new GradientStop(this._color.clone(), this._rampPoint); + }, + + _changed: function() { + for (var i = 0, l = this._owners && this._owners.length; i < l; i++) + this._owners[i]._changed(Change.STYLE); + }, + + _addOwner: function(gradient) { + if (!this._owners) + this._owners = []; + this._owners.push(gradient); + }, + + _removeOwner: function(gradient) { + var index = this._owners ? this._owners.indexOf(gradient) : -1; + if (index != -1) { + this._owners.splice(index, 1); + if (this._owners.length == 0) + delete this._owners; + } + }, + + getRampPoint: function() { + return this._rampPoint; + }, + + setRampPoint: function(rampPoint) { + this._defaultRamp = rampPoint == null; + this._rampPoint = rampPoint || 0; + this._changed(); + }, + + getColor: function() { + return this._color; + }, + + setColor: function(color) { + if (this._color) + this._color._removeOwner(this); + this._color = Color.read(arguments); + this._color._addOwner(this); + this._changed(); + }, + + equals: function(stop) { + return stop == this || stop instanceof GradientStop + && this._color.equals(stop._color) + && this._rampPoint == stop._rampPoint; + } +}); + +var DomElement = { + getBounds: function(el, viewport) { + var rect = el.getBoundingClientRect(), + doc = el.ownerDocument, + body = doc.body, + docEl = doc.documentElement, + x = rect.left - (docEl.clientLeft || body.clientLeft || 0), + y = rect.top - (docEl.clientTop || body.clientTop || 0); + if (!viewport) { + var win = DomElement.getViewport(doc); + x += win.pageXOffset || docEl.scrollLeft || body.scrollLeft; + y += win.pageYOffset || docEl.scrollTop || body.scrollTop; + } + return new Rectangle(x, y, rect.width, rect.height); + }, + + getOffset: function(el, viewport) { + return this.getBounds(el, viewport).getPoint(); + }, + + getSize: function(el) { + return this.getBounds(el, true).getSize(); + }, + + isInvisible: function(el) { + return this.getSize(el).equals([0, 0]); + }, + + isVisible: function(el) { + return !this.isInvisible(el) && this.getViewportBounds(el).intersects( + this.getBounds(el, true)); + }, + + getViewport: function(doc) { + return doc.defaultView || doc.parentWindow; + }, + + getViewportBounds: function(el) { + var doc = el.ownerDocument, + view = this.getViewport(doc), + body = doc.getElementsByTagName( + doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; + return Rectangle.create(0, 0, + view.innerWidth || body.clientWidth, + view.innerHeight || body.clientHeight + ); + }, + + getComputedStyle: function(el, name) { + if (el.currentStyle) + return el.currentStyle[Base.camelize(name)]; + var style = this.getViewport(el.ownerDocument) + .getComputedStyle(el, null); + return style ? style.getPropertyValue(Base.hyphenate(name)) : null; + } +}; + +var DomEvent = { + add: function(el, events) { + for (var type in events) { + var func = events[type]; + if (el.addEventListener) { + el.addEventListener(type, func, false); + } else if (el.attachEvent) { + el.attachEvent('on' + type, func.bound = function() { + func.call(el, window.event); + }); + } + } + }, + + remove: function(el, events) { + for (var type in events) { + var func = events[type]; + if (el.removeEventListener) { + el.removeEventListener(type, func, false); + } else if (el.detachEvent) { + el.detachEvent('on' + type, func.bound); + } + } + }, + + getPoint: function(event) { + var pos = event.targetTouches + ? event.targetTouches.length + ? event.targetTouches[0] + : event.changedTouches[0] + : event; + return Point.create( + pos.pageX || pos.clientX + document.documentElement.scrollLeft, + pos.pageY || pos.clientY + document.documentElement.scrollTop + ); + }, + + getTarget: function(event) { + return event.target || event.srcElement; + }, + + getOffset: function(event, target) { + return DomEvent.getPoint(event).subtract(DomElement.getOffset( + target || DomEvent.getTarget(event))); + }, + + preventDefault: function(event) { + if (event.preventDefault) { + event.preventDefault(); + } else { + event.returnValue = false; + } + }, + + stopPropagation: function(event) { + if (event.stopPropagation) { + event.stopPropagation(); + } else { + event.cancelBubble = true; + } + }, + + stop: function(event) { + DomEvent.stopPropagation(event); + DomEvent.preventDefault(event); + } +}; + +DomEvent.requestAnimationFrame = new function() { + var part = 'equestAnimationFrame', + request = window['r' + part] || window['webkitR' + part] + || window['mozR' + part] || window['oR' + part] + || window['msR' + part]; + if (request) { + request(function(time) { + if (time == undefined) + request = null; + }); + } + + var callbacks = [], + focused = true, + timer; + + DomEvent.add(window, { + focus: function() { + focused = true; + }, + blur: function() { + focused = false; + } + }); + + return function(callback, element) { + if (request) + return request(callback, element); + callbacks.push([callback, element]); + if (timer) + return; + timer = window.setInterval(function() { + for (var i = callbacks.length - 1; i >= 0; i--) { + var entry = callbacks[i], + func = entry[0], + el = entry[1]; + if (!el || (PaperScript.getAttribute(el, 'keepalive') == 'true' + || focused) && DomElement.isVisible(el)) { + callbacks.splice(i, 1); + func(Date.now()); + } + } + }, 1000 / 60); + }; +}; + +var View = this.View = Base.extend(Callback, { + _events: { + onFrame: { + install: function() { + var that = this, + requested = false, + before, + time = 0, + count = 0; + this._onFrameCallback = function(param, dontRequest) { + requested = false; + if (!that._onFrameCallback) + return; + paper = that._scope; + if (!dontRequest) { + requested = true; + DomEvent.requestAnimationFrame(that._onFrameCallback, + that._element); + } + var now = Date.now() / 1000, + delta = before ? now - before : 0; + that.fire('frame', Base.merge({ + delta: delta, + time: time += delta, + count: count++ + })); + before = now; + if (that._stats) + that._stats.update(); + that.draw(true); + }; + if (!requested) + this._onFrameCallback(); + }, + + uninstall: function() { + delete this._onFrameCallback; + } + }, + + onResize: {} + }, + + initialize: function(element) { + this._scope = paper; + this._project = paper.project; + this._element = element; + var size; + this._id = element.getAttribute('id'); + if (this._id == null) + element.setAttribute('id', this._id = 'view-' + View._id++); + DomEvent.add(element, this._handlers); + if (PaperScript.hasAttribute(element, 'resize')) { + var offset = DomElement.getOffset(element, true), + that = this; + size = DomElement.getViewportBounds(element) + .getSize().subtract(offset); + element.width = size.width; + element.height = size.height; + DomEvent.add(window, { + resize: function(event) { + if (!DomElement.isInvisible(element)) + offset = DomElement.getOffset(element, true); + that.setViewSize(DomElement.getViewportBounds(element) + .getSize().subtract(offset)); + } + }); + } else { + size = DomElement.isInvisible(element) + ? Size.create(parseInt(element.getAttribute('width')), + parseInt(element.getAttribute('height'))) + : DomElement.getSize(element); + } + if (PaperScript.hasAttribute(element, 'stats')) { + this._stats = new Stats(); + var stats = this._stats.domElement, + style = stats.style, + offset = DomElement.getOffset(element); + style.position = 'absolute'; + style.left = offset.x + 'px'; + style.top = offset.y + 'px'; + document.body.appendChild(stats); + } + View._views.push(this); + View._viewsById[this._id] = this; + this._viewSize = LinkedSize.create(this, 'setViewSize', + size.width, size.height); + this._matrix = new Matrix(); + this._zoom = 1; + if (!View._focused) + View._focused = this; + }, + + remove: function() { + if (!this._project) + return false; + if (View._focused == this) + View._focused = null; + View._views.splice(View._views.indexOf(this), 1); + delete View._viewsById[this._id]; + if (this._project.view == this) + this._project.view = null; + DomEvent.remove(this._element, this._handlers); + this._element = this._project = null; + this.detach('frame'); + return true; + }, + + _redraw: function() { + this._redrawNeeded = true; + if (this._onFrameCallback) { + this._onFrameCallback(0, true); + } else { + this.draw(); + } + }, + + _transform: function(matrix) { + this._matrix.preConcatenate(matrix); + this._bounds = null; + this._inverse = null; + this._redraw(); + }, + + getElement: function() { + return this._element; + }, + + getViewSize: function() { + return this._viewSize; + }, + + setViewSize: function(size) { + size = Size.read(arguments); + var delta = size.subtract(this._viewSize); + if (delta.isZero()) + return; + this._element.width = size.width; + this._element.height = size.height; + this._viewSize.set(size.width, size.height, true); + this._bounds = null; + this._redrawNeeded = true; + this.fire('resize', { + size: size, + delta: delta + }); + this._redraw(); + }, + + getBounds: function() { + if (!this._bounds) + this._bounds = this._getInverse()._transformBounds( + new Rectangle(new Point(), this._viewSize)); + return this._bounds; + }, + + getSize: function() { + return this.getBounds().getSize(); + }, + + getCenter: function() { + return this.getBounds().getCenter(); + }, + + setCenter: function(center) { + this.scrollBy(Point.read(arguments).subtract(this.getCenter())); + }, + + getZoom: function() { + return this._zoom; + }, + + setZoom: function(zoom) { + this._transform(new Matrix().scale(zoom / this._zoom, + this.getCenter())); + this._zoom = zoom; + }, + + isVisible: function() { + return DomElement.isVisible(this._element); + }, + + scrollBy: function(point) { + this._transform(new Matrix().translate(Point.read(arguments).negate())); + }, + + projectToView: function(point) { + return this._matrix._transformPoint(Point.read(arguments)); + }, + + viewToProject: function(point) { + return this._getInverse()._transformPoint(Point.read(arguments)); + }, + + _getInverse: function() { + if (!this._inverse) + this._inverse = this._matrix.createInverse(); + return this._inverse; + } + +}, { + statics: { + _views: [], + _viewsById: {}, + _id: 0, + + create: function(element) { + if (typeof element === 'string') + element = document.getElementById(element); + return new CanvasView(element); + } + } +}, new function() { + var tool, + curPoint, + tempFocus, + dragging = false; + + function getView(event) { + return View._viewsById[DomEvent.getTarget(event).getAttribute('id')]; + } + + function viewToProject(view, event) { + return view.viewToProject(DomEvent.getOffset(event, view._element)); + } + + function updateFocus() { + if (!View._focused || !View._focused.isVisible()) { + for (var i = 0, l = View._views.length; i < l; i++) { + var view = View._views[i]; + if (view && view.isVisible()) { + View._focused = tempFocus = view; + break; + } + } + } + } + + function mousedown(event) { + var view = View._focused = getView(event); + curPoint = viewToProject(view, event); + dragging = true; + if (view._onMouseDown) + view._onMouseDown(event, curPoint); + if (tool = view._scope.tool) + tool._onHandleEvent('mousedown', curPoint, event); + view.draw(true); + } + + function mousemove(event) { + var view; + if (!dragging) { + view = getView(event); + if (view) { + View._focused = tempFocus = view; + } else if (tempFocus && tempFocus == View._focused) { + View._focused = null; + updateFocus(); + } + } + if (!(view = view || View._focused)) + return; + var point = event && viewToProject(view, event); + if (view._onMouseMove) + view._onMouseMove(event, point); + if (tool = view._scope.tool) { + var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove); + if (dragging && !onlyMove) { + if ((curPoint = point || curPoint) + && tool._onHandleEvent('mousedrag', curPoint, event)) + DomEvent.stop(event); + } else if ((!dragging || onlyMove) + && tool._onHandleEvent('mousemove', point, event)) { + DomEvent.stop(event); + } + } + view.draw(true); + } + + function mouseup(event) { + var view = View._focused; + if (!view || !dragging) + return; + var point = viewToProject(view, event); + curPoint = null; + dragging = false; + if (view._onMouseUp) + view._onMouseUp(event, point); + if (tool && tool._onHandleEvent('mouseup', point, event)) + DomEvent.stop(event); + view.draw(true); + } + + function selectstart(event) { + if (dragging) + DomEvent.stop(event); + } + + DomEvent.add(document, { + mousemove: mousemove, + mouseup: mouseup, + touchmove: mousemove, + touchend: mouseup, + selectstart: selectstart, + scroll: updateFocus + }); + + DomEvent.add(window, { + load: updateFocus + }); + + return { + _handlers: { + mousedown: mousedown, + touchstart: mousedown, + selectstart: selectstart + }, + + statics: { + updateFocus: updateFocus + } + }; +}); + +var CanvasView = View.extend({ + initialize: function(canvas) { + if (!(canvas instanceof HTMLCanvasElement)) { + var size = Size.read(arguments, 1); + if (size.isZero()) + size = Size.create(1024, 768); + canvas = CanvasProvider.getCanvas(size); + } + this._context = canvas.getContext('2d'); + this._eventCounters = {}; + this.base(canvas); + }, + + draw: function(checkRedraw) { + if (checkRedraw && !this._redrawNeeded) + return false; + var ctx = this._context, + size = this._viewSize; + ctx.clearRect(0, 0, size._width + 1, size._height + 1); + this._project.draw(ctx, this._matrix); + this._redrawNeeded = false; + return true; + } +}, new function() { + + var hitOptions = { + fill: true, + stroke: true, + tolerance: 0 + }; + + var downPoint, + lastPoint, + overPoint, + downItem, + overItem, + hasDrag, + doubleClick, + clickTime; + + function callEvent(type, event, point, target, lastPoint, bubble) { + var item = target, + mouseEvent, + called = false; + while (item) { + if (item.responds(type)) { + if (!mouseEvent) + mouseEvent = new MouseEvent(type, event, point, target, + lastPoint ? point.subtract(lastPoint) : null); + called = item.fire(type, mouseEvent) || called; + if (called && (!bubble || mouseEvent._stopped)) + break; + } + item = item.getParent(); + } + return called; + } + + function handleEvent(view, type, event, point, lastPoint) { + if (view._eventCounters[type]) { + var hit = view._project.hitTest(point, hitOptions), + item = hit && hit.item; + if (item) { + if (type == 'mousemove' && item != overItem) + lastPoint = point; + if (type != 'mousemove' || !hasDrag) + callEvent(type, event, point, item, lastPoint); + return item; + } + } + } + + return { + _onMouseDown: function(event, point) { + var item = handleEvent(this, 'mousedown', event, point); + doubleClick = downItem == item && Date.now() - clickTime < 300; + downItem = item; + downPoint = lastPoint = overPoint = point; + hasDrag = downItem && downItem.responds('mousedrag'); + }, + + _onMouseUp: function(event, point) { + var item = handleEvent(this, 'mouseup', event, point); + if (hasDrag) { + if (lastPoint && !lastPoint.equals(point)) + callEvent('mousedrag', event, point, downItem, lastPoint); + if (item != downItem) { + overPoint = point; + callEvent('mousemove', event, point, item, overPoint); + } + } + if (item == downItem) { + clickTime = Date.now(); + callEvent(doubleClick ? 'doubleclick' : 'click', event, + downPoint, overItem); + doubleClick = false; + } + downItem = null; + hasDrag = false; + }, + + _onMouseMove: function(event, point) { + if (downItem) + callEvent('mousedrag', event, point, downItem, lastPoint); + var item = handleEvent(this, 'mousemove', event, point, overPoint); + lastPoint = overPoint = point; + if (item != overItem) { + callEvent('mouseleave', event, point, overItem); + overItem = item; + callEvent('mouseenter', event, point, item); + } + } + }; +}); + +var Event = this.Event = Base.extend({ + initialize: function(event) { + this.event = event; + }, + + preventDefault: function() { + this._prevented = true; + DomEvent.preventDefault(this.event); + return this; + }, + + stopPropagation: function() { + this._stopped = true; + DomEvent.stopPropagation(this.event); + return this; + }, + + stop: function() { + return this.stopPropagation().preventDefault(); + }, + + getModifiers: function() { + return Key.modifiers; + } +}); + +var KeyEvent = this.KeyEvent = Event.extend({ + initialize: function(down, key, character, event) { + this.base(event); + this.type = down ? 'keydown' : 'keyup'; + this.key = key; + this.character = character; + }, + + toString: function() { + return '{ type: ' + this.type + + ', key: ' + this.key + + ', character: ' + this.character + + ', modifiers: ' + this.getModifiers() + + ' }'; + } +}); + +var Key = this.Key = new function() { + + var keys = { + 8: 'backspace', + 13: 'enter', + 16: 'shift', + 17: 'control', + 18: 'option', + 19: 'pause', + 20: 'caps-lock', + 27: 'escape', + 32: 'space', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 46: 'delete', + 91: 'command', + 93: 'command', + 224: 'command' + }, + + modifiers = Base.merge({ + shift: false, + control: false, + option: false, + command: false, + capsLock: false + }), + + charCodeMap = {}, + keyMap = {}, + downCode; + + function handleKey(down, keyCode, charCode, event) { + var character = String.fromCharCode(charCode), + key = keys[keyCode] || character.toLowerCase(), + type = down ? 'keydown' : 'keyup', + view = View._focused, + scope = view && view.isVisible() && view._scope, + tool = scope && scope.tool; + keyMap[key] = down; + if (tool && tool.responds(type)) { + tool.fire(type, new KeyEvent(down, key, character, event)); + if (view) + view.draw(true); + } + } + + DomEvent.add(document, { + keydown: function(event) { + var code = event.which || event.keyCode; + var key = keys[code], name; + if (key) { + if ((name = Base.camelize(key)) in modifiers) + modifiers[name] = true; + charCodeMap[code] = 0; + handleKey(true, code, null, event); + } else { + downCode = code; + } + }, + + keypress: function(event) { + if (downCode != null) { + var code = event.which || event.keyCode; + charCodeMap[downCode] = code; + handleKey(true, downCode, code, event); + downCode = null; + } + }, + + keyup: function(event) { + var code = event.which || event.keyCode, + key = keys[code], name; + if (key && (name = Base.camelize(key)) in modifiers) + modifiers[name] = false; + if (charCodeMap[code] != null) { + handleKey(false, code, charCodeMap[code], event); + delete charCodeMap[code]; + } + } + }); + + return { + modifiers: modifiers, + + isDown: function(key) { + return !!keyMap[key]; + } + }; +}; + +var MouseEvent = this.MouseEvent = Event.extend({ + initialize: function(type, event, point, target, delta) { + this.base(event); + this.type = type; + this.point = point; + this.target = target; + this.delta = delta; + }, + + toString: function() { + return '{ type: ' + this.type + + ', point: ' + this.point + + ', target: ' + this.target + + (this.delta ? ', delta: ' + this.delta : '') + + ', modifiers: ' + this.getModifiers() + + ' }'; + } +}); + +var ToolEvent = this.ToolEvent = Event.extend({ + initialize: function(tool, type, event) { + this.tool = tool; + this.type = type; + this.event = event; + }, + + _choosePoint: function(point, toolPoint) { + return point ? point : toolPoint ? toolPoint.clone() : null; + }, + + getPoint: function() { + return this._choosePoint(this._point, this.tool._point); + }, + + setPoint: function(point) { + this._point = point; + }, + + getLastPoint: function() { + return this._choosePoint(this._lastPoint, this.tool._lastPoint); + }, + + setLastPoint: function(lastPoint) { + this._lastPoint = lastPoint; + }, + + getDownPoint: function() { + return this._choosePoint(this._downPoint, this.tool._downPoint); + }, + + setDownPoint: function(downPoint) { + this._downPoint = downPoint; + }, + + getMiddlePoint: function() { + if (!this._middlePoint && this.tool._lastPoint) { + return this.tool._point.add(this.tool._lastPoint).divide(2); + } + return this.middlePoint; + }, + + setMiddlePoint: function(middlePoint) { + this._middlePoint = middlePoint; + }, + + getDelta: function() { + return !this._delta && this.tool._lastPoint + ? this.tool._point.subtract(this.tool._lastPoint) + : this._delta; + }, + + setDelta: function(delta) { + this._delta = delta; + }, + + getCount: function() { + return /^mouse(down|up)$/.test(this.type) + ? this.tool._downCount + : this.tool._count; + }, + + setCount: function(count) { + this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] + = count; + }, + + getItem: function() { + if (!this._item) { + var result = this.tool._scope.project.hitTest(this.getPoint()); + if (result) { + var item = result.item, + parent = item._parent; + while ((parent instanceof Group && !(parent instanceof Layer)) + || parent instanceof CompoundPath) { + item = parent; + parent = parent._parent; + } + this._item = item; + } + } + return this._item; + }, + setItem: function(item) { + this._item = item; + }, + + toString: function() { + return '{ type: ' + this.type + + ', point: ' + this.getPoint() + + ', count: ' + this.getCount() + + ', modifiers: ' + this.getModifiers() + + ' }'; + } +}); + +var Tool = this.Tool = PaperScopeItem.extend(Callback, { + _list: 'tools', + _reference: '_tool', + _events: [ 'onEditOptions', 'onSelect', 'onDeselect', 'onReselect', + 'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove', + 'onKeyDown', 'onKeyUp' ], + + initialize: function() { + this.base(); + this._firstMove = true; + this._count = 0; + this._downCount = 0; + }, + + getMinDistance: function() { + return this._minDistance; + }, + + setMinDistance: function(minDistance) { + this._minDistance = minDistance; + if (this._minDistance != null && this._maxDistance != null + && this._minDistance > this._maxDistance) { + this._maxDistance = this._minDistance; + } + }, + + getMaxDistance: function() { + return this._maxDistance; + }, + + setMaxDistance: function(maxDistance) { + this._maxDistance = maxDistance; + if (this._minDistance != null && this._maxDistance != null + && this._maxDistance < this._minDistance) { + this._minDistance = maxDistance; + } + }, + + getFixedDistance: function() { + return this._minDistance == this._maxDistance + ? this._minDistance : null; + }, + + setFixedDistance: function(distance) { + this._minDistance = distance; + this._maxDistance = distance; + }, + + _updateEvent: function(type, pt, minDistance, maxDistance, start, + needsChange, matchMaxDistance) { + if (!start) { + if (minDistance != null || maxDistance != null) { + var minDist = minDistance != null ? minDistance : 0; + var vector = pt.subtract(this._point); + var distance = vector.getLength(); + if (distance < minDist) + return false; + var maxDist = maxDistance != null ? maxDistance : 0; + if (maxDist != 0) { + if (distance > maxDist) { + pt = this._point.add(vector.normalize(maxDist)); + } else if (matchMaxDistance) { + return false; + } + } + } + if (needsChange && pt.equals(this._point)) + return false; + } + this._lastPoint = start && type == 'mousemove' ? pt : this._point; + this._point = pt; + switch (type) { + case 'mousedown': + this._lastPoint = this._downPoint; + this._downPoint = this._point; + this._downCount++; + break; + case 'mouseup': + this._lastPoint = this._downPoint; + break; + } + this._count = start ? 0 : this._count + 1; + return true; + }, + + _onHandleEvent: function(type, pt, event) { + paper = this._scope; + var sets = Tool._removeSets; + if (sets) { + if (type === 'mouseup') + sets.mousedrag = null; + var set = sets[type]; + if (set) { + for (var id in set) { + var item = set[id]; + for (var key in sets) { + var other = sets[key]; + if (other && other != set && other[item._id]) + delete other[item._id]; + } + item.remove(); + } + sets[type] = null; + } + } + var called = false; + switch (type) { + case 'mousedown': + this._updateEvent(type, pt, null, null, true, false, false); + if (this.responds(type)) + called = this.fire(type, new ToolEvent(this, type, event)); + break; + case 'mousedrag': + var needsChange = false, + matchMaxDistance = false; + while (this._updateEvent(type, pt, this.minDistance, + this.maxDistance, false, needsChange, matchMaxDistance)) { + if (this.responds(type)) + called = this.fire(type, new ToolEvent(this, type, event)); + needsChange = true; + matchMaxDistance = true; + } + break; + case 'mouseup': + if ((this._point.x != pt.x || this._point.y != pt.y) + && this._updateEvent('mousedrag', pt, this.minDistance, + this.maxDistance, false, false, false)) { + if (this.responds('mousedrag')) + called = this.fire('mousedrag', + new ToolEvent(this, type, event)); + } + this._updateEvent(type, pt, null, this.maxDistance, false, + false, false); + if (this.responds(type)) + called = this.fire(type, new ToolEvent(this, type, event)); + this._updateEvent(type, pt, null, null, true, false, false); + this._firstMove = true; + break; + case 'mousemove': + while (this._updateEvent(type, pt, this.minDistance, + this.maxDistance, this._firstMove, true, false)) { + if (this.responds(type)) + called = this.fire(type, new ToolEvent(this, type, event)); + this._firstMove = false; + } + break; + } + return called; + } + +}); + +var CanvasProvider = { + canvases: [], + getCanvas: function(size) { + if (this.canvases.length) { + var canvas = this.canvases.pop(); + if ((canvas.width != size.width) + || (canvas.height != size.height)) { + canvas.width = size.width; + canvas.height = size.height; + } else { + canvas.getContext('2d').clearRect(0, 0, + size.width + 1, size.height + 1); + } + return canvas; + } else { + var canvas = document.createElement('canvas'); + canvas.width = size.width; + canvas.height = size.height; + return canvas; + } + }, + + returnCanvas: function(canvas) { + this.canvases.push(canvas); + } +}; + +var Numerical = new function() { + + var abscissas = [ + [ 0.5773502691896257645091488], + [0,0.7745966692414833770358531], + [ 0.3399810435848562648026658,0.8611363115940525752239465], + [0,0.5384693101056830910363144,0.9061798459386639927976269], + [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], + [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], + [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], + [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], + [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], + [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], + [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], + [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], + [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], + [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], + [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] + ]; + + var weights = [ + [1], + [0.8888888888888888888888889,0.5555555555555555555555556], + [0.6521451548625461426269361,0.3478548451374538573730639], + [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], + [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], + [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], + [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], + [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], + [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], + [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], + [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], + [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], + [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], + [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], + [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] + ]; + + var abs = Math.abs, + sqrt = Math.sqrt, + cos = Math.cos, + PI = Math.PI; + + return { + TOLERANCE: 10e-6, + EPSILON: 10e-12, + + integrate: function(f, a, b, n) { + var x = abscissas[n - 2], + w = weights[n - 2], + A = 0.5 * (b - a), + B = A + a, + i = 0, + m = (n + 1) >> 1, + sum = n & 1 ? w[i++] * f(B) : 0; + while (i < m) { + var Ax = A * x[i]; + sum += w[i++] * (f(B + Ax) + f(B - Ax)); + } + return A * sum; + }, + + findRoot: function(f, df, x, a, b, n, tolerance) { + for (var i = 0; i < n; i++) { + var fx = f(x), + dx = fx / df(x); + if (abs(dx) < tolerance) + return x; + var nx = x - dx; + if (fx > 0) { + b = x; + x = nx <= a ? 0.5 * (a + b) : nx; + } else { + a = x; + x = nx >= b ? 0.5 * (a + b) : nx; + } + } + }, + + solveQuadratic: function(a, b, c, roots, tolerance) { + if (abs(a) < tolerance) { + if (abs(b) >= tolerance) { + roots[0] = -c / b; + return 1; + } + if (abs(c) < tolerance) + return -1; + return 0; + } + var q = b * b - 4 * a * c; + if (q < 0) + return 0; + q = sqrt(q); + if (b < 0) + q = -q; + q = (b + q) * -0.5; + var n = 0; + if (abs(q) >= tolerance) + roots[n++] = c / q; + if (abs(a) >= tolerance) + roots[n++] = q / a; + return n; + }, + + solveCubic: function(a, b, c, d, roots, tolerance) { + if (abs(a) < tolerance) + return Numerical.solveQuadratic(b, c, d, roots, tolerance); + b /= a; + c /= a; + d /= a; + var Q = (b * b - 3 * c) / 9, + R = (2 * b * b * b - 9 * b * c + 27 * d) / 54, + Q3 = Q * Q * Q, + R2 = R * R; + b /= 3; + if (R2 < Q3) { + var theta = Math.acos(R / sqrt(Q3)), + q = -2 * sqrt(Q); + roots[0] = q * cos(theta / 3) - b; + roots[1] = q * cos((theta + 2 * PI) / 3) - b; + roots[2] = q * cos((theta - 2 * PI) / 3) - b; + return 3; + } else { + var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3); + if (R < 0) A = -A; + var B = (abs(A) < tolerance) ? 0 : Q / A; + roots[0] = (A + B) - b; + return 1; + } + return 0; + } + }; +}; + +var BlendMode = { + process: function(blendMode, srcContext, dstContext, alpha, offset) { + var srcCanvas = srcContext.canvas, + dstData = dstContext.getImageData(offset.x, offset.y, + srcCanvas.width, srcCanvas.height), + dst = dstData.data, + src = srcContext.getImageData(0, 0, + srcCanvas.width, srcCanvas.height).data, + min = Math.min, + max = Math.max, + abs = Math.abs, + sr, sg, sb, sa, + br, bg, bb, ba, + dr, dg, db; + + function getLum(r, g, b) { + return 0.2989 * r + 0.587 * g + 0.114 * b; + } + + function setLum(r, g, b, l) { + var d = l - getLum(r, g, b); + dr = r + d; + dg = g + d; + db = b + d; + var l = getLum(dr, dg, db), + mn = min(dr, dg, db), + mx = max(dr, dg, db); + if (mn < 0) { + var lmn = l - mn; + dr = l + (dr - l) * l / lmn; + dg = l + (dg - l) * l / lmn; + db = l + (db - l) * l / lmn; + } + if (mx > 255) { + var ln = 255 - l, mxl = mx - l; + dr = l + (dr - l) * ln / mxl; + dg = l + (dg - l) * ln / mxl; + db = l + (db - l) * ln / mxl; + } + } + + function getSat(r, g, b) { + return max(r, g, b) - min(r, g, b); + } + + function setSat(r, g, b, s) { + var col = [r, g, b], + mx = max(r, g, b), + mn = min(r, g, b), + md; + mn = mn == r ? 0 : mn == g ? 1 : 2; + mx = mx == r ? 0 : mx == g ? 1 : 2; + md = min(mn, mx) == 0 ? max(mn, mx) == 1 ? 2 : 1 : 0; + if (col[mx] > col[mn]) { + col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); + col[mx] = s; + } else { + col[md] = col[mx] = 0; + } + col[mn] = 0; + dr = col[0]; + dg = col[1]; + db = col[2]; + } + + var modes = { + multiply: function() { + dr = br * sr / 255; + dg = bg * sg / 255; + db = bb * sb / 255; + }, + + screen: function() { + dr = 255 - (255 - br) * (255 - sr) / 255; + dg = 255 - (255 - bg) * (255 - sg) / 255; + db = 255 - (255 - bb) * (255 - sb) / 255; + }, + + overlay: function() { + dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; + dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; + db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; + }, + + 'soft-light': function() { + var t = sr * br / 255; + dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; + t = sg * bg / 255; + dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; + t = sb * bb / 255; + db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; + }, + + 'hard-light': function() { + dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; + dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; + db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; + }, + + 'color-dodge': function() { + dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr)); + dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg)); + db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb)); + }, + + 'color-burn': function() { + dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0); + dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0); + db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0); + }, + + darken: function() { + dr = br < sr ? br : sr; + dg = bg < sg ? bg : sg; + db = bb < sb ? bb : sb; + }, + + lighten: function() { + dr = br > sr ? br : sr; + dg = bg > sg ? bg : sg; + db = bb > sb ? bb : sb; + }, + + difference: function() { + dr = br - sr; + if (dr < 0) + dr = -dr; + dg = bg - sg; + if (dg < 0) + dg = -dg; + db = bb - sb; + if (db < 0) + db = -db; + }, + + exclusion: function() { + dr = br + sr * (255 - br - br) / 255; + dg = bg + sg * (255 - bg - bg) / 255; + db = bb + sb * (255 - bb - bb) / 255; + }, + + hue: function() { + setSat(sr, sg, sb, getSat(br, bg, bb)); + setLum(dr, dg, db, getLum(br, bg, bb)); + }, + + saturation: function() { + setSat(br, bg, bb, getSat(sr, sg, sb)); + setLum(dr, dg, db, getLum(br, bg, bb)); + }, + + luminosity: function() { + setLum(br, bg, bb, getLum(sr, sg, sb)); + }, + + color: function() { + setLum(sr, sg, sb, getLum(br, bg, bb)); + }, + + add: function() { + dr = min(br + sr, 255); + dg = min(bg + sg, 255); + db = min(bb + sb, 255); + }, + + subtract: function() { + dr = max(br - sr, 0); + dg = max(bg - sg, 0); + db = max(bb - sb, 0); + }, + + average: function() { + dr = (br + sr) / 2; + dg = (bg + sg) / 2; + db = (bb + sb) / 2; + }, + + negation: function() { + dr = 255 - abs(255 - sr - br); + dg = 255 - abs(255 - sg - bg); + db = 255 - abs(255 - sb - bb); + } + }; + + var process = modes[blendMode]; + if (!process) + return; + + for (var i = 0, l = dst.length; i < l; i += 4) { + sr = src[i]; + br = dst[i]; + sg = src[i + 1]; + bg = dst[i + 1]; + sb = src[i + 2]; + bb = dst[i + 2]; + sa = src[i + 3]; + ba = dst[i + 3]; + process(); + var a1 = sa * alpha / 255, + a2 = 1 - a1; + dst[i] = a1 * dr + a2 * br; + dst[i + 1] = a1 * dg + a2 * bg; + dst[i + 2] = a1 * db + a2 * bb; + dst[i + 3] = sa * alpha + a2 * ba; + } + dstContext.putImageData(dstData, offset.x, offset.y); + } +}; + +var PaperScript = this.PaperScript = new function() { +var parse_js=new function(){function W(a,b,c){var d=[];for(var e=0;e0,g=j(function(){return h(a[0]?k(["case",z(a[0])+":"]):"default:")},.5)+(f?e+j(function(){return u(a[1]).join(e)}):"");!c&&f&&d0?h(a):a}).join(e)},block:w,"var":function(a){return"var "+l(W(a,x))+";"},"const":function(a){return"const "+l(W(a,x))+";"},"try":function(a,b,c){var d=["try",w(a)];b&&d.push("catch","("+b[0]+")",w(b[1])),c&&d.push("finally",w(c));return k(d)},"throw":function(a){return k(["throw",z(a)])+";"},"new":function(a,b){b=b.length>0?"("+l(W(b,z))+")":"";return k(["new",m(a,"seq","binary","conditional","assign",function(a){var b=N(),c={};try{b.with_walkers({call:function(){throw c},"function":function(){return this}},function(){b.walk(a)})}catch(d){if(d===c)return!0;throw d}})+b])},"switch":function(a,b){return k(["switch","("+z(a)+")",v(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+g(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+g(a));return b+";"},conditional:function(a,b,c){return k([m(a,"assign","seq","conditional"),"?",m(b,"seq"),":",m(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return k([z(b),a,m(c,"seq")])},dot:function(a){var b=z(a),c=1;a[0]=="num"?/\./.test(a[1])||(b+="."):o(a)&&(b="("+b+")");while(cB[b[1]])d="("+d+")";if(L(c[0],["assign","conditional","seq"])||c[0]=="binary"&&B[a]>=B[c[1]]&&(c[1]!=a||!L(a,["&&","||","*"])))e="("+e+")";return k([d,a,e])},"unary-prefix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-prefix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return a+(p(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-postfix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=z(a);o(a)&&(c="("+c+")");return c+"["+z(b)+"]"},object:function(a){return a.length==0?"{}":"{"+e+j(function(){return W(a,function(a){if(a.length==3)return h(t(a[0],a[1][2],a[1][3],a[2]));var d=a[0],e=z(a[1]);b.quote_keys?d=Q(d):(typeof d=="number"||!c&&+d+""==d)&&parseFloat(d)>=0?d=q(+d):V(d)||(d=Q(d));return h(k(c&&b.space_colon?[d,":",e]:[d+":",e]))}).join(","+e)})+e+h("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){return a.length==0?"[]":k(["[",l(W(a,function(a){return!c&&a[0]=="atom"&&a[1]=="undefined"?"":m(a,"seq")})),"]"])},stat:function(a){return z(a).replace(/;*\s*$/,";")},seq:function(){return l(W(J(arguments),z))},label:function(a,b){return k([g(a),":",z(b)])},"with":function(a,b){return k(["with","("+z(a)+")",z(b)])},atom:function(a){return g(a)}},y=[];return z(a)}function Q(a){var b=0,c=0;a=a.replace(/[\\\b\f\n\r\t\x22\x27]/g,function(a){switch(a){case"\\":return"\\\\";case"\b":return"\\b";case"\f":return"\\f";case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";case'"':++b;return'"';case"'":++c;return"'"}return a});return b>c?"'"+a.replace(/\x27/g,"\\'")+"'":'"'+a.replace(/\x22/g,'\\"')+'"'}function O(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function N(){function g(a,b){var c={},e;for(e in a)M(a,e)&&(c[e]=d[e],d[e]=a[e]);var f=b();for(e in c)M(c,e)&&(c[e]?d[e]=c[e]:delete d[e]);return f}function f(a){if(a==null)return null;try{e.push(a);var b=a[0],f=d[b];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=c[b];return f.apply(a,a.slice(1))}finally{e.pop()}}function b(a){var b=[this[0]];a!=null&&b.push(W(a,f));return b}function a(a){return[this[0],W(a,function(a){var b=[a[0]];a.length>1&&(b[1]=f(a[1]));return b})]}var c={string:function(a){return[this[0],a]},num:function(a){return[this[0],a]},name:function(a){return[this[0],a]},toplevel:function(a){return[this[0],W(a,f)]},block:b,splice:b,"var":a,"const":a,"try":function(a,b,c){return[this[0],W(a,f),b!=null?[b[0],W(b[1],f)]:null,c!=null?W(c,f):null]},"throw":function(a){return[this[0],f(a)]},"new":function(a,b){return[this[0],f(a),W(b,f)]},"switch":function(a,b){return[this[0],f(a),W(b,function(a){return[a[0]?f(a[0]):null,W(a[1],f)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],f(a),f(b),f(c)]},assign:function(a,b,c){return[this[0],a,f(b),f(c)]},dot:function(a){return[this[0],f(a)].concat(J(arguments,1))},call:function(a,b){return[this[0],f(a),W(b,f)]},"function":function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},defun:function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},"if":function(a,b,c){return[this[0],f(a),f(b),f(c)]},"for":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"for-in":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"while":function(a,b){return[this[0],f(a),f(b)]},"do":function(a,b){return[this[0],f(a),f(b)]},"return":function(a){return[this[0],f(a)]},binary:function(a,b,c){return[this[0],a,f(b),f(c)]},"unary-prefix":function(a,b){return[this[0],a,f(b)]},"unary-postfix":function(a,b){return[this[0],a,f(b)]},sub:function(a,b){return[this[0],f(a),f(b)]},object:function(a){return[this[0],W(a,function(a){return a.length==2?[a[0],f(a[1])]:[a[0],f(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],W(a,f)]},stat:function(a){return[this[0],f(a)]},seq:function(){return[this[0]].concat(W(J(arguments),f))},label:function(a,b){return[this[0],a,f(b)]},"with":function(a,b){return[this[0],f(a),f(b)]},atom:function(a){return[this[0],a]}},d={},e=[];return{walk:f,with_walkers:g,parent:function(){return e[e.length-2]},stack:function(){return e}}}function M(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function L(a,b){for(var c=b.length;--c>=0;)if(b[c]===a)return!0;return!1}function K(a){return a.split("")}function J(a,b){return Array.prototype.slice.call(a,b||0)}function I(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function G(a){var b=J(arguments,1);return function(){return a.apply(this,b.concat(J(arguments)))}}function F(a,b,c){function bk(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){var b=bg(a),c=d.token.value;if(e("operator")&&M(A,c)){if(bh(b)){g();return p("assign",A[c],b,bi(a))}i("Invalid assignment")}return b}function bh(a){if(!b)return!0;switch(a[0]){case"dot":case"sub":case"new":case"call":return!0;case"name":return a[1]!="this"}}function bg(a){var b=bf(a);if(e("operator","?")){g();var c=bj(!1);m(":");return p("conditional",b,c,bj(!1,a))}return b}function bf(a){return be(Y(!0),0,a)}function be(a,b,c){var f=e("operator")?d.token.value:null;f&&f=="in"&&c&&(f=null);var h=f!=null?B[f]:null;if(h!=null&&h>b){g();var i=be(Y(!0),h,c);return be(p("binary",f,a,i),b,c)}return a}function bd(a,b,c){(b=="++"||b=="--")&&!bh(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bc(a,b){if(e("punc",".")){g();return bc(p("dot",a,bb()),b)}if(e("punc","[")){g();return bc(p("sub",a,H(bj,G(m,"]"))),b)}if(b&&e("punc","(")){g();return bc(p("call",a,Z(")")),!0)}return b&&e("operator")&&M(z,d.token.value)?H(G(bd,"unary-postfix",d.token.value,a),g):a}function bb(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return H(d.token.value,g);default:k()}}function ba(){switch(d.token.type){case"num":case"string":return H(d.token.value,g)}return bb()}function _(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=ba();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bj(!1)])):c.push([bb(),P(!1),h])}g();return p("object",c)}function $(){return p("array",Z("]",!b,!0))}function Z(a,b,c){var d=!0,f=[];while(!e("punc",a)){d?d=!1:m(",");if(b&&e("punc",a))break;e("punc",",")&&c?f.push(["atom","undefined"]):f.push(bj(!1))}g();return f}function X(){var a=Y(!1),b;e("punc","(")?(g(),b=Z(")")):b=[];return bc(p("new",a,b),!0)}function W(){return p("const",U())}function V(a){return p("var",U(a))}function U(a){var b=[];for(;;){e("name")||k();var c=d.token.value;g(),e("operator","=")?(g(),b.push([c,bj(!1,a)])):b.push([c]);if(!e("punc",","))break;g()}return b}function T(){var a=R(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,R()]}e("keyword","finally")&&(g(),c=R()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function R(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(t());g();return a}function Q(){var a=q(),b=t(),c;e("keyword","else")&&(g(),c=t());return p("if",a,b,c)}function O(a){var b=a[0]=="var"?p("name",a[1][0]):a;g();var c=bj();m(")");return p("for-in",a,b,c,bk(t))}function N(a){m(";");var b=e("punc",";")?null:bj();m(";");var c=e("punc",")")?null:bj();m(")");return p("for",a,b,c,bk(t))}function K(){m("(");var a=null;if(!e("punc",";")){a=e("keyword","var")?(g(),V(!0)):bj(!0,!0);if(e("operator","in"))return O(a)}return N(a)}function I(a){var b;n()||(b=e("name")?d.token.value:null),b!=null?(g(),L(b,d.labels)||i("Label "+b+" without matching loop or statement")):d.in_loop==0&&i(a+" not inside a loop or switch"),o();return p(a,b)}function F(){return p("stat",H(bj,o))}function w(a){d.labels.push(a);var c=d.token,e=t();b&&!M(C,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function s(a){return c?function(){var b=d.token,c=a.apply(this,arguments);c[0]=r(c[0],b,h());return c}:a}function r(a,b,c){return a instanceof E?a:new E(a,b,c)}function q(){m("(");var a=bj();m(")");return a}function p(){return J(arguments)}function o(){e("punc",";")?g():n()||k()}function n(){return!b&&(d.token.nlb||e("eof")||e("punc","}"))}function m(a){return l("punc",a)}function l(a,b){if(e(a,b))return g();j(d.token,"Unexpected token "+d.token.type+", expected "+a)}function k(a){a==null&&(a=d.token),j(a,"Unexpected token: "+a.type+" ("+a.value+")")}function j(a,b){i(b,a.line,a.col)}function i(a,b,c,e){var f=d.input.context();u(a,b!=null?b:f.tokline,c!=null?c:f.tokcol,e!=null?e:f.tokpos)}function h(){return d.prev}function g(){d.prev=d.token,d.peeked?(d.token=d.peeked,d.peeked=null):d.token=d.input();return d.token}function f(){return d.peeked||(d.peeked=d.input())}function e(a,b){return v(d.token,a,b)}var d={input:typeof a=="string"?x(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var t=s(function(){e("operator","/")&&(d.peeked=null,d.token=d.input(!0));switch(d.token.type){case"num":case"string":case"regexp":case"operator":case"atom":return F();case"name":return v(f(),"punc",":")?w(H(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",R());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(H(d.token.value,g)){case"break":return I("break");case"continue":return I("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",H(q,o),a)}(bk(t));case"for":return K();case"function":return P(!0);case"if":return Q();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:H(bj,o));case"switch":return p("switch",q(),S());case"throw":return p("throw",H(bj,o));case"try":return T();case"var":return H(V,o);case"const":return H(W,o);case"while":return p("while",q(),bk(t));case"with":return p("with",q(),t());default:k()}}}),P=s(function(a){var b=e("name")?H(d.token.value,g):null;a&&!b&&k(),m("(");return p(a?"defun":"function",b,function(a,b){while(!e("punc",")"))a?a=!1:m(","),e("name")||k(),b.push(d.token.value),g();g();return b}(!0,[]),function(){++d.in_function;var a=d.in_loop;d.in_loop=0;var b=R();--d.in_function,d.in_loop=a;return b}())}),S=G(bk,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bj(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(t()));g();return a}),Y=s(function(a){if(e("operator","new")){g();return X()}if(e("operator")&&M(y,d.token.value))return bd("unary-prefix",H(d.token.value,g),Y(a));if(e("punc")){switch(d.token.value){case"(":g();return bc(H(bj,G(m,")")),a);case"[":g();return bc($(),a);case"{":g();return bc(_(),a)}k()}if(e("keyword","function")){g();return bc(P(!1),a)}if(M(D,d.token.type)){var b=d.token.type=="regexp"?p("regexp",d.token.value[0],d.token.value[1]):p(d.token.type,d.token.value);return bc(H(b,g),a)}k()}),bj=s(function(a,b){arguments.length==0&&(a=!0);var c=bi(b);if(a&&e("punc",",")){g();return p("seq",c,bj(!0,b))}return c});return p("toplevel",function(a){while(!e("eof"))a.push(t());return a}([]))}function E(a,b,c){this.name=a,this.start=b,this.end=c}function x(b){function P(a){if(a)return I();y(),v();var b=g();if(!b)return x("eof");if(o(b))return C();if(b=='"'||b=="'")return F();if(M(l,b))return x("punc",h());if(b==".")return L();if(b=="/")return K();if(M(e,b))return J();if(b=="\\"||q(b))return N();B("Unexpected character '"+b+"'")}function O(a,b){try{return b()}catch(c){if(c===w)B(a);else throw c}}function N(){var b=A(r);return M(a,b)?M(i,b)?x("operator",b):M(d,b)?x("atom",b):x("keyword",b):x("name",b)}function L(){h();return o(g())?C("."):x("punc",".")}function K(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(G()),f.regex_allowed=a;return P();case"*":f.comments_before.push(H()),f.regex_allowed=a;return P()}return f.regex_allowed?I():J("/")}function J(a){function b(a){if(!g())return a;var c=a+g();if(M(i,c)){h();return b(c)}return a}return x("operator",b(a||h()))}function I(){return O("Unterminated regular expression",function(){var a=!1,b="",c,d=!1;while(c=h(!0))if(a)b+="\\"+c,a=!1;else if(c=="[")d=!0,b+=c;else if(c=="]"&&d)d=!1,b+=c;else{if(c=="/"&&!d)break;c=="\\"?a=!0:b+=c}var e=A(function(a){return M(m,a)});return x("regexp",[b,e])})}function H(){h();return O("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=x("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function G(){h();var a=t("\n"),b;a==-1?(b=f.text.substr(f.pos),f.pos=f.text.length):(b=f.text.substring(f.pos,a),f.pos=a);return x("comment1",b,!0)}function F(){return O("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=D();else if(c==a)break;b+=c}return x("string",b)})}function E(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&B("Invalid hex-character pattern in string"),b=b<<4|c}return b}function D(){var a=h(!0);switch(a){case"n":return"\n";case"r":return"\r";case"t":return"\t";case"b":return"\b";case"v":return" ";case"f":return"\f";case"0":return"";case"x":return String.fromCharCode(E(2));case"u":return String.fromCharCode(E(4));case"\n":return"";default:return a}}function C(a){var b=!1,c=!1,d=!1,e=a==".",f=A(function(f,g){if(f=="x"||f=="X")return d?!1:d=!0;if(!d&&(f=="E"||f=="e"))return b?!1:b=c=!0;if(f=="-")return c||g==0&&!a?!0:!1;if(f=="+")return c;c=!1;if(f==".")return!e&&!d?e=!0:!1;return p(f)});a&&(f=a+f);var g=s(f);if(!isNaN(g))return x("num",g);B("Invalid syntax: "+f)}function B(a){u(a,f.tokline,f.tokcol,f.tokpos)}function A(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(M(j,g()))h()}function x(a,b,d){f.regex_allowed=a=="operator"&&!M(z,b)||a=="keyword"&&M(c,b)||a=="punc"&&M(k,b);var e={type:a,value:b,line:f.tokline,col:f.tokcol,pos:f.tokpos,nlb:f.newline_before};d||(e.comments_before=f.comments_before,f.comments_before=[]),f.newline_before=!1;return e}function v(){f.tokline=f.line,f.tokcol=f.col,f.tokpos=f.pos}function t(a,b){var c=f.text.indexOf(a,f.pos);if(b&&c==-1)throw w;return c}function n(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw w;b=="\n"?(f.newline_before=!0,++f.line,f.col=0):++f.col;return b}function g(){return f.text.charAt(f.pos)}var f={text:b.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,""),pos:0,tokpos:0,line:0,tokline:0,col:0,tokcol:0,newline_before:!1,regex_allowed:!1,comments_before:[]};P.context=function(a){a&&(f=a);return f};return P}function v(a,b,c){return a.type==b&&(c==null||a.value==c)}function u(a,b,c,d){throw new t(a,b,c,d)}function t(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d}function s(a){if(f.test(a))return parseInt(a.substr(2),16);if(g.test(a))return parseInt(a.substr(1),8);if(h.test(a))return parseFloat(a)}function r(a){return q(a)||o(a)}function q(a){return a=="$"||a=="_"||n(a)}function p(a){return o(a)||n(a)}function o(a){a=a.charCodeAt(0);return a>=48&&a<=57}function n(a){a=a.charCodeAt(0);return a>=65&&a<=90||a>=97&&a<=122}var a=I(["break","case","catch","const","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","throw","try","typeof","var","void","while","with"]),b=I(["abstract","boolean","byte","char","class","debugger","double","enum","export","extends","final","float","goto","implements","import","int","interface","long","native","package","private","protected","public","short","static","super","synchronized","throws","transient","volatile"]),c=I(["return","new","delete","throw","else","case"]),d=I(["false","null","true","undefined"]),e=I(K("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=I(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","|=","^=","&=","&&","||"]),j=I(K(" \n\r\t")),k=I(K("[{}(,.;:")),l=I(K("[]{}(),;:")),m=I(K("gmsiy"));t.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"};var w={},y=I(["typeof","void","delete","--","++","!","~","-","+"]),z=I(["--","++"]),A=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),B=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),C=I(["for","do","while","switch"]),D=I(["atom","num","string","regexp","name"]);E.prototype.toString=function(){return this.name};var P=I(["name","array","object","string","dot","sub","call","regexp"]),R=I(["if","while","do","for","for-in","with"]);return{parse:F,gen_code:S,tokenizer:x,ast_walker:N}} + + // Math Operators + + var operators = { + '+': 'add', + '-': 'subtract', + '*': 'multiply', + '/': 'divide', + '%': 'modulo', + '==': 'equals', + '!=': 'equals' + }; + + function $eval(left, operator, right) { + var handler = operators[operator]; + if (left && left[handler]) { + var res = left[handler](right); + return operator == '!=' ? !res : res; + } + switch (operator) { + case '+': return left + right; + case '-': return left - right; + case '*': return left * right; + case '/': return left / right; + case '%': return left % right; + case '==': return left == right; + case '!=': return left != right; + default: + throw new Error('Implement Operator: ' + operator); + } + }; + + // Sign Operators + + var signOperators = { + '-': 'negate' + }; + + function $sign(operator, value) { + var handler = signOperators[operator]; + if (value && value[handler]) { + return value[handler](); + } + switch (operator) { + case '+': return +value; + case '-': return -value; + default: + throw new Error('Implement Sign Operator: ' + operator); + } + } + + // AST Helpers + + function isDynamic(exp) { + var type = exp[0]; + return type != 'num' && type != 'string'; + } + + function handleOperator(operator, left, right) { + // Only replace operators with calls to $operator if the left hand side + // is potentially an object. + if (operators[operator] && isDynamic(left)) { + // Replace with call to $operator(left, operator, right): + return ['call', ['name', '$eval'], + [left, ['string', operator], right]]; + } + } + + /** + * Compiles PaperScript code into JavaScript code. + * + * @name PaperScript.compile + * @function + * @param {String} code The PaperScript code. + * @return {String} The compiled PaperScript as JavaScript code. + */ + function compile(code) { + // Use parse-js to translate the code into a AST structure which is then + // walked and parsed for operators to overload. The resulting AST is + // translated back to code and evaluated. + var ast = parse_js.parse(code), + walker = parse_js.ast_walker(), + walk = walker.walk; + + ast = walker.with_walkers({ + 'binary': function(operator, left, right) { + // Handle simple mathematical operators here: + return handleOperator(operator, left = walk(left), + right = walk(right)) + // Always return something since we're walking left and + || [this[0], operator, left, right]; + }, + + 'assign': function(operator, left, right) { + var res = handleOperator(operator, left = walk(left), + right = walk(right)); + if (res) + return [this[0], true, left, res]; + return [this[0], operator, left, right]; + }, + + 'unary-prefix': function(operator, exp) { + if (signOperators[operator] && isDynamic(exp)) { + return ['call', ['name', '$sign'], + [['string', operator], walk(exp)]]; + } + } + }, function() { + return walk(ast); + }); + + return parse_js.gen_code(ast, { + beautify: true + }); + } + + function evaluate(code, scope) { + paper = scope; + var view = scope.project && scope.project.view, + res; + with (scope) { + (function() { + var onEditOptions, onSelect, onDeselect, onReselect, + onMouseDown, onMouseUp, onMouseDrag, onMouseMove, + onKeyDown, onKeyUp, onFrame, onResize; + res = eval(compile(code)); + if (/on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)) { + Base.each(Tool.prototype._events, function(key) { + var value = eval(key); + if (value) { + scope.getTool()[key] = value; + } + }); + } + if (view) { + view.setOnResize(onResize); + view.fire('resize', { + size: view.size, + delta: new Point() + }); + view.setOnFrame(onFrame); + view.draw(); + } + }).call(scope); + } + return res; + } + + function request(url, scope) { + var xhr = new (window.ActiveXObject || XMLHttpRequest)( + 'Microsoft.XMLHTTP'); + xhr.open('GET', url, true); + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain'); + } + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + return evaluate(xhr.responseText, scope); + } + }; + return xhr.send(null); + } + + function load() { + var scripts = document.getElementsByTagName('script'); + for (var i = 0, l = scripts.length; i < l; i++) { + var script = scripts[i]; + if (/^text\/(?:x-|)paperscript$/.test(script.type) + && !script.getAttribute('data-paper-loaded')) { + var scope = new PaperScope(script); + scope.setup(PaperScript.getAttribute(script, 'canvas')); + if (script.src) { + request(script.src, scope); + } else { + evaluate(script.innerHTML, scope); + } + script.setAttribute('data-paper-loaded', true); + } + } + } + + DomEvent.add(window, { load: load }); + + function handleAttribute(name) { + name += 'Attribute'; + return function(el, attr) { + return el[name](attr) || el[name]('data-paper-' + attr); + }; + } + + return { + compile: compile, + evaluate: evaluate, + load: load, + getAttribute: handleAttribute('get'), + hasAttribute: handleAttribute('has') + }; + +}; + +this.load = PaperScript.load; + +Base.each(this, function(val, key) { + if (val && val.prototype instanceof Base) { + val._name = key; + } +}); + +this.enumerable = true; +return new (PaperScope.inject(this)); +}; diff --git a/dist/docs/resources/js/reference.js b/dist/docs/resources/js/reference.js new file mode 100644 index 00000000..b39ee690 --- /dev/null +++ b/dist/docs/resources/js/reference.js @@ -0,0 +1,258 @@ +ContentEnd = HtmlElement.extend({ + _class: 'content-end', + + initialize: function() { + var anchor = $$('a[name]').getLast(), + that = this; + if (anchor) { + function resize() { + var bottom = $window.getScrollSize().height + - anchor.getOffset().y - $window.getSize().height; + that.setHeight(that.getHeight() - bottom); + } + $window.addEvents({ + load: resize, + resize: resize + }); + // Not sure why these are required twice, in addition to load().. + resize(); + resize(); + } + } +}); + +function createCodeMirror(place, options, source) { + return new CodeMirror(place, Hash.create({}, { + lineNumbers: true, + matchBrackets: true, + indentUnit: 4, + tabMode: 'shift', + value: source.getText().replace(/\t/gi, ' ').match( + // Remove first & last empty line + /^\s*?[\n\r]?([\u0000-\uffff]*?)[\n\r]?\s*?$/)[1] + }, options)); +} + +Code = HtmlElement.extend({ + _class: 'code', + + initialize: function() { + // Only format this element if it is visible, otherwise wait until + // it is made visible and then call initialize() manually. + if (this.initialized || this.getBounds().height == 0) + return; + var that = this; + var start = this.getProperty('start'); + var highlight = this.getProperty('highlight'); + var editor = createCodeMirror(function(el) { + that.replaceWith(el); + }, { + lineNumbers: !this.hasParent('.resource-text'), + firstLineNumber: (start || 1).toInt(), + readOnly: true + }, this); + if (highlight) { + var highlights = highlight.split(','); + for (var i = 0, l = highlights.length; i < l; i++) { + var highlight = highlights[i].split('-'); + var hlStart = highlight[0].toInt() - 1; + var hlEnd = highlight.length == 2 + ? highlight[1].toInt() - 1 : hlStart; + if (start) { + hlStart -= start - 1; + hlEnd -= start - 1; + } + for (var j = hlStart; j <= hlEnd; j++) { + editor.setLineClass(j, 'highlight'); + } + } + } + this.initialized = true; + } +}); + +PaperScript = HtmlElement.extend({ + _class: 'paperscript', + + initialize: function() { + // Only format this element if it is visible, otherwise wait until + // it is made visible and then call initialize() manually. + if (this.initialized || this.getBounds().height == 0) + return; + var script = $('script', this), + button = $('.button', this); + if (!script || !button) + return; + var source = button.injectAfter('div', { + className: 'source hidden' + }); + var that = this, + canvas = $('canvas', this), + hasResize = canvas.getProperty('resize'), + showSplit = this.hasClass('split'), + sourceFirst = this.hasClass('source'), + width, height, + editor = null, + hasBorders = true; + + function showSource(show) { + source.modifyClass('hidden', !show); + button.setText(show ? 'Run' : 'Source'); + if (show && !editor) { + editor = createCodeMirror(source.$, { + /* + onKeyEvent: function(editor, event) { + event = new DomEvent(event); + if (event.type == 'keydown') { + var pos = editor.getCursor(); + pos.ch += 4; + editor.setCursor(pos); + event.stop(); + } + }, + */ + }, script); + } + } + + function runScript() { + var scope = paper.PaperScope.get(script.$); + if (scope) { + // Update script to edited version + var code = editor.getValue(); + script.setText(code); + // Keep a reference to the used canvas, since we're going to + // fully clear the scope and initialize again with this canvas. + var canvas = scope.view.canvas; + // Clear scope first, then evaluate a new script. + scope.clear(); + scope.initialize(canvas); + scope.evaluate(code); + } + } + + function resize() { + if (!canvas.hasClass('hidden')) { + width = canvas.getWidth(); + height = canvas.getHeight(); + } else if (hasResize) { + // Can't get correct dimensions from hidden canvas, + // so calculate again. + var size = $window.getScrollSize(); + var offset = source.getOffset(); + width = size.width - offset.x; + height = size.height - offset.y; + } + // Resize the main element as well, so that the float:right button + // is always positioned correctly. + that.set({ width: width, height: height }); + source.set({ + width: width - (hasBorders ? 2 : 1), + height: height - (hasBorders ? 2 : 0) + }); + } + + function toggleView() { + var show = source.hasClass('hidden'); + resize(); + canvas.modifyClass('hidden', show); + showSource(show); + if (!show) + runScript(); + // Remove padding + button.setStyle('right', + $('.CodeMirror', source).getScrollSize().height > height + ? 24 : 8); + } + + if (hasResize) { + // Delay the installing of the resize event, so paper.js installs + // its own before us. + (function() { + $window.addEvents({ + resize: resize + }); + }).delay(1); + hasBorders = false; + source.setStyles({ + borderWidth: '0 0 0 1px' + }); + } + + if (showSplit) { + showSource(true); + } else if (sourceFirst) { + toggleView(); + } + + button.addEvents({ + click: function(event) { + if (showSplit) { + runScript(); + } else { + toggleView(); + } + event.stop(); + }, + + mousedown: function(event) { + event.stop(); + } + }); + this.initialized = true; + } +}); + +var lastMemberId = null; +function toggleMember(id, scrollTo, dontScroll) { + var link = $('#' + id + '-link'); + if (!link) + return true; + var desc = $('#' + id + '-description'); + var v = !link.hasClass('hidden'); + // Retrieve y-offset before any changes, so we can correct scrolling after + var offset = (v ? link : desc).getOffset().y; + if (lastMemberId && lastMemberId != id) { + var prevId = lastMemberId; + lastMemberId = null; + toggleMember(prevId, false, true); + } + lastMemberId = v && id; + link.modifyClass('hidden', v); + desc.modifyClass('hidden', !v); + if (!dontScroll) { + // Correct scrolling relatively to where we are, by checking the amount + // the element has shifted due to the above toggleMember call, and + // correcting by 11px offset, caused by 1px border and 10px padding. + var scroll = $window.getScrollOffset(); + $window.setScrollOffset(scroll.x, scroll.y + + (v ? desc : link).getOffset().y - offset + 11 * (v ? 1 : -1)); + } + if (!desc.editor && v) { + desc.editor = $$('pre.code, .paperscript', desc).each(function(code) { + code.initialize(); + }); + } + if (scrollTo) + scrollToMember(id); + return false; +} + +function scrollToElement(id) { + var e = $('#' + id + '-member'); + if (e) { + if (e.hasClass('member')) + toggleMember(id); + var offs = e.getOffset(); + $window.setScrollOffset(offs); + } else { + window.location.hash = id; + } +} + +$document.addEvent('domready', function() { + var h = unescape(window.location.hash); + if (h) scrollToElement(h.substring(1)); + if (window.paper) + paper.load(); +}); diff --git a/dist/paper.js b/dist/paper.js new file mode 100644 index 00000000..7b2639d8 --- /dev/null +++ b/dist/paper.js @@ -0,0 +1,3 @@ +// Paper.js loader for development, as produced by the build/load.sh script +document.write(''); +document.write(''); diff --git a/lib/bootstrap.js b/lib/bootstrap.js new file mode 100644 index 00000000..aaed4e9f --- /dev/null +++ b/lib/bootstrap.js @@ -0,0 +1,411 @@ +/** + * Bootstrap JavaScript Library + * (c) 2006 - 2011 Juerg Lehni, http://lehni.org/ + * + * Bootstrap is released under the MIT license + * http://bootstrapjs.org/ + * + * Inspirations: + * http://dean.edwards.name/weblog/2006/03/base/ + * http://dev.helma.org/Wiki/JavaScript+Inheritance+Sugar/ + * http://prototypejs.org/ + */ + +var Base = new function() { // Bootstrap scope + // Fix __proto__ for browsers where it is not implemented (IE and Opera). + var fix = !this.__proto__, + hidden = /^(statics|generics|preserve|enumerable|prototype|__proto__|toString|valueOf)$/, + proto = Object.prototype, + /** + * Private function that checks if an object contains a given property. + * Naming it 'has' causes problems on Opera when defining + * Object.prototype.has, as the local version then seems to be overriden + * by that. Giving it a idfferent name fixes it. + */ + has = fix + ? function(name) { + return name !== '__proto__' && this.hasOwnProperty(name); + } + : proto.hasOwnProperty, + toString = proto.toString, + proto = Array.prototype, + isArray = Array.isArray = Array.isArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }, + slice = proto.slice, + forEach = proto.forEach || function(iter, bind) { + for (var i = 0, l = this.length; i < l; i++) + iter.call(bind, this[i], i, this); + }, + forIn = function(iter, bind) { + // Do not use Object.keys for iteration as iterators might modify + // the object we're iterating over, making the hasOwnProperty still + // necessary. + for (var i in this) + if (this.hasOwnProperty(i)) + iter.call(bind, this[i], i, this); + }, + _define = Object.defineProperty, + _describe = Object.getOwnPropertyDescriptor; + + // Support a mixed environment of some ECMAScript 5 features present, + // along with __defineGetter/Setter__ functions, as found in browsers today. + function define(obj, name, desc) { + // Unfortunately Safari seems to ignore configurable: true and + // does not override existing properties, so we need to delete + // first: + if (_define) { + try { + delete obj[name]; + return _define(obj, name, desc); + } catch (e) {} + } + if ((desc.get || desc.set) && obj.__defineGetter__) { + desc.get && obj.__defineGetter__(name, desc.get); + desc.set && obj.__defineSetter__(name, desc.set); + } else { + obj[name] = desc.value; + } + return obj; + } + + function describe(obj, name) { + if (_describe) { + try { + return _describe(obj, name); + } catch (e) {} + } + var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); + return get + ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, + configurable: true } + : has.call(obj, name) + ? { value: obj[name], enumerable: true, configurable: true, + writable: true } + : null; + } + + /** + * Private function that injects functions from src into dest, overriding + * (and inherinting from) base. + */ + function inject(dest, src, enumerable, base, preserve, generics) { + var beans, bean; + + /** + * Private function that injects one field with given name and checks if + * the field is a function that needs to be wrapped for calls of base(). + * This is only needed if the function in base is different from the one + * in src, and if the one in src is actually calling base through base. + * The string of the function is parsed for this.base to detect calls. + */ + function field(name, val, dontCheck, generics) { + // This does even work for prop: 0, as it will just be looked up + // again through describe. + var val = val || (val = describe(src, name)) + && (val.get ? val : val.value), + func = typeof val === 'function', + res = val, + // Only lookup previous value if we preserve or define a + // function that might need it for this.base(). If we're + // defining a getter, don't lookup previous value, but look if + // the property exists (name in dest) and store result in prev + prev = preserve || func + ? (val && val.get ? name in dest : dest[name]) : null; + // Make generics first, as we might jump out bellow in the + // val !== (src.__proto__ || Object.prototype)[name] check, + // e.g. when explicitely reinjecting Array.prototype methods + // to produce generics of them. + if (generics && func && (!preserve || !generics[name])) { + generics[name] = function(bind) { + // Do not call Array.slice generic here, as on Safari, + // this seems to confuse scopes (calling another + // generic from generic-producing code). + return bind && dest[name].apply(bind, + slice.call(arguments, 1)); + } + } + if ((dontCheck || val !== undefined && has.call(src, name)) + && (!preserve || !prev)) { + if (func) { + if (prev && /\bthis\.base\b/.test(val)) { + var fromBase = base && base[name] == prev; + res = function() { + // Look up the base function each time if we can, + // to reflect changes to the base class after + // inheritance. + var tmp = describe(this, 'base'); + define(this, 'base', { value: fromBase + ? base[name] : prev, configurable: true }); + try { + return val.apply(this, arguments); + } finally { + tmp ? define(this, 'base', tmp) + : delete this.base; + } + }; + // Make wrapping closure pretend to be the original + // function on inspection + res.toString = function() { + return val.toString(); + } + res.valueOf = function() { + return val.valueOf(); + } + } + // Produce bean properties if getters are specified. This + // does not produce properties for setter-only properties. + // Just collect beans for now, and look them up in dest at + // the end of fields injection. This ensures this.base() + // works in beans too, and inherits setters for redefined + // getters in subclasses. Only add getter beans if they do + // not expect arguments. Functions that should function both + // with optional arguments and as beans should not declare + // the parameters and use the arguments array internally + // instead. + if (beans && val.length == 0 + && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) + beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); + } + // No need to look up getter if this is a function already. + if (!res || func || !res.get) + res = { value: res, writable: true }; + // Only set/change configurable and enumerable if this field is + // configurable + if ((describe(dest, name) + || { configurable: true }).configurable) { + res.configurable = true; + res.enumerable = enumerable; + } + define(dest, name, res); + } + } + // Iterate through all definitions in src now and call field() for each. + if (src) { + beans = []; + for (var name in src) + if (has.call(src, name) && !hidden.test(name)) + field(name, null, true, generics); + // IE (and some other browsers?) never enumerate these, even if + // they are simply set on an object. Force their creation. Do not + // create generics for these, and check them for not being defined + // (by passing undefined for dontCheck). + field('toString'); + field('valueOf'); + // Now finally define beans as well. Look up methods on dest, for + // support of this.base() (See above). + for (var i = 0, l = beans && beans.length; i < l; i++) + try { + var bean = beans[i], part = bean[1]; + field(bean[0], { + get: dest['get' + part] || dest['is' + part], + set: dest['set' + part] + }, true); + } catch (e) {} + } + return dest; + } + + /** + * Private function that creates a constructor to extend the given object. + * When this constructor is called through new, a new object is craeted + * that inherits all from obj. + */ + function extend(obj) { + // Create the constructor for the new prototype that calls initialize + // if it is defined. + var ctor = function(dont) { + // Fix __proto__ + if (fix) define(this, '__proto__', { value: obj }); + // Call the constructor function, if defined and we are not + // inheriting, in which case ctor.dont would be set, see bellow. + if (this.initialize && dont !== ctor.dont) + return this.initialize.apply(this, arguments); + } + ctor.prototype = obj; + // Add a toString function that delegates to initialize if possible + ctor.toString = function() { + return (this.prototype.initialize || function() {}).toString(); + } + return ctor; + } + + /** + * Converts the argument to an iterator function. If none is specified, the + * identity function is returned. + * This supports normal functions, which are returned unmodified, and values + * to compare to. Wherever this function is used in the Enumerable + * functions, a value, a Function or null may be passed. + */ + function iterator(iter) { + return !iter + ? function(val) { return val } + : typeof iter !== 'function' + ? function(val) { return val == iter } + : iter; + } + + function each(obj, iter, bind, asArray) { + try { + if (obj) + (asArray || asArray === undefined && isArray(obj) + ? forEach : forIn).call(obj, iterator(iter), + bind = bind || obj); + } catch (e) { + if (e !== Base.stop) throw e; + } + return bind; + } + + function clone(obj) { + return each(obj, function(val, i) { + this[i] = val; + }, new obj.constructor()); + } + + // Inject into new ctor object that's passed to inject(), and then returned + return inject(function() {}, { + inject: function(src/*, ... */) { + if (src) { + var proto = this.prototype, + base = proto.__proto__ && proto.__proto__.constructor, + // Allow the whole scope to just define statics by defining + // statics: true. + statics = src.statics == true ? src : src.statics; + if (statics != src) + inject(proto, src, src.enumerable, base && base.prototype, + src.preserve, src.generics && this); + // Define new static fields as enumerable, and inherit from + // base. enumerable is necessary so they can be copied over from + // base, and it does not harm to have enumerable properties in + // the constructor. Use the preserve setting in src.preserve for + // statics too, not their own. + inject(this, statics, true, base, src.preserve); + } + // If there are more than one argument, loop through them and call + // inject again. Do not simple inline the above code in one loop, + // since each of the passed objects might override this.inject. + for (var i = 1, l = arguments.length; i < l; i++) + this.inject(arguments[i]); + return this; + }, + + extend: function(src/* , ... */) { + // The new prototype extends the constructor on which extend is + // called. Fix constructor. + // TODO: Consider using Object.create instead of using this.dont if + // available? + var proto = new this(this.dont), + ctor = extend(proto); + define(proto, 'constructor', + { value: ctor, writable: true, configurable: true }); + // Define an object to be passed as the first parameter in + // constructors when initialize should not be called. + ctor.dont = {}; + // Copy over static fields, as prototype-like inheritance + // is not possible for static fields. Mark them as enumerable + // so they can be copied over again. + inject(ctor, this, true); + // Inject all the definitions in src. Use the new inject instead of + // the one in ctor, in case it was overriden. this is needed when + // overriding the static .inject(). But only inject if there's + // something to actually inject. + return arguments.length ? this.inject.apply(ctor, arguments) : ctor; + } + // Pass true for enumerable, so inject() and extend() can be passed on + // to subclasses of Base through Base.inject() / extend(). + }, true).inject({ + /** + * Returns true if the object contains a property with the given name, + * false otherwise. + * Just like in .each, objects only contained in the prototype(s) are + * filtered. + */ + has: has, + each: each, + + /** + * Injects the fields from the given object, adding this.base() + * functionality + */ + inject: function(/* src, ... */) { + for (var i = 0, l = arguments.length; i < l; i++) + inject(this, arguments[i]); + return this; + }, + + /** + * Returns a new object that inherits all properties from "this", + * through proper JS inheritance, not copying. + * Optionally, src and hide parameters can be passed to fill in the + * newly created object just like in inject(), to copy the behavior + * of Function.prototype.extend. + */ + extend: function(/* src, ... */) { + // Notice the "new" here: the private extend returns a constructor + // as it's used for Function.prototype.extend as well. But when + // extending objects, we want to return a new object that inherits + // from "this". In that case, the constructor is never used again, + // its just created to create a new object with the proper + // inheritance set and is garbage collected right after. + var res = new (extend(this)); + return res.inject.apply(res, arguments); + }, + + each: function(iter, bind) { + return each(this, iter, bind); + }, + + /** + * Creates a new object of the same type and copies over all + * name / value pairs from this object. + */ + clone: function() { + return clone(this); + }, + + statics: { + // Expose some local privates as Base generics. + each: each, + clone: clone, + define: define, + describe: describe, + iterator: iterator, + + has: function(obj, name) { + return has.call(obj, name); + }, + + type: function(obj) { + return (obj || obj === 0) && (obj._type || typeof obj) || null; + }, + + check: function(obj) { + return !!(obj || obj === 0); + }, + + /** + * Returns the first argument that is defined. + * Null is counted as defined too, since !== undefined is used for + * comparisons. In this it differs from Mootools! + */ + pick: function() { + for (var i = 0, l = arguments.length; i < l; i++) + if (arguments[i] !== undefined) + return arguments[i]; + return null; + }, + + /** + * A special constant, to be thrown by closures passed to each() + * + * $continue / Base.next is not implemented, as the same + * functionality can achieved by using return in the closure. + * In prototype, the implementation of $continue also leads to a + * huge speed decrease, as the closure is wrapped in another closure + * that does nothing else than handling $continue. + */ + stop: {} + } + }); +} diff --git a/lib/parse-js-min.js b/lib/parse-js-min.js new file mode 100644 index 00000000..c0bdddac --- /dev/null +++ b/lib/parse-js-min.js @@ -0,0 +1,14 @@ +/** + * A JavaScript tokenizer / parser / generator, originally written in Lisp. + * Copyright (c) Marijn Haverbeke + * http://marijn.haverbeke.nl/parse-js/ + * + * Ported by to JavaScript by Mihai Bazon + * Copyright (c) 2010, Mihai Bazon + * http://mihai.bazon.net/blog/ + * + * Modifications and adaptions to browser (c) 2011, Juerg Lehni + * http://lehni.org/ + * + * Distributed under the BSD license. + */var parse_js=new function(){function W(a,b,c){var d=[];for(var e=0;e0,g=j(function(){return h(a[0]?k(["case",z(a[0])+":"]):"default:")},.5)+(f?e+j(function(){return u(a[1]).join(e)}):"");!c&&f&&d0?h(a):a}).join(e)},block:w,"var":function(a){return"var "+l(W(a,x))+";"},"const":function(a){return"const "+l(W(a,x))+";"},"try":function(a,b,c){var d=["try",w(a)];b&&d.push("catch","("+b[0]+")",w(b[1])),c&&d.push("finally",w(c));return k(d)},"throw":function(a){return k(["throw",z(a)])+";"},"new":function(a,b){b=b.length>0?"("+l(W(b,z))+")":"";return k(["new",m(a,"seq","binary","conditional","assign",function(a){var b=N(),c={};try{b.with_walkers({call:function(){throw c},"function":function(){return this}},function(){b.walk(a)})}catch(d){if(d===c)return!0;throw d}})+b])},"switch":function(a,b){return k(["switch","("+z(a)+")",v(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+g(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+g(a));return b+";"},conditional:function(a,b,c){return k([m(a,"assign","seq","conditional"),"?",m(b,"seq"),":",m(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return k([z(b),a,m(c,"seq")])},dot:function(a){var b=z(a),c=1;a[0]=="num"?/\./.test(a[1])||(b+="."):o(a)&&(b="("+b+")");while(cB[b[1]])d="("+d+")";if(L(c[0],["assign","conditional","seq"])||c[0]=="binary"&&B[a]>=B[c[1]]&&(c[1]!=a||!L(a,["&&","||","*"])))e="("+e+")";return k([d,a,e])},"unary-prefix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-prefix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return a+(p(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=z(b);b[0]=="num"||b[0]=="unary-postfix"&&!M(i,a+b[1])||!o(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=z(a);o(a)&&(c="("+c+")");return c+"["+z(b)+"]"},object:function(a){return a.length==0?"{}":"{"+e+j(function(){return W(a,function(a){if(a.length==3)return h(t(a[0],a[1][2],a[1][3],a[2]));var d=a[0],e=z(a[1]);b.quote_keys?d=Q(d):(typeof d=="number"||!c&&+d+""==d)&&parseFloat(d)>=0?d=q(+d):V(d)||(d=Q(d));return h(k(c&&b.space_colon?[d,":",e]:[d+":",e]))}).join(","+e)})+e+h("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){return a.length==0?"[]":k(["[",l(W(a,function(a){return!c&&a[0]=="atom"&&a[1]=="undefined"?"":m(a,"seq")})),"]"])},stat:function(a){return z(a).replace(/;*\s*$/,";")},seq:function(){return l(W(J(arguments),z))},label:function(a,b){return k([g(a),":",z(b)])},"with":function(a,b){return k(["with","("+z(a)+")",z(b)])},atom:function(a){return g(a)}},y=[];return z(a)}function Q(a){var b=0,c=0;a=a.replace(/[\\\b\f\n\r\t\x22\x27]/g,function(a){switch(a){case"\\":return"\\\\";case"\b":return"\\b";case"\f":return"\\f";case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";case'"':++b;return'"';case"'":++c;return"'"}return a});return b>c?"'"+a.replace(/\x27/g,"\\'")+"'":'"'+a.replace(/\x22/g,'\\"')+'"'}function O(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function N(){function g(a,b){var c={},e;for(e in a)M(a,e)&&(c[e]=d[e],d[e]=a[e]);var f=b();for(e in c)M(c,e)&&(c[e]?d[e]=c[e]:delete d[e]);return f}function f(a){if(a==null)return null;try{e.push(a);var b=a[0],f=d[b];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=c[b];return f.apply(a,a.slice(1))}finally{e.pop()}}function b(a){var b=[this[0]];a!=null&&b.push(W(a,f));return b}function a(a){return[this[0],W(a,function(a){var b=[a[0]];a.length>1&&(b[1]=f(a[1]));return b})]}var c={string:function(a){return[this[0],a]},num:function(a){return[this[0],a]},name:function(a){return[this[0],a]},toplevel:function(a){return[this[0],W(a,f)]},block:b,splice:b,"var":a,"const":a,"try":function(a,b,c){return[this[0],W(a,f),b!=null?[b[0],W(b[1],f)]:null,c!=null?W(c,f):null]},"throw":function(a){return[this[0],f(a)]},"new":function(a,b){return[this[0],f(a),W(b,f)]},"switch":function(a,b){return[this[0],f(a),W(b,function(a){return[a[0]?f(a[0]):null,W(a[1],f)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],f(a),f(b),f(c)]},assign:function(a,b,c){return[this[0],a,f(b),f(c)]},dot:function(a){return[this[0],f(a)].concat(J(arguments,1))},call:function(a,b){return[this[0],f(a),W(b,f)]},"function":function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},defun:function(a,b,c){return[this[0],a,b.slice(),W(c,f)]},"if":function(a,b,c){return[this[0],f(a),f(b),f(c)]},"for":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"for-in":function(a,b,c,d){return[this[0],f(a),f(b),f(c),f(d)]},"while":function(a,b){return[this[0],f(a),f(b)]},"do":function(a,b){return[this[0],f(a),f(b)]},"return":function(a){return[this[0],f(a)]},binary:function(a,b,c){return[this[0],a,f(b),f(c)]},"unary-prefix":function(a,b){return[this[0],a,f(b)]},"unary-postfix":function(a,b){return[this[0],a,f(b)]},sub:function(a,b){return[this[0],f(a),f(b)]},object:function(a){return[this[0],W(a,function(a){return a.length==2?[a[0],f(a[1])]:[a[0],f(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],W(a,f)]},stat:function(a){return[this[0],f(a)]},seq:function(){return[this[0]].concat(W(J(arguments),f))},label:function(a,b){return[this[0],a,f(b)]},"with":function(a,b){return[this[0],f(a),f(b)]},atom:function(a){return[this[0],a]}},d={},e=[];return{walk:f,with_walkers:g,parent:function(){return e[e.length-2]},stack:function(){return e}}}function M(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function L(a,b){for(var c=b.length;--c>=0;)if(b[c]===a)return!0;return!1}function K(a){return a.split("")}function J(a,b){return Array.prototype.slice.call(a,b||0)}function I(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function G(a){var b=J(arguments,1);return function(){return a.apply(this,b.concat(J(arguments)))}}function F(a,b,c){function bk(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){var b=bg(a),c=d.token.value;if(e("operator")&&M(A,c)){if(bh(b)){g();return p("assign",A[c],b,bi(a))}i("Invalid assignment")}return b}function bh(a){if(!b)return!0;switch(a[0]){case"dot":case"sub":case"new":case"call":return!0;case"name":return a[1]!="this"}}function bg(a){var b=bf(a);if(e("operator","?")){g();var c=bj(!1);m(":");return p("conditional",b,c,bj(!1,a))}return b}function bf(a){return be(Y(!0),0,a)}function be(a,b,c){var f=e("operator")?d.token.value:null;f&&f=="in"&&c&&(f=null);var h=f!=null?B[f]:null;if(h!=null&&h>b){g();var i=be(Y(!0),h,c);return be(p("binary",f,a,i),b,c)}return a}function bd(a,b,c){(b=="++"||b=="--")&&!bh(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bc(a,b){if(e("punc",".")){g();return bc(p("dot",a,bb()),b)}if(e("punc","[")){g();return bc(p("sub",a,H(bj,G(m,"]"))),b)}if(b&&e("punc","(")){g();return bc(p("call",a,Z(")")),!0)}return b&&e("operator")&&M(z,d.token.value)?H(G(bd,"unary-postfix",d.token.value,a),g):a}function bb(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return H(d.token.value,g);default:k()}}function ba(){switch(d.token.type){case"num":case"string":return H(d.token.value,g)}return bb()}function _(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=ba();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bj(!1)])):c.push([bb(),P(!1),h])}g();return p("object",c)}function $(){return p("array",Z("]",!b,!0))}function Z(a,b,c){var d=!0,f=[];while(!e("punc",a)){d?d=!1:m(",");if(b&&e("punc",a))break;e("punc",",")&&c?f.push(["atom","undefined"]):f.push(bj(!1))}g();return f}function X(){var a=Y(!1),b;e("punc","(")?(g(),b=Z(")")):b=[];return bc(p("new",a,b),!0)}function W(){return p("const",U())}function V(a){return p("var",U(a))}function U(a){var b=[];for(;;){e("name")||k();var c=d.token.value;g(),e("operator","=")?(g(),b.push([c,bj(!1,a)])):b.push([c]);if(!e("punc",","))break;g()}return b}function T(){var a=R(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,R()]}e("keyword","finally")&&(g(),c=R()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function R(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(t());g();return a}function Q(){var a=q(),b=t(),c;e("keyword","else")&&(g(),c=t());return p("if",a,b,c)}function O(a){var b=a[0]=="var"?p("name",a[1][0]):a;g();var c=bj();m(")");return p("for-in",a,b,c,bk(t))}function N(a){m(";");var b=e("punc",";")?null:bj();m(";");var c=e("punc",")")?null:bj();m(")");return p("for",a,b,c,bk(t))}function K(){m("(");var a=null;if(!e("punc",";")){a=e("keyword","var")?(g(),V(!0)):bj(!0,!0);if(e("operator","in"))return O(a)}return N(a)}function I(a){var b;n()||(b=e("name")?d.token.value:null),b!=null?(g(),L(b,d.labels)||i("Label "+b+" without matching loop or statement")):d.in_loop==0&&i(a+" not inside a loop or switch"),o();return p(a,b)}function F(){return p("stat",H(bj,o))}function w(a){d.labels.push(a);var c=d.token,e=t();b&&!M(C,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function s(a){return c?function(){var b=d.token,c=a.apply(this,arguments);c[0]=r(c[0],b,h());return c}:a}function r(a,b,c){return a instanceof E?a:new E(a,b,c)}function q(){m("(");var a=bj();m(")");return a}function p(){return J(arguments)}function o(){e("punc",";")?g():n()||k()}function n(){return!b&&(d.token.nlb||e("eof")||e("punc","}"))}function m(a){return l("punc",a)}function l(a,b){if(e(a,b))return g();j(d.token,"Unexpected token "+d.token.type+", expected "+a)}function k(a){a==null&&(a=d.token),j(a,"Unexpected token: "+a.type+" ("+a.value+")")}function j(a,b){i(b,a.line,a.col)}function i(a,b,c,e){var f=d.input.context();u(a,b!=null?b:f.tokline,c!=null?c:f.tokcol,e!=null?e:f.tokpos)}function h(){return d.prev}function g(){d.prev=d.token,d.peeked?(d.token=d.peeked,d.peeked=null):d.token=d.input();return d.token}function f(){return d.peeked||(d.peeked=d.input())}function e(a,b){return v(d.token,a,b)}var d={input:typeof a=="string"?x(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var t=s(function(){e("operator","/")&&(d.peeked=null,d.token=d.input(!0));switch(d.token.type){case"num":case"string":case"regexp":case"operator":case"atom":return F();case"name":return v(f(),"punc",":")?w(H(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",R());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(H(d.token.value,g)){case"break":return I("break");case"continue":return I("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",H(q,o),a)}(bk(t));case"for":return K();case"function":return P(!0);case"if":return Q();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:H(bj,o));case"switch":return p("switch",q(),S());case"throw":return p("throw",H(bj,o));case"try":return T();case"var":return H(V,o);case"const":return H(W,o);case"while":return p("while",q(),bk(t));case"with":return p("with",q(),t());default:k()}}}),P=s(function(a){var b=e("name")?H(d.token.value,g):null;a&&!b&&k(),m("(");return p(a?"defun":"function",b,function(a,b){while(!e("punc",")"))a?a=!1:m(","),e("name")||k(),b.push(d.token.value),g();g();return b}(!0,[]),function(){++d.in_function;var a=d.in_loop;d.in_loop=0;var b=R();--d.in_function,d.in_loop=a;return b}())}),S=G(bk,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bj(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(t()));g();return a}),Y=s(function(a){if(e("operator","new")){g();return X()}if(e("operator")&&M(y,d.token.value))return bd("unary-prefix",H(d.token.value,g),Y(a));if(e("punc")){switch(d.token.value){case"(":g();return bc(H(bj,G(m,")")),a);case"[":g();return bc($(),a);case"{":g();return bc(_(),a)}k()}if(e("keyword","function")){g();return bc(P(!1),a)}if(M(D,d.token.type)){var b=d.token.type=="regexp"?p("regexp",d.token.value[0],d.token.value[1]):p(d.token.type,d.token.value);return bc(H(b,g),a)}k()}),bj=s(function(a,b){arguments.length==0&&(a=!0);var c=bi(b);if(a&&e("punc",",")){g();return p("seq",c,bj(!0,b))}return c});return p("toplevel",function(a){while(!e("eof"))a.push(t());return a}([]))}function E(a,b,c){this.name=a,this.start=b,this.end=c}function x(b){function P(a){if(a)return I();y(),v();var b=g();if(!b)return x("eof");if(o(b))return C();if(b=='"'||b=="'")return F();if(M(l,b))return x("punc",h());if(b==".")return L();if(b=="/")return K();if(M(e,b))return J();if(b=="\\"||q(b))return N();B("Unexpected character '"+b+"'")}function O(a,b){try{return b()}catch(c){if(c===w)B(a);else throw c}}function N(){var b=A(r);return M(a,b)?M(i,b)?x("operator",b):M(d,b)?x("atom",b):x("keyword",b):x("name",b)}function L(){h();return o(g())?C("."):x("punc",".")}function K(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(G()),f.regex_allowed=a;return P();case"*":f.comments_before.push(H()),f.regex_allowed=a;return P()}return f.regex_allowed?I():J("/")}function J(a){function b(a){if(!g())return a;var c=a+g();if(M(i,c)){h();return b(c)}return a}return x("operator",b(a||h()))}function I(){return O("Unterminated regular expression",function(){var a=!1,b="",c,d=!1;while(c=h(!0))if(a)b+="\\"+c,a=!1;else if(c=="[")d=!0,b+=c;else if(c=="]"&&d)d=!1,b+=c;else{if(c=="/"&&!d)break;c=="\\"?a=!0:b+=c}var e=A(function(a){return M(m,a)});return x("regexp",[b,e])})}function H(){h();return O("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=x("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function G(){h();var a=t("\n"),b;a==-1?(b=f.text.substr(f.pos),f.pos=f.text.length):(b=f.text.substring(f.pos,a),f.pos=a);return x("comment1",b,!0)}function F(){return O("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=D();else if(c==a)break;b+=c}return x("string",b)})}function E(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&B("Invalid hex-character pattern in string"),b=b<<4|c}return b}function D(){var a=h(!0);switch(a){case"n":return"\n";case"r":return"\r";case"t":return"\t";case"b":return"\b";case"v":return" ";case"f":return"\f";case"0":return"";case"x":return String.fromCharCode(E(2));case"u":return String.fromCharCode(E(4));case"\n":return"";default:return a}}function C(a){var b=!1,c=!1,d=!1,e=a==".",f=A(function(f,g){if(f=="x"||f=="X")return d?!1:d=!0;if(!d&&(f=="E"||f=="e"))return b?!1:b=c=!0;if(f=="-")return c||g==0&&!a?!0:!1;if(f=="+")return c;c=!1;if(f==".")return!e&&!d?e=!0:!1;return p(f)});a&&(f=a+f);var g=s(f);if(!isNaN(g))return x("num",g);B("Invalid syntax: "+f)}function B(a){u(a,f.tokline,f.tokcol,f.tokpos)}function A(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(M(j,g()))h()}function x(a,b,d){f.regex_allowed=a=="operator"&&!M(z,b)||a=="keyword"&&M(c,b)||a=="punc"&&M(k,b);var e={type:a,value:b,line:f.tokline,col:f.tokcol,pos:f.tokpos,nlb:f.newline_before};d||(e.comments_before=f.comments_before,f.comments_before=[]),f.newline_before=!1;return e}function v(){f.tokline=f.line,f.tokcol=f.col,f.tokpos=f.pos}function t(a,b){var c=f.text.indexOf(a,f.pos);if(b&&c==-1)throw w;return c}function n(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw w;b=="\n"?(f.newline_before=!0,++f.line,f.col=0):++f.col;return b}function g(){return f.text.charAt(f.pos)}var f={text:b.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,""),pos:0,tokpos:0,line:0,tokline:0,col:0,tokcol:0,newline_before:!1,regex_allowed:!1,comments_before:[]};P.context=function(a){a&&(f=a);return f};return P}function v(a,b,c){return a.type==b&&(c==null||a.value==c)}function u(a,b,c,d){throw new t(a,b,c,d)}function t(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d}function s(a){if(f.test(a))return parseInt(a.substr(2),16);if(g.test(a))return parseInt(a.substr(1),8);if(h.test(a))return parseFloat(a)}function r(a){return q(a)||o(a)}function q(a){return a=="$"||a=="_"||n(a)}function p(a){return o(a)||n(a)}function o(a){a=a.charCodeAt(0);return a>=48&&a<=57}function n(a){a=a.charCodeAt(0);return a>=65&&a<=90||a>=97&&a<=122}var a=I(["break","case","catch","const","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","throw","try","typeof","var","void","while","with"]),b=I(["abstract","boolean","byte","char","class","debugger","double","enum","export","extends","final","float","goto","implements","import","int","interface","long","native","package","private","protected","public","short","static","super","synchronized","throws","transient","volatile"]),c=I(["return","new","delete","throw","else","case"]),d=I(["false","null","true","undefined"]),e=I(K("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=I(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","|=","^=","&=","&&","||"]),j=I(K(" \n\r\t")),k=I(K("[{}(,.;:")),l=I(K("[]{}(),;:")),m=I(K("gmsiy"));t.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"};var w={},y=I(["typeof","void","delete","--","++","!","~","-","+"]),z=I(["--","++"]),A=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),B=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),C=I(["for","do","while","switch"]),D=I(["atom","num","string","regexp","name"]);E.prototype.toString=function(){return this.name};var P=I(["name","array","object","string","dot","sub","call","regexp"]),R=I(["if","while","do","for","for-in","with"]);return{parse:F,gen_code:S,tokenizer:x,ast_walker:N}} \ No newline at end of file diff --git a/lib/parse-js-unicode.js b/lib/parse-js-unicode.js new file mode 100644 index 00000000..6baa67f3 --- /dev/null +++ b/lib/parse-js-unicode.js @@ -0,0 +1,1997 @@ +/** + * A JavaScript tokenizer / parser / generator, originally written in Lisp. + * Copyright (c) Marijn Haverbeke + * http://marijn.haverbeke.nl/parse-js/ + * + * Ported by to JavaScript by Mihai Bazon + * Copyright (c) 2010, Mihai Bazon + * http://mihai.bazon.net/blog/ + * + * Modifications and adaptions to browser (c) 2011, Juerg Lehni + * http://lehni.org/ + * + * Distributed under the BSD license. + */ + +var parse_js = new function() { + +/* -----[ Tokenizer (constants) ]----- */ + +var KEYWORDS = array_to_hash([ + "break", + "case", + "catch", + "const", + "continue", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with" +]); + +var RESERVED_WORDS = array_to_hash([ + "abstract", + "boolean", + "byte", + "char", + "class", + "debugger", + "double", + "enum", + "export", + "extends", + "final", + "float", + "goto", + "implements", + "import", + "int", + "interface", + "long", + "native", + "package", + "private", + "protected", + "public", + "short", + "static", + "super", + "synchronized", + "throws", + "transient", + "volatile" +]); + +var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ + "return", + "new", + "delete", + "throw", + "else", + "case" +]); + +var KEYWORDS_ATOM = array_to_hash([ + "false", + "null", + "true", + "undefined" +]); + +var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); + +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; + +var OPERATORS = array_to_hash([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "/=", + "*=", + "%=", + ">>=", + "<<=", + ">>>=", + "|=", + "^=", + "&=", + "&&", + "||" +]); + +var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\v\u200b")); + +var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); + +var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); + +var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); + +/* -----[ Tokenizer ]----- */ + +// regexps adapted from http://xregexp.com/plugins/#unicode +var UNICODE = { + letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), + non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), + space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), + connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") +}; + +function is_letter(ch) { + return UNICODE.letter.test(ch); +}; + +function is_digit(ch) { + ch = ch.charCodeAt(0); + return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 +}; + +function is_alphanumeric_char(ch) { + return is_digit(ch) || is_letter(ch); +}; + +function is_unicode_combining_mark(ch) { + return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); +}; + +function is_unicode_connector_punctuation(ch) { + return UNICODE.connector_punctuation.test(ch); +}; + +function is_identifier_start(ch) { + return ch == "$" || ch == "_" || is_letter(ch); +}; + +function is_identifier_char(ch) { + return is_identifier_start(ch) + || is_unicode_combining_mark(ch) + || is_digit(ch) + || is_unicode_connector_punctuation(ch) + || ch == "\u200c" // zero-width non-joiner + || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) + ; +}; + +function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } +}; + +function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line; + this.col = col; + this.pos = pos; +}; + +JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")"; +}; + +function js_error(message, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); +}; + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +}; + +var EX_EOF = {}; + +function tokenizer($TEXT) { + + var S = { + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] + }; + + function peek() { return S.text.charAt(S.pos); }; + + function next(signal_eof) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (ch == "\n") { + S.newline_before = true; + ++S.line; + S.col = 0; + } else { + ++S.col; + } + return ch; + }; + + function eof() { + return !S.peek(); + }; + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + }; + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + }; + + function token(type, value, is_comment) { + S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || + (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || + (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); + var ret = { + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + nlb : S.newline_before + }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + } + S.newline_before = false; + return ret; + }; + + function skip_whitespace() { + while (HOP(WHITESPACE_CHARS, peek())) + next(); + }; + + function read_while(pred) { + var ret = "", ch = peek(), i = 0; + while (ch && pred(ch, i++)) { + ret += next(); + ch = peek(); + } + return ret; + }; + + function parse_error(err) { + js_error(err, S.tokline, S.tokcol, S.tokpos); + }; + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; + var num = read_while(function(ch, i){ + if (ch == "x" || ch == "X") { + if (has_x) return false; + return has_x = true; + } + if (!has_x && (ch == "E" || ch == "e")) { + if (has_e) return false; + return has_e = after_e = true; + } + if (ch == "-") { + if (after_e || (i == 0 && !prefix)) return true; + return false; + } + if (ch == "+") return after_e; + after_e = false; + if (ch == ".") { + if (!has_dot && !has_x) + return has_dot = true; + return false; + } + return is_alphanumeric_char(ch); + }); + if (prefix) + num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + }; + + function read_escaped_char() { + var ch = next(true); + switch (ch) { + case "n" : return "\n"; + case "r" : return "\r"; + case "t" : return "\t"; + case "b" : return "\b"; + case "v" : return "\v"; + case "f" : return "\f"; + case "0" : return "\0"; + case "x" : return String.fromCharCode(hex_bytes(2)); + case "u" : return String.fromCharCode(hex_bytes(4)); + case "\n": return ""; + default : return ch; + } + }; + + function hex_bytes(n) { + var num = 0; + for (; n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) + parse_error("Invalid hex-character pattern in string"); + num = (num << 4) | digit; + } + return num; + }; + + function read_string() { + return with_eof_error("Unterminated string constant", function(){ + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") { + // read OctalEscapeSequence (XXX: deprecated if "strict mode") + // https://github.com/mishoo/UglifyJS/issues/178 + var octal_len = 0, first = null; + ch = read_while(function(ch){ + if (ch >= "0" && ch <= "7") { + if (!first) { + first = ch; + return ++octal_len; + } + else if (first <= "3" && octal_len <= 2) return ++octal_len; + else if (first >= "4" && octal_len <= 1) return ++octal_len; + } + return false; + }); + if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); + else ch = read_escaped_char(); + } + else if (ch == quote) break; + ret += ch; + } + return token("string", ret); + }); + }; + + function read_line_comment() { + next(); + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + return token("comment1", ret, true); + }; + + function read_multiline_comment() { + next(); + return with_eof_error("Unterminated multiline comment", function(){ + var i = find("*/", true), + text = S.text.substring(S.pos, i), + tok = token("comment2", text, true); + S.pos = i + 2; + S.line += text.split("\n").length - 1; + S.newline_before = text.indexOf("\n") >= 0; + return tok; + }); + }; + + function read_name() { + var backslash = false, name = "", ch; + while ((ch = peek()) != null) { + if (!backslash) { + if (ch == "\\") backslash = true, next(); + else if (is_identifier_char(ch)) name += next(); + else break; + } + else { + if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); + ch = read_escaped_char(); + if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); + name += ch; + backslash = false; + } + } + return name; + }; + + function read_regexp() { + return with_eof_error("Unterminated regular expression", function(){ + var prev_backslash = false, regexp = "", ch, in_class = false; + while ((ch = next(true))) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; + } + var mods = read_name(); + return token("regexp", [ regexp, mods ]); + }); + }; + + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (HOP(OPERATORS, bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + }; + return token("operator", grow(prefix || next())); + }; + + function handle_slash() { + next(); + var regex_allowed = S.regex_allowed; + switch (peek()) { + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + } + return S.regex_allowed ? read_regexp() : read_operator("/"); + }; + + function handle_dot() { + next(); + return is_digit(peek()) + ? read_num(".") + : token("punc", "."); + }; + + function read_word() { + var word = read_name(); + return !HOP(KEYWORDS, word) + ? token("name", word) + : HOP(OPERATORS, word) + ? token("operator", word) + : HOP(KEYWORDS_ATOM, word) + ? token("atom", word) + : token("keyword", word); + }; + + function with_eof_error(eof_error, cont) { + try { + return cont(); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; + } + }; + + function next_token(force_regexp) { + if (force_regexp) + return read_regexp(); + skip_whitespace(); + start_token(); + var ch = peek(); + if (!ch) return token("eof"); + if (is_digit(ch)) return read_num(); + if (ch == '"' || ch == "'") return read_string(); + if (HOP(PUNC_CHARS, ch)) return token("punc", next()); + if (ch == ".") return handle_dot(); + if (ch == "/") return handle_slash(); + if (HOP(OPERATOR_CHARS, ch)) return read_operator(); + if (ch == "\\" || is_identifier_start(ch)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = array_to_hash([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); + +var ASSIGNMENT = (function(a, ret, i){ + while (i < a.length) { + ret[a[i]] = a[i].substr(0, a[i].length - 1); + i++; + } + return ret; +})( + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], + { "=": true }, + 0 +); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0, n = 1; i < a.length; ++i, ++n) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = n; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function NodeWithToken(str, start, end) { + this.name = str; + this.start = start; + this.end = end; +}; + +NodeWithToken.prototype.toString = function() { return this.name; }; + +function parse($TEXT, exigent_mode, embed_tokens) { + + var S = { + input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, + token : null, + prev : null, + peeked : null, + in_function : 0, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !exigent_mode && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function as() { + return slice(arguments); + }; + + function parenthesised() { + expect("("); + var ex = expression(); + expect(")"); + return ex; + }; + + function add_tokens(str, start, end) { + return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); + }; + + function maybe_embed_tokens(parser) { + if (embed_tokens) return function() { + var start = S.token; + var ast = parser.apply(this, arguments); + ast[0] = add_tokens(ast[0], start, prev()); + return ast; + }; + else return parser; + }; + + var statement = maybe_embed_tokens(function() { + if (is("operator", "/")) { + S.peeked = null; + S.token = S.input(true); // force regexp + } + switch (S.token.type) { + case "num": + case "string": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement(prog1(S.token.value, next, next)) + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return as("block", block_()); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return as("block"); + default: + unexpected(); + } + + case "keyword": + switch (prog1(S.token.value, next)) { + case "break": + return break_cont("break"); + + case "continue": + return break_cont("continue"); + + case "debugger": + semicolon(); + return as("debugger"); + + case "do": + return (function(body){ + expect_token("keyword", "while"); + return as("do", prog1(parenthesised, semicolon), body); + })(in_loop(statement)); + + case "for": + return for_(); + + case "function": + return function_(true); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return as("return", + is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : prog1(expression, semicolon)); + + case "switch": + return as("switch", parenthesised(), switch_block_()); + + case "throw": + return as("throw", prog1(expression, semicolon)); + + case "try": + return try_(); + + case "var": + return prog1(var_, semicolon); + + case "const": + return prog1(const_, semicolon); + + case "while": + return as("while", parenthesised(), in_loop(statement)); + + case "with": + return as("with", parenthesised(), statement()); + + default: + unexpected(); + } + } + }); + + function labeled_statement(label) { + S.labels.push(label); + var start = S.token, stat = statement(); + if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + unexpected(start); + S.labels.pop(); + return as("label", label, stat); + }; + + function simple_statement() { + return as("stat", prog1(expression, semicolon)); + }; + + function break_cont(type) { + var name; + if (!can_insert_semicolon()) { + name = is("name") ? S.token.value : null; + } + if (name != null) { + next(); + if (!member(name, S.labels)) + croak("Label " + name + " without matching loop or statement"); + } + else if (S.in_loop == 0) + croak(type + " not inside a loop or switch"); + semicolon(); + return as(type, name); + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) + return for_in(init); + } + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); + }; + + function for_in(init) { + var lhs = init[0] == "var" ? as("name", init[1][0]) : init; + next(); + var obj = expression(); + expect(")"); + return as("for-in", init, lhs, obj, in_loop(statement)); + }; + + var function_ = maybe_embed_tokens(function(in_statement) { + var name = is("name") ? prog1(S.token.value, next) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return as(in_statement ? "defun" : "function", + name, + // arguments + (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + if (!is("name")) unexpected(); + a.push(S.token.value); + next(); + } + next(); + return a; + })(true, []), + // body + (function(){ + ++S.in_function; + var loop = S.in_loop; + S.in_loop = 0; + var a = block_(); + --S.in_function; + S.in_loop = loop; + return a; + })()); + }); + + function if_() { + var cond = parenthesised(), body = statement(), belse; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return as("if", cond, body, belse); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + var switch_block_ = curry(in_loop, function(){ + expect("{"); + var a = [], cur = null; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + next(); + cur = []; + a.push([ expression(), cur ]); + expect(":"); + } + else if (is("keyword", "default")) { + next(); + expect(":"); + cur = []; + a.push([ null, cur ]); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + next(); + return a; + }); + + function try_() { + var body = block_(), bcatch, bfinally; + if (is("keyword", "catch")) { + next(); + expect("("); + if (!is("name")) + croak("Name expected"); + var name = S.token.value; + next(); + expect(")"); + bcatch = [ name, block_() ]; + } + if (is("keyword", "finally")) { + next(); + bfinally = block_(); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return as("try", body, bcatch, bfinally); + }; + + function vardefs(no_in) { + var a = []; + for (;;) { + if (!is("name")) + unexpected(); + var name = S.token.value; + next(); + if (is("operator", "=")) { + next(); + a.push([ name, expression(false, no_in) ]); + } else { + a.push([ name ]); + } + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + function var_(no_in) { + return as("var", vardefs(no_in)); + }; + + function const_() { + return as("const", vardefs()); + }; + + function new_() { + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(as("new", newexp, args), true); + }; + + var expr_atom = maybe_embed_tokens(function(allow_calls) { + if (is("operator", "new")) { + next(); + return new_(); + } + if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { + return make_unary("unary-prefix", + prog1(S.token.value, next), + expr_atom(allow_calls)); + } + if (is("punc")) { + switch (S.token.value) { + case "(": + next(); + return subscripts(prog1(expression, curry(expect, ")")), allow_calls); + case "[": + next(); + return subscripts(array_(), allow_calls); + case "{": + next(); + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + return subscripts(function_(false), allow_calls); + } + if (HOP(ATOMIC_START_TOKEN, S.token.type)) { + var atom = S.token.type == "regexp" + ? as("regexp", S.token.value[0], S.token.value[1]) + : as(S.token.type, S.token.value); + return subscripts(prog1(atom, next), allow_calls); + } + unexpected(); + }); + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push([ "atom", "undefined" ]); + } else { + a.push(expression(false)); + } + } + next(); + return a; + }; + + function array_() { + return as("array", expr_list("]", !exigent_mode, true)); + }; + + function object_() { + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!exigent_mode && is("punc", "}")) + // allow trailing comma + break; + var type = S.token.type; + var name = as_property_name(); + if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { + a.push([ as_name(), function_(false), name ]); + } else { + expect(":"); + a.push([ name, expression(false) ]); + } + } + next(); + return as("object", a); + }; + + function as_property_name() { + switch (S.token.type) { + case "num": + case "string": + return prog1(S.token.value, next); + } + return as_name(); + }; + + function as_name() { + switch (S.token.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return prog1(S.token.value, next); + default: + unexpected(); + } + }; + + function subscripts(expr, allow_calls) { + if (is("punc", ".")) { + next(); + return subscripts(as("dot", expr, as_name()), allow_calls); + } + if (is("punc", "[")) { + next(); + return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(as("call", expr, expr_list(")")), true); + } + if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { + return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), + next); + } + return expr; + }; + + function make_unary(tag, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return as(tag, op, expr); + }; + + function expr_op(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op && op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(expr_atom(true), prec, no_in); + return expr_op(as("binary", op, left, right), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(expr_atom(true), 0, no_in); + }; + + function maybe_conditional(no_in) { + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return as("conditional", expr, yes, expression(false, no_in)); + } + return expr; + }; + + function is_assignable(expr) { + if (!exigent_mode) return true; + switch (expr[0]) { + case "dot": + case "sub": + case "new": + case "call": + return true; + case "name": + return expr[1] != "this"; + } + }; + + function maybe_assign(no_in) { + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && HOP(ASSIGNMENT, val)) { + if (is_assignable(left)) { + next(); + return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); + } + croak("Invalid assignment"); + } + return left; + }; + + var expression = maybe_embed_tokens(function(commas, no_in) { + if (arguments.length == 0) + commas = true; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return as("seq", expr, expression(true, no_in)); + } + return expr; + }); + + function in_loop(cont) { + try { + ++S.in_loop; + return cont(); + } finally { + --S.in_loop; + } + }; + + return as("toplevel", (function(a){ + while (!is("eof")) + a.push(statement()); + return a; + })([])); + +}; + +/* -----[ Utilities ]----- */ + +function curry(f) { + var args = slice(arguments, 1); + return function() { return f.apply(this, args.concat(slice(arguments))); }; +}; + +function prog1(ret) { + if (ret instanceof Function) + ret = ret(); + for (var i = 1, n = arguments.length; --n > 0; ++i) + arguments[i](); + return ret; +}; + +function array_to_hash(a) { + var ret = {}; + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] === name) + return true; + return false; +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +/* -----[ helper for AST traversal ]----- */ + +function ast_walker() { + function _vardefs(defs) { + return [ this[0], MAP(defs, function(def){ + var a = [ def[0] ]; + if (def.length > 1) + a[1] = walk(def[1]); + return a; + }) ]; + }; + function _block(statements) { + var out = [ this[0] ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }; + var walkers = { + "string": function(str) { + return [ this[0], str ]; + }, + "num": function(num) { + return [ this[0], num ]; + }, + "name": function(name) { + return [ this[0], name ]; + }, + "toplevel": function(statements) { + return [ this[0], MAP(statements, walk) ]; + }, + "block": _block, + "splice": _block, + "var": _vardefs, + "const": _vardefs, + "try": function(t, c, f) { + return [ + this[0], + MAP(t, walk), + c != null ? [ c[0], MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null + ]; + }, + "throw": function(expr) { + return [ this[0], walk(expr) ]; + }, + "new": function(ctor, args) { + return [ this[0], walk(ctor), MAP(args, walk) ]; + }, + "switch": function(expr, body) { + return [ this[0], walk(expr), MAP(body, function(branch){ + return [ branch[0] ? walk(branch[0]) : null, + MAP(branch[1], walk) ]; + }) ]; + }, + "break": function(label) { + return [ this[0], label ]; + }, + "continue": function(label) { + return [ this[0], label ]; + }, + "conditional": function(cond, t, e) { + return [ this[0], walk(cond), walk(t), walk(e) ]; + }, + "assign": function(op, lvalue, rvalue) { + return [ this[0], op, walk(lvalue), walk(rvalue) ]; + }, + "dot": function(expr) { + return [ this[0], walk(expr) ].concat(slice(arguments, 1)); + }, + "call": function(expr, args) { + return [ this[0], walk(expr), MAP(args, walk) ]; + }, + "function": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "defun": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "if": function(conditional, t, e) { + return [ this[0], walk(conditional), walk(t), walk(e) ]; + }, + "for": function(init, cond, step, block) { + return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; + }, + "for-in": function(vvar, key, hash, block) { + return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; + }, + "while": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "do": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "return": function(expr) { + return [ this[0], walk(expr) ]; + }, + "binary": function(op, left, right) { + return [ this[0], op, walk(left), walk(right) ]; + }, + "unary-prefix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "unary-postfix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "sub": function(expr, subscript) { + return [ this[0], walk(expr), walk(subscript) ]; + }, + "object": function(props) { + return [ this[0], MAP(props, function(p){ + return p.length == 2 + ? [ p[0], walk(p[1]) ] + : [ p[0], walk(p[1]), p[2] ]; // get/set-ter + }) ]; + }, + "regexp": function(rx, mods) { + return [ this[0], rx, mods ]; + }, + "array": function(elements) { + return [ this[0], MAP(elements, walk) ]; + }, + "stat": function(stat) { + return [ this[0], walk(stat) ]; + }, + "seq": function() { + return [ this[0] ].concat(MAP(slice(arguments), walk)); + }, + "label": function(name, block) { + return [ this[0], name, walk(block) ]; + }, + "with": function(expr, block) { + return [ this[0], walk(expr), walk(block) ]; + }, + "atom": function(name) { + return [ this[0], name ]; + } + }; + + var user = {}; + var stack = []; + function walk(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + var type = ast[0]; + var gen = user[type]; + if (gen) { + var ret = gen.apply(ast, ast.slice(1)); + if (ret != null) + return ret; + } + gen = walkers[type]; + return gen.apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + + function with_walkers(walkers, cont){ + var save = {}, i; + for (i in walkers) if (HOP(walkers, i)) { + save[i] = user[i]; + user[i] = walkers[i]; + } + var ret = cont(); + for (i in save) if (HOP(save, i)) { + if (!save[i]) delete user[i]; + else user[i] = save[i]; + } + return ret; + }; + + return { + walk: walk, + with_walkers: with_walkers, + parent: function() { + return stack[stack.length - 2]; // last one is current node + }, + stack: function() { + return stack; + } + }; +}; + +function empty(b) { + return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); +}; + +/* -----[ re-generate code from the AST ]----- */ + +var DOT_CALL_NO_PARENS = array_to_hash([ + "name", + "array", + "object", + "string", + "dot", + "sub", + "call", + "regexp" +]); + +function make_string(str, ascii_only) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + } + return s; + }); + if (ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; +}; + +function to_ascii(str) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + while (code.length < 4) code = "0" + code; + return "\\u" + code; + }); +}; + +var SPLICE_NEEDS_BRACKETS = array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); + +function gen_code(ast, options) { + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : false, + beautify : false, + ascii_only : false, + inline_script: false + }); + var beautify = !!options.beautify; + var indentation = 0, + newline = beautify ? "\n" : "", + space = beautify ? " " : ""; + + function encode_string(str) { + var ret = make_string(str, options.ascii_only); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; + + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name); + return name; + }; + + function indent(line) { + if (line == null) + line = ""; + if (beautify) + line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; + return line; + }; + + function with_indent(cont, incr) { + if (incr == null) incr = 1; + indentation += incr; + try { return cont.apply(null, slice(arguments, 1)); } + finally { indentation -= incr; } + }; + + function add_spaces(a) { + if (beautify) + return a.join(" "); + var b = []; + for (var i = 0; i < a.length; ++i) { + var next = a[i + 1]; + b.push(a[i]); + if (next && + ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || + (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { + b.push(" "); + } + } + return b.join(""); + }; + + function add_commas(a) { + return a.join("," + space); + }; + + function parenthesize(expr) { + var gen = make(expr); + for (var i = 1; i < arguments.length; ++i) { + var el = arguments[i]; + if ((el instanceof Function && el(expr)) || expr[0] == el) + return "(" + gen + ")"; + } + return gen; + }; + + function best_of(a) { + if (a.length == 1) { + return a[0]; + } + if (a.length == 2) { + var b = a[1]; + a = a[0]; + return a.length <= b.length ? a : b; + } + return best_of([ a[0], best_of(a.slice(1)) ]); + }; + + function needs_parens(expr) { + if (expr[0] == "function" || expr[0] == "object") { + // dot/call on a literal function requires the + // function literal itself to be parenthesized + // only if it's the first "thing" in a + // statement. This means that the parent is + // "stat", but it could also be a "seq" and + // we're the first in this "seq" and the + // parent is "stat", and so on. Messy stuff, + // but it worths the trouble. + var a = slice($stack), self = a.pop(), p = a.pop(); + while (p) { + if (p[0] == "stat") return true; + if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || + ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { + self = p; + p = a.pop(); + } else { + return false; + } + } + } + return !HOP(DOT_CALL_NO_PARENS, expr[0]); + }; + + function make_num(num) { + var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; + if (Math.floor(num) === num) { + a.push("0x" + num.toString(16).toLowerCase(), // probably pointless + "0" + num.toString(8)); // same. + if ((m = /^(.*?)(0+)$/.exec(num))) { + a.push(m[1] + "e" + m[2].length); + } + } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { + a.push(m[2] + "e-" + (m[1].length + m[2].length), + str.substr(str.indexOf("."))); + } + return best_of(a); + }; + + var generators = { + "string": encode_string, + "num": make_num, + "name": make_name, + "toplevel": function(statements) { + return make_block_statements(statements) + .join(newline); + }, + "splice": function(statements) { + var parent = $stack[$stack.length - 2][0]; + if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { + // we need block brackets in this case + return make_block.apply(this, arguments); + } else { + return MAP(make_block_statements(statements, true), + function(line, i) { + // the first line is already indented + return i > 0 ? indent(line) : line; + }).join(newline); + } + }, + "block": make_block, + "var": function(defs) { + return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "const": function(defs) { + return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "try": function(tr, ca, fi) { + var out = [ "try", make_block(tr) ]; + if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); + if (fi) out.push("finally", make_block(fi)); + return add_spaces(out); + }, + "throw": function(expr) { + return add_spaces([ "throw", make(expr) ]) + ";"; + }, + "new": function(ctor, args) { + args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; + return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ + var w = ast_walker(), has_call = {}; + try { + w.with_walkers({ + "call": function() { throw has_call }, + "function": function() { return this } + }, function(){ + w.walk(expr); + }); + } catch(ex) { + if (ex === has_call) + return true; + throw ex; + } + }) + args ]); + }, + "switch": function(expr, body) { + return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); + }, + "break": function(label) { + var out = "break"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "continue": function(label) { + var out = "continue"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "conditional": function(co, th, el) { + return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", + parenthesize(th, "seq"), ":", + parenthesize(el, "seq") ]); + }, + "assign": function(op, lvalue, rvalue) { + if (op && op !== true) op += "="; + else op = "="; + return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); + }, + "dot": function(expr) { + var out = make(expr), i = 1; + if (expr[0] == "num") { + if (!/\./.test(expr[1])) + out += "."; + } else if (needs_parens(expr)) + out = "(" + out + ")"; + while (i < arguments.length) + out += "." + make_name(arguments[i++]); + return out; + }, + "call": function(func, args) { + var f = make(func); + if (needs_parens(func)) + f = "(" + f + ")"; + return f + "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")"; + }, + "function": make_function, + "defun": make_function, + "if": function(co, th, el) { + var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; + if (el) { + out.push("else", make(el)); + } + return add_spaces(out); + }, + "for": function(init, cond, step, block) { + var out = [ "for" ]; + init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); + cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); + step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); + var args = init + cond + step; + if (args == "; ; ") args = ";;"; + out.push("(" + args + ")", make(block)); + return add_spaces(out); + }, + "for-in": function(vvar, key, hash, block) { + return add_spaces([ "for", "(" + + (vvar ? make(vvar).replace(/;+$/, "") : make(key)), + "in", + make(hash) + ")", make(block) ]); + }, + "while": function(condition, block) { + return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); + }, + "do": function(condition, block) { + return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; + }, + "return": function(expr) { + var out = [ "return" ]; + if (expr != null) out.push(make(expr)); + return add_spaces(out) + ";"; + }, + "binary": function(operator, lvalue, rvalue) { + var left = make(lvalue), right = make(rvalue); + // XXX: I'm pretty sure other cases will bite here. + // we need to be smarter. + // adding parens all the time is the safest bet. + if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || + lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { + left = "(" + left + ")"; + } + if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && + !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { + right = "(" + right + ")"; + } + else if (!beautify && options.inline_script && (operator == "<" || operator == "<<") + && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) { + right = " " + right; + } + return add_spaces([ left, operator, right ]); + }, + "unary-prefix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return operator + (is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; + }, + "unary-postfix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return val + operator; + }, + "sub": function(expr, subscript) { + var hash = make(expr); + if (needs_parens(expr)) + hash = "(" + hash + ")"; + return hash + "[" + make(subscript) + "]"; + }, + "object": function(props) { + if (props.length == 0) + return "{}"; + return "{" + newline + with_indent(function(){ + return MAP(props, function(p){ + if (p.length == 3) { + // getter/setter. The name is in p[0], the arg.list in p[1][2], the + // body in p[1][3] and type ("get" / "set") in p[2]. + return indent(make_function(p[0], p[1][2], p[1][3], p[2])); + } + var key = p[0], val = parenthesize(p[1], "seq"); + if (options.quote_keys) { + key = encode_string(key); + } else if ((typeof key == "number" || !beautify && +key + "" == key) + && parseFloat(key) >= 0) { + key = make_num(+key); + } else if (!is_identifier(key)) { + key = encode_string(key); + } + return indent(add_spaces(beautify && options.space_colon + ? [ key, ":", val ] + : [ key + ":", val ])); + }).join("," + newline); + }) + newline + indent("}"); + }, + "regexp": function(rx, mods) { + return "/" + rx + "/" + mods; + }, + "array": function(elements) { + if (elements.length == 0) return "[]"; + return add_spaces([ "[", add_commas(MAP(elements, function(el){ + if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; + return parenthesize(el, "seq"); + })), "]" ]); + }, + "stat": function(stmt) { + return make(stmt).replace(/;*\s*$/, ";"); + }, + "seq": function() { + return add_commas(MAP(slice(arguments), make)); + }, + "label": function(name, block) { + return add_spaces([ make_name(name), ":", make(block) ]); + }, + "with": function(expr, block) { + return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); + }, + "atom": function(name) { + return make_name(name); + } + }; + + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + function make_then(th) { + if (th[0] == "do") { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 + // IE croaks with "syntax error" on code like this: + // if (foo) do ... while(cond); else ... + // we need block brackets around do/while + return make([ "block", [ th ]]); + } + var b = th; + while (true) { + var type = b[0]; + if (type == "if") { + if (!b[3]) + // no else, we must add the block + return make([ "block", [ th ]]); + b = b[3]; + } + else if (type == "while" || type == "do") b = b[2]; + else if (type == "for" || type == "for-in") b = b[4]; + else break; + } + return make(th); + }; + + function make_function(name, args, body, keyword) { + var out = keyword || "function"; + if (name) { + out += " " + make_name(name); + } + out += "(" + add_commas(MAP(args, make_name)) + ")"; + return add_spaces([ out, make_block(body) ]); + }; + + function make_block_statements(statements, noindent) { + for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { + var stat = statements[i]; + var code = make(stat); + if (code != ";") { + if (!beautify && i == last) { + if ((stat[0] == "while" && empty(stat[2])) || + (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || + (stat[0] == "if" && empty(stat[2]) && !stat[3]) || + (stat[0] == "if" && stat[3] && empty(stat[3]))) { + code = code.replace(/;*\s*$/, ";"); + } else { + code = code.replace(/;+\s*$/, ""); + } + } + a.push(code); + } + } + return noindent ? a : MAP(a, indent); + }; + + function make_switch_block(body) { + var n = body.length; + if (n == 0) return "{}"; + return "{" + newline + MAP(body, function(branch, i){ + var has_body = branch[1].length > 0, code = with_indent(function(){ + return indent(branch[0] + ? add_spaces([ "case", make(branch[0]) + ":" ]) + : "default:"); + }, 0.5) + (has_body ? newline + with_indent(function(){ + return make_block_statements(branch[1]).join(newline); + }) : ""); + if (!beautify && has_body && i < n - 1) + code += ";"; + return code; + }).join(newline) + newline + indent("}"); + }; + + function make_block(statements) { + if (!statements) return ";"; + if (statements.length == 0) return "{}"; + return "{" + newline + with_indent(function(){ + return make_block_statements(statements).join(newline); + }) + newline + indent("}"); + }; + + function make_1vardef(def) { + var name = def[0], val = def[1]; + if (val != null) + name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); + return name; + }; + + var $stack = []; + + function make(node) { + var type = node[0]; + var gen = generators[type]; + if (!gen) + throw new Error("Can't find generator for \"" + type + "\""); + $stack.push(node); + var ret = gen.apply(type, node.slice(1)); + $stack.pop(); + return ret; + }; + + return make(ast); +}; + +/* -----[ Utilities ]----- */ + +function repeat_string(str, i) { + return i < 1 ? "" : new Array(i + 1).join(str); +}; + +function defaults(args, defs) { + var ret = {}; + if (args === true) + args = {}; + for (var i in defs) if (HOP(defs, i)) { + ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + } + return ret; +}; + +function is_identifier(name) { + return /^[a-z_$][a-z0-9_$]*$/i.test(name) + && name != "this" + && !HOP(KEYWORDS_ATOM, name) + && !HOP(RESERVED_WORDS, name) + && !HOP(KEYWORDS, name); +}; + +function MAP(a, f, o) { + var ret = []; + for (var i = 0; i < a.length; ++i) { + ret.push(f.call(o, a[i], i)); + } + return ret; +}; + +/* -----[ Exports ]----- */ + +return { + parse: parse, + gen_code: gen_code, + tokenizer: tokenizer, + ast_walker: ast_walker +}; + +}; diff --git a/lib/parse-js.js b/lib/parse-js.js new file mode 100644 index 00000000..749b715b --- /dev/null +++ b/lib/parse-js.js @@ -0,0 +1,1916 @@ +/** + * A JavaScript tokenizer / parser / generator, originally written in Lisp. + * Copyright (c) Marijn Haverbeke + * http://marijn.haverbeke.nl/parse-js/ + * + * Ported by to JavaScript by Mihai Bazon + * Copyright (c) 2010, Mihai Bazon + * http://mihai.bazon.net/blog/ + * + * Modifications and adaptions to browser (c) 2011, Juerg Lehni + * http://lehni.org/ + * + * Distributed under the BSD license. + */ + +var parse_js = new function() { + +/* -----[ Tokenizer (constants) ]----- */ + +var KEYWORDS = array_to_hash([ + "break", + "case", + "catch", + "const", + "continue", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with" +]); + +var RESERVED_WORDS = array_to_hash([ + "abstract", + "boolean", + "byte", + "char", + "class", + "debugger", + "double", + "enum", + "export", + "extends", + "final", + "float", + "goto", + "implements", + "import", + "int", + "interface", + "long", + "native", + "package", + "private", + "protected", + "public", + "short", + "static", + "super", + "synchronized", + "throws", + "transient", + "volatile" +]); + +var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ + "return", + "new", + "delete", + "throw", + "else", + "case" +]); + +var KEYWORDS_ATOM = array_to_hash([ + "false", + "null", + "true", + "undefined" +]); + +var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); + +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; + +var OPERATORS = array_to_hash([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "/=", + "*=", + "%=", + ">>=", + "<<=", + ">>>=", + "|=", + "^=", + "&=", + "&&", + "||" +]); + +var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t")); + +var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); + +var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); + +var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); + +/* -----[ Tokenizer ]----- */ + +function is_letter(ch) { + ch = ch.charCodeAt(0); + return (ch >= 65 && ch <= 90) || + (ch >= 97 && ch <= 122); +}; + +function is_digit(ch) { + ch = ch.charCodeAt(0); + return ch >= 48 && ch <= 57; +}; + +function is_alphanumeric_char(ch) { + return is_digit(ch) || is_letter(ch); +}; + +function is_identifier_start(ch) { + return ch == "$" || ch == "_" || is_letter(ch); +}; + +function is_identifier_char(ch) { + return is_identifier_start(ch) || is_digit(ch); +}; + +function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } +}; + +function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line; + this.col = col; + this.pos = pos; +}; + +JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")"; +}; + +function js_error(message, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); +}; + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +}; + +var EX_EOF = {}; + +function tokenizer($TEXT) { + + var S = { + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] + }; + + function peek() { return S.text.charAt(S.pos); }; + + function next(signal_eof) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (ch == "\n") { + S.newline_before = true; + ++S.line; + S.col = 0; + } else { + ++S.col; + } + return ch; + }; + + function eof() { + return !S.peek(); + }; + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + }; + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + }; + + function token(type, value, is_comment) { + S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || + (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || + (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); + var ret = { + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + nlb : S.newline_before + }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + } + S.newline_before = false; + return ret; + }; + + function skip_whitespace() { + while (HOP(WHITESPACE_CHARS, peek())) + next(); + }; + + function read_while(pred) { + var ret = "", ch = peek(), i = 0; + while (ch && pred(ch, i++)) { + ret += next(); + ch = peek(); + } + return ret; + }; + + function parse_error(err) { + js_error(err, S.tokline, S.tokcol, S.tokpos); + }; + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; + var num = read_while(function(ch, i){ + if (ch == "x" || ch == "X") { + if (has_x) return false; + return has_x = true; + } + if (!has_x && (ch == "E" || ch == "e")) { + if (has_e) return false; + return has_e = after_e = true; + } + if (ch == "-") { + if (after_e || (i == 0 && !prefix)) return true; + return false; + } + if (ch == "+") return after_e; + after_e = false; + if (ch == ".") { + if (!has_dot && !has_x) + return has_dot = true; + return false; + } + return is_alphanumeric_char(ch); + }); + if (prefix) + num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + }; + + function read_escaped_char() { + var ch = next(true); + switch (ch) { + case "n" : return "\n"; + case "r" : return "\r"; + case "t" : return "\t"; + case "b" : return "\b"; + case "v" : return "\v"; + case "f" : return "\f"; + case "0" : return "\0"; + case "x" : return String.fromCharCode(hex_bytes(2)); + case "u" : return String.fromCharCode(hex_bytes(4)); + case "\n": return ""; + default : return ch; + } + }; + + function hex_bytes(n) { + var num = 0; + for (; n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) + parse_error("Invalid hex-character pattern in string"); + num = (num << 4) | digit; + } + return num; + }; + + function read_string() { + return with_eof_error("Unterminated string constant", function(){ + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") ch = read_escaped_char(); + else if (ch == quote) break; + ret += ch; + } + return token("string", ret); + }); + }; + + function read_line_comment() { + next(); + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + return token("comment1", ret, true); + }; + + function read_multiline_comment() { + next(); + return with_eof_error("Unterminated multiline comment", function(){ + var i = find("*/", true), + text = S.text.substring(S.pos, i), + tok = token("comment2", text, true); + S.pos = i + 2; + S.line += text.split("\n").length - 1; + S.newline_before = text.indexOf("\n") >= 0; + return tok; + }); + }; + + function read_regexp() { + return with_eof_error("Unterminated regular expression", function(){ + var prev_backslash = false, regexp = "", ch, in_class = false; + while ((ch = next(true))) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; + } + var mods = read_while(function(ch){ + return HOP(REGEXP_MODIFIERS, ch); + }); + return token("regexp", [ regexp, mods ]); + }); + }; + + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (HOP(OPERATORS, bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + }; + return token("operator", grow(prefix || next())); + }; + + function handle_slash() { + next(); + var regex_allowed = S.regex_allowed; + switch (peek()) { + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + } + return S.regex_allowed ? read_regexp() : read_operator("/"); + }; + + function handle_dot() { + next(); + return is_digit(peek()) + ? read_num(".") + : token("punc", "."); + }; + + function read_word() { + var word = read_while(is_identifier_char); + return !HOP(KEYWORDS, word) + ? token("name", word) + : HOP(OPERATORS, word) + ? token("operator", word) + : HOP(KEYWORDS_ATOM, word) + ? token("atom", word) + : token("keyword", word); + }; + + function with_eof_error(eof_error, cont) { + try { + return cont(); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; + } + }; + + function next_token(force_regexp) { + if (force_regexp) + return read_regexp(); + skip_whitespace(); + start_token(); + var ch = peek(); + if (!ch) return token("eof"); + if (is_digit(ch)) return read_num(); + if (ch == '"' || ch == "'") return read_string(); + if (HOP(PUNC_CHARS, ch)) return token("punc", next()); + if (ch == ".") return handle_dot(); + if (ch == "/") return handle_slash(); + if (HOP(OPERATOR_CHARS, ch)) return read_operator(); + if (ch == "\\" || is_identifier_start(ch)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = array_to_hash([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); + +var ASSIGNMENT = (function(a, ret, i){ + while (i < a.length) { + ret[a[i]] = a[i].substr(0, a[i].length - 1); + i++; + } + return ret; +})( + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], + { "=": true }, + 0 +); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0, n = 1; i < a.length; ++i, ++n) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = n; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function NodeWithToken(str, start, end) { + this.name = str; + this.start = start; + this.end = end; +}; + +NodeWithToken.prototype.toString = function() { return this.name; }; + +function parse($TEXT, exigent_mode, embed_tokens) { + + var S = { + input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, + token : null, + prev : null, + peeked : null, + in_function : 0, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !exigent_mode && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function as() { + return slice(arguments); + }; + + function parenthesised() { + expect("("); + var ex = expression(); + expect(")"); + return ex; + }; + + function add_tokens(str, start, end) { + return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); + }; + + function maybe_embed_tokens(parser) { + if (embed_tokens) return function() { + var start = S.token; + var ast = parser.apply(this, arguments); + ast[0] = add_tokens(ast[0], start, prev()); + return ast; + }; + else return parser; + }; + + var statement = maybe_embed_tokens(function() { + if (is("operator", "/")) { + S.peeked = null; + S.token = S.input(true); // force regexp + } + switch (S.token.type) { + case "num": + case "string": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement(prog1(S.token.value, next, next)) + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return as("block", block_()); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return as("block"); + default: + unexpected(); + } + + case "keyword": + switch (prog1(S.token.value, next)) { + case "break": + return break_cont("break"); + + case "continue": + return break_cont("continue"); + + case "debugger": + semicolon(); + return as("debugger"); + + case "do": + return (function(body){ + expect_token("keyword", "while"); + return as("do", prog1(parenthesised, semicolon), body); + })(in_loop(statement)); + + case "for": + return for_(); + + case "function": + return function_(true); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return as("return", + is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : prog1(expression, semicolon)); + + case "switch": + return as("switch", parenthesised(), switch_block_()); + + case "throw": + return as("throw", prog1(expression, semicolon)); + + case "try": + return try_(); + + case "var": + return prog1(var_, semicolon); + + case "const": + return prog1(const_, semicolon); + + case "while": + return as("while", parenthesised(), in_loop(statement)); + + case "with": + return as("with", parenthesised(), statement()); + + default: + unexpected(); + } + } + }); + + function labeled_statement(label) { + S.labels.push(label); + var start = S.token, stat = statement(); + if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + unexpected(start); + S.labels.pop(); + return as("label", label, stat); + }; + + function simple_statement() { + return as("stat", prog1(expression, semicolon)); + }; + + function break_cont(type) { + var name; + if (!can_insert_semicolon()) { + name = is("name") ? S.token.value : null; + } + if (name != null) { + next(); + if (!member(name, S.labels)) + croak("Label " + name + " without matching loop or statement"); + } + else if (S.in_loop == 0) + croak(type + " not inside a loop or switch"); + semicolon(); + return as(type, name); + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) + return for_in(init); + } + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); + }; + + function for_in(init) { + var lhs = init[0] == "var" ? as("name", init[1][0]) : init; + next(); + var obj = expression(); + expect(")"); + return as("for-in", init, lhs, obj, in_loop(statement)); + }; + + var function_ = maybe_embed_tokens(function(in_statement) { + var name = is("name") ? prog1(S.token.value, next) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return as(in_statement ? "defun" : "function", + name, + // arguments + (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + if (!is("name")) unexpected(); + a.push(S.token.value); + next(); + } + next(); + return a; + })(true, []), + // body + (function(){ + ++S.in_function; + var loop = S.in_loop; + S.in_loop = 0; + var a = block_(); + --S.in_function; + S.in_loop = loop; + return a; + })()); + }); + + function if_() { + var cond = parenthesised(), body = statement(), belse; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return as("if", cond, body, belse); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + var switch_block_ = curry(in_loop, function(){ + expect("{"); + var a = [], cur = null; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + next(); + cur = []; + a.push([ expression(), cur ]); + expect(":"); + } + else if (is("keyword", "default")) { + next(); + expect(":"); + cur = []; + a.push([ null, cur ]); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + next(); + return a; + }); + + function try_() { + var body = block_(), bcatch, bfinally; + if (is("keyword", "catch")) { + next(); + expect("("); + if (!is("name")) + croak("Name expected"); + var name = S.token.value; + next(); + expect(")"); + bcatch = [ name, block_() ]; + } + if (is("keyword", "finally")) { + next(); + bfinally = block_(); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return as("try", body, bcatch, bfinally); + }; + + function vardefs(no_in) { + var a = []; + for (;;) { + if (!is("name")) + unexpected(); + var name = S.token.value; + next(); + if (is("operator", "=")) { + next(); + a.push([ name, expression(false, no_in) ]); + } else { + a.push([ name ]); + } + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + function var_(no_in) { + return as("var", vardefs(no_in)); + }; + + function const_() { + return as("const", vardefs()); + }; + + function new_() { + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(as("new", newexp, args), true); + }; + + var expr_atom = maybe_embed_tokens(function(allow_calls) { + if (is("operator", "new")) { + next(); + return new_(); + } + if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { + return make_unary("unary-prefix", + prog1(S.token.value, next), + expr_atom(allow_calls)); + } + if (is("punc")) { + switch (S.token.value) { + case "(": + next(); + return subscripts(prog1(expression, curry(expect, ")")), allow_calls); + case "[": + next(); + return subscripts(array_(), allow_calls); + case "{": + next(); + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + return subscripts(function_(false), allow_calls); + } + if (HOP(ATOMIC_START_TOKEN, S.token.type)) { + var atom = S.token.type == "regexp" + ? as("regexp", S.token.value[0], S.token.value[1]) + : as(S.token.type, S.token.value); + return subscripts(prog1(atom, next), allow_calls); + } + unexpected(); + }); + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push([ "atom", "undefined" ]); + } else { + a.push(expression(false)); + } + } + next(); + return a; + }; + + function array_() { + return as("array", expr_list("]", !exigent_mode, true)); + }; + + function object_() { + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!exigent_mode && is("punc", "}")) + // allow trailing comma + break; + var type = S.token.type; + var name = as_property_name(); + if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { + a.push([ as_name(), function_(false), name ]); + } else { + expect(":"); + a.push([ name, expression(false) ]); + } + } + next(); + return as("object", a); + }; + + function as_property_name() { + switch (S.token.type) { + case "num": + case "string": + return prog1(S.token.value, next); + } + return as_name(); + }; + + function as_name() { + switch (S.token.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return prog1(S.token.value, next); + default: + unexpected(); + } + }; + + function subscripts(expr, allow_calls) { + if (is("punc", ".")) { + next(); + return subscripts(as("dot", expr, as_name()), allow_calls); + } + if (is("punc", "[")) { + next(); + return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(as("call", expr, expr_list(")")), true); + } + if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { + return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), + next); + } + return expr; + }; + + function make_unary(tag, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return as(tag, op, expr); + }; + + function expr_op(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op && op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(expr_atom(true), prec, no_in); + return expr_op(as("binary", op, left, right), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(expr_atom(true), 0, no_in); + }; + + function maybe_conditional(no_in) { + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return as("conditional", expr, yes, expression(false, no_in)); + } + return expr; + }; + + function is_assignable(expr) { + if (!exigent_mode) return true; + switch (expr[0]) { + case "dot": + case "sub": + case "new": + case "call": + return true; + case "name": + return expr[1] != "this"; + } + }; + + function maybe_assign(no_in) { + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && HOP(ASSIGNMENT, val)) { + if (is_assignable(left)) { + next(); + return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); + } + croak("Invalid assignment"); + } + return left; + }; + + var expression = maybe_embed_tokens(function(commas, no_in) { + if (arguments.length == 0) + commas = true; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return as("seq", expr, expression(true, no_in)); + } + return expr; + }); + + function in_loop(cont) { + try { + ++S.in_loop; + return cont(); + } finally { + --S.in_loop; + } + }; + + return as("toplevel", (function(a){ + while (!is("eof")) + a.push(statement()); + return a; + })([])); + +}; + +/* -----[ Utilities ]----- */ + +function curry(f) { + var args = slice(arguments, 1); + return function() { return f.apply(this, args.concat(slice(arguments))); }; +}; + +function prog1(ret) { + if (ret instanceof Function) + ret = ret(); + for (var i = 1, n = arguments.length; --n > 0; ++i) + arguments[i](); + return ret; +}; + +function array_to_hash(a) { + var ret = {}; + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] === name) + return true; + return false; +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +/* -----[ helper for AST traversal ]----- */ + +function ast_walker() { + function _vardefs(defs) { + return [ this[0], MAP(defs, function(def){ + var a = [ def[0] ]; + if (def.length > 1) + a[1] = walk(def[1]); + return a; + }) ]; + }; + function _block(statements) { + var out = [ this[0] ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }; + var walkers = { + "string": function(str) { + return [ this[0], str ]; + }, + "num": function(num) { + return [ this[0], num ]; + }, + "name": function(name) { + return [ this[0], name ]; + }, + "toplevel": function(statements) { + return [ this[0], MAP(statements, walk) ]; + }, + "block": _block, + "splice": _block, + "var": _vardefs, + "const": _vardefs, + "try": function(t, c, f) { + return [ + this[0], + MAP(t, walk), + c != null ? [ c[0], MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null + ]; + }, + "throw": function(expr) { + return [ this[0], walk(expr) ]; + }, + "new": function(ctor, args) { + return [ this[0], walk(ctor), MAP(args, walk) ]; + }, + "switch": function(expr, body) { + return [ this[0], walk(expr), MAP(body, function(branch){ + return [ branch[0] ? walk(branch[0]) : null, + MAP(branch[1], walk) ]; + }) ]; + }, + "break": function(label) { + return [ this[0], label ]; + }, + "continue": function(label) { + return [ this[0], label ]; + }, + "conditional": function(cond, t, e) { + return [ this[0], walk(cond), walk(t), walk(e) ]; + }, + "assign": function(op, lvalue, rvalue) { + return [ this[0], op, walk(lvalue), walk(rvalue) ]; + }, + "dot": function(expr) { + return [ this[0], walk(expr) ].concat(slice(arguments, 1)); + }, + "call": function(expr, args) { + return [ this[0], walk(expr), MAP(args, walk) ]; + }, + "function": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "defun": function(name, args, body) { + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "if": function(conditional, t, e) { + return [ this[0], walk(conditional), walk(t), walk(e) ]; + }, + "for": function(init, cond, step, block) { + return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; + }, + "for-in": function(vvar, key, hash, block) { + return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; + }, + "while": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "do": function(cond, block) { + return [ this[0], walk(cond), walk(block) ]; + }, + "return": function(expr) { + return [ this[0], walk(expr) ]; + }, + "binary": function(op, left, right) { + return [ this[0], op, walk(left), walk(right) ]; + }, + "unary-prefix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "unary-postfix": function(op, expr) { + return [ this[0], op, walk(expr) ]; + }, + "sub": function(expr, subscript) { + return [ this[0], walk(expr), walk(subscript) ]; + }, + "object": function(props) { + return [ this[0], MAP(props, function(p){ + return p.length == 2 + ? [ p[0], walk(p[1]) ] + : [ p[0], walk(p[1]), p[2] ]; // get/set-ter + }) ]; + }, + "regexp": function(rx, mods) { + return [ this[0], rx, mods ]; + }, + "array": function(elements) { + return [ this[0], MAP(elements, walk) ]; + }, + "stat": function(stat) { + return [ this[0], walk(stat) ]; + }, + "seq": function() { + return [ this[0] ].concat(MAP(slice(arguments), walk)); + }, + "label": function(name, block) { + return [ this[0], name, walk(block) ]; + }, + "with": function(expr, block) { + return [ this[0], walk(expr), walk(block) ]; + }, + "atom": function(name) { + return [ this[0], name ]; + } + }; + + var user = {}; + var stack = []; + function walk(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + var type = ast[0]; + var gen = user[type]; + if (gen) { + var ret = gen.apply(ast, ast.slice(1)); + if (ret != null) + return ret; + } + gen = walkers[type]; + return gen.apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + + function with_walkers(walkers, cont){ + var save = {}, i; + for (i in walkers) if (HOP(walkers, i)) { + save[i] = user[i]; + user[i] = walkers[i]; + } + var ret = cont(); + for (i in save) if (HOP(save, i)) { + if (!save[i]) delete user[i]; + else user[i] = save[i]; + } + return ret; + }; + + return { + walk: walk, + with_walkers: with_walkers, + parent: function() { + return stack[stack.length - 2]; // last one is current node + }, + stack: function() { + return stack; + } + }; +}; + +function empty(b) { + return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); +}; + +/* -----[ re-generate code from the AST ]----- */ + +var DOT_CALL_NO_PARENS = array_to_hash([ + "name", + "array", + "object", + "string", + "dot", + "sub", + "call", + "regexp" +]); + +function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + } + return s; + }); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; +}; + +var SPLICE_NEEDS_BRACKETS = array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); + +function gen_code(ast, options) { + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : false, + beautify : false + }); + var beautify = !!options.beautify; + var indentation = 0, + newline = beautify ? "\n" : "", + space = beautify ? " " : ""; + + function make_name(name) { + return name.toString(); + }; + + function indent(line) { + if (line == null) + line = ""; + if (beautify) + line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; + return line; + }; + + function with_indent(cont, incr) { + if (incr == null) incr = 1; + indentation += incr; + try { return cont.apply(null, slice(arguments, 1)); } + finally { indentation -= incr; } + }; + + function add_spaces(a) { + if (beautify) + return a.join(" "); + var b = []; + for (var i = 0; i < a.length; ++i) { + var next = a[i + 1]; + b.push(a[i]); + if (next && + ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || + (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { + b.push(" "); + } + } + return b.join(""); + }; + + function add_commas(a) { + return a.join("," + space); + }; + + function parenthesize(expr) { + var gen = make(expr); + for (var i = 1; i < arguments.length; ++i) { + var el = arguments[i]; + if ((el instanceof Function && el(expr)) || expr[0] == el) + return "(" + gen + ")"; + } + return gen; + }; + + function best_of(a) { + if (a.length == 1) { + return a[0]; + } + if (a.length == 2) { + var b = a[1]; + a = a[0]; + return a.length <= b.length ? a : b; + } + return best_of([ a[0], best_of(a.slice(1)) ]); + }; + + function needs_parens(expr) { + if (expr[0] == "function" || expr[0] == "object") { + // dot/call on a literal function requires the + // function literal itself to be parenthesized + // only if it's the first "thing" in a + // statement. This means that the parent is + // "stat", but it could also be a "seq" and + // we're the first in this "seq" and the + // parent is "stat", and so on. Messy stuff, + // but it worths the trouble. + var a = slice($stack), self = a.pop(), p = a.pop(); + while (p) { + if (p[0] == "stat") return true; + if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || + ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { + self = p; + p = a.pop(); + } else { + return false; + } + } + } + return !HOP(DOT_CALL_NO_PARENS, expr[0]); + }; + + function make_num(num) { + var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; + if (Math.floor(num) === num) { + a.push("0x" + num.toString(16).toLowerCase(), // probably pointless + "0" + num.toString(8)); // same. + if ((m = /^(.*?)(0+)$/.exec(num))) { + a.push(m[1] + "e" + m[2].length); + } + } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { + a.push(m[2] + "e-" + (m[1].length + m[2].length), + str.substr(str.indexOf("."))); + } + return best_of(a); + }; + + var generators = { + "string": make_string, + "num": make_num, + "name": make_name, + "toplevel": function(statements) { + return make_block_statements(statements) + .join(newline); + }, + "splice": function(statements) { + var parent = $stack[$stack.length - 2][0]; + if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { + // we need block brackets in this case + return make_block.apply(this, arguments); + } else { + return MAP(make_block_statements(statements, true), + function(line, i) { + // the first line is already indented + return i > 0 ? indent(line) : line; + }).join(newline); + } + }, + "block": make_block, + "var": function(defs) { + return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "const": function(defs) { + return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "try": function(tr, ca, fi) { + var out = [ "try", make_block(tr) ]; + if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); + if (fi) out.push("finally", make_block(fi)); + return add_spaces(out); + }, + "throw": function(expr) { + return add_spaces([ "throw", make(expr) ]) + ";"; + }, + "new": function(ctor, args) { + args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; + return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ + var w = ast_walker(), has_call = {}; + try { + w.with_walkers({ + "call": function() { throw has_call }, + "function": function() { return this } + }, function(){ + w.walk(expr); + }); + } catch(ex) { + if (ex === has_call) + return true; + throw ex; + } + }) + args ]); + }, + "switch": function(expr, body) { + return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); + }, + "break": function(label) { + var out = "break"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "continue": function(label) { + var out = "continue"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "conditional": function(co, th, el) { + return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", + parenthesize(th, "seq"), ":", + parenthesize(el, "seq") ]); + }, + "assign": function(op, lvalue, rvalue) { + if (op && op !== true) op += "="; + else op = "="; + return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); + }, + "dot": function(expr) { + var out = make(expr), i = 1; + if (expr[0] == "num") { + if (!/\./.test(expr[1])) + out += "."; + } else if (needs_parens(expr)) + out = "(" + out + ")"; + while (i < arguments.length) + out += "." + make_name(arguments[i++]); + return out; + }, + "call": function(func, args) { + var f = make(func); + if (needs_parens(func)) + f = "(" + f + ")"; + return f + "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")"; + }, + "function": make_function, + "defun": make_function, + "if": function(co, th, el) { + var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; + if (el) { + out.push("else", make(el)); + } + return add_spaces(out); + }, + "for": function(init, cond, step, block) { + var out = [ "for" ]; + init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); + cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); + step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); + var args = init + cond + step; + if (args == "; ; ") args = ";;"; + out.push("(" + args + ")", make(block)); + return add_spaces(out); + }, + "for-in": function(vvar, key, hash, block) { + return add_spaces([ "for", "(" + + (vvar ? make(vvar).replace(/;+$/, "") : make(key)), + "in", + make(hash) + ")", make(block) ]); + }, + "while": function(condition, block) { + return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); + }, + "do": function(condition, block) { + return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; + }, + "return": function(expr) { + var out = [ "return" ]; + if (expr != null) out.push(make(expr)); + return add_spaces(out) + ";"; + }, + "binary": function(operator, lvalue, rvalue) { + var left = make(lvalue), right = make(rvalue); + // XXX: I'm pretty sure other cases will bite here. + // we need to be smarter. + // adding parens all the time is the safest bet. + if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || + lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { + left = "(" + left + ")"; + } + if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && + !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { + right = "(" + right + ")"; + } + return add_spaces([ left, operator, right ]); + }, + "unary-prefix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return operator + (is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; + }, + "unary-postfix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return val + operator; + }, + "sub": function(expr, subscript) { + var hash = make(expr); + if (needs_parens(expr)) + hash = "(" + hash + ")"; + return hash + "[" + make(subscript) + "]"; + }, + "object": function(props) { + if (props.length == 0) + return "{}"; + return "{" + newline + with_indent(function(){ + return MAP(props, function(p){ + if (p.length == 3) { + // getter/setter. The name is in p[0], the arg.list in p[1][2], the + // body in p[1][3] and type ("get" / "set") in p[2]. + return indent(make_function(p[0], p[1][2], p[1][3], p[2])); + } + var key = p[0], val = make(p[1]); + if (options.quote_keys) { + key = make_string(key); + } else if ((typeof key == "number" || !beautify && +key + "" == key) + && parseFloat(key) >= 0) { + key = make_num(+key); + } else if (!is_identifier(key)) { + key = make_string(key); + } + return indent(add_spaces(beautify && options.space_colon + ? [ key, ":", val ] + : [ key + ":", val ])); + }).join("," + newline); + }) + newline + indent("}"); + }, + "regexp": function(rx, mods) { + return "/" + rx + "/" + mods; + }, + "array": function(elements) { + if (elements.length == 0) return "[]"; + return add_spaces([ "[", add_commas(MAP(elements, function(el){ + if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; + return parenthesize(el, "seq"); + })), "]" ]); + }, + "stat": function(stmt) { + return make(stmt).replace(/;*\s*$/, ";"); + }, + "seq": function() { + return add_commas(MAP(slice(arguments), make)); + }, + "label": function(name, block) { + return add_spaces([ make_name(name), ":", make(block) ]); + }, + "with": function(expr, block) { + return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); + }, + "atom": function(name) { + return make_name(name); + } + }; + + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + function make_then(th) { + if (th[0] == "do") { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 + // IE croaks with "syntax error" on code like this: + // if (foo) do ... while(cond); else ... + // we need block brackets around do/while + return make([ "block", [ th ]]); + } + var b = th; + while (true) { + var type = b[0]; + if (type == "if") { + if (!b[3]) + // no else, we must add the block + return make([ "block", [ th ]]); + b = b[3]; + } + else if (type == "while" || type == "do") b = b[2]; + else if (type == "for" || type == "for-in") b = b[4]; + else break; + } + return make(th); + }; + + function make_function(name, args, body, keyword) { + var out = keyword || "function"; + if (name) { + out += " " + make_name(name); + } + out += "(" + add_commas(MAP(args, make_name)) + ")"; + return add_spaces([ out, make_block(body) ]); + }; + + function make_block_statements(statements, noindent) { + for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { + var stat = statements[i]; + var code = make(stat); + if (code != ";") { + if (!beautify && i == last) { + if ((stat[0] == "while" && empty(stat[2])) || + (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || + (stat[0] == "if" && empty(stat[2]) && !stat[3]) || + (stat[0] == "if" && stat[3] && empty(stat[3]))) { + code = code.replace(/;*\s*$/, ";"); + } else { + code = code.replace(/;+\s*$/, ""); + } + } + a.push(code); + } + } + return noindent ? a : MAP(a, indent); + }; + + function make_switch_block(body) { + var n = body.length; + if (n == 0) return "{}"; + return "{" + newline + MAP(body, function(branch, i){ + var has_body = branch[1].length > 0, code = with_indent(function(){ + return indent(branch[0] + ? add_spaces([ "case", make(branch[0]) + ":" ]) + : "default:"); + }, 0.5) + (has_body ? newline + with_indent(function(){ + return make_block_statements(branch[1]).join(newline); + }) : ""); + if (!beautify && has_body && i < n - 1) + code += ";"; + return code; + }).join(newline) + newline + indent("}"); + }; + + function make_block(statements) { + if (!statements) return ";"; + if (statements.length == 0) return "{}"; + return "{" + newline + with_indent(function(){ + return make_block_statements(statements).join(newline); + }) + newline + indent("}"); + }; + + function make_1vardef(def) { + var name = def[0], val = def[1]; + if (val != null) + name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); + return name; + }; + + var $stack = []; + + function make(node) { + var type = node[0]; + var gen = generators[type]; + if (!gen) + throw new Error("Can't find generator for \"" + type + "\""); + $stack.push(node); + var ret = gen.apply(type, node.slice(1)); + $stack.pop(); + return ret; + }; + + return make(ast); +}; + +/* -----[ Utilities ]----- */ + +function repeat_string(str, i) { + return i < 1 ? "" : new Array(i + 1).join(str); +}; + +function defaults(args, defs) { + var ret = {}; + if (args === true) + args = {}; + for (var i in defs) if (HOP(defs, i)) { + ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + } + return ret; +}; + +function is_identifier(name) { + return /^[a-z_$][a-z0-9_$]*$/i.test(name) + && name != "this" + && !HOP(KEYWORDS_ATOM, name) + && !HOP(RESERVED_WORDS, name) + && !HOP(KEYWORDS, name); +}; + +function MAP(a, f, o) { + var ret = []; + for (var i = 0; i < a.length; ++i) { + ret.push(f.call(o, a[i], i)); + } + return ret; +}; + +/* -----[ Exports ]----- */ + +return { + parse: parse, + gen_code: gen_code, + tokenizer: tokenizer, + ast_walker: ast_walker +}; + +}; diff --git a/lib/prepro.js b/lib/prepro.js new file mode 100644 index 00000000..c92796a7 --- /dev/null +++ b/lib/prepro.js @@ -0,0 +1,43 @@ +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +// Since loading prepro.js is also used further down to prevent inline scripts +// from executing right away, check that its actual code is only executed once. +if (!window.include) { + // Determine the source of prepro.js, so we can use it to prevent inline + // scripts from loading straight away. + var scripts = document.getElementsByTagName('script'); + var script = scripts[scripts.length - 1]; + var src = script.getAttribute('src'); + var root = src.match(/^(.*\/)/)[1]; + + window.include = function(url) { + url = root + url; + var newRoot = url.match(/^(.*\/)/)[1]; + // Load prepro.js again, just to prevent the setting of newRoot frome + // executing straight away, and delaying it until right before the + // script at 'url' is loaded. + document.write([ + '', + // Set newRoot, so include() from 'url' load from the right place + '', + // Load the actual script + '', + // Set root back to the root before + '' + ].join('')); + } +} diff --git a/lib/stats.js b/lib/stats.js new file mode 100644 index 00000000..5d85f626 --- /dev/null +++ b/lib/stats.js @@ -0,0 +1,10 @@ +// stats.js r5 - http://github.com/mrdoob/stats.js +var Stats=function(){function w(d,K,n){var u,f,c;for(f=0;f<30;f++)for(u=0;u<73;u++){c=(u+f*74)*4;d[c]=d[c+4];d[c+1]=d[c+5];d[c+2]=d[c+6]}for(f=0;f<30;f++){c=(73+f*74)*4;if(f'+q+" MS ("+D+"-"+E+")";r.putImageData(F,0,0);J=l;if(l> +z+1E3){o=Math.round(y*1E3/(l-z));A=Math.min(A,o);B=Math.max(B,o);w(C.data,Math.min(30,30-o/100*30),"fps");g.innerHTML=''+o+" FPS ("+A+"-"+B+")";p.putImageData(C,0,0);if(x==3){s=performance.memory.usedJSHeapSize*9.54E-7;G=Math.min(G,s);H=Math.max(H,s);w(I.data,Math.min(30,30-s/2),"mem");k.innerHTML=''+Math.round(s)+" MEM ("+Math.round(G)+"-"+Math.round(H)+")";t.putImageData(I,0,0)}z=l;y=0}}}}; + diff --git a/node.js/index.js b/node.js/index.js new file mode 100644 index 00000000..243a9d1b --- /dev/null +++ b/node.js/index.js @@ -0,0 +1,58 @@ +var fs = require('fs'), + vm = require('vm'), + path = require('path'), + Canvas = require('canvas'); + +__dirname = path.resolve(__dirname, '../src/'); + +// Create the context within which we will run the source files: +var context = vm.createContext({ + options: { + server: true, + version: 'dev' + }, + fs: fs, + // Node Canvas library: https://github.com/learnboost/node-canvas + Canvas: Canvas, + HTMLCanvasElement: Canvas, + Image: Canvas.Image, + // Copy over global variables: + console: console, + require: require, + __dirname: __dirname, + __filename: __filename, + // Used to load and run source files within the same context: + include: function(uri) { + var source = fs.readFileSync(path.resolve(__dirname, uri), 'utf8'); + // For relative includes, we save the current directory and then + // add the uri directory to __dirname: + var oldDirname = __dirname; + __dirname = path.resolve(__dirname, path.dirname(uri)); + vm.runInContext(source, context, uri); + __dirname = oldDirname; + } +}); + +// Load Paper.js library files: +context.include('paper.js'); + +context.Base.each(context, function(val, key) { + if (val && val.prototype instanceof context.Base) { + val._name = key; + // Export all classes through PaperScope: + context.PaperScope.prototype[key] = val; + } +}); +context.PaperScope.prototype['Canvas'] = context.Canvas; + +require.extensions['.pjs'] = function(module, uri) { + var source = context.PaperScript.compile(fs.readFileSync(uri, 'utf8')); + var envVars = 'var __dirname = \'' + path.dirname(uri) + '\';' + + 'var __filename = \'' + uri + '\';'; + vm.runInContext(envVars, context); + var scope = new context.PaperScope(); + context.PaperScript.evaluate(source, scope); + module.exports = scope; +}; + +module.exports = new context.PaperScope(); \ No newline at end of file From 981f11365237a0284e6197e52083f839a2a8fa32 Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:11:00 -0300 Subject: [PATCH 42/51] Update src/svg/ExportSVG.js --- src/svg/ExportSVG.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/svg/ExportSVG.js b/src/svg/ExportSVG.js index fb24a2ee..26bc5464 100644 --- a/src/svg/ExportSVG.js +++ b/src/svg/ExportSVG.js @@ -221,12 +221,11 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ break; } //If the object is a circle, ellipse, rectangle, or rounded rectangle, it will find the angle - //found by the transformCheck method and make a path that accommodates for the transformed object + //found by the determineIfTransformed method and make a path that accommodates for the transformed object if(type != 'text' && type != undefined && type != 'polygon' && type != 'polyline' && type != 'line') { //TODO: Need to implement exported transforms for circle, ellipse, and rectangles instead of //making them paths var angle = this._determineIfTransformed(path, pointArray, type) + 90; - console.log(angle); if(angle != 0) { if(type == 'rect' || type == 'roundRect') { svgEle = document.createElementNS(this.NS, 'path'); @@ -307,7 +306,7 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ return svgEle; }, - //Determines whether the object has been transformed or not through determining the angle + //Determines whether the object has been transformed or not through finding the angle _determineIfTransformed: function(path, pointArray, type) { var topMidBoundx = (path.bounds.topRight.getX() + path.bounds.topLeft.getX() )/2; var topMidBoundy = (path.bounds.topRight.getY() + path.bounds.topLeft.getY() )/2; @@ -473,7 +472,6 @@ var ExportSVG = this.ExportSVG = Base.extend(/** @Lends ExportSVG# */{ } else { type = null; } - console.log(type); return type; } }); From e0617b3c21e29fe1b18a54d0e36dffc375d9655a Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:12:17 -0300 Subject: [PATCH 43/51] Update examples/ExportSVGTests/Circle Testing.html --- examples/ExportSVGTests/Circle Testing.html | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/ExportSVGTests/Circle Testing.html b/examples/ExportSVGTests/Circle Testing.html index b81d0035..ee665747 100644 --- a/examples/ExportSVGTests/Circle Testing.html +++ b/examples/ExportSVGTests/Circle Testing.html @@ -13,23 +13,22 @@ initializePath(); function initializePath() { - var topLeft = new Point(-200, -200); - var size = new Size(-150, -100); + var topLeft = new Point(200, 200); + var size = new Size(150, 100); var rectangle = new Rectangle(topLeft, size); var path = new Path.Oval(rectangle); path.fillColor = 'black'; - var topLeft = new Point(-5, -400); - var size = new Size(-100, -50); + var topLeft = new Point(5, 400); + var size = new Size(100, 50); var rectangle = new Rectangle(topLeft, size); var path = new Path.Oval(rectangle); path.fillColor = 'yellow'; - var path = new Path.Circle(new Point(-25, -25), -7); + var path = new Path.Circle(new Point(50, 50), 25); path.fillColor = 'red'; var esvg = new ExportSVG(); - //esvg.exportProject(paper.project); var output = esvg.exportProject(paper.project); console.log(output); var test = document.getElementById('svg') From 333b6bb0edf1f74e8cbd41208647effabe8cd556 Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:12:42 -0300 Subject: [PATCH 44/51] Update examples/ExportSVGTests/Empty Path Testing.html --- examples/ExportSVGTests/Empty Path Testing.html | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/ExportSVGTests/Empty Path Testing.html b/examples/ExportSVGTests/Empty Path Testing.html index da75294e..36a71de5 100644 --- a/examples/ExportSVGTests/Empty Path Testing.html +++ b/examples/ExportSVGTests/Empty Path Testing.html @@ -24,7 +24,6 @@ var esvg = new ExportSVG(); - //esvg.exportProject(paper.project); var output = esvg.exportProject(paper.project); console.log(output); var test = document.getElementById('svg') From db6e712203644a8c6a7a103b303d5aa2b60dfb7f Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:13:09 -0300 Subject: [PATCH 45/51] Update examples/ExportSVGTests/Line Testing.html --- examples/ExportSVGTests/Line Testing.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/ExportSVGTests/Line Testing.html b/examples/ExportSVGTests/Line Testing.html index 97e1a874..0a249da2 100644 --- a/examples/ExportSVGTests/Line Testing.html +++ b/examples/ExportSVGTests/Line Testing.html @@ -19,7 +19,7 @@ y2 = 45; var line1 = new Path.Line([x1, y1], [x2, y2]); line1.strokeColor = "blue"; - line1.strokeWidth = "10px"; + line1.strokeWidth = "10"; var x3 = 20, x4 = 99, @@ -35,10 +35,9 @@ y6 = 300; var line3 = new Path.Line([x5, y5], [x6, y6]); line3.strokeColor = "yellow"; - line3.strokeWidth = "5px"; + line3.strokeWidth = "5"; var esvg = new ExportSVG(); - //esvg.exportProject(paper.project); var output = esvg.exportProject(paper.project); console.log(output); var test = document.getElementById('svg') From 834a6466082631dd6e6f8d2b2f6d3aa110c2177a Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:13:48 -0300 Subject: [PATCH 46/51] Update examples/ExportSVGTests/Rect and Attribute Testing.html --- examples/ExportSVGTests/Rect and Attribute Testing.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ExportSVGTests/Rect and Attribute Testing.html b/examples/ExportSVGTests/Rect and Attribute Testing.html index e384fc0e..10610cdd 100644 --- a/examples/ExportSVGTests/Rect and Attribute Testing.html +++ b/examples/ExportSVGTests/Rect and Attribute Testing.html @@ -29,7 +29,7 @@ var point22 = new Point(100, 100); var path2 = new Path.Rectangle(point2, point22); path2.strokeColor = 'red'; - path2.strokeWidth = '4px'; + path2.strokeWidth = '4'; path2.fillColor = 'blue'; path2.id = "square2"; path2.strokeCap = "butt"; From b2c4d1b6d78fb16039f69256a5f6aa88d1b4b830 Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:14:07 -0300 Subject: [PATCH 47/51] Update examples/ExportSVGTests/Transform Test 1.html --- examples/ExportSVGTests/Transform Test 1.html | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/ExportSVGTests/Transform Test 1.html b/examples/ExportSVGTests/Transform Test 1.html index d44566cd..028b2597 100644 --- a/examples/ExportSVGTests/Transform Test 1.html +++ b/examples/ExportSVGTests/Transform Test 1.html @@ -26,7 +26,6 @@ }; var esvg = new ExportSVG(); - //esvg.exportProject(paper.project); var output = esvg.exportProject(paper.project); console.log(output); var test = document.getElementById('svg') From 0efcaade4b5e8798fac54717eb03b464f82d5842 Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:14:43 -0300 Subject: [PATCH 48/51] Update examples/ExportSVGTests/Text Testing.html --- examples/ExportSVGTests/Text Testing.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/ExportSVGTests/Text Testing.html b/examples/ExportSVGTests/Text Testing.html index c7c824e7..565eaf1f 100644 --- a/examples/ExportSVGTests/Text Testing.html +++ b/examples/ExportSVGTests/Text Testing.html @@ -26,9 +26,6 @@ center = new Point(100,100); var path2 = new Path.Circle(center,radius); path2.strokeColor = 'black'; - console.log(path2.getSegments()); - //copy = path2.clone(); - //copy.strokeColor = 'blue'; point = new Point(120,100); path2.shear(.5, .5); colors = ['red', 'blue', 'green', 'orange']; @@ -36,12 +33,10 @@ var p = path2.segments[i].point; var c = new Path.Circle(p, 2); c.fillColor = colors[i]; - } - console.log(path2.segments); + } var esvg = new ExportSVG(); var output = esvg.exportProject(paper.project); - //console.log(output); var test = document.getElementById('svg') test.innerHTML = ""; test.appendChild (output); From 644ed772d5e892e4071eee8b07e0941c96d46a5c Mon Sep 17 00:00:00 2001 From: jaroles Date: Sun, 30 Sep 2012 22:15:07 -0300 Subject: [PATCH 49/51] Update examples/ExportSVGTests/Transform Test 2.html --- examples/ExportSVGTests/Transform Test 2.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/ExportSVGTests/Transform Test 2.html b/examples/ExportSVGTests/Transform Test 2.html index 9e9da551..527e2b33 100644 --- a/examples/ExportSVGTests/Transform Test 2.html +++ b/examples/ExportSVGTests/Transform Test 2.html @@ -22,9 +22,7 @@ copy.rotate(-45); copy.scale(0.5); var esvg = new ExportSVG(); - //esvg.exportProject(paper.project); var output = esvg.exportProject(paper.project); - console.log(output); var test = document.getElementById('svg') test.innerHTML = ""; test.appendChild (output); From 25081366027097477a82d75886966abba4e9ae65 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 30 Sep 2012 21:17:02 -0400 Subject: [PATCH 50/51] Got rid of swp files --- examples/Tools/.SVGCircles.html.swp | Bin 12288 -> 0 bytes examples/Tools/.SVGRect.html.swp | Bin 12288 -> 0 bytes src/path/.Path.Constructors.js.swp | Bin 16384 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/Tools/.SVGCircles.html.swp delete mode 100644 examples/Tools/.SVGRect.html.swp delete mode 100644 src/path/.Path.Constructors.js.swp diff --git a/examples/Tools/.SVGCircles.html.swp b/examples/Tools/.SVGCircles.html.swp deleted file mode 100644 index 56100d522b699739475fdbbd8ad66a657478d5f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2Pj4GV7>6g^0<<7{<1}4V;tG4$aT8inJ5uCS1wj>~xRDSS#_QMiCgYuDX4Xks z;J_!~!e7BB-~e|{aNrAYg$oBHZb)$AK>5wC?Ica56mg4Yl}Fypyz}lm&v^EbOs~H4 z+8us9yvA@n%b5Ohr{iwr3S--`vex}_#UL|L_8DO;UW@J;(k3brN14b-hr1@C z12N7dnW(FjMDNb+cA{f6gd;naXJz&M-hemocm^)AYmMdl3&CZ6>AAa)H^fJI1Kxl) z;0<^K-hemY4R{0Iz_~GCvjz45vv~r%3>K!~!(ZNjH{cC;1Kxl);0<^K-hemY4R{0I zfH!bX42V8suRO`vm8UQv{Quwm4d9Pw82cUk3cdm#f;Yhh@WVyMJ^}=8gO|W1@b?AA z{sMo3-@uRHd+;^52i^f2;CZkB82IUF#=ZsLfDgbM;C1jKxB?!arhmXM;Aik1_yT+m zJ_DbEPr%3EJ#Zi7U>Eej+h7&cKrz2_vSxl7-hemY4R{0IfH&X`cmw~-Kr?d3OxIa6 z>ZxP*kG@s?!*#aUj72&Th9~`2P~HYylS%H;dNV2;kgrz+BM*tb8x)yXCz-|V;^O-^ znfqAGgdK&N#%e-a>82LL%2o8ZYu4Kcg^s(bVpY~rNouRy>YNZY58y4H(mwAXRYlUk z7GW-pi5QpNMK8)$&o)L}>16=&G*D zUKMFyQsYE?y~=B=t6`&YV>*RLjCg238NM>FWIo3eaq~LdtfOcw_L6kSHwrazah{k9 z%LR`~TalzZb0$hhu}Y1S6iPL$n8{G(_E>FY10IE&kPb4XZDHE2+{v(MIk$=!oMLuM z>53`V*pQ^yQXfHX{f>HOlW<>z^4xQUCY0K+D6q=4=qI^3_N1}_!*p#nR;xW~E2;DvU+PH_?=2M_gG9<%^ZqEY zv{ZHNnO3`)MHuH=qr`1{C<%oW1w;|IBQnHI(TY$U@3skESk6@+1g zAKXS*#b~}lIDH;q$Cjc0DOEo))51>WkV(3S`N&pKm@p$E8}N~)K~YC+OjLA)xC`7v zZDJ*@A02ydMr8}S#$*K_S)0}9-8`AJg0@O6%-6cm0~zISQ%~+Sc9X{=p$*wqZU?m+ Z$lokqKh5b&?(*hVyZct>7P7jR-oLlv#(e+) diff --git a/examples/Tools/.SVGRect.html.swp b/examples/Tools/.SVGRect.html.swp deleted file mode 100644 index 0e8ea1331f14726d24e8667d7e0c64bc6dbbb5b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2J#W)M7{{+n1f)_?Ay(H6O{>ICTUDUu1wmR>9jZnot;B>J=aM*ae8zW4Ur+~z zegRlm5E2psAz0Y>0DJ)W2yBRjjS>E5r>&q!EfXSoto-8h-E(K(Prb)#d-dGb+PZPw zT3|RP82j{StD=i<))=e0LMeT5%26$E)N0vE`IIo`F4>!sN79Z5wnHc6k=2nl-*I}O z&!t@x!bj`Y>K*PXtF3zeX+u&w86X2^HZZ=qFh7^OW=fDDiU zGC&5%02vq!11cP2KQNVZUfDDiUGC&5%02v?yWMD)LI1R>L zpJ%L|!i4bufBiRrZlLWN># zKR;{ZlyXHNh0iTtw9<0W5`8t3*YyJ@GLmbfs0$X~2}PtTj%ueveEkxIkbrL+D{%<6 zUZ#^)9XD*!{VcsB(+OHWPlv(_R7OAU@i=kaVYqHj&*yR(a2%pL3?r&2rWbRW#iaQG zp4pyl_5)XWA~1SRmmlA4293#QKc3sanKK{oKv@m39aR1>``@QFhq(hfk%Is3ryyRi zdPN?sM-i-xzU0f1(@MwdKrcz1Vswhg<2O9yBYdT#ibR)}g)gEdW4i7;Zg*POH$C4! ztle&Vice=yt#1)VqN6u@yZtD_`l_m3A1MO4E=hHU+6{TpRD4Gzd&QG#(@1jUQS#K; z@nnyVgB%;DOw*8&TQn`p#s@_kDbYU4ci4b#BJU=le>GIYlfwr)F^2C2UF3AXXi7aP z+2&lCMmyro_&HoD?YO~0$<#Mhp7MEVxbwYWCzq)2apf3orNS(~-}eSZvn&DySJ@ie tz(jI2l%(G?dBbfxk>sk_SIz7V3|>gyAcf&uXli+*T)SIY!KnJJ^b>)_^o;-j diff --git a/src/path/.Path.Constructors.js.swp b/src/path/.Path.Constructors.js.swp deleted file mode 100644 index f5c885e4cb553ac42c8aea2854fec711af57b665..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI2ZHOdC8OQrBFJ?TAAqi1DF?A;KW_I^_Ue?PU8`s-qbH-bCi^-B&8&7lMl-w1vXMea*f40uS8n0z@2h;M;FAj0V(sE9HCpQ`Gf zo_)F9J2q&v2Yxf%)%DcNQ%^nhR87}Qr%ueWBj%`q&n<@W^5<(+x@=DyM$Pu4h;Fv| z)TTZ@H+QHywM{m|9xI*P!#|I-=3>+dp*%it3D4)`QE4i195!Jlq6jGusKz%mHI zJU9(b0TbK+t_PRiX&65OUjQe;UEogeey|t(^Bsoq8}Jf12hM`iU_bctKAbmz--2hr zIpBd=@BpZQz2MT@4dXfRb?{a2W$-2N1h^j@1NVS^;4eAk1wRAl!5Odw#=t)C+D(S> z3ius313m_B1be`%Z!?TR@GbB;&;u*rL*RYj-QXWL7{-g>7vRU> zNg%)^xD{N!9(@JB1W$vr;BjDqNiYQVgG)Gwxd6TbT)@FB7zane5l{wy#dux@7r|5D z5#WMPfun%N`!=xICzoSGY}pblbROeuoOyhO)o__Fmr5fHUxoXOBv0TwUZgWs>3T!1 z3I3?n30y8^l;DKmQCE0ujo$d^v8c_d5_gr^f?E-9FnS$CXALZ2b=Vp;pr=|y*=5uG zrW6%^*K0t?_JxPnO9tg0;&xN9m%0%wH^io7T_LmN1LWzt=rgs5orrjctvI+^ zSGEcH;?R(RpWX<*a=IhbUQ$YqF3g8**ALO4afTOJxJ+M=I?LsxE_tiNp(v>?Q*}8n zoK`y;VRgK6<97-LDr?)!kslNavKd=vb$JuT?mTDQ09mZ+jn!!6=VgQFJ|1ga=5?o( z40YEJ*sxTm+2*oCQcU&@kEt#3^A)ENwN=|mYFtUJ$`rCanOCPiDpP6rkS`ff6XVy& zTcXt^ZHBTf$-^<$?0R^hHDIQOWj9c>dHw|N*^!ht9EIK~@d zbuK$Yb6ieo3!T;eLb(O)wc(@MYKgcu(~=4dO;Sk6S;J?ZPtJaK%`BPYX%kBl--;8z zzpQR;W%|jLt>>EjfwFos337%T7FVg|T&||p%XR)94mIL|`c}*3R{1d9DXUs3^@2?v zx=KqJI+v5N4su`sXOU($UEde|mBns$ta87%iKd+fr1PvdUdu zQB=wIO^QY;6_iCQK1<7otm%sm`Av&qwUUO!)bfJ$tA!XYh@1#MtJYtj!X7G--a%Ug zuGs`ex)G`cY^aF;K648c5Tt{)`I31ULGZ!|n_semz#3sCMmLAzy9F}F0f{p5n1?A7 z21e!6H&TWzNXr}$k(HDN%N?k36OnW+y5NB-NrddhU$$I5RYDloJbFpVN@Sc>VCSP) z;PY}SgpY_QUn#IdtPHcHaWEZk5i3)E4U@`>96KD7;Z726(R45<(n1-NuFIsC4-wws z)$e8AFp*A=?su@*IQ1??`xL$lX&bXA<}iXb_d;&68s}{0#MJQzYsazrVE8b~tidD8 zal^Qnb`%9;#iGmGo@4r=Rb(GzI&IPS&|J$4y7m%ZHEq8m+cf0|t7_%R+Xc*%GKOcm z%SDULP$7_?)`F}mC3S;!si7^LAo5$n3fg#movNhn=%@0X_Qfzsu3HrL_#Ufm5Q7Cb z(3{X{dC5wN4M>Y)@tmxlz;334spQmMm@_JvYdbJ=(gJ=F3PcR^t*T$4AA#XdTg#TJ zg`L9qKvfS=8!21$+F9;6?BPcn+Kc zXTfQ32lxZ__UFO(!8gEXz)3I(hQX`Y+g|`b1wQ~^1a&YAj)2S9-#-t24$gokm;q&Q zJNP~J_0NK*Km?}2o#4HI_WZA5FaK-sD{v9K0GV_*L~I1j!C7QjcqQDA_Vu)n_mz6+iJK9~jvz~7*=AA;|JC&6cd2NppSkWN1h zvQMUgOaqw){x3Dq>rpt{qcDmht{oqkQ5b1HOh-?l3jfssk17NqyIkT-;Ufm&c?$2b zMmhzv({&>!a98sVy9c4nF(#~r(+w+ZOkb4?1--3^%bj-?bd0T|qCDb{2x~i4PEDq; zBTpfcgM6j?@bh8jbvrU74skm?thNBTTwJ6sZ&CTbEL}Pl$Wa}`hr1^Lh$JyZ$HF_Yqj80b4$#OqJ zvF*L7yoo;K*6&R`seZ8AsdIsYG-Y|JwejiA;KTCf5BsBuGZ7jIltmKWf{fBqq71d z&<8%MY#hcg8Ph76wF%pA@L04bWe3tKJ)F8HWzgvpS6x)a^*4mnhYiP#8_o}QdN_Yo zz6PFU7z${H9H+`d>SSTJTuRNshG0h?Mds8FMKuQI9<>FwOvm6$;O=M(3AM$p5|8_a zkIA3p)q@@TN9~2w<8gL?+?T8j{&aK;7bTx>!{| zpSGiQ-l)NCtIZq2_slE%q<+R&HMHUkR-gE&kOn69OdA~&N*M4X|I%Mpg#`l z|4=Iy_2DP>bE)>}b9FLPH4!#B)4^t1{`;^^uj6cQUY|#=&gZ7PoHTAH9iGs$`zroJ z9CW_Y84kL-Kv|tuvOaK+rILv-=#rWPN+$N1whV;czX3{Qu~h&7 From 777e1c6275c09668b0567df85bd667a62792c126 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 30 Sep 2012 21:18:39 -0400 Subject: [PATCH 51/51] Removed unnecessary files --- examples/Scripts/ImportSVG.html | 32 ----------- examples/Tools/SVGBezierTool.html | 89 ------------------------------- examples/Tools/SVGCircles.html | 54 ------------------- examples/Tools/SVGGrid.html | 48 ----------------- examples/Tools/SVGRect.html | 32 ----------- examples/Tools/SVGStars.html | 34 ------------ 6 files changed, 289 deletions(-) delete mode 100644 examples/Scripts/ImportSVG.html delete mode 100644 examples/Tools/SVGBezierTool.html delete mode 100644 examples/Tools/SVGCircles.html delete mode 100644 examples/Tools/SVGGrid.html delete mode 100644 examples/Tools/SVGRect.html delete mode 100644 examples/Tools/SVGStars.html diff --git a/examples/Scripts/ImportSVG.html b/examples/Scripts/ImportSVG.html deleted file mode 100644 index da8d79cc..00000000 --- a/examples/Scripts/ImportSVG.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Stroke Bounds - - - - - - - - - - - - - - - I love SVG - - - - \ No newline at end of file diff --git a/examples/Tools/SVGBezierTool.html b/examples/Tools/SVGBezierTool.html deleted file mode 100644 index e09541a1..00000000 --- a/examples/Tools/SVGBezierTool.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - Bezier Tool - - - - - - -

- An emulation of a vector pen tool. - Click and drag to add a points.
- Drag segment handles and points to manipulate them. - Close the path to start a new one. -

- - - \ No newline at end of file diff --git a/examples/Tools/SVGCircles.html b/examples/Tools/SVGCircles.html deleted file mode 100644 index 9468bed8..00000000 --- a/examples/Tools/SVGCircles.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - SVGCircles - - - - - - - - - diff --git a/examples/Tools/SVGGrid.html b/examples/Tools/SVGGrid.html deleted file mode 100644 index 0fd8e5a9..00000000 --- a/examples/Tools/SVGGrid.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - Grid - - - - - - - - - \ No newline at end of file diff --git a/examples/Tools/SVGRect.html b/examples/Tools/SVGRect.html deleted file mode 100644 index becba17d..00000000 --- a/examples/Tools/SVGRect.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - SVGRect - - - - - - - - - diff --git a/examples/Tools/SVGStars.html b/examples/Tools/SVGStars.html deleted file mode 100644 index b0550020..00000000 --- a/examples/Tools/SVGStars.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - Stars - - - - - - - - -