From 0ebdc2a719b1801925131a0704b978f2347e8c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 12 Jun 2011 19:04:25 +0100 Subject: [PATCH] Also include prebuilt docs for now. --- dist/docs/classes/CharacterStyle.html | 402 ++ dist/docs/classes/Color.html | 632 ++ dist/docs/classes/CompoundPath.html | 3412 ++++++++++ dist/docs/classes/Curve.html | 781 +++ dist/docs/classes/CurveLocation.html | 461 ++ dist/docs/classes/Gradient.html | 197 + dist/docs/classes/GradientColor.html | 462 ++ dist/docs/classes/GradientStop.html | 255 + dist/docs/classes/GrayColor.html | 708 +++ dist/docs/classes/Group.html | 2960 +++++++++ dist/docs/classes/HSBColor.html | 725 +++ dist/docs/classes/Item.html | 2826 +++++++++ dist/docs/classes/Key.html | 97 + dist/docs/classes/KeyEvent.html | 175 + dist/docs/classes/Layer.html | 2961 +++++++++ dist/docs/classes/Line.html | 326 + dist/docs/classes/Matrix.html | 1511 +++++ dist/docs/classes/ParagraphStyle.html | 87 + dist/docs/classes/Path.html | 5274 ++++++++++++++++ dist/docs/classes/PathStyle.html | 323 + dist/docs/classes/PlacedSymbol.html | 2952 +++++++++ dist/docs/classes/Point.html | 2184 +++++++ dist/docs/classes/PointText.html | 3061 +++++++++ dist/docs/classes/Project.html | 449 ++ dist/docs/classes/RGBColor.html | 724 +++ dist/docs/classes/Raster.html | 3536 +++++++++++ dist/docs/classes/Rectangle.html | 1232 ++++ dist/docs/classes/Segment.html | 517 ++ dist/docs/classes/Size.html | 1243 ++++ dist/docs/classes/Symbol.html | 269 + dist/docs/classes/TextItem.html | 2973 +++++++++ dist/docs/classes/Tool.html | 568 ++ dist/docs/classes/ToolEvent.html | 326 + dist/docs/classes/View.html | 419 ++ dist/docs/classes/global.html | 428 ++ dist/docs/classes/index.html | 84 + dist/docs/index.html | 12 + dist/docs/resources/css/assets/bullet.gif | Bin 0 -> 44 bytes dist/docs/resources/css/codemirror.css | 110 + dist/docs/resources/css/paperscript.css | 53 + dist/docs/resources/css/reference.css | 133 + 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 | 6922 +++++++++++++++++++++ dist/docs/resources/js/reference.js | 230 + 46 files changed, 57127 insertions(+) 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/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/HSBColor.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/ParagraphStyle.html create mode 100644 dist/docs/classes/Path.html create mode 100644 dist/docs/classes/PathStyle.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/RGBColor.html create mode 100644 dist/docs/classes/Raster.html create mode 100644 dist/docs/classes/Rectangle.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 diff --git a/dist/docs/classes/CharacterStyle.html b/dist/docs/classes/CharacterStyle.html new file mode 100644 index 00000000..3b87c2aa --- /dev/null +++ b/dist/docs/classes/CharacterStyle.html @@ -0,0 +1,402 @@ + + + +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..13c27a23 --- /dev/null +++ b/dist/docs/classes/Color.html @@ -0,0 +1,632 @@ + + + +Color + + + + + + + + + + + +
+

Color

+ + +
+ + + + +

Operators

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

Properties

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

RGB Components

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

Gray Components

+ +
+ + +
+ + +

HSB Components

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

Functions

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

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..3bfdcdec --- /dev/null +++ b/dist/docs/classes/CompoundPath.html @@ -0,0 +1,3412 @@ + + + +CompoundPath + + + + + + + + + + + +
+

CompoundPath

+ +

Extends 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

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

Functions

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

Postscript Style Drawing Commands

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

Properties inherited from Item

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

Project Hierarchy

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

Bounding Rectangles

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

Stroke Style

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

Fill Style

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

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..c22cf247 --- /dev/null +++ b/dist/docs/classes/Curve.html @@ -0,0 +1,781 @@ + + + +Curve + + + + + + + + + + + +
+

Curve

+ +

The Curve object represents...

+
+ + +

Constructors

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

Properties

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

Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..d96fcb48 --- /dev/null +++ b/dist/docs/classes/CurveLocation.html @@ -0,0 +1,461 @@ + + + +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.

+
+ + +

Constructors

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

Properties

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..64ea80a8 --- /dev/null +++ b/dist/docs/classes/Gradient.html @@ -0,0 +1,197 @@ + + + +Gradient + + + + + + + + + + + +
+

Gradient

+ +

The Gradient object.

+
+ + +

Constructors

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

Operators

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

Properties

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..cb7d84d8 --- /dev/null +++ b/dist/docs/classes/GradientColor.html @@ -0,0 +1,462 @@ + + + +GradientColor + + + + + + + + + + + +
+

GradientColor

+ +

The GradientColor object.

+
+ + +

Constructors

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

Properties

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

Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..71f7e967 --- /dev/null +++ b/dist/docs/classes/GradientStop.html @@ -0,0 +1,255 @@ + + + +GradientStop + + + + + + + + + + + +
+

GradientStop

+ +

The GradientStop object.

+
+ + +

Constructors

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

Properties

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..7ed1e7a8 --- /dev/null +++ b/dist/docs/classes/GrayColor.html @@ -0,0 +1,708 @@ + + + +GrayColor + + + + + + + + + + + +
+

GrayColor

+ +

Extends Color

+ +

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

+
+ + +

Constructors

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

Properties inherited from Color

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

RGB Components

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

Gray Components

+ +
+ + +
+ + +

HSB Components

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

Functions 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..297cb939 --- /dev/null +++ b/dist/docs/classes/Group.html @@ -0,0 +1,2960 @@ + + + +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

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..5afe6f66 --- /dev/null +++ b/dist/docs/classes/HSBColor.html @@ -0,0 +1,725 @@ + + + +HSBColor + + + + + + + + + + + +
+

HSBColor

+ +

Extends Color

+ +

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

+
+ + +

Constructors

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

Properties inherited from Color

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

RGB Components

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

Gray Components

+ +
+ + +
+ + +

HSB Components

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

Functions 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..fc9b2561 --- /dev/null +++ b/dist/docs/classes/Item.html @@ -0,0 +1,2826 @@ + + + +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

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

Functions

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

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..b73c7e21 --- /dev/null +++ b/dist/docs/classes/Key.html @@ -0,0 +1,97 @@ + + + +Key + + + + + + + + + + + +
+

Key

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

Static Functions

+ + +
+ + +
+ +
+ + + + + + + \ 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..64fe4ccd --- /dev/null +++ b/dist/docs/classes/KeyEvent.html @@ -0,0 +1,175 @@ + + + +KeyEvent + + + + + + + + + + + +
+

KeyEvent

+ +

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

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..eaa15ca0 --- /dev/null +++ b/dist/docs/classes/Layer.html @@ -0,0 +1,2961 @@ + + + +Layer + + + + + + + + + + + +
+

Layer

+ +

Extends Group, Item

+ +

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

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

Functions

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

Properties inherited from Group

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

Properties inherited from Item

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

Project Hierarchy

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

Bounding Rectangles

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

Stroke Style

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

Fill Style

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..d2a509db --- /dev/null +++ b/dist/docs/classes/Line.html @@ -0,0 +1,326 @@ + + + +Line + + + + + + + + + + + +
+

Line

+ +

The Line object represents..

+
+ + +

Constructors

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

Properties

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

Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..e8f82bf0 --- /dev/null +++ b/dist/docs/classes/Matrix.html @@ -0,0 +1,1511 @@ + + + +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']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
+     [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
+     [ 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

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

Functions

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

Static Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..66e79e50 --- /dev/null +++ b/dist/docs/classes/ParagraphStyle.html @@ -0,0 +1,87 @@ + + + +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..45fff5ec --- /dev/null +++ b/dist/docs/classes/Path.html @@ -0,0 +1,5274 @@ + + + +Path + + + + + + + + + + + +
+

Path

+ +

Extends Item

+ +

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

+
+ + +

Constructors

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

Properties

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

Functions

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

Positions on Paths and Curves

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

Path Smoothing

+ +
+ + +
+ + +

Postscript Style Drawing Commands

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

Properties inherited from Item

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

Project Hierarchy

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

Bounding Rectangles

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

Stroke Style

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

Fill Style

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

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..c4e3d888 --- /dev/null +++ b/dist/docs/classes/PathStyle.html @@ -0,0 +1,323 @@ + + + +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:

+
+var circleStyle = {
+	fillColor: new RGBColor(1, 0, 0),
+	strokeColor: 'black',
+	strokeWidth: 5
+};
+var path = new Path.Circle(new Point(50, 50), 30);
+path.style = circleStyle;
+
+
+ + + + + +

Properties

+ + +

Stroke Style

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

Fill Style

+ +
+ + +
+ +
+ + + + + + + + + + \ 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..ed177fd5 --- /dev/null +++ b/dist/docs/classes/PlacedSymbol.html @@ -0,0 +1,2952 @@ + + + +PlacedSymbol + + + + + + + + + + + +
+

PlacedSymbol

+ +

Extends Item

+ +

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

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..7424fd3f --- /dev/null +++ b/dist/docs/classes/Point.html @@ -0,0 +1,2184 @@ + + + +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

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

Functions

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

Distance & Length

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

Angle & Rotation

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

Tests

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

Vector Math Functions

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

Math Functions

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

Static Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..529c6dca --- /dev/null +++ b/dist/docs/classes/PointText.html @@ -0,0 +1,3061 @@ + + + +PointText + + + + + + + + + + + +
+

PointText

+ +

Extends TextItem, Item

+ +

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 TextItem

+ + +
+ + +
+ + +

Style Properties

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

Properties inherited from Item

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

Project Hierarchy

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

Bounding Rectangles

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

Stroke Style

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

Fill Style

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..3edf695e --- /dev/null +++ b/dist/docs/classes/Project.html @@ -0,0 +1,449 @@ + + + +Project + + + + + + + + + + + +
+

Project

+ +

The Project item refers to..

+

The currently active project can be accessed through the global project variable.

+

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

+
+ + +

Constructors

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

Properties

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

Project Hierarchy

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

Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..c3cd315b --- /dev/null +++ b/dist/docs/classes/RGBColor.html @@ -0,0 +1,724 @@ + + + +RGBColor + + + + + + + + + + + +
+

RGBColor

+ +

Extends Color

+ +

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

+
+ + +

Constructors

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

Properties inherited from Color

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

RGB Components

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

Gray Components

+ +
+ + +
+ + +

HSB Components

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

Functions inherited from Color

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

String Representations

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..0b7a6ff8 --- /dev/null +++ b/dist/docs/classes/Raster.html @@ -0,0 +1,3536 @@ + + + +Raster + + + + + + + + + + + +
+

Raster

+ +

Extends Item

+ +

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

+
+ + +

Constructors

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

Properties

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

Functions

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

Pixels

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

Image Data

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

Properties inherited from Item

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

Project Hierarchy

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

Bounding Rectangles

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

Stroke Style

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

Fill Style

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

Remove On Event

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..0ef95ad6 --- /dev/null +++ b/dist/docs/classes/Rectangle.html @@ -0,0 +1,1232 @@ + + + +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

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

Functions

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

Geometric Tests

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

Boolean Operations

+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..b15f4210 --- /dev/null +++ b/dist/docs/classes/Segment.html @@ -0,0 +1,517 @@ + + + +Segment + + + + + + + + + + + +
+

Segment

+ +

The Segment object represents a part of a path which is +described by the path.segments array. Every segment of a +path corresponds to an anchor point (anchor points are the path handles +that are visible when the path is selected).

+
+ + +

Constructors

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

Properties

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

Hierarchy

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

Sibling Segments

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

Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..fc350d1e --- /dev/null +++ b/dist/docs/classes/Size.html @@ -0,0 +1,1243 @@ + + + +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

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

Functions

+ + +
+ + +
+ + +

Tests

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

Math Functions

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

Static Functions

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + \ 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..1bdba9ff --- /dev/null +++ b/dist/docs/classes/Symbol.html @@ -0,0 +1,269 @@ + + + +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

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

Functions

+ + +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + \ 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..d608956c --- /dev/null +++ b/dist/docs/classes/TextItem.html @@ -0,0 +1,2973 @@ + + + +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

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

Functions inherited from Item

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

Tests

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

Hierarchy Tests

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

Transform Functions

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

Hierarchy Operations

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

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..b5674160 --- /dev/null +++ b/dist/docs/classes/Tool.html @@ -0,0 +1,568 @@ + + + +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 code:

+
+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);
+}
+
+
+ + +

Constructors

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

Properties

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

Mouse Event Handlers

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

Keyboard Event Handlers

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + + + \ 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..ae43c7e0 --- /dev/null +++ b/dist/docs/classes/ToolEvent.html @@ -0,0 +1,326 @@ + + + +ToolEvent + + + + + + + + + + + +
+

ToolEvent

+ +

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

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..d80b5c33 --- /dev/null +++ b/dist/docs/classes/View.html @@ -0,0 +1,419 @@ + + + +View + + + + + + + + + + + +
+

View

+ +

The View object..

+
+ + +

Constructors

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

Properties

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

Event Handlers

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

Functions

+ + +
+ + +
+ +
+ + + + + + + + \ 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..4b181575 --- /dev/null +++ b/dist/docs/classes/global.html @@ -0,0 +1,428 @@ + + + +_global_ + + + + + + + + + + + +
+

Global Scope

+ + +
+ + + + + +

Properties

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

View Event Handlers

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

Mouse Event Handlers

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

Keyboard Event Handlers

+ +
+ + +
+ + +
+ + +
+ +
+ + + + + + + + + + \ 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..62dbe08c --- /dev/null +++ b/dist/docs/classes/index.html @@ -0,0 +1,84 @@ + + + +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..b815ec0d --- /dev/null +++ b/dist/docs/index.html @@ -0,0 +1,12 @@ + + + + +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..35bc1277 --- /dev/null +++ b/dist/docs/resources/css/codemirror.css @@ -0,0 +1,110 @@ +.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.js-comment { + color: #8c868f; +} +span.js-keyword { + color: #ff7800; +} +span.js-atom { + color: #3b5bb5; +} +span.js-string { + color: #409b1c; +} +span.js-variable { + color: #000000; +} +span.js-variabledef, +span.js-localvariable { + color: #3a4a64; +} diff --git a/dist/docs/resources/css/paperscript.css b/dist/docs/resources/css/paperscript.css new file mode 100644 index 00000000..9665fae4 --- /dev/null +++ b/dist/docs/resources/css/paperscript.css @@ -0,0 +1,53 @@ +.paperscript .button { + 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) */ + top: 8px; /* margin to top */ + right: 8px; /* margin to right */ + background: #eee; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + z-index: 1; +} + +.paperscript .source { + overflow: auto; + border: 1px solid #999; +} + +.paperscript:hover .button { + display: block; +} + +.paperscript .button:hover { + background: #ddd; + cursor: pointer; +} + +.paperscript .CodeMirror { + margin-bottom: 0; /* Override any potential bottom 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..4ba326fb --- /dev/null +++ b/dist/docs/resources/css/reference.css @@ -0,0 +1,133 @@ +/* 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 a tt, +.reference a tt b { + padding-bottom: 1px; +} +*/ + +.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..9339a758 --- /dev/null +++ b/dist/docs/resources/js/codemirror.js @@ -0,0 +1 @@ +var CodeMirror=function(){function D(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 B(a){return a.replace(/[<>&]/g,function(a){return a=="&"?"&":a=="<"?"<":">"})}function A(a){return{line:a.line,ch:a.ch}}function z(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 g(a,b){this.styles=b||[a,null],this.stateAfter=null,this.text=a,this.marked=this.gutterMarker=this.className=null}function f(a){this.pos=this.start=0,this.string=a}function e(a,b,c){return a.startState?a.startState(b,c):!0}function d(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 cG(a,b,c){this.atOccurrence=!1,c==null&&(c=typeof a=="string"&&a==a.toLowerCase()),b&&typeof b=="object"?b=bX(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=S[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}}else var d=S[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(S[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(S[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==S.length-1)return;h=d(S[c+=a?-1:1].text),g=e[a?--f:++f];if(f>0&&f=S.length)continue;var c=cy(b),g=c&&S[c-1].stateAfter;g?g=d(R,g):g=e(R);for(var h=c,i=S.length;ha){T.push(h),cB(f.workDelay),_.push({from:b,to:h});return}var l=j.highlight(R,g);j.stateAfter=d(R,g);if(k&&!l&&j.text)break}_.push({from:b,to:h})}}function cz(a){var b=cy(a),c=b&&S[b-1].stateAfter;c?c=d(R,c):c=e(R);for(var f=b;fe;--d){if(d==0)return 0;var f=S[d-1];if(f.stateAfter)return d;var g=f.indentation();if(c==null||b>g)c=d,b=g}return c}function cx(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=W.inverted?W.from:W.to,c=S[b.line],d=b.ch-1,e=d>=0&&cw[c.text.charAt(d)]||cw[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;kl.clientWidth||e-c.top>l.clientHeight))return null;var f=w(L),g=bd+Math.floor((e-f.top)/cq());return bX({line:g,ch:cn(bW(g),d-f.left)})}function cs(){return L.offsetLeft}function cr(){return L.offsetTop}function cq(){var a=N.childNodes.length;if(a)return N.offsetHeight/a;v.innerHTML="
x
";return v.firstChild.offsetHeight||1}function cp(a){var b=co(a,!0),c=w(L);return{x:c.left+b.x,y:c.top+b.y,yBot:c.top+b.yBot}}function co(a,b){var c=cq(),d=a.line-(b?bd:0);return{x:cm(a.line,a.ch),y:d*c,yBot:(d+1)*c}}function cn(a,b){function e(a){v.innerHTML="
"+c.getHTML(null,null,!1,a)+"
";return v.firstChild.firstChild.offsetWidth}if(b<=0)return 0;var c=S[a],d=c.text,f=0,g=0,h=d.length,i,j=Math.min(h,Math.ceil(b/cl("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 cm(a,b){if(b==0)return 0;v.innerHTML="
"+S[a].getHTML(null,null,!1,b)+"
";return v.firstChild.firstChild.offsetWidth}function cl(a){v.innerHTML="
x
",v.firstChild.firstChild.firstChild.nodeValue=a;return v.firstChild.firstChild.offsetWidth||10}function ck(a){if(typeof a=="number"){var b=a;a=S[a];if(!a)return null}else{var b=D(S,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 cj(a,b){if(typeof a=="number"){var c=a;a=S[bW(a)]}else{var c=D(S,a);if(c==-1)return null}a.className=b,_.push({from:c,to:c+1});return a}function ci(a){typeof a=="number"&&(a=S[bW(a)]),a.gutterMarker=null,bR()}function ch(a,b,c){typeof a=="number"&&(a=S[bW(a)]),a.gutterMarker={text:b,style:c},bR();return a}function cg(a,b,c){function e(a,b,c,e){var a=S[a],f=a.addMark(b,c,e);f.line=a,d.push(f)}a=bX(a),b=bX(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&&_.push({from:a,to:b+1})}}function cf(){var a=f.gutter||f.lineNumbers;H.style.display=a?"":"none",a?bR():N.parentNode.style.marginLeft=0}function ce(){R=a.getMode(f,f.mode);for(var b=0,c=S.length;b0&&/\w/.test(b.charAt(c-1)))--c;while(d=S.length)return{line:S.length-1,ch:S[S.length-1].text.length};var b=a.ch,c=S[a.line].text.length;return b==null||b>c?{line:a.line,ch:c}:b<0?{line:a.line,ch:0}:a}function bW(a){return Math.max(0,Math.min(a,S.length-1))}function bV(a,b,c){var d=bX({line:a,ch:b||0});(c?bT:bU)(d,d)}function bU(a,b,c,d){if(!y(W.from,a)||!y(W.to,b)){if(z(b,a)){var e=b;b=a,a=e}var f=y(W.to,b),g=y(W.from,a);y(a,b)?W.inverted=!1:f&&!g?W.inverted=!0:g&&!f&&(W.inverted=!1),c==null&&(c=W.from.line,d=W.to.line),y(a,b)?y(W.from,W.to)||_.push({from:c,to:d+1}):y(W.from,W.to)?_.push({from:a.line,to:b.line+1}):(y(a,W.from)||(a.line':"
",g,"
")}H.style.display="none",I.innerHTML=c.join("");var h=String(S.length).length,i=I.firstChild,j=x(i),k="";while(j.length+k.length0;--k)N.removeChild(j?j.previousSibling:N.lastChild);else if(i){for(var k=Math.max(0,i);k>0;--k)N.insertBefore(document.createElement("pre"),j);for(var k=Math.max(0,-i);k>0;--k)N.removeChild(j?j.previousSibling:N.lastChild)}var l=N.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=n)break;if(j.domStart>p||j.from>r)o.push({from:r,to:j.from,domSize:j.domStart-p,domStart:p}),s+=j.from-r;r=j.to,p=j.domStart+(j.to-j.from)}if(p!=q||r!=n)s+=Math.abs(n-r),o.push({from:r,to:n,domSize:q-p,domStart:p});if(!o.length)return;N.style.display="none",s>(k.to-k.from)*.3?bP(m=Math.max(k.from-10,0),n=Math.min(k.to+7,S.length)):bQ(o),N.style.display="";var t=m!=bd||n!=be||bf!=l.clientHeight;bd=m,be=n,B.style.top=m*cq()+"px",t&&(bf=l.clientHeight,u.style.height=S.length*cq()+2*cr()+"px",bR());var v=cl(bj);L.style.width=v>l.clientWidth?v+"px":"";if(N.childNodes.length!=be-bd)throw new Error("BAD PATCH! "+JSON.stringify(o)+" size="+(be-bd)+" nodes="+N.childNodes.length);bS()}}function bN(){var a=cq(),b=l.scrollTop-cr();return{from:Math.min(S.length,Math.max(0,Math.floor(b/a))),to:Math.min(S.length,Math.ceil((b+l.clientHeight)/a))}}function bM(a,b,c,d){var e=cs(),g=cr();b+=g,d+=g,a+=e,c+=e;var h=l.clientHeight,i=l.scrollTop,j=!1,k=!0;bi+h&&(l.scrollTop=d+10-h,j=!0);var m=l.clientWidth,n=l.scrollLeft;am+n&&(l.scrollLeft=c+10-m,j=!0,c>u.clientWidth&&(k=!1)),j&&f.onScroll&&f.onScroll(bl);return k}function bL(){var a=co(W.inverted?W.from:W.to);return bM(a.x,a.y,a.x,a.yBot)}function bK(){var a=[],b=Math.max(0,W.from.line-1),c=Math.min(S.length,W.to.line+2);for(var d=b;d=a)return{line:c,ch:a-d};++c,d=e+1}}var a=!1,b=K.value,c=F(K);if(!c)return!1;var a=bh.text!=b,d=Y,e=a||c.start!=bh.start||c.end!=(d?bh.start:bh.end);if(!e&&!d)return!1;if(a){X=Y=null;if(f.readOnly){$=!0;return"changed"}}var h=g(c.start,bh.from),i=g(c.end,bh.from);if(d){h=c.start==d.anchor?i:h,i=X?W.to:c.start==d.anchor?h:i;if(!z(h,i)){Y=null,W.inverted=!1;var j=h;h=i,i=j}}h.line==i.line&&h.line==W.from.line&&h.line==W.to.line&&!X&&($=!1);if(a){var k=0,l=b.length,m=Math.min(l,bh.text.length),n,o=bh.from,p=-1;while(k-1?k-p:k,r=bh.to-1,s=bh.text.length;for(;;){n=bh.text.charAt(s),n=="\n"&&r--;if(b.charAt(l)!=n){++l,++s;break}if(s<=k||l<=k)break;--l,--s}var p=bh.text.lastIndexOf("\n",s-1),t=p==-1?s:s-p-1;bw({line:o,ch:q},{line:r,ch:t},E(b.slice(k,l)),h,i);if(o!=r||h.line!=o)$=!0}else bU(h,i);bh.text=b,bh.start=c.start,bh.end=c.end;return a?"changed":e?"moved":!1}function bI(a){function c(){cC();var d=bJ();d=="moved"&&a&&(t[a]=!0),!d&&!b?(b=!0,O.set(80,c)):(bG=!1,bH()),cD()}var b=!1;bG=!0,O.set(20,c)}function bH(){bG||O.set(2e3,function(){cC(),bJ(),V&&bH(),cD()})}function bF(){return bE(W.from,W.to)}function bE(a,b){var c=a.line,d=b.line;if(c==d)return S[c].text.slice(a.ch,b.ch);var e=[S[c].text.slice(a.ch)];for(var f=c+1;fh&&(bj=o,h=o.length,f=!1)}if(f){h=0;for(var i=0,n=S.length;ih&&(h=o.length,bj=o)}}var p=[],q=c.length-j-1;for(var i=0,o=T.length;ib.line&&p.push(r+q)}c.length&&p.push(a.line),T=p,cB(100),_.push({from:a.line,to:b.line+1,diff:q}),ba={from:a,to:b,text:c},bU(d,e,s(W.from.line),s(W.to.line)),u.style.height=S.length*cq()+2*cr()+"px"}function bz(){bx(U.undone,U.done)}function by(){bx(U.done,U.undone)}function bx(a,b){var c=a.pop();if(c){var d=[],e=c.start+c.added;for(var f=c.start;ff.undoDepth)U.done.shift()}bA(a,b,c,d,e)}function bv(){V&&f.onBlur&&f.onBlur(bl),clearInterval(Q),X=null,V=!1,l.className=l.className.replace(" CodeMirror-focused","")}function bu(){!V&&f.onFocus&&f.onFocus(bl),V=!0,bH(),l.className.search(/\bCodeMirror-focused\b/)==-1&&(l.className+=" CodeMirror-focused"),cv()}function bt(a){if(!f.onKeyEvent||!f.onKeyEvent(bl,k(a.e))){if(f.electricChars&&R.electricChars){var b=String.fromCharCode(a.e.charCode==null?a.e.keyCode:a.e.charCode);R.electricChars.indexOf(b)>-1&&setTimeout(cF(function(){cd(W.to.line,"smart")}),50)}var c=a.e.keyCode;c==13?(f.readOnly||cb(),a.stop()):!a.e.ctrlKey&&!a.e.altKey&&!a.e.metaKey&&c==9&&f.tabMode!="default"?a.stop():bI(bg)}}function bs(a){Y&&(Y=null,$=!0),a.e.keyCode==16&&(X=null)}function br(a){V||bu();var b=a.e.keyCode,c=(s?a.e.metaKey:a.e.ctrlKey)&&!a.e.altKey,d=a.e.ctrlKey||a.e.altKey||a.e.metaKey;b==16||a.e.shiftKey?X=X||(W.inverted?W.to:W.from):X=null;if(!f.onKeyEvent||!f.onKeyEvent(bl,k(a.e))){if(b==33||b==34){bY(b==34);return a.stop()}if(c&&(b==36||b==35||s&&(b==38||b==40))){bZ(b==36||b==38);return a.stop()}if(c&&b==65){b$();return a.stop()}if(!f.readOnly){if(!d&&b==13)return;if(!d&&b==9&&cc(a.e.shiftKey))return a.stop();if(c&&b==90){by();return a.stop()}if(c&&(a.e.shiftKey&&b==90||b==89)){bz();return a.stop()}}bg=(c?"c":"")+b;if(W.inverted&&t.hasOwnProperty(bg)){var e=F(K);e&&(Y={anchor:e.start},G(K,e.start,e.start))}bI(bg)}}function bq(a){var b=ct(a,!0),c=a.e.dataTransfer.files;if(!!b&&!f.readOnly)if(c&&c.length&&window.FileReader&&window.File){var d=c.length,e=Array(d),g=0;for(var h=0;h=c.to||b.line=0&&a",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},cE=0;cG.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=bX(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:S[c.line-1].text.length}}else{if(c.line==S.length-1)return d(S.length);c={line:c.line+1,ch:0}}}},from:function(){if(this.atOccurrence)return A(this.pos.from)},to:function(){if(this.atOccurrence)return A(this.pos.to)}};return bl}a.defaults={value:"",mode:null,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,onFocus:null,onBlur:null,onScroll:null,matchBrackets:!1,workTime:100,workDelay:200,undoDepth:40,tabindex:null};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 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},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=m(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=e,a.copyState=d,f.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 v(this.string,this.start)},indentation:function(){return v(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)}},g.prototype={replace:function(a,b,c){var d=[],e=this.marked;h(0,a,this.styles,d),c&&d.push(c,null),h(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 i(a){return a<=Math.min(b,b+f)?a:a+f}for(var j=0;j=g?l=!0:(k.from=i(k.from),k.to!=null&&(k.to=i(k.to)));if(l||k.from>=k.to)e.splice(j,1),j--}}},split:function(a,b){var c=[b,null];h(a,this.text.length,this.styles,c);return new g(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,g=!0),e&&d[e-2]!=i&&(g=!0);return g},getTokenAt:function(a,b,c){var d=this.text,e=new f(d);while(e.pos',B(a),""):e.push(B(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,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=g[k++]}}a!=null&&b==null&&f(" ","CodeMirror-selected")}c&&e.push("
");return e.join("")}},i.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&&(q="\r\n")})();var r=8,s=/Mac/.test(navigator.platform),t={};for(var u=35;u<=40;++u)t[u]=t["c"+u]=!0;if("\n\nb".split(/\n/).length!=3)var E=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};else var E=function(a){return a.split(/\r?\n/)};if(window.getSelection)var F=function(a){try{return{start:a.selectionStart,end:a.selectionEnd}}catch(b){return null}},G=function(a,b,c){try{a.setSelectionRange(b,c)}catch(d){}};else var F=function(a){try{var b=document.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"js-localvariable";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","js-comment")}function m(a){return function(b,c){h(b,a)||(c.tokenize=l);return k("string","js-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","js-atom")}if(/\d/.test(c)){a.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);return k("number","js-atom")}if(c=="/"){if(a.eat("*"))return g(a,b,n);if(a.eat("/")){a.skipToEnd();return k("comment","js-comment")}if(b.reAllowed){h(a,"/"),a.eatWhile(/[gimy]/);return k("regexp","js-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","js-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:"js-keyword"}}var b=a("keyword a"),c=a("keyword b"),d=a("keyword c"),e=a("operator"),f={type:"atom",style:"js-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}) \ 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..8a491ae2 --- /dev/null +++ b/dist/docs/resources/js/paper.js @@ -0,0 +1,6922 @@ +/*** + * + * Paper.js + * + * A JavaScript Vector Graphics Library, based on Scriptographer.org and + * designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * All rights reserved. + * + *** + * + * Bootstrap.js JavaScript Framework. + * http://bootstrapjs.org/ + * + * Distributed under the MIT license. + * + * Copyright (c) 2006 - 2011 Juerg Lehni + * http://lehni.org/ + * + *** + * + * Parse-JS, A JavaScript tokenizer / parser / generator. + * + * Distributed under the BSD license. + * + * Copyright (c) 2010, Mihai Bazon + * http://mihai.bazon.net/blog/ + * + ***/ + +var paper = new function() { + +var Base = new function() { + var fix = !this.__proto__, + hidden = /^(statics|generics|preserve|enumerable|beans|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 = 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({ + + clone: function() { + return new this.constructor(this); + }, + + 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; + }, + + initialize: function(object, values, defaults) { + if (!values) + values = defaults; + return Base.each(defaults, function(value, key) { + this[key] = values[key] || value; + }, object); + }, + + 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; + } + }, + + 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(); + }); + }, + + formatNumber: function(num) { + return (Math.round(num * 100000) / 100000).toString(); + }, + + formatObject: function(obj) { + return '{ ' + Base.each(obj, function(value, key) { + this.push(key + ': ' + value); + }, []).join(', ') + ' }'; + } + } +}); + +var PaperScope = this.PaperScope = Base.extend({ + + initialize: function(id) { + this.project = null; + + this.projects = []; + + this.view = null; + this.views = []; + + this.tool = null; + this.tools = []; + this.id = id; + PaperScope._scopes[id] = this; + + }, + + evaluate: function(code) { + return PaperScript.evaluate(code, this); + }, + + install: function(scope) { + return Base.each(this, function(value, key) { + this[key] = value; + }, scope); + }, + + 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]; + }, + + statics: { + _scopes: {}, + + get: function(id) { + if (typeof id === 'object') + id = id.getAttribute('id'); + return this._scopes[id] || null; + } + } +}); + +var Point = this.Point = Base.extend({ + + beans: true, + + 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._transformPoint(this); + }, + + getDistance: function(point) { + point = Point.read(arguments); + var x = point.x - this.x, + y = point.y - this.y; + return Math.sqrt(x * x + y * y); + }, + + getLength: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, + + 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); + var angle = this.getAngle() - point.getAngle(); + return angle < -180 ? angle + 360 : angle > 180 ? angle - 360 : angle; + }, + + 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({ + beans: true, + + 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) { + 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; + }, + + 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.width == 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({ + beans: true, + + 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) { + var point = new LinkedSize(LinkedSize.dont); + point._width = width; + point._height = height; + point._owner = owner; + point._setter = setter; + return point; + } + } +}); + +var Rectangle = this.Rectangle = Base.extend({ + beans: true, + + 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); + }, + + 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); + }, + + 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()); + }, + + 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(rect) { + if (rect.width !== undefined) { + return rect.x >= this.x && rect.y >= this.y + && rect.x + rect.width <= this.x + this.width + && rect.y + rect.height <= this.y + this.height; + } else { + var point = Point.read(arguments); + return point.x >= this.x && point.y >= this.y + && point.x <= this.x + this.width + && point.y <= 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); + }, + + 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]()); + }; + this[set] = function(point) { + point = Point.read(arguments); + return this[setX](point.x)[setY](point.y); + }; + }, { beans: true }); +}); + +var LinkedRectangle = Rectangle.extend({ + beans: true, + + 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; + }; + }, { beans: true }) + ); +}); + +var Matrix = this.Matrix = Base.extend({ + + beans: true, + + initialize: function(m00, m10, m01, m11, m02, m12) { + var ok = true; + if (arguments.length == 6) { + this.set(m00, m10, m01, m11, m02, m12); + } else if (arguments.length == 1) { + if (m00 instanceof Matrix) { + this.set(m00._m00, m00._m10, m00._m01, + m00._m11, m00._m02, m00._m12); + } else if (Array.isArray(m00)) { + this.set.apply(this, m00); + } else { + ok = false; + } + } else if (arguments.length > 0) { + ok = false; + } else { + this._m00 = this._m11 = 1; + this._m10 = this._m01 = this._m02 = this._m12 = 0; + } + if (!ok) + throw new Error('Unsupported matrix parameters'); + }, + + clone: function() { + return Matrix.create(this._m00, this._m10, this._m01, + this._m11, this._m02, this._m12); + }, + + set: function(m00, m10, m01, m11, m02, m12) { + this._m00 = m00; + this._m10 = m10; + this._m01 = m01; + this._m11 = m11; + this._m02 = m02; + this._m12 = m12; + return this; + }, + + scale: function(sx, sy , center) { + if (arguments.length < 2 || typeof sy === 'object') { + center = Point.read(arguments, 1); + sy = sx; + } else { + center = Point.read(arguments, 2); + } + if (center) + this.translate(center); + this._m00 *= sx; + this._m10 *= sx; + this._m01 *= sy; + this._m11 *= sy; + if (center) + this.translate(center.negate()); + return this; + }, + + translate: function(point) { + point = Point.read(arguments); + var x = point.x, y = point.y; + this._m02 += x * this._m00 + y * this._m01; + this._m12 += x * this._m10 + y * this._m11; + return this; + }, + + rotate: function(angle, center) { + return this.concatenate( + Matrix.getRotateInstance.apply(Matrix, arguments)); + }, + + shear: function(shx, shy, center) { + if (arguments.length < 2 || typeof shy === 'object') { + center = Point.read(arguments, 1); + sy = sx; + } else { + center = Point.read(arguments, 2); + } + if (center) + this.translate(center); + var m00 = this._m00; + var m10 = this._m10; + this._m00 += shy * this._m01; + this._m10 += shy * this._m11; + this._m01 += shx * m00; + this._m11 += shx * m10; + if (center) + this.translate(center.negate()); + return this; + }, + + toString: function() { + var format = Base.formatNumber; + return '[[' + [format(this._m00), format(this._m01), + format(this._m02)].join(', ') + '], [' + + [format(this._m10), format(this._m11), + format(this._m12)].join(', ') + ']]'; + }, + + concatenate: function(mx) { + var m0 = this._m00, + m1 = this._m01; + this._m00 = mx._m00 * m0 + mx._m10 * m1; + this._m01 = mx._m01 * m0 + mx._m11 * m1; + this._m02 += mx._m02 * m0 + mx._m12 * m1; + + m0 = this._m10; + m1 = this._m11; + this._m10 = mx._m00 * m0 + mx._m10 * m1; + this._m11 = mx._m01 * m0 + mx._m11 * m1; + this._m12 += mx._m02 * m0 + mx._m12 * m1; + return this; + }, + + preConcatenate: function(mx) { + var m0 = this._m00, + m1 = this._m10; + this._m00 = mx._m00 * m0 + mx._m01 * m1; + this._m10 = mx._m10 * m0 + mx._m11 * m1; + + m0 = this._m01; + m1 = this._m11; + this._m01 = mx._m00 * m0 + mx._m01 * m1; + this._m11 = mx._m10 * m0 + mx._m11 * m1; + + m0 = this._m02; + m1 = this._m12; + this._m02 = mx._m00 * m0 + mx._m01 * m1 + mx._m02; + this._m12 = mx._m10 * m0 + mx._m11 * m1 + mx._m12; + 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._m00 + y * this._m01 + this._m02, + x * this._m10 + y * this._m11 + this._m12, + 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._m00 + y * this._m01 + this._m02; + dst[j++] = x * this._m10 + y * this._m11 + this._m12; + } + 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]); + }, + + getDeterminant: function() { + return this._m00 * this._m11 - this._m01 * this._m10; + }, + + isIdentity: function() { + return this._m00 == 1 && this._m10 == 0 && this._m01 == 0 && + this._m11 == 1 && this._m02 == 0 && this._m12 == 0; + }, + + isInvertible: function() { + var det = this.getDeterminant(); + return isFinite(det) && det != 0 && isFinite(this._m02) + && isFinite(this._m12); + }, + + isSingular: function() { + return !this.isInvertible(); + }, + + createInverse: function() { + var det = this.getDeterminant(); + if (isFinite(det) && det != 0 && isFinite(this._m02) + && isFinite(this._m12)) { + return Matrix.create( + this._m11 / det, + -this._m10 / det, + -this._m01 / det, + this._m00 / det, + (this._m01 * this._m12 - this._m11 * this._m02) / det, + (this._m10 * this._m02 - this._m00 * this._m12) / det); + } + return null; + }, + + createShiftless: function() { + return Matrix.create(this._m00, this._m10, this._m01, this._m11, 0, 0); + }, + + setToScale: function(sx, sy) { + return this.set(sx, 0, 0, sy, 0, 0); + }, + + setToTranslation: function(delta) { + delta = Point.read(arguments); + return this.set(1, 0, 0, 1, delta.x, delta.y); + }, + + setToShear: function(shx, shy) { + return this.set(1, shy, shx, 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._m00, this._m10, this._m01, + this._m11, this._m02, this._m12 + ); + return this; + }, + + statics: { + + create: function(m00, m10, m01, m11, m02, m12) { + return new Matrix(Matrix.dont).set(m00, m10, m01, m11, m02, m12); + }, + + getScaleInstance: function(sx, sy) { + 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(shx, shy, 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: '_m00', + scaleY: '_m11', + translateX: '_m02', + translateY: '_m12', + shearX: '_m01', + shearY: '_m10' + }, function(prop, name) { + name = Base.capitalize(name); + this['get' + name] = function() { + return this[prop]; + }; + this['set' + name] = function(value) { + this[prop] = value; + }; + }, { beans: true }); +}); + +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.TOLERANCE) + 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 - 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 = Base.extend({ + + beans: true, + + initialize: function() { + this._scope = paper; + this._index = this._scope.projects.push(this) - 1; + this._currentStyle = PathStyle.create(null); + this.setCurrentStyle({ + strokeWidth: 1, + strokeCap: 'butt', + strokeJoin: 'miter', + miterLimit: 10, + dashOffset: 0, + dashArray: [] + }); + this._selectedItems = {}; + this._selectedItemCount = 0; + this.activate(); + this.layers = []; + this.symbols = []; + this.activeLayer = new Layer(); + }, + + getCurrentStyle: function() { + return this._currentStyle; + }, + + setCurrentStyle: function(style) { + this._currentStyle.initialize(style); + }, + + activate: function() { + if (this._index != null) { + this._scope.project = this; + return true; + } + return false; + }, + + remove: function() { + var res = Base.splice(this._scope.projects, null, this._index, 1); + this._scope = null; + return !!res.length; + }, + + getIndex: function() { + return this._index; + }, + + getSelectedItems: function() { + var items = []; + Base.each(this._selectedItems, function(item) { + items.push(item); + }); + return items; + }, + + _selectItem: function(item, select) { + if (select) { + 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); + }, + + 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(); + } + }, + + redraw: function() { + this._scope.view.draw(); + } +}); + +var Symbol = this.Symbol = Base.extend({ + + beans: true, + + initialize: function(item) { + this.project = paper.project; + this.project.symbols.push(this); + this.setDefinition(item); + }, + + getDefinition: function() { + return this._definition; + }, + + setDefinition: function(item) { + this._definition = item; + item.setSelected(false); + item._removeFromParent(); + item.setPosition(new Point()); + }, + + place: function(position) { + return new PlacedSymbol(this, position); + }, + + clone: function() { + return new Symbol(this._definition.clone()); + } +}); + +var ChangeFlags = { + GEOMETRY: 1, + STROKE: 2, + STYLE: 4, + HIERARCHY: 8 +}; + +var Item = this.Item = Base.extend({ + beans: true, + + initialize: function() { + if (!this._project) + paper.project.activeLayer.appendTop(this); + this._style = PathStyle.create(this); + this.setStyle(this._project.getCurrentStyle()); + }, + + _changed: function(flags) { + if (flags & ChangeFlags.GEOMETRY) { + delete this._position; + } + }, + + getId: function() { + if (this._id == null) + this._id = Item._id = (Item._id || 0) + 1; + return this._id; + }, + + getName: function() { + return this._name; + }, + + setName: function(name) { + var children = this._parent._children, + namedChildren = this._parent._namedChildren; + if (name != this._name) { + if (this._name) + this._removeFromNamed(); + this._name = name || undefined; + } + if (name) { + (namedChildren[name] = namedChildren[name] || []).push(this); + children[name] = this; + } else { + delete children[name]; + } + }, + + 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); + }, + + isSelected: function() { + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) { + if (this._children[i].isSelected()) { + return true; + } + } + } else { + return !!this._selected; + } + return false; + }, + + 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._selectItem(this, selected); + } + } + }, + + locked: false, + + visible: true, + + isClipMask: function() { + return this._clipMask; + }, + + setClipMask: function(clipMask) { + this._clipMask = clipMask; + if (this._clipMask) { + this.setFillColor(null); + this.setStrokeColor(null); + } + }, + + blendMode: 'normal', + + opacity: 1, + + 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); + } + } + } + }, + + getParent: function() { + return this._parent; + }, + + getChildren: function() { + return this._children; + }, + + setChildren: function(items) { + this.removeChildren(); + for (var i = 0, l = items && items.length; i < l; i++) + this.appendTop(items[i]); + }, + + 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; + }, + + _removeFromNamed: function() { + var children = this._parent._children, + namedChildren = this._parent._namedChildren, + name = this._name, + namedArray = namedChildren[name]; + if (children[name] = this) + delete children[name]; + namedArray.splice(namedArray.indexOf(this), 1); + if (namedArray.length) { + children[name] = namedArray[namedArray.length - 1]; + } else { + delete namedChildren[name]; + } + }, + + _removeFromParent: function() { + if (this._parent) { + if (this._name) + this._removeFromNamed(); + var res = Base.splice(this._parent._children, null, this._index, 1); + this._parent = null; + return !!res.length; + } + return false; + }, + + remove: function() { + if (this.isSelected()) + this.setSelected(false); + return this._removeFromParent(); + }, + + removeChildren: function() { + var removed = false; + if (this._children) { + for (var i = this._children.length - 1; i >= 0; i--) + removed = this._children[i].remove() || removed; + } + return removed; + }, + + copyTo: function(itemOrProject) { + var copy = this.clone(); + if (itemOrProject.layers) { + itemOrProject.activeLayer.appendTop(copy); + } else { + itemOrProject.appendTop(copy); + } + return copy; + }, + + 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.appendTop(this._children[i].clone()); + } + var keys = ['locked', 'visible', 'opacity', 'blendMode', '_clipMask']; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (this.hasOwnProperty(key)) + copy[key] = this[key]; + } + copy.moveAbove(this); + if (this._name) + copy.setName(this._name); + return copy; + }, + + reverseChildren: function() { + if (this._children) { + this._children.reverse(); + for (var i = 0, l = this._children.length; i < l; i++) { + this._children[i]._index = i; + } + } + }, + + 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.setPosition(this.getPosition()); + raster.scale(1 / scale); + return raster; + }, + + hasChildren: function() { + return this._children && this._children.length > 0; + }, + + 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; + }, + + 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() { + return this._getBounds(false); + }, + + getStrokeBounds: function() { + return this._getBounds(true); + }, + + _getBounds: function(includeStroke) { + var children = this._children; + if (children && children.length) { + var x1 = Infinity, + x2 = -Infinity, + y1 = x1, + y2 = x2; + for (var i = 0, l = children.length; i < l; i++) { + var child = children[i]; + if (child.visible) { + var rect = includeStroke + ? child.getStrokeBounds() + : child.getBounds(); + 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 includeStroke + ? Rectangle.create(x1, y1, x2 - x1, y2 - y1) + : LinkedRectangle.create(this, 'setBounds', + x1, y1, x2 - x1, y2 - y1); + } + return new Rectangle(); + }, + + setBounds: function(rect) { + rect = Rectangle.read(arguments); + var bounds = this.getBounds(), + matrix = new Matrix(), + center = rect.center; + 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.center; + matrix.translate(-center.x, -center.y); + this.transform(matrix); + }, + + scale: function(sx, sy , center) { + if (arguments.length < 2 || typeof sy === 'object') { + center = sy; + sy = sx; + } + return this.transform(new Matrix().scale(sx, sy, + 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(shx, shy, center) { + if (arguments.length < 2 || typeof sy === 'object') { + center = shy; + shy = shx; + } + return this.transform(new Matrix().shear(shx, shy, + center || this.getPosition())); + }, + + transform: function(matrix, flags) { + if (this._transform) + this._transform(matrix, flags); + if (this._position) + matrix._transformPoint(this._position, this._position, true); + if (this._children) { + for (var i = 0, l = this._children.length; i < l; i++) { + var child = this._children[i]; + child.transform(matrix, flags); + } + } + return this; + }, + + 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() { + + function append(top) { + return function(item) { + item._removeFromParent(); + if (this._children) { + Base.splice(this._children, [item], top ? undefined : 0, 0); + item._parent = this; + item._setProject(this._project); + if (item._name) + item.setName(item._name); + return true; + } + return false; + }; + } + + function move(above) { + return function(item) { + if (item._parent && this._removeFromParent()) { + Base.splice(item._parent._children, [this], + item._index + (above ? 1 : -1), 0); + this._parent = item._parent; + this._setProject(item._project); + if (item._name) + item.setName(item._name); + return true; + } + return false; + }; + } + + return { + + appendTop: append(true), + + appendBottom: append(false), + + moveAbove: move(true), + + moveBelow: move(false) + }; +}, 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({ + + beans: true, + + initialize: function(items) { + this.base(); + this._children = []; + this._namedChildren = {}; + this._clipped = false; + this.setChildren(!items || !Array.isArray(items) + || typeof items[0] !== 'object' ? arguments : items); + }, + + clone: function() { + var copy = this.base(); + copy._clipped = this._clipped; + return copy; + }, + + isClipped: function() { + return this._clipped; + }, + + setClipped: function(clipped) { + this._clipped = clipped; + var child = this.getFirstChild(); + if (child) + child.setClipMask(clipped); + }, + + draw: function(ctx, param) { + for (var i = 0, l = this._children.length; i < l; i++) { + Item.draw(this._children[i], ctx, param); + if (this._clipped && i == 0) + ctx.clip(); + } + } +}); + +var Layer = this.Layer = Group.extend({ + + beans: true, + initialize: function(items) { + this._project = paper.project; + this._index = this._project.layers.push(this) - 1; + this.base.apply(this, arguments); + this.activate(); + }, + + _removeFromParent: function() { + return this._parent ? this.base() + : !!Base.splice(this._project.layers, null, this._index, 1).length; + }, + + 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 move(above) { + return function(item) { + if (item instanceof Layer && !item._parent + && this._removeFromParent()) { + Base.splice(item._project.layers, [this], + item._index + (above ? 1 : -1), 0); + this._setProject(item._project); + return true; + } + return this.base(item); + }; + } + + return { + moveAbove: move(true), + + moveBelow: move(false) + }; +}); + +var Raster = this.Raster = Item.extend({ + + beans: true, + + 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().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'); + } + 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().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._bounds = null; + }, + + 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._bounds = null; + }, + + 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().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(), + 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().putImageData(data, point.x, point.y); + }, + + _transform: function(matrix, flags) { + this.matrix.preConcatenate(matrix); + this._bounds = null; + }, + + getBounds: function() { + if (!this._bounds) { + this._bounds = this.matrix._transformBounds( + new Rectangle(this._size).setCenter(0, 0)); + } + return this._bounds; + }, + getStrokeBounds: function() { + return this.getBounds(); + }, + + 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 = Item.extend({ + + beans: true, + + initialize: function(symbol, matrixOrOffset) { + this.base(); + this.symbol = symbol instanceof Symbol ? symbol : new Symbol(symbol); + this.matrix = matrixOrOffset !== undefined + ? matrixOrOffset instanceof Matrix + ? matrixOrOffset + : new Matrix().translate(Point.read(arguments, 1)) + : new Matrix(); + }, + + clone: function() { + return this._clone(new PlacedSymbol(this.symbol, this.matrix.clone())); + }, + + _transform: function(matrix, flags) { + this.matrix.preConcatenate(matrix); + }, + + getBounds: function() { + var bounds = this.symbol._definition.getStrokeBounds(this.matrix); + return LinkedRectangle.create(this, 'setBounds', + bounds.x, bounds.y, bounds.width, bounds.height); + }, + + getStrokeBounds: function() { + return this.getBounds(); + }, + + 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(); + } + } + +}); + +var PathStyle = this.PathStyle = Base.extend(new function() { + + var keys = ['strokeColor', 'strokeWidth', 'strokeCap', 'strokeJoin', + 'miterLimit', 'dashOffset','dashArray', 'fillColor']; + + var strokeFlags = { + strokeWidth: true, + strokeCap: true, + strokeJoin: true, + miterLimit: true + }; + + var fields = { + beans: true, + + initialize: function(style) { + var clone = style instanceof PathStyle; + for (var i = 0, l = style && keys.length; i < l; i++) { + var key = keys[i], + value = style[key]; + if (value !== undefined) { + this[key] = value && clone && value.clone + ? value.clone() : value; + } + } + }, + + statics: { + create: function(item) { + var style = new PathStyle(PathStyle.dont); + style._item = item; + return style; + } + } + }; + + Item.inject(Base.each(keys, function(key) { + var isColor = !!key.match(/Color$/), + part = Base.capitalize(key), + set = 'set' + part, + get = 'get' + part; + + fields[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]._style[set](value); + } else { + var old = this['_' + key]; + if (old != value && !(old && old.equals && old.equals(value))) { + this['_' + key] = value; + if (this._item) { + this._item._changed(ChangeFlags.STYLE + | (strokeFlags[key] ? ChangeFlags.STROKE : 0)); + } + } + } + return this; + }; + + fields[get] = function() { + var children = this._item && this._item._children, + style; + if (children) { + for (var i = 0, l = children.length; i < l; i++) { + var childStyle = children[i]._style[get](); + if (!style) { + style = childStyle; + } else if (style != childStyle && !(style && style.equals + && style.equals(childStyle))) { + return undefined; + } + } + return style; + } else { + return this['_' + key]; + } + }; + + this[set] = function(value) { + this._style[set](value); + return this; + }; + + this[get] = function() { + return this._style[get](); + }; + }, { beans: true })); + + return fields; +}); + +var Segment = this.Segment = Base.extend({ + beans: true, + + 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(ChangeFlags.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); + }, + + getHandleInIfSet: function() { + return this._handleIn._x == 0 && this._handleIn._y == 0 + ? null : this._handleIn; + }, + + getHandleOut: function() { + return this._handleOut; + }, + + setHandleOut: function(point) { + point = Point.read(arguments); + this._handleOut.set(point.x, point.y); + }, + + getHandleOutIfSet: function() { + return this._handleOut._x == 0 && this._handleOut._y == 0 + ? null : this._handleOut; + }, + + _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, + wasSelected = !!state, + 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; + } + } + this._selectionState = (selection[0] ? SelectionState.POINT : 0) + | (selection[1] ? SelectionState.HANDLE_IN : 0) + | (selection[2] ? SelectionState.HANDLE_OUT : 0); + if (path && wasSelected != !!this._selectionState) + path._updateSelection(this); + }, + + 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 = matrix && this.getHandleInIfSet() || this._handleIn, + handleOut = matrix && this.getHandleOutIfSet() || this._handleOut, + 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) { + 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({ + beans: true, + + 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); + }, + 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 (pt.x !== undefined) { + x = pt.x; + y = pt.y; + selected = pt.selected; + } else { + x = pt[0]; + y = pt[1]; + } + point._x = x; + point._y = y; + point._owner = segment; + segment[key] = point; + if (selected) + point.setSelected(true); + return point; + } + } +}); + +var SelectionState = { + POINT: 1, + HANDLE_IN: 2, + HANDLE_OUT: 4, + HANDLE_BOTH: 6 +}; + +var Curve = this.Curve = Base.extend({ + + beans: true, + + 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); + p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y + 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); + }, + + 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 args = this.getValues(); + if (!fullLength) + args.push(from, to); + var length = Curve.getLength.apply(Curve, args); + if (fullLength) + this._length = length; + return length; + }, + + getPart: function(from, to) { + var args = this.getValues(); + args.push(from, to); + return new Curve(Curve.getPart.apply(Curve, args)); + }, + + isLinear: function() { + return this._segment1._handleOut.isZero() + && this._segment2._handleIn.isZero(); + }, + + getParameter: function(length, start) { + var args = this.getValues(); + args.push(length, start !== undefined ? start : length < 0 ? 1 : 0); + return Curve.getParameter.apply(Curve, args); + }, + + _evaluate: function(parameter, type) { + var args = this.getValues(); + args.push(parameter, type); + return Curve.evaluate.apply(Curve, args); + }, + + getPoint: function(parameter) { + return this._evaluate(parameter, 0); + }, + + getTangent: function(parameter) { + return this._evaluate(parameter, 1); + }, + + getNormal: function(parameter) { + return this._evaluate(parameter, 2); + }, + + 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(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t, type) { + var x, y; + + if (t == 0 || t == 1) { + var point; + switch (type) { + case 0: + x = t == 0 ? p1x : p2x; + y = t == 0 ? p1y : p2y; + break; + case 1: + case 2: + var px, py; + if (t == 0) { + if (c1x == p1x && c1y == p1y) { + if (c2x == p2x && c2y == p2y) { + px = p2x; py = p2y; + } else { + px = c2x; py = c2y; + } + } else { + px = c1x; py = c1y; + } + x = px - p1x; + y = py - p1y; + } else { + if (c2x == p2x && c2y == p2y) { + if (c1x == p1x && c1y == p1y) { + px = p1x; py = p1y; + } else { + px = c1x; py = c1y; + } + } else { + px = c2x; py = c2y; + } + x = p2x - px; + y = p2y - py; + } + break; + } + } else { + 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(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + 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] + ]; + }, + + getPart: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, from, to) { + var curve = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + if (from > 0) { + curve[8] = from; + curve = Curve.subdivide.apply(Curve, curve)[1]; + } + if (to < 1) { + curve[8] = (to - from) / (1 - from); + curve = Curve.subdivide.apply(Curve, curve)[0]; + } + return curve; + }, + + isSufficientlyFlat: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + var vx = (p2x - p1x) / 3, + vy = (p2y - p1y) / 3, + m1x = p1x + vx, + m1y = p1y + vy, + m2x = p2x - vx, + m2y = p2y - vy; + return Math.max( + Math.abs(m1x - c1x), Math.abs(m1y - c1y), + Math.abs(m2x - c1x), Math.abs(m1y - c1y)) < 1 / 2; + } + } +}, new function() { + + function getLengthIntegrand(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + var 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(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, a, b) { + if (a === undefined) + a = 0; + if (b === undefined) + b = 1; + if (p1x == c1x && p1y == c1y && p2x == c2x && p2y == c2y) { + var dx = p2x - p1x, + dy = p2y - p1y; + return (b - a) * Math.sqrt(dx * dx + dy * dy); + } + var ds = getLengthIntegrand( + p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + return Numerical.integrate(ds, a, b, getIterations(a, b)); + }, + + getParameter: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + length, start) { + if (length == 0) + return start; + var forward = length > 0, + a = forward ? start : 0, + b = forward ? 1 : start, + length = Math.abs(length), + ds = getLengthIntegrand( + p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y), + rangeLength = Numerical.integrate(ds, a, b, + getIterations(a, b)); + if (length >= rangeLength) + return forward ? b : a; + var guess = length / rangeLength, + len = 0; + function f(t) { + var count = getIterations(start, t); + if (start < t) { + len += Numerical.integrate(ds, start, t, count); + } else { + len -= Numerical.integrate(ds, t, start, count); + } + start = t; + return len - length; + } + return Numerical.findRoot(f, ds, + forward ? a + guess : b - guess, + a, b, 16, Numerical.TOLERANCE); + } + }; +}); + +CurveLocation = Base.extend({ + + beans: true, + + initialize: function(curve, parameter, point) { + this._curve = curve; + this._parameter = parameter; + this._point = point; + }, + + getSegment: function() { + if (!this._segment) { + var 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; + }, + + getItem: 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._curve && this.getParameter(); + return parameter != null ? this._curve.getLength(0, parameter) : null; + }, + + getParameter: function() { + if (this._parameter == null && this._point) + this._parameter = this._curve.getParameter(this._point); + return this._parameter; + }, + + getPoint: function() { + if (!this._point && this._curve) { + var parameter = this.getParameter(); + if (parameter != null) + this._point = this._curve.getPoint(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); + }, + + 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)); + return '{ ' + parts.join(', ') + ' }'; + } +}); + +var PathItem = this.PathItem = Item.extend({ +}); + +var Path = this.Path = PathItem.extend({ + + beans: true, + + initialize: function(segments) { + this.base(); + this._closed = false; + this._selectedSegmentCount = 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) { + if (flags & ChangeFlags.GEOMETRY) { + delete this._length; + delete this._bounds; + delete this._position; + delete this._strokeBounds; + delete this._clockwise; + } else if (flags & ChangeFlags.STROKE) { + delete this._strokeBounds; + } + }, + + getSegments: function() { + return this._segments; + }, + + setSegments: function(segments) { + if (!this._segments) { + this._segments = []; + } else { + this.setSelected(false); + 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(ChangeFlags.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); + } + this._changed(ChangeFlags.GEOMETRY); + }, + + _add: function(segs, index) { + var segments = this._segments, + curves = this._curves, + amount = segs.length, + append = index == null, + index = append ? segments.length : index; + 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 (segment._selectionState) + this._updateSelection(segment); + } + 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(ChangeFlags.GEOMETRY); + return segs; + }, + + _updateSelection: function(segment) { + var count = this._selectedSegmentCount += + segment._selectionState ? 1 : -1; + if (count <= 1) + this._project._selectItem(this, count == 1); + }, + + 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 - 1); + 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) { + segment._selectionState = 0; + this._updateSelection(segment); + } + 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(ChangeFlags.GEOMETRY); + return removed; + }, + + isSelected: function() { + return this._selectedSegmentCount > 0; + }, + setSelected: function(selected) { + var wasSelected = this.isSelected(), + length = this._segments.length; + if (!wasSelected != !selected && length) + this._project._selectItem(this, selected); + this._selectedSegmentCount = selected ? length : 0; + for (var i = 0; i < length; i++) + this._segments[i]._selectionState = selected + ? SelectionState.POINT : 0; + }, + + isFullySelected: function() { + return this._selectedSegmentCount == this._segments.length; + }, + + setFullySelected: function(selected) { + this.setSelected(selected); + }, + + curvesToPoints: function(maxDistance) { + var flattener = new PathFlattener(this), + pos = 0, + step = flattener.length / Math.ceil(flattener.length / maxDistance), + end = flattener.length + step / 2; + var segments = []; + while (pos <= end) { + segments.push(new Segment(flattener.evaluate(pos, 0))); + pos += step; + } + this.setSegments(segments); + }, + + pointsToCurves: function(tolerance) { + 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(ChangeFlags.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; + }, + + 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.getParameter(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(); + } +}, new function() { + + function drawHandles(ctx, segments) { + for (var i = 0, l = segments.length; i < l; i++) { + var segment = segments[i], + point = segment._point, + pointSelected = segment._selectionState == SelectionState.POINT; + if (pointSelected || segment._isSelected(segment._handleIn)) + drawHandle(ctx, point, segment._handleIn); + if (pointSelected || segment._isSelected(segment._handleOut)) + drawHandle(ctx, point, segment._handleOut); + ctx.save(); + ctx.beginPath(); + ctx.rect(point._x - 2, point._y - 2, 4, 4); + ctx.fill(); + if (!pointSelected) { + 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 || param.clip || fillColor + || strokeColor && !hasDash) { + drawSegments(ctx, this); + } + + if (param.selection) { + ctx.stroke(); + drawHandles(ctx, this._segments); + } else if (param.clip) { + 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('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)) ]); + }, + + 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), + through; + if (arguments[1] && typeof arguments[1] !== 'boolean') { + through = Point.read(arguments, 0, 1); + to = Point.read(arguments, 1, 1); + } else { + to = Point.read(arguments, 0, 1); + if (clockwise === undefined) + clockwise = true; + var middle = current._point.add(to).divide(2), + step = middle.subtract(current._point); + through = clockwise + ? middle.subtract(-step.y, step.x) + : middle.add(-step.y, step.x); + } + + var x1 = current._point._x, x2 = through.x, x3 = to.x, + y1 = current._point._y, y2 = through.y, y3 = to.y, + + f = x3 * x3 - x3 * x2 - x1 * x3 + x1 * x2 + y3 * y3 - y3 * y2 + - y1 * y3 + y1 * y2, + g = x3 * y1 - x3 * y2 + x1 * y2 - x1 * y3 + x2 * y3 - x2 * y1, + m = g == 0 ? 0 : f / g, + e = x1 * x2 + y1 * y2 - m * (x1 * y2 - y1 * x2), + cx = (x1 + x2 - m * (y2 - y1)) / 2, + cy = (y1 + y2 - m * (x1 - x2)) / 2, + radius = Math.sqrt(cx * cx + cy * cy - e), + angle = Math.atan2(y1 - cy, x1 - cx), + middle = Math.atan2(y2 - cy, x2 - cx), + extent = Math.atan2(y3 - cy, x3 - cx), + diff = middle - angle, + d90 = Math.PI, + d180 = d90 * 2; + + if (diff < -d90) + diff += d180; + else if (diff > d90) + diff -= d180; + + extent -= angle; + if (extent <= 0) + extent += d180; + if (diff < 0) + extent -= d180; + + var ext = Math.abs(extent), + arcSegs = ext >= d180 + ? 4 : Math.ceil(ext * 2 / Math.PI), + inc = Math.min(Math.max(extent, -d180), d180) / arcSegs, + z = 4 / 3 * Math.sin(inc / 2) / (1 + Math.cos(inc / 2)), + segments = []; + for (var i = 0; i <= arcSegs; i++) { + var relx = Math.cos(angle), + rely = Math.sin(angle); + var pt = new Point( + cx + relx * radius, + cy + rely * radius + ); + var out = i == arcSegs + ? null + : new Point( + cx + (relx - z * rely) * radius - pt.x, + cy + (rely + z * relx) * radius - pt.y + ); + if (i == 0) { + current.setHandleOut(out); + } else { + segments.push(new Segment(pt, new Point( + cx + (relx + z * rely) * radius - pt.x, + cy + (rely - z * relx) * radius - pt.y + ), out)); + } + angle += 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 b2ac = b * b - 4 * a * c; + if (b2ac < 0) + continue; + var sqrt = Math.sqrt(b2ac), + f = 1 / (a * -2), + 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 { + beans: true, + + getBounds: function() { + var useCache = arguments.length == 0; + if (!useCache || !this._bounds) { + var bounds = getBounds(this, arguments[0]); + if (!useCache) + return bounds; + this._bounds = LinkedRectangle.create(this, 'setBounds', + bounds.x, bounds.y, bounds.width, bounds.height); + } + return this._bounds; + }, + + getStrokeBounds: function() { + if (!this._style._strokeColor || !this._style._strokeWidth) + return this.getBounds.apply(this, arguments); + var useCache = arguments.length == 0; + if (this._strokeBounds && useCache) + 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) { + var handleIn = segment.getHandleInIfSet(), + handleOut = segment.getHandleOutIfSet(); + if (join === 'round' || handleIn && handleOut) { + 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.add(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; + }, + + getControlBounds: function() { + } + }; +}); + +var CompoundPath = this.CompoundPath = PathItem.extend({ + + initialize: function(paths) { + this.base(); + this._children = []; + var items = !paths || !Array.isArray(paths) + || typeof paths[0] !== 'object' ? arguments : paths; + for (var i = 0, l = items.length; i < l; i++) { + var path = items[i]; + if (path._clockwise === undefined) + path.setClockwise(i < l - 1); + this.appendTop(path); + } + }, + + simplify: function() { + if (this._children.length == 1) { + var child = this._children[0]; + child.moveAbove(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 firstChild = this._children[0]; + ctx.beginPath(); + param.compound = true; + for (var i = 0, l = this._children.length; 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.appendTop(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; +}); + +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 path = new Path(), + corners = ['getBottomLeft', 'getTopLeft', 'getTopRight', + 'getBottomRight'], + segments = new Array(4); + for (var i = 0; i < 4; i++) + segments[i] = new Segment(rect[corners[i]]()); + path._add(segments); + 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().divide(2)); + var path = new Path(), + uSize = size.multiply(kappa * 2), + bl = rect.getBottomLeft(), + tl = rect.getTopLeft(), + tr = rect.getTopRight(), + br = rect.getBottomRight(); + 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(), + topLeft = rect.getTopLeft(), + size = new Size(rect.width, rect.height), + segments = new Array(4); + for (var i = 0; i < 4; i++) { + var segment = ovalSegments[i]; + segments[i] = new Segment( + segment._point.multiply(size).add(topLeft), + 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), + new Size(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 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.isSufficientlyFlat.apply(Curve, curve)) { + var curves = Curve.subdivide.apply(Curve, 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 + }); + } + } + }, + + getParameter: 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.getParameter(offset); + return Curve.evaluate.apply(Curve, + this.curves[param.index].concat([param.value, type])); + }, + + drawPart: function(ctx, from, to) { + from = this.getParameter(from); + to = this.getParameter(to); + for (var i = from.index; i <= to.index; i++) { + var curve = Curve.getPart.apply(Curve, this.curves[i].concat( + 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.TOLERANCE, + 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 ParagraphStyle = this.ParagraphStyle = Base.extend({ + + initialize: function(style) { + Base.initialize(this, style, { + justification: 'left' + }); + }, + + statics: { + create: function(item) { + var style = new ParagraphStyle(ParagraphStyle.dont); + style._item = item; + return style; + } + } +}); + +var CharacterStyle = this.CharacterStyle = PathStyle.extend({ + + initialize: function(style) { + Base.initialize(this, style, { + fontSize: 10, + font: 'sans-serif' + }); + this.base(style); + }, + + statics: { + create: function(item) { + var style = new CharacterStyle(CharacterStyle.dont); + style._item = item; + return style; + } + } +}); + +var TextItem = this.TextItem = Item.extend({ + + beans: true, + + initialize: function() { + this.base(); + this.content = null; + this._characterStyle = CharacterStyle.create(this); + this.setCharacterStyle(this._project.getCurrentStyle()); + this._paragraphStyle = ParagraphStyle.create(this); + this.setParagraphStyle(); + }, + + _clone: function(copy) { + copy.setCharacterStyle(this._characterStyle); + copy.setParagraphStyle(this._paragraphStyle); + return this.base(copy); + }, + + 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({ + + beans: true, + + initialize: function(point) { + this.base(); + var point = Point.read(arguments); + this.content = ''; + this._point = LinkedPoint.create(this, 'setPoint', point.x, point.y); + this._matrix = new Matrix().translate(point); + }, + + clone: function() { + var copy = this._clone(new PointText(this._point)); + copy.content = this.content; + copy._matrix.initialize(this._matrix); + return copy; + }, + + getPoint: function() { + return this._point; + }, + + setPoint: function(point) { + this._transform(new Matrix().translate( + Point.read(arguments).subtract(this._point))); + }, + getPosition: function() { + return this._point; + }, + setPosition: function(point) { + this.setPoint.apply(this, arguments); + }, + _transform: function(matrix, flags) { + this._matrix.preConcatenate(matrix); + matrix._transformPoint(this._point, this._point, true); + }, + draw: function(ctx) { + if (this.content == null) + return; + ctx.save(); + ctx.font = this._characterStyle.fontSize + 'pt ' + + this._characterStyle.font; + ctx.textAlign = this._paragraphStyle.justification; + 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 Color = this.Color = Base.extend(new function() { + var components = { + gray: ['gray'], + rgb: ['red', 'green', 'blue'], + hsb: ['hue', 'saturation', 'brightness'] + }; + + 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, + s = max == 0 ? 0 : delta / max, + v = max; + if (delta == 0) { + h = 0; + } else { + switch (max) { + case r: h = (g - b) / delta + (g < b ? 6 : 0); break; + case g: h = (b - r) / delta + 2; break; + case b: h = (r - g) / delta + 4; break; + } + h /= 6; + } + return new HSBColor(h * 360, 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-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); + }, + + 'hsb-gray': function(color) { + return converters['rgb-gray'](converters['hsb-rgb'](color)); + }, + + 'gray-hsb': function(color) { + return new HSBColor(0, 0, 1 - color._gray, color._alpha); + } + }; + + var fields = { + + beans: true, + _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.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) { + return this._colorType == type + ? this.clone() + : converters[this._colorType + '-' + type](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._cssString = null; + 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; +}, { + + beans: true, + + 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._cssString = null; + 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 = Color.extend({ + + _colorType: 'rgb' +}); + +var HSBColor = this.HSBColor = Color.extend({ + + _colorType: 'hsb' +}); + +var GradientColor = this.GradientColor = Color.extend({ + + beans: true, + + 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); + 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); + 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; + } + 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({ + + beans: true, + + 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({ + + beans: true, + + 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 = new function() { + function cumulate(el, name, parent, positioned) { + var left = name + 'Left', + top = name + 'Top', + x = 0, + y = 0; + while (el && (!positioned + || !/^(relative|absolute)$/.test(el.style.position))) { + x += el[left] || 0; + y += el[top] || 0; + el = el[parent]; + } + return Point.create(x, y); + } + + return { + getOffset: function(el, positioned, scroll) { + var point = cumulate(el, 'offset', 'offsetParent', positioned); + return scroll + ? point.subtract(cumulate(el, 'scroll', 'parentNode')) + : point; + }, + + getSize: function(el) { + return Size.create(el.offsetWidth, el.offsetHeight); + }, + + getBounds: function(el, positioned, scroll) { + return new Rectangle(DomElement.getOffset(el, positioned, scroll), + DomElement.getSize(el)); + }, + + getWindowSize: function() { + var doc = document.getElementsByTagName( + document.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; + return Size.create( + window.innerWidth || doc.clientWidth, + window.innerHeight || doc.clientHeight + ); + }, + + isVisible: function(el) { + return new Rectangle([0, 0], DomElement.getWindowSize()) + .intersects(DomElement.getBounds(el, false, true)); + } + }; +}; + +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 + ); + }, + + getElement: function(event) { + return event.target || event.srcElement; + }, + + getOffset: function(event) { + return DomEvent.getPoint(event).subtract( + DomElement.getOffset(DomEvent.getElement(event), true)); + }, + + preventDefault: function(event) { + if (event.preventDefault) { + event.preventDefault(); + } else { + event.returnValue = false; + } + }, + + stopPropagation: function(event) { + if (event.stopPropagation) { + event.stopPropagation(); + } else { + event.cancelBubble = true; + } + } +}; + +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) { + timer = window.setInterval(function() { + for (var i = callbacks.length - 1; i >= 0; i--) { + var entry = callbacks[i], + func = entry[0], + element = entry[1]; + if (!element || element.getAttribute('keepalive') == 'true' + || focused && DomElement.isVisible(element)) { + callbacks.splice(i, 1); + func(Date.now()); + } + } + }, 1000 / 60); + } + }; +}; + +var View = this.View = Base.extend({ + + beans: true, + + initialize: function(canvas) { + this._scope = paper; + this._index = this._scope.views.push(this) - 1; + var size; + if (canvas && canvas instanceof HTMLCanvasElement) { + this._canvas = canvas; + var offset = DomElement.getOffset(canvas); + if (canvas.attributes.resize) { + size = DomElement.getWindowSize().subtract(offset); + canvas.width = size.width; + canvas.height = size.height; + var that = this; + DomEvent.add(window, { + resize: function(event) { + if (!DomElement.getSize(canvas).equals([0, 0])) + offset = DomElement.getOffset(canvas); + that.setViewSize( + DomElement.getWindowSize().subtract(offset)); + if (that._onFrameCallback) { + that._onFrameCallback(0, true); + } else { + that.draw(); + } + } + }); + } else { + size = Size.create(canvas.offsetWidth, canvas.offsetHeight); + } + if (canvas.attributes.stats) { + this._stats = new Stats(); + var element = this._stats.domElement, + style = element.style; + 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._viewBounds = LinkedRectangle.create(this, 'setViewBounds', + 0, 0, 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; + }, + + getCanvas: function() { + return this._canvas; + }, + + getViewBounds: function() { + return this._viewBounds; + }, + + setViewBounds: function(bounds) { + bounds = Rectangle.read(arguments); + var size = bounds.getSize(), + delta = size.subtract(this._viewBounds.getSize()); + this._canvas.width = size.width; + this._canvas.height = size.height; + if (this.onResize) { + this.onResize({ + size: size, + delta: delta + }); + } + this._bounds = null; + }, + + getViewSize: function() { + return this._viewBounds.getSize(); + }, + + setViewSize: function(size) { + this._viewBounds.setSize.apply(this._viewBounds, arguments); + }, + + getBounds: function() { + if (!this._bounds) + this._bounds = this._matrix._transformBounds(this._viewBounds); + 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; + }, + + scrollBy: function(point) { + this._transform(new Matrix().translate(Point.read(arguments).negate())); + }, + + _transform: function(matrix, flags) { + this._matrix.preConcatenate(matrix); + this._bounds = null; + this._inverse = null; + }, + + draw: function() { + if (this._stats) + this._stats.update(); + var ctx =this._context, + bounds = this._viewBounds; + ctx.clearRect(bounds._x, bounds._y, + bounds._width + 1, bounds._height + 1); + + ctx.save(); + this._matrix.applyToContext(ctx); + this._scope.project.draw(ctx); + ctx.restore(); + }, + + activate: function() { + this._scope.view = this; + }, + + remove: function() { + var res = Base.splice(this._scope.views, null, this._index, 1); + DomEvent.remove(this._canvas, this._events); + this._scope = this._canvas = this._events = this._onFrame = null; + return !!res.length; + }, + + artworkToView: function(point) { + return this._matrix._transformPoint(Point.read(arguments)); + }, + + viewToArtwork: 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({ + delta: delta, + time: time += delta, + count: count++ + }); + before = now; + that.draw(); + }; + if (!requested) + this._onFrameCallback(); + }, + + onResize: null, + + _createEvents: function() { + var that = this, + tool, + timer, + curPoint, + dragging = false; + + function viewToArtwork(event) { + return that.viewToArtwork(DomEvent.getOffset(event)); + } + + function mousedown(event) { + View.focused = that; + if (!(tool = that._scope.tool)) + return; + curPoint = viewToArtwork(event); + tool.onHandleEvent('mousedown', curPoint, event); + if (tool.onMouseDown) + that.draw(); + if (tool.eventInterval != null) + timer = setInterval(mousemove, tool.eventInterval); + dragging = true; + } + + function mousemove(event) { + if (!(tool = that._scope.tool)) + return; + if (event && event.targetTouches) + DomEvent.preventDefault(event); + var point = event && viewToArtwork(event); + var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove); + if (dragging && !onlyMove) { + curPoint = point || curPoint; + if (curPoint) + tool.onHandleEvent('mousedrag', curPoint, event); + if (tool.onMouseDrag && !tool.onFrame) + that.draw(); + } else if (!dragging || onlyMove) { + tool.onHandleEvent('mousemove', point, event); + if (tool.onMouseMove && !tool.onFrame) + that.draw(); + } + } + + function mouseup(event) { + if (!dragging) + return; + dragging = false; + curPoint = null; + if (tool) { + if (tool.eventInterval != null) + timer = clearInterval(timer); + tool.onHandleEvent('mouseup', viewToArtwork(event), event); + if (tool.onMouseUp) + that.draw(); + } + } + + return { + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + touchstart: mousedown, + touchmove: mousemove, + touchend: mouseup + }; + } +}); + +var Event = this.Event = Base.extend({ + beans: true, + + initialize: function(event) { + this.event = event; + }, + + preventDefault: function() { + DomEvent.preventDefault(this.event); + }, + + stopPropagation: function() { + DomEvent.stopPropagation(this.event); + }, + + stop: function() { + this.stopPropagation(); + this.preventDefault(); + }, + + getModifiers: function() { + return Key.modifiers; + } +}); + +var KeyEvent = this.KeyEvent = Event.extend(new function() { + return { + + beans: true, + + 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' + }, + + modifiers = { + shift: false, + control: false, + option: false, + command: false, + capsLock: false, + + toString: function() { + return Base.formatObject(this); + } + }, + + charCodeMap = {}, + keyMap = {}, + downCode; + + function handleKey(down, keyCode, charCode, event) { + var character = String.fromCharCode(charCode), + key = keys[keyCode] || character.toLowerCase(), + handler = down ? 'onKeyDown' : 'onKeyUp', + scope = View.focused && View.focused._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(); + } + } + + DomEvent.add(document, { + keydown: function(event) { + var code = event.which || event.keyCode; + var key = keys[code], name; + if (key) { + if (modifiers[name = Base.camelize(key)] !== undefined) { + modifiers[name] = true; + } else { + 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 && modifiers[name = Base.camelize(key)] !== undefined) { + modifiers[name] = false; + } else 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 = Base.extend({ + + beans: true, + + 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; + }, + + getModifiers: function() { + return Key.modifiers; + }, + + toString: function() { + return '{ type: ' + this.type + + ', point: ' + this.getPoint() + + ', count: ' + this.getCount() + + ', modifiers: ' + this.getModifiers() + + ' }'; + } +}); + +var Tool = this.Tool = Base.extend({ + + beans: true, + + initialize: function(handlers, scope) { + this._scope = scope; + this._firstMove = true; + this._count = 0; + this._downCount = 0; + for (var i in handlers) + this[i] = handlers[i]; + }, + + 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; + switch (type) { + case 'mousedown': + this.updateEvent(type, pt, null, null, true, false, false); + if (this.onMouseDown) + this.onMouseDown(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.onMouseDrag) + this.onMouseDrag(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.onMouseDrag) + this.onMouseDrag(new ToolEvent(this, type, event)); + } + this.updateEvent(type, pt, null, this.maxDistance, false, + false, false); + if (this.onMouseUp) + this.onMouseUp(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.onMouseMove) + this.onMouseMove(new ToolEvent(this, type, event)); + this._firstMove = false; + } + break; + } + } +}); + +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] + ], + + 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] + ]; + + return { + TOLERANCE: 10e-6, + + 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, tol) { + for (var i = 0; i < n; i++) { + var fx = f(x), + dx = fx / df(x); + if (Math.abs(dx) < tol) + 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; + } + } + } + }; +}; + +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 S(a,b,c){var d=[];for(var e=0;e=0;)if(b[c]===a)return!0;return!1}function N(a){return a.split("")}function M(a,b){return Array.prototype.slice.call(a,b==null?0:b)}function L(a){var b={};for(var c=0;c0;++b)arguments[b]();return a}function J(a){var b=M(arguments,1);return function(){return a.apply(this,b.concat(M(arguments)))}}function I(a,b){function y(a){var b=a[0],c=p[b];if(!c)throw new Error("Can't find generator for \""+b+'"');x.push(a);var d=c.apply(b,a.slice(1));x.pop();return d}function w(a){var b=a[0],c=a[1];c!=null&&(b=h([b,"=",y(c)]));return b}function v(a){if(!a)return";";if(a.length==0)return"{}";return"{"+d+g(function(){return t(a).join(d)})+d+f("}")}function u(a){var c=a.length;if(c==0)return"{}";return"{"+d+S(a,function(a,e){var i=a[1].length>0,j=g(function(){return f(a[0]?h(["case",y(a[0])+":"]):"default:")},.5)+(i?d+g(function(){return t(a[1]).join(d)}):"");!b&&i&&e0?"("+j(S(b,y))+")":"";return h(["new",k(a,"seq","binary","conditional","assign",function(a){var b=E(),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 h(["switch","("+y(a)+")",u(b)])},"break":function(a){var b="break";a!=null&&(b+=" "+s(a));return b+";"},"continue":function(a){var b="continue";a!=null&&(b+=" "+s(a));return b+";"},conditional:function(a,b,c){return h([k(a,"assign","seq","conditional"),"?",k(b,"seq"),":",k(c,"seq")])},assign:function(a,b,c){a&&a!==!0?a+="=":a="=";return h([y(b),a,k(c,"seq")])},dot:function(a){var b=y(a),c=1;a[0]=="num"?b+=".":m(a)&&(b="("+b+")");while(cz[b[1]])d="("+d+")";if(O(c[0],["assign","conditional","seq"])||c[0]=="binary"&&z[a]>=z[c[1]]&&(c[1]!=a||!O(a,["&&","||","*"])))e="("+e+")";return h([d,a,e])},"unary-prefix":function(a,b){var c=y(b);b[0]=="num"||b[0]=="unary-prefix"&&!R(i,a+b[1])||!m(b)||(c="("+c+")");return a+(n(a.charAt(0))?" ":"")+c},"unary-postfix":function(a,b){var c=y(b);b[0]=="num"||b[0]=="unary-postfix"&&!R(i,a+b[1])||!m(b)||(c="("+c+")");return c+a},sub:function(a,b){var c=y(a);m(a)&&(c="("+c+")");return c+"["+y(b)+"]"},object:function(a){if(a.length==0)return"{}";return"{"+d+g(function(){return S(a,function(a){if(a.length==3)return f(r(a[0],a[1][2],a[1][3],a[2]));var c=a[0],d=y(a[1]);b&&b.quote_keys?c=H(c):(typeof c=="number"||!b&&+c+""==c)&&parseFloat(c)>=0?c=o(+c):Q(c)||(c=H(c));return f(h(b&&b.space_colon?[c,":",d]:[c+":",d]))}).join(","+d)})+d+f("}")},regexp:function(a,b){return"/"+a+"/"+b},array:function(a){if(a.length==0)return"[]";return h(["[",j(S(a,function(a){if(!b&&a[0]=="atom"&&a[1]=="undefined")return"";return k(a,"seq")})),"]"])},stat:function(a){return y(a).replace(/;*\s*$/,";")},seq:function(){return j(S(M(arguments),y))},label:function(a,b){return h([s(a),":",y(b)])},"with":function(a,b){return h(["with","("+y(a)+")",y(b)])},atom:function(a){return s(a)}},x=[];return y(a)}function H(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 F(a){return!a||a[0]=="block"&&(!a[1]||a[1].length==0)}function E(){function f(a,b){var d={},e;for(e in a)R(a,e)&&(d[e]=c[e],c[e]=a[e]);var f=b();for(e in d)R(d,e)&&(d[e]?c[e]=d[e]:delete c[e]);return f}function e(a){if(a==null)return null;try{d.push(a);var e=a[0],f=c[e];if(f){var g=f.apply(a,a.slice(1));if(g!=null)return g}f=b[e];return f.apply(a,a.slice(1))}finally{d.pop()}}function a(a){return[this[0],S(a,function(a){var b=[a[0]];a.length>1&&(b[1]=e(a[1]));return b})]}var b={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],S(a,e)]},block:function(a){var b=[this[0]];a!=null&&b.push(S(a,e));return b},"var":a,"const":a,"try":function(a,b,c){return[this[0],S(a,e),b!=null?[b[0],S(b[1],e)]:null,c!=null?S(c,e):null]},"throw":function(a){return[this[0],e(a)]},"new":function(a,b){return[this[0],e(a),S(b,e)]},"switch":function(a,b){return[this[0],e(a),S(b,function(a){return[a[0]?e(a[0]):null,S(a[1],e)]})]},"break":function(a){return[this[0],a]},"continue":function(a){return[this[0],a]},conditional:function(a,b,c){return[this[0],e(a),e(b),e(c)]},assign:function(a,b,c){return[this[0],a,e(b),e(c)]},dot:function(a){return[this[0],e(a)].concat(M(arguments,1))},call:function(a,b){return[this[0],e(a),S(b,e)]},"function":function(a,b,c){return[this[0],a,b.slice(),S(c,e)]},defun:function(a,b,c){return[this[0],a,b.slice(),S(c,e)]},"if":function(a,b,c){return[this[0],e(a),e(b),e(c)]},"for":function(a,b,c,d){return[this[0],e(a),e(b),e(c),e(d)]},"for-in":function(a,b,c,d){return[this[0],a,b,e(c),e(d)]},"while":function(a,b){return[this[0],e(a),e(b)]},"do":function(a,b){return[this[0],e(a),e(b)]},"return":function(a){return[this[0],e(a)]},binary:function(a,b,c){return[this[0],a,e(b),e(c)]},"unary-prefix":function(a,b){return[this[0],a,e(b)]},"unary-postfix":function(a,b){return[this[0],a,e(b)]},sub:function(a,b){return[this[0],e(a),e(b)]},object:function(a){return[this[0],S(a,function(a){return a.length==2?[a[0],e(a[1])]:[a[0],e(a[1]),a[2]]})]},regexp:function(a,b){return[this[0],a,b]},array:function(a){return[this[0],S(a,e)]},stat:function(a){return[this[0],e(a)]},seq:function(){return[this[0]].concat(S(M(arguments),e))},label:function(a,b){return[this[0],a,e(b)]},"with":function(a,b){return[this[0],e(a),e(b)]},atom:function(a){return[this[0],a]}},c={},d=[];return{walk:e,with_walkers:f,parent:function(){return d[d.length-2]},stack:function(){return d}}}function D(a,b,c){function bj(a){try{++d.in_loop;return a()}finally{--d.in_loop}}function bi(a){arguments.length==0&&(a=!0);var b=bh();if(a&&e("punc",",")){g();return p("seq",b,bi())}return b}function bh(){var a=bf(),b=d.token.value;if(e("operator")&&R(y,b)){if(bg(a)){g();return p("assign",y[b],a,bh())}i("Invalid assignment")}return a}function bg(a){switch(a[0]){case"dot":case"sub":return!0;case"name":return a[1]!="this"}}function bf(){var a=be();if(e("operator","?")){g();var b=bi(!1);m(":");return p("conditional",a,b,bi(!1))}return a}function be(){return bd(X(!0),0)}function bd(a,b){var c=e("operator")?d.token.value:null,f=c!=null?z[c]:null;if(f!=null&&f>b){g();var h=bd(X(!0),f);return bd(p("binary",c,a,h),b)}return a}function bc(a,b,c){(b=="++"||b=="--")&&!bg(c)&&i("Invalid use of "+b+" operator");return p(a,b,c)}function bb(a,b){if(e("punc",".")){g();return bb(p("dot",a,ba()),b)}if(e("punc","[")){g();return bb(p("sub",a,K(bi,J(m,"]"))),b)}if(b&&e("punc","(")){g();return bb(p("call",a,Y(")")),!0)}if(b&&e("operator")&&R(x,d.token.value))return K(J(bc,"unary-postfix",d.token.value,a),g);return a}function ba(){switch(d.token.type){case"name":case"operator":case"keyword":case"atom":return K(d.token.value,g);default:k()}}function _(){switch(d.token.type){case"num":case"string":return K(d.token.value,g)}return ba()}function $(){var a=!0,c=[];while(!e("punc","}")){a?a=!1:m(",");if(!b&&e("punc","}"))break;var f=d.token.type,h=_();f!="name"||h!="get"&&h!="set"||!!e("punc",":")?(m(":"),c.push([h,bi(!1)])):c.push([ba(),I(!1),h])}g();return p("object",c)}function Z(){return p("array",Y("]",!b,!0))}function Y(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(bi(!1))}g();return f}function X(a){if(e("operator","new")){g();return W()}if(e("operator")&&R(w,d.token.value))return bc("unary-prefix",K(d.token.value,g),X(a));if(e("punc")){switch(d.token.value){case"(":g();return bb(K(bi,J(m,")")),a);case"[":g();return bb(Z(),a);case"{":g();return bb($(),a)}k()}if(e("keyword","function")){g();return bb(I(!1),a)}if(R(B,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 bb(K(b,g),a)}k()}function W(){var a=X(!1),b;e("punc","(")?(g(),b=Y(")")):b=[];return bb(p("new",a,b),!0)}function V(){return p("const",T())}function U(){return p("var",T())}function T(){var a=[];for(;;){e("name")||k();var b=d.token.value;g(),e("operator","=")?(g(),a.push([b,bi(!1)])):a.push([b]);if(!e("punc",","))break;g()}return a}function S(){var a=P(),b,c;if(e("keyword","catch")){g(),m("("),e("name")||i("Name expected");var f=d.token.value;g(),m(")"),b=[f,P()]}e("keyword","finally")&&(g(),c=P()),!b&&!c&&i("Missing catch/finally blocks");return p("try",a,b,c)}function P(){m("{");var a=[];while(!e("punc","}"))e("eof")&&k(),a.push(u());g();return a}function N(){var a=q(),b=u(),c;e("keyword","else")&&(g(),c=u());return p("if",a,b,c)}function L(a){var b=e("name")?K(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=P();--d.in_function,d.in_loop=a;return b}())}function H(){m("(");var a=e("keyword","var");a&&g();if(e("name")&&t(f(),"operator","in")){var b=d.token.value;g(),g();var c=bi();m(")");return p("for-in",a,b,c,bj(u))}var h=e("punc",";")?null:a?U():bi();m(";");var i=e("punc",";")?null:bi();m(";");var j=e("punc",")")?null:bi();m(")");return p("for",h,i,j,bj(u))}function G(a){var b=e("name")?d.token.value:null;b!=null?(g(),O(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",K(bi,o))}function E(a){d.labels.push(a);var c=d.token,e=u();b&&!R(A,e[0])&&k(c),d.labels.pop();return p("label",a,e)}function D(){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 t(f(),"punc",":")?E(K(d.token.value,g,g)):F();case"punc":switch(d.token.value){case"{":return p("block",P());case"[":case"(":return F();case";":g();return p("block");default:k()};case"keyword":switch(K(d.token.value,g)){case"break":return G("break");case"continue":return G("continue");case"debugger":o();return p("debugger");case"do":return function(a){l("keyword","while");return p("do",K(q,o),a)}(bj(u));case"for":return H();case"function":return I(!0);case"if":return N();case"return":d.in_function==0&&i("'return' outside of function");return p("return",e("punc",";")?(g(),null):n()?null:K(bi,o));case"switch":return p("switch",q(),Q());case"throw":return p("throw",K(bi,o));case"try":return S();case"var":return K(U,o);case"const":return K(V,o);case"while":return p("while",q(),bj(u));case"with":return p("with",q(),u());default:k()}}}function r(a,b,c){return a instanceof C?a:new C(a,b,c)}function q(){m("(");var a=bi();m(")");return a}function p(){return M(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();s(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 t(d.token,a,b)}var d={input:typeof a=="string"?v(a,!0):a,token:null,prev:null,peeked:null,in_function:0,in_loop:0,labels:[]};d.token=g();var u=c?function(){var a=d.token,b=D.apply(this,arguments);b[0]=r(b[0],a,h());return b}:D,I=c?function(){var a=h(),b=L.apply(this,arguments);b[0]=r(b[0],a,h());return b}:L,Q=J(bj,function(){m("{");var a=[],b=null;while(!e("punc","}"))e("eof")&&k(),e("keyword","case")?(g(),b=[],a.push([bi(),b]),m(":")):e("keyword","default")?(g(),m(":"),b=[],a.push([null,b])):(b||k(),b.push(u()));g();return a});return p("toplevel",function(a){while(!e("eof"))a.push(u());return a}([]))}function C(a,b,c){this.name=a,this.start=b,this.end=c}function v(b){function N(a){if(a)return H();y(),v();var b=g();if(!b)return w("eof");if(p(b))return B();if(b=='"'||b=="'")return E();if(R(l,b))return w("punc",h());if(b==".")return K();if(b=="/")return J();if(R(e,b))return I();if(o(b))return L();A("Unexpected character '"+b+"'")}function M(a,b){try{return b()}catch(c){if(c===u)A(a);else throw c}}function L(){var b=z(o);return R(a,b)?R(i,b)?w("operator",b):R(d,b)?w("atom",b):w("keyword",b):w("name",b)}function K(){h();return p(g())?B("."):w("punc",".")}function J(){h();var a=f.regex_allowed;switch(g()){case"/":f.comments_before.push(F()),f.regex_allowed=a;return N();case"*":f.comments_before.push(G()),f.regex_allowed=a;return N()}return f.regex_allowed?H():I("/")}function I(a){function b(a){if(!g())return a;var c=a+g();if(R(i,c)){h();return b(c)}return a}return w("operator",b(a||h()))}function H(){return M("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=z(function(a){return R(m,a)});return w("regexp",[b,e])})}function G(){h();return M("Unterminated multiline comment",function(){var a=t("*/",!0),b=f.text.substring(f.pos,a),c=w("comment2",b,!0);f.pos=a+2,f.line+=b.split("\n").length-1,f.newline_before=b.indexOf("\n")>=0;return c})}function F(){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 w("comment1",b,!0)}function E(){return M("Unterminated string constant",function(){var a=h(),b="";for(;;){var c=h(!0);if(c=="\\")c=C();else if(c==a)break;b+=c}return w("string",b)})}function D(a){var b=0;for(;a>0;--a){var c=parseInt(h(!0),16);isNaN(c)&&A("Invalid hex-character pattern in string"),b=b<<4|c}return b}function C(){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(D(2));case"u":return String.fromCharCode(D(4));default:return a}}function B(a){var b=!1,c=!1,d=!1,e=a==".",f=z(function(f,g){if(f=="x"||f=="X"){if(d)return!1;return d=!0}if(!d&&(f=="E"||f=="e")){if(b)return!1;return b=c=!0}if(f=="-"){if(c||g==0&&!a)return!0;return!1}if(f=="+")return c;c=!1;if(f=="."){if(!e)return e=!0;return!1}return n(f)});a&&(f=a+f);var g=q(f);if(!isNaN(g))return w("num",g);A("Invalid syntax: "+f)}function A(a){s(a,f.tokline,f.tokcol,f.tokpos)}function z(a){var b="",c=g(),d=0;while(c&&a(c,d++))b+=h(),c=g();return b}function y(){while(R(j,g()))h()}function w(a,b,d){f.regex_allowed=a=="operator"&&!R(x,b)||a=="keyword"&&R(c,b)||a=="punc"&&R(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 u;return c}function r(){return!f.peek()}function h(a){var b=f.text.charAt(f.pos++);if(a&&!b)throw u;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:[]};N.context=function(a){a&&(f=a);return f};return N}function t(a,b,c){return a.type==b&&(c==null||a.value==c)}function s(a,b,c,d){throw new r(a,b,c,d)}function r(a,b,c,d){this.message=a,this.line=b,this.col=c,this.pos=d;try{({})()}catch(e){this.stack=e.stack}}function q(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 p(a){a=a.charCodeAt(0);return a>=48&&a<=57}function o(a){return n(a)||a=="$"||a=="_"}function n(a){a=a.charCodeAt(0);return a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122}var a=L(["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=L(["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=L(["return","new","delete","throw","else","case"]),d=L(["false","null","true","undefined"]),e=L(N("+-*&%=<>!?|~^")),f=/^0x[0-9a-f]+$/i,g=/^0[0-7]+$/,h=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,i=L(["in","instanceof","typeof","new","void","delete","++","--","+","-","!","~","&","|","^","*","/","%",">>","<<",">>>","<",">","<=",">=","==","===","!=","!==","?","=","+=","-=","/=","*=","%=",">>=","<<=",">>>=","%=","|=","^=","&=","&&","||"]),j=L(N(" \n\r\t")),k=L(N("[{}(,.;:")),l=L(N("[]{}(),;:")),m=L(N("gmsiy"));r.prototype.toString=function(){return this.message+" (line: "+this.line+", col: "+this.col+", pos: "+this.pos+")"+"\n\n"+this.stack};var u={},w=L(["typeof","void","delete","--","++","!","~","-","+"]),x=L(["--","++"]),y=function(a,b,c){while(c>=","<<=",">>>=","|=","^=","&="],{"=":!0},0),z=function(a,b){for(var c=0,d=1;c","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"]],{}),A=L(["for","do","while","switch"]),B=L(["atom","num","string","regexp","name"]);C.prototype.toString=function(){return this.name};var G=L(["name","array","string","dot","sub","call","regexp"]);return{parse:D,stringify:I,tokenizer:v,walker:E}} + + 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); + } + }; + + 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); + } + } + + function isDynamic(exp) { + var type = exp[0]; + return type != 'num' && type != 'string'; + } + + function handleOperator(operator, left, right) { + if (operators[operator] && isDynamic(left)) { + return ['call', ['name', '$eval'], + [left, ['string', operator], right]]; + } + } + + function compile(code) { + var ast = parse_js.parse(code), + walker = parse_js.walker(), + walk = walker.walk; + + ast = walker.with_walkers({ + 'binary': function(operator, left, right) { + return handleOperator(operator, left = walk(left), + right = walk(right)) + || [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.stringify(ast, true); + } + + function evaluate(code, scope) { + if (typeof code !== 'string') { + var canvas = code.getAttribute('canvas'); + if (canvas = canvas && document.getElementById(canvas)) { + paper = scope; + new Project(); + new View(canvas).activate(); + } + if (code.src) { + return request(code.src, scope); + } else { + code = code.innerHTML; + } + } + var view = scope.view, + tool = scope.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) + && new Tool(null, scope), + res; + paper = scope; + 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; + if (onFrame) { + view.setOnFrame(onFrame); + } else { + 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'), + count = 0; + for (var i = 0, l = scripts.length; i < l; i++) { + var script = scripts[i]; + if (script.type === 'text/paperscript' + && !script.getAttribute('loaded')) { + var scope = new PaperScope(script.getAttribute('id') + || script.src || ('paperscript-' + (count++))); + script.setAttribute('id', scope.id); + evaluate(script, scope); + script.setAttribute('loaded', true); + } + } + } + + DomEvent.add(window, { load: load }); + + return { + compile: compile, + evaluate: evaluate, + load: load + }; + +}; + +this.load = PaperScript.load; + +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..e6640581 --- /dev/null +++ b/dist/docs/resources/js/reference.js @@ -0,0 +1,230 @@ +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 + script.setText(editor.getValue()); + // Clear scope first, then evaluate a new script. + scope.clear(); + scope.evaluate(script.$); + } + } + + 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(document.location.hash); + if (h) scrollToElement(h.substring(1)); + if (window.paper) + paper.load(); +});