diff --git a/.gitignore b/.gitignore index c2ef6f2..e01f87c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,3 @@ -build/firefox/* -build/opera/* -build/svg-edit-2.6/* -build/svg-edit-2.6-src/* -build/svg-edit-2.6-src.tar.gz -build/svg-edit-2.6.wgt -build/svg-edit-2.6.xpi -build/svg-edit-2.6.zip +node_modules/* .DS_Store deploy.sh \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index d20fb02..0000000 --- a/Makefile +++ /dev/null @@ -1,97 +0,0 @@ -NAME=method-draw -VERSION=2.6 -PACKAGE=$(NAME) -MAKEDOCS=naturaldocs/NaturalDocs -CLOSURE=build/tools/closure-compiler.jar -YUICOMPRESSOR=build/tools/yuicompressor-2.4.7.jar - -# All files that will be compiled by the Closure compiler. - -JS_FILES=\ - lib/pathseg.js \ - lib/touch.js \ - lib/js-hotkeys/jquery.hotkeys.min.js \ - icons/jquery.svgicons.js \ - lib/jgraduate/jquery.jgraduate.js \ - lib/contextmenu/jquery.contextMenu.js \ - src/browser.js \ - src/svgtransformlist.js \ - src/math.js \ - src/units.js \ - src/svgutils.js \ - src/sanitize.js \ - src/history.js \ - src/select.js \ - src/draw.js \ - src/path.js \ - src/svgcanvas.js \ - src/method-draw.js \ - lib/jquery-draginput.js \ - lib/contextmenu.js \ - lib/jquery-ui/jquery-ui-1.8.17.custom.min.js \ - lib/jgraduate/jpicker.min.js \ - lib/mousewheel.js \ - extensions/ext-eyedropper.js \ - extensions/ext-grid.js \ - extensions/ext-shapes.js \ - lib/requestanimationframe.js \ - lib/taphold.js \ - lib/filesaver.js - -CSS_FILES=\ - lib/jgraduate/css/jPicker.css \ - lib/jgraduate/css/jgraduate.css \ - css/method-draw.css \ - -JS_INPUT_FILES=$(addprefix editor/, $(JS_FILES)) -CSS_INPUT_FILES=$(addprefix editor/, $(CSS_FILES)) -JS_BUILD_FILES=$(addprefix $(PACKAGE)/, $(JS_FILES)) -CSS_BUILD_FILES=$(addprefix $(PACKAGE)/, $(CSS_FILES)) -CLOSURE_JS_ARGS=$(addprefix --js , $(JS_INPUT_FILES)) -COMPILED_JS=editor/method-draw.compiled.js -COMPILED_CSS=editor/css/method-draw.compiled.css - -all: release - -# The build directory relies on the JS being compiled. -$(PACKAGE): $(COMPILED_JS) $(COMPILED_CSS) - rm -rf config; - mkdir config; - if [ -x $(MAKEDOCS) ] ; then $(MAKEDOCS) -i editor/ -o html docs/ -p config/ -oft -r ; fi - - # Make build directory and copy all editor contents into it - mkdir -p $(PACKAGE) - cp -r editor/* $(PACKAGE) - - # Remove all hidden .svn directories - -find $(PACKAGE) -name .svn -type d | xargs rm -rf {} \; - -find $(PACKAGE) -name .git -type d | xargs rm -rf {} \; - - # Create the release version of the main HTML file. - build/tools/ship.py --i=editor/index.html --on=svg_edit_release > $(PACKAGE)/index.html - -# NOTE: Some files are not ready for the Closure compiler: (jquery) -# NOTE: Our code safely compiles under SIMPLE_OPTIMIZATIONS -# NOTE: Our code is *not* ready for ADVANCED_OPTIMIZATIONS -# NOTE: WHITESPACE_ONLY and --formatting PRETTY_PRINT is helpful for debugging. - -$(COMPILED_CSS): - cat $(CSS_INPUT_FILES) > editor/temp.css; - java -jar $(YUICOMPRESSOR) editor/temp.css -o $(COMPILED_CSS) --line-break 0; - rm editor/temp.css; - -$(COMPILED_JS): - java -jar $(CLOSURE) \ - --compilation_level SIMPLE_OPTIMIZATIONS \ - $(CLOSURE_JS_ARGS) \ - --js_output_file $(COMPILED_JS) - -compile: $(COMPILED_JS) $(COMPILED_CSS) - -release: $(PACKAGE) - -clean: - rm -rf config - rm -rf $(PACKAGE) - rm -rf $(COMPILED_JS) - rm -rf $(COMPILED_CSS) diff --git a/build/tools/COPYING b/build/tools/COPYING deleted file mode 100644 index d645695..0000000 --- a/build/tools/COPYING +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/build/tools/README b/build/tools/README deleted file mode 100644 index d3c90e7..0000000 --- a/build/tools/README +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Contents -// - -The Closure Compiler performs checking, instrumentation, and -optimizations on JavaScript code. The purpose of this README is to -explain how to build and run the Closure Compiler. - -The Closure Compiler requires Java 6 or higher. -http://www.java.com/ - - -// -// Building The Closure Compiler -// - -There are three ways to get a Closure Compiler executable. - -1) Use one we built for you. - -Pre-built Closure binaries can be found at -http://code.google.com/p/closure-compiler/downloads/list - - -2) Check out the source and build it with Apache Ant. - -First, check out the full source tree of the Closure Compiler. There -are instructions on how to do this at the project site. -http://code.google.com/p/closure-compiler/source/checkout - -Apache Ant is a cross-platform build tool. -http://ant.apache.org/ - -At the root of the source tree, there is an Ant file named -build.xml. To use it, navigate to the same directory and type the -command - -ant jar - -This will produce a jar file called "build/compiler.jar". - - -3) Check out the source and build it with Eclipse. - -Eclipse is a cross-platform IDE. -http://www.eclipse.org/ - -Under Eclipse's File menu, click "New > Project ..." and create a -"Java Project." You will see an options screen. Give the project a -name, select "Create project from existing source," and choose the -root of the checked-out source tree as the existing directory. Verify -that you are using JRE version 6 or higher. - -Eclipse can use the build.xml file to discover rules. When you -navigate to the build.xml file, you will see all the build rules in -the "Outline" pane. Run the "jar" rule to build the compiler in -build/compiler.jar. - - -// -// Running The Closure Compiler -// - -Once you have the jar binary, running the Closure Compiler is straightforward. - -On the command line, type - -java -jar compiler.jar - -This starts the compiler in interactive mode. Type - -var x = 17 + 25; - -then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux) -and "Enter" again. The Compiler will respond: - -var x=42; - -The Closure Compiler has many options for reading input from a file, -writing output to a file, checking your code, and running -optimizations. To learn more, type - -java -jar compiler.jar --help - -You can read more detailed documentation about the many flags at -http://code.google.com/closure/compiler/docs/gettingstarted_app.html - - -// -// Compiling Multiple Scripts -// - -If you have multiple scripts, you should compile them all together with -one compile command. - -java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js - -The Closure Compiler will concatenate the files in the order they're -passed at the command line. - -If you need to compile many, many scripts together, you may start to -run into problems with managing dependencies between scripts. You -should check out the Closure Library. It contains functions for -enforcing dependencies between scripts, and a tool called calcdeps.py -that knows how to give scripts to the Closure Compiler in the right -order. - -http://code.google.com/p/closure-library/ - -// -// Licensing -// - -Unless otherwise stated, all source files are licensed under -the Apache License, Version 2.0. - - ------ -Code under: -src/com/google/javascript/rhino -test/com/google/javascript/rhino - -URL: http://www.mozilla.org/rhino -Version: 1.5R3, with heavy modifications -License: Netscape Public License and MPL / GPL dual license - -Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an -implementation of JavaScript for the JVM. The JavaScript parser and -the parse tree data structures were extracted and modified -significantly for use by Google's JavaScript compiler. - -Local Modifications: The packages have been renamespaced. All code not -relavant to parsing has been removed. A JSDoc parser and static typing -system have been added. - - ------ -Code in: -lib/libtrunk_rhino_parser_jarjared.jar - -Rhino -URL: http://www.mozilla.org/rhino -Version: Trunk -License: Netscape Public License and MPL / GPL dual license - -Description: Mozilla Rhino is an implementation of JavaScript for the JVM. - -Local Modifications: None. We've used JarJar to renamespace the code -post-compilation. See: -http://code.google.com/p/jarjar/ - - ------ -Code in: -lib/args4j_deploy.jar - -Args4j -URL: https://args4j.dev.java.net/ -Version: 2.0.9 -License: MIT - -Description: -args4j is a small Java class library that makes it easy to parse command line -options/arguments in your CUI application. - -Local Modifications: None. - - ------ -Code in: -lib/guava-r06.jar - -Guava Libraries -URL: http://code.google.com/p/guava-libraries/ -Version: R6 -License: Apache License 2.0 - -Description: Google's core Java libraries. - -Local Modifications: None. - - ------ -Code in: -lib/hamcrest-core-1.1.jar - -Hamcrest -URL: http://code.google.com/p/hamcrest -License: BSD -License File: LICENSE - -Description: -Provides a library of matcher objects (also known as constraints or -predicates) allowing 'match' rules to be defined declaratively, to be used in -other frameworks. Typical scenarios include testing frameworks, mocking -libraries and UI validation rules. - -Local modifications: -The original jars contained both source code and compiled classes. - -hamcrest-core-1.1.jar just contains the compiled classes. - - - ------ -Code in: -lib/jsr305.jar - -Annotations for software defect detection -URL: http://code.google.com/p/jsr-305/ -Version: svn revision 47 -License: BSD License - -Description: Annotations for software defect detection. - -Local Modifications: None. - - ----- -Code in: -lib/junit.jar - -JUnit -URL: http://sourceforge.net/projects/junit/ -Version: 4.5 -License: Common Public License 1.0 - -Description: A framework for writing and running automated tests in Java. - -Local Modifications: None. - - ---- -Code in: -lib/protobuf-java-2.3.0.jar - -Protocol Buffers -URL: http://code.google.com/p/protobuf/ -Version: 2.3.0 -License: New BSD License - -Description: Supporting libraries for protocol buffers, -an encoding of structured data. - -Local Modifications: None - - ---- -Code in: -lib/ant_deploy.jar - -URL: http://ant.apache.org/bindownload.cgi -Version: 1.6.5 -License: Apache License 2.0 -Description: - Ant is a Java based build tool. In theory it is kind of like "make" - without make's wrinkles and with the full portability of pure java code. - -Local Modifications: - Modified apache-ant-1.6.5/bin/ant to look in the ant.runfiles directory - - ---- -Code in: -lib/json.jar -URL: http://json.org/java/index.html -Version: JSON version 2 -License: MIT license -Description: -JSON is a set of java files for use in transmitting data in JSON format. - -Local Modifications: None - diff --git a/build/tools/closure-compiler.jar b/build/tools/closure-compiler.jar deleted file mode 100644 index 4dfa5ad..0000000 Binary files a/build/tools/closure-compiler.jar and /dev/null differ diff --git a/build/tools/ship.py b/build/tools/ship.py deleted file mode 100755 index d2c3052..0000000 --- a/build/tools/ship.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# ship.py -# -# Licensed under the Apache 2 License as is the rest of the project -# Copyright (c) 2011 Jeff Schiller -# -# This script has very little real-world application. It is only used in our pure-client web app -# served on GoogleCode so we can have one HTML file, run a build script and generate a 'release' -# version without having to maintain two separate HTML files. It does this by evaluating -# 'processing comments' that are suspicously similar to IE conditional comments and then outputting -# a new HTML file after evaluating particular variables. -# -# This script takes the following inputs: -# -# * a HTML file (--i=in.html) -# * a series of flag names (--on=Foo --on=Bar) -# -# Example: -# -# in.html: -# -# BAR! -# -# -# $ ship.py --i in.html --on foo -# -# out.html: -# -# FOO! -# -# -# It has the following limitations: -# -# 1) Only if-else-endif are currently supported. -# 2) All processing comments must be on one line with no other non-whitespace characters. -# 3) Comments cannot be nested. - -import optparse -import os - -inside_if = False -last_if_true = False - -_options_parser = optparse.OptionParser( - usage='%prog --i input.html [--on flag1]', - description=('Rewrites an HTML file based on conditional comments and flags')) -_options_parser.add_option('--i', - action='store', dest='input_html_file', help='Input HTML filename') -_options_parser.add_option('--on', - action='append', type='string', dest='enabled_flags', - help='name of flag to enable') - -def parse_args(args=None): - options, rargs = _options_parser.parse_args(args) - return options, (None, None) - -def parseComment(line, line_num, enabled_flags): - global inside_if - global last_if_true - - start = line.find('{') - end = line.find('}') - statement = line[start+1:end].strip() - if statement.startswith('if '): - if inside_if == True: - print 'Fatal Error: Nested {if} found on line ' + str(line_num) - print line - quit() - - # Evaluate whether the expression is true/false. - # only one variable name allowed for now - variable_name = statement[3:].strip() - if variable_name in enabled_flags: - last_if_true = True - line = '' - else: - last_if_true = False - line = '' - - # invert the logic so the endif clause is closed properly - last_if_true = not last_if_true - - # ensure we don't have two else statements in the same if - inside_if = 'else' - - elif statement == 'endif': - if inside_if == False: - print 'Fatal Error: {endif} found without {if} on line ' + str(line_num) - print line - quit() - - if last_if_true: - line = '' - else: - line = '' - - inside_if = False - - return line - - -def ship(inFileName, enabled_flags): - # read in HTML file - lines = file(inFileName, 'r').readlines() - out_lines = [] - i = 0 - - # loop for each line of markup - for line in lines: - strline = line.strip() - # if we find a comment, process it and print out - if strline.startswith('"); + break; + } // switch on node type + } + indent--; + if (!bOneLine) { + out.push("\n"); + for (var i=0; i"); + } else { + out.push("/>"); + } + } + return out.join(''); +}; // end svgToString() + +// Function: embedImage +// Converts a given image file to a data URL when possible, then runs a given callback +// +// Parameters: +// val - String with the path/URL of the image +// callback - Optional function to run when image data is found, supplies the +// result (data URL or false) as first parameter. +this.embedImage = function(val, callback) { + + // load in the image and once it's loaded, get the dimensions + $(new Image()).on("load", + function() { + // create a canvas the same size as the raster image + var canvas = document.createElement("canvas"); + canvas.width = this.width; + canvas.height = this.height; + // load the raster image into the canvas + canvas.getContext("2d").drawImage(this,0,0); + // retrieve the data: URL + try { + var urldata = ';svgedit_url=' + encodeURIComponent(val); + urldata = canvas.toDataURL().replace(';base64',urldata+';base64'); + encodableImages[val] = urldata; + } catch(e) { + encodableImages[val] = false; + } + last_good_img_url = val; + if(callback) callback(encodableImages[val]); + }).attr('src',val); +} + +// Function: setGoodImage +// Sets a given URL to be a "last good image" URL +this.setGoodImage = function(val) { + last_good_img_url = val; +} + +this.open = function() { + // Nothing by default, handled by optional widget/extension +}; + +// Function: save +// Serializes the current drawing into SVG XML text and returns it to the 'saved' handler. +// This function also includes the XML prolog. Clients of the SvgCanvas bind their save +// function to the 'saved' event. +// +// Returns: +// Nothing +this.save = function(opts) { + // remove the selected outline before serializing + clearSelection(); + // Update save options if provided + if(opts) $.extend(save_options, opts); + save_options.apply = true; + + // no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration + var str = this.svgCanvasToString(); + var blob = new Blob([ str ], {type: "image/svg+xml;charset=utf-8"}); + var dropAutoBOM = true; + saveAs(blob, "method-draw-image.svg", dropAutoBOM); +}; + +// Function: rasterExport +// Generates a PNG Data URL based on the current image, then calls "exported" +// with an object including the string and any issues found +this.rasterExport = function() { + // remove the selected outline before serializing + clearSelection(); + + // Check for known CanVG issues + var issues = []; + + // Selector and notice + var issue_list = { + 'feGaussianBlur': "Blurred elements will appear as un-blurred", + 'foreignObject': "foreignObject elements will not appear", + '[stroke-dasharray]': "Strokes will appear filled" + }; + var content = $(svgcontent); + + // Add font/text check if Canvas Text API is not implemented + if(!("font" in $('')[0].getContext('2d'))) { + issue_list['text'] = "Text may not appear as expected"; + } + + $.each(issue_list, function(sel, descr) { + if(content.find(sel).length) { + issues.push(descr); + } + }); + + var str = this.svgCanvasToString(); + call("exported", {svg: str, issues: issues}); +}; + +// Function: getSvgString +// Returns the current drawing as raw SVG XML text. +// +// Returns: +// The current drawing as raw SVG XML text. +this.getSvgString = function() { + save_options.apply = false; + return this.svgCanvasToString(); +}; + +// Function: randomizeIds +// This function determines whether to use a nonce in the prefix, when +// generating IDs for future documents in SVG-Edit. +// +// Parameters: +// an opional boolean, which, if true, adds a nonce to the prefix. Thus +// svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true) +// +// if you're controlling SVG-Edit externally, and want randomized IDs, call +// this BEFORE calling svgCanvas.setSvgString +// +this.randomizeIds = function() { + if (arguments.length > 0 && arguments[0] == false) { + svgedit.draw.randomizeIds(false, getCurrentDrawing()); + } else { + svgedit.draw.randomizeIds(true, getCurrentDrawing()); + } +}; + +// Function: uniquifyElems +// Ensure each element has a unique ID +// +// Parameters: +// g - The parent element of the tree to give unique IDs +var uniquifyElems = this.uniquifyElems = function(g) { + var ids = {}; + // TODO: Handle markers and connectors. These are not yet re-identified properly + // as their referring elements do not get remapped. + // + // + // + // + // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute + // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute + var ref_elems = ["filter", "linearGradient", "pattern", "radialGradient", "symbol", "textPath", "use"]; + + svgedit.utilities.walkTree(g, function(n) { + // if it's an element node + if (n.nodeType == 1) { + // and the element has an ID + if (n.id) { + // and we haven't tracked this ID yet + if (!(n.id in ids)) { + // add this id to our map + ids[n.id] = {elem:null, attrs:[], hrefs:[]}; + } + ids[n.id]["elem"] = n; + } + + // now search for all attributes on this element that might refer + // to other elements + $.each(ref_attrs,function(i,attr) { + var attrnode = n.getAttributeNode(attr); + if (attrnode) { + // the incoming file has been sanitized, so we should be able to safely just strip off the leading # + var url = svgedit.utilities.getUrlFromAttr(attrnode.value), + refid = url ? url.substr(1) : null; + if (refid) { + if (!(refid in ids)) { + // add this id to our map + ids[refid] = {elem:null, attrs:[], hrefs:[]}; + } + ids[refid]["attrs"].push(attrnode); + } + } + }); + + // check xlink:href now + var href = svgedit.utilities.getHref(n); + // TODO: what if an or element refers to an element internally? + if(href && ref_elems.indexOf(n.nodeName) >= 0) + { + var refid = href.substr(1); + if (refid) { + if (!(refid in ids)) { + // add this id to our map + ids[refid] = {elem:null, attrs:[], hrefs:[]}; + } + ids[refid]["hrefs"].push(n); + } + } + } + }); + + // in ids, we now have a map of ids, elements and attributes, let's re-identify + for (var oldid in ids) { + if (!oldid) continue; + var elem = ids[oldid]["elem"]; + if (elem) { + var newid = getNextId(); + + // assign element its new id + elem.id = newid; + + // remap all url() attributes + var attrs = ids[oldid]["attrs"]; + var j = attrs.length; + while (j--) { + var attr = attrs[j]; + attr.ownerElement.setAttribute(attr.name, "url(#" + newid + ")"); + } + + // remap all href attributes + var hreffers = ids[oldid]["hrefs"]; + var k = hreffers.length; + while (k--) { + var hreffer = hreffers[k]; + svgedit.utilities.setHref(hreffer, "#"+newid); + } + } + } +} + +// Function setUseData +// Assigns reference data for each use element +var setUseData = this.setUseData = function(parent) { + var elems = $(parent); + + if(parent.tagName !== 'use') { + elems = elems.find('use'); + } + + elems.each(function() { + var id = getHref(this).substr(1); + var ref_elem = getElem(id); + if(!ref_elem) return; + $(this).data('ref', ref_elem); + if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { + $(this).data('symbol', ref_elem).data('ref', ref_elem); + } + }); +} + +// Function convertGradients +// Converts gradients from userSpaceOnUse to objectBoundingBox +var convertGradients = this.convertGradients = function(elem) { + var elems = $(elem).find('linearGradient, radialGradient'); + if(!elems.length && svgedit.browser.isWebkit()) { + // Bug in webkit prevents regular *Gradient selector search + elems = $(elem).find('*').filter(function() { + return (this.tagName.indexOf('Gradient') >= 0); + }); + } + + elems.each(function() { + var grad = this; + if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { + // TODO: Support more than one element with this ref by duplicating parent grad + var elems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); + if(!elems.length) return; + + // get object's bounding box + var bb = svgedit.utilities.getBBox(elems[0]); + + // This will occur if the element is inside a or a , + // in which we shouldn't need to convert anyway. + if(!bb) return; + + if(grad.tagName === 'linearGradient') { + var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); + + // If has transform, convert + var tlist = grad.gradientTransform.baseVal; + if(tlist && tlist.numberOfItems > 0) { + var m = transformListToTransform(tlist).matrix; + var pt1 = transformPoint(g_coords.x1, g_coords.y1, m); + var pt2 = transformPoint(g_coords.x2, g_coords.y2, m); + + g_coords.x1 = pt1.x; + g_coords.y1 = pt1.y; + g_coords.x2 = pt2.x; + g_coords.y2 = pt2.y; + grad.removeAttribute('gradientTransform'); + } + + $(grad).attr({ + x1: (g_coords.x1 - bb.x) / bb.width, + y1: (g_coords.y1 - bb.y) / bb.height, + x2: (g_coords.x2 - bb.x) / bb.width, + y2: (g_coords.y2 - bb.y) / bb.height + }); + grad.removeAttribute('gradientUnits'); + } else { + // Note: radialGradient elements cannot be easily converted + // because userSpaceOnUse will keep circular gradients, while + // objectBoundingBox will x/y scale the gradient according to + // its bbox. + + // For now we'll do nothing, though we should probably have + // the gradient be updated as the element is moved, as + // inkscape/illustrator do. + +// var g_coords = $(grad).attr(['cx', 'cy', 'r']); +// +// $(grad).attr({ +// cx: (g_coords.cx - bb.x) / bb.width, +// cy: (g_coords.cy - bb.y) / bb.height, +// r: g_coords.r +// }); +// +// grad.removeAttribute('gradientUnits'); + } + + + } + }); +} + +// Function: convertToGroup +// Converts selected/given or child SVG element to a group +var convertToGroup = this.convertToGroup = function(elem) { + if(!elem) { + elem = selectedElements[0]; + } + var $elem = $(elem); + + var batchCmd = new BatchCommand(); + + var ts; + + if($elem.data('gsvg')) { + // Use the gsvg as the new group + var svg = elem.firstChild; + var pt = $(svg).attr(['x', 'y']); + + $(elem.firstChild.firstChild).unwrap(); + $(elem).removeData('gsvg'); + + var tlist = getTransformList(elem); + var xform = svgroot.createSVGTransform(); + xform.setTranslate(pt.x, pt.y); + tlist.appendItem(xform); + recalculateDimensions(elem); + call("selected", [elem]); + } else if($elem.data('symbol')) { + elem = $elem.data('symbol'); + + ts = $elem.attr('transform'); + var pos = $elem.attr(['x','y']); + + var vb = elem.getAttribute('viewBox'); + + if(vb) { + var nums = vb.split(' '); + pos.x -= +nums[0]; + pos.y -= +nums[1]; + } + + // Not ideal, but works + ts += " translate(" + (pos.x || 0) + "," + (pos.y || 0) + ")"; + + var prev = $elem.prev(); + + // Remove element + batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].nextSibling, $elem[0].parentNode)); + $elem.remove(); + + // See if other elements reference this symbol + var has_more = $(svgcontent).find('use:data(symbol)').length; + + var g = svgdoc.createElementNS(svgns, "g"); + var childs = elem.childNodes; + + for(var i = 0; i < childs.length; i++) { + g.appendChild(childs[i].cloneNode(true)); + } + + // Duplicate the gradients for Gecko, since they weren't included in the + if(svgedit.browser.isGecko()) { + var dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone(); + $(g).append(dupeGrads); + } + + if (ts) { + g.setAttribute("transform", ts); + } + + var parent = elem.parentNode; + + uniquifyElems(g); + + // Put the dupe gradients back into (after uniquifying them) + if(svgedit.browser.isGecko()) { + $(findDefs()).append( $(g).find('linearGradient,radialGradient,pattern') ); + } + + // now give the g itself a new id + g.id = getNextId(); + + prev.after(g); + + if(parent) { + if(!has_more) { + // remove symbol/svg element + var nextSibling = elem.nextSibling; + parent.removeChild(elem); + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + } + batchCmd.addSubCommand(new InsertElementCommand(g)); + } + + setUseData(g); + + if(svgedit.browser.isGecko()) { + convertGradients(findDefs()); + } else { + convertGradients(g); + } + + // recalculate dimensions on the top-level children so that unnecessary transforms + // are removed + svgedit.utilities.walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); + + // Give ID for any visible element missing one + $(g).find(visElems).each(function() { + if(!this.id) this.id = getNextId(); + }); + + selectOnly([g]); + + var cm = pushGroupProperties(g, true); + if(cm) { + batchCmd.addSubCommand(cm); + } + + addCommandToHistory(batchCmd); + + } else { + console.log('Unexpected element to ungroup:', elem); + } +} + +// +// Function: setSvgString +// This function sets the current drawing as the input SVG XML. +// +// Parameters: +// xmlString - The SVG as XML text. +// +// Returns: +// This function returns false if the set was unsuccessful, true otherwise. +this.setSvgString = function(xmlString) { + try { + // convert string into XML document + var newDoc = svgedit.utilities.text2xml(xmlString); + + this.prepareSvg(newDoc); + + var batchCmd = new BatchCommand("Change Source"); + + // remove old svg document + var nextSibling = svgcontent.nextSibling; + var oldzoom = svgroot.removeChild(svgcontent); + batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgroot)); + + // set new svg document + // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() + if(svgdoc.adoptNode) { + svgcontent = svgdoc.adoptNode(newDoc.documentElement); + } + else { + svgcontent = svgdoc.importNode(newDoc.documentElement, true); + } + + svgroot.appendChild(svgcontent); + var content = $(svgcontent); + + canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); + + // retrieve or set the nonce + var nonce = getCurrentDrawing().getNonce(); + if (nonce) { + call("setnonce", nonce); + } else { + call("unsetnonce"); + } + + // change image href vals if possible + content.find('image').each(function() { + var image = this; + preventClickDefault(image); + var val = getHref(this); + if(val.indexOf('data:') === 0) { + // Check if an SVG-edit data URI + var m = val.match(/svgedit_url=(.*?);/); + if(m) { + var url = decodeURIComponent(m[1]); + $(new Image()).load(function() { + image.setAttributeNS(xlinkns,'xlink:href',url); + }).attr('src',url); + } + } + // Add to encodableImages if it loads + canvas.embedImage(val); + }); + + // Wrap child SVGs in group elements + content.find('svg').each(function() { + // Skip if it's in a + if($(this).closest('defs').length) return; + + uniquifyElems(this); + + // Check if it already has a gsvg group + var pa = this.parentNode; + if(pa.childNodes.length === 1 && pa.nodeName === 'g') { + $(pa).data('gsvg', this); + pa.id = pa.id || getNextId(); + } else { + groupSvgElem(this); + } + }); + + // Put all paint elems in defs + + content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); + + // Set ref element for elements + + // TODO: This should also be done if the object is re-added through "redo" + setUseData(content); + + convertGradients(content[0]); + + // recalculate dimensions on the top-level children so that unnecessary transforms + // are removed + svgedit.utilities.walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); + + var attrs = { + id: 'svgcontent', + overflow: curConfig.show_outside_canvas?'visible':'hidden' + }; + + var percs = false; + + // determine proper size + if (content.attr("viewBox")) { + var vb = content.attr("viewBox").split(' '); + attrs.width = vb[2]; + attrs.height = vb[3]; + } + // handle content that doesn't have a viewBox + else { + $.each(['width', 'height'], function(i, dim) { + // Set to 100 if not given + var val = content.attr(dim); + + if(!val) val = '100%'; + + if((val+'').substr(-1) === "%") { + // Use user units if percentage given + percs = true; + } else { + attrs[dim] = convertToNum(dim, val); + } + }); + } + + // identify layers + identifyLayers(); + + // Give ID for any visible layer children missing one + content.children().find(visElems).each(function() { + if(!this.id) this.id = getNextId(); + }); + + // Percentage width/height, so let's base it on visible elements + if(percs) { + var bb = getStrokedBBox(); + attrs.width = bb.width + bb.x; + attrs.height = bb.height + bb.y; + } + + // Just in case negative numbers are given or + // result from the percs calculation + if(attrs.width <= 0) attrs.width = 200; + if(attrs.height <= 0) attrs.height = 200; + + content.attr(attrs); + this.contentW = attrs['width']; + this.contentH = attrs['height']; + + $("#canvas_width").val(this.contentW) + $("#canvas_height").val(this.contentH) + var background = $("#canvas_background") + if (background.length) { + var opacity = background.attr("fill-opacity") + opacity = opacity ? parseInt(opacity)*100 : 100 + fill = this.getPaint(background.attr("fill"), opacity, "canvas") + methodDraw.paintBox.canvas.setPaint(fill) + } + else { + fill = this.getPaint("none", 100, "canvas") + methodDraw.paintBox.canvas.setPaint(fill) + } + + batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); + // update root to the correct size + var changes = content.attr(["width", "height"]); + batchCmd.addSubCommand(new ChangeElementCommand(svgroot, changes)); + + // reset zoom + current_zoom = 1; + + // reset transform lists + svgedit.transformlist.resetListMap(); + clearSelection(); + svgedit.path.clearData(); + svgroot.appendChild(selectorManager.selectorParentGroup); + + addCommandToHistory(batchCmd); + call("changed", [svgcontent]); + } catch(e) { + console.log(e); + return false; + } + + return true; +}; + + +this.getPaint = function(color, opac, type) { + // update the editor's fill paint + var opts = null; + if (color.indexOf("url(#") === 0) { + var refElem = svgCanvas.getRefElem(color); + if(refElem) { + refElem = refElem.cloneNode(true); + } else { + refElem = $("#" + type + "_color defs *")[0]; + } + + opts = { alpha: opac }; + opts[refElem.tagName] = refElem; + } + else if (color.indexOf("#") === 0) { + opts = { + alpha: opac, + solidColor: color.substr(1) + }; + } + else { + opts = { + alpha: opac, + solidColor: 'none' + }; + } + return new $.jGraduate.Paint(opts); +}; + +// Function: importSvgString +// This function imports the input SVG XML as a in the , then adds a +// to the current layer. +// +// Parameters: +// xmlString - The SVG as XML text. +// +// Returns: +// This function returns false if the import was unsuccessful, true otherwise. +// TODO: +// * properly handle if namespace is introduced by imported content (must add to svgcontent +// and update all prefixes in the imported node) +// * properly handle recalculating dimensions, recalculateDimensions() doesn't handle +// arbitrary transform lists, but makes some assumptions about how the transform list +// was obtained +// * import should happen in top-left of current zoomed viewport +this.importSvgString = function(xmlString) { + + try { + // Get unique ID + var uid = svgedit.utilities.encode64(xmlString.length + xmlString).substr(0,32); + + var useExisting = false; + + // Look for symbol and make sure symbol exists in image + if(import_ids[uid]) { + if( $(import_ids[uid].symbol).parents('#svgroot').length ) { + useExisting = true; + } + } + + var batchCmd = new BatchCommand("Import SVG"); + + if(useExisting) { + var symbol = import_ids[uid].symbol; + var ts = import_ids[uid].xform; + } else { + // convert string into XML document + var newDoc = svgedit.utilities.text2xml(xmlString); + + this.prepareSvg(newDoc); + + // import new svg document into our document + var svg; + // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() + if(svgdoc.adoptNode) { + svg = svgdoc.adoptNode(newDoc.documentElement); + } + else { + svg = svgdoc.importNode(newDoc.documentElement, true); + } + + uniquifyElems(svg); + + var innerw = convertToNum('width', svg.getAttribute("width")), + innerh = convertToNum('height', svg.getAttribute("height")), + innervb = svg.getAttribute("viewBox"), + // if no explicit viewbox, create one out of the width and height + vb = innervb ? innervb.split(" ") : [0,0,innerw,innerh]; + for (var j = 0; j < 4; ++j) + vb[j] = +(vb[j]); + + // TODO: properly handle preserveAspectRatio + var canvasw = +svgcontent.getAttribute("width"), + canvash = +svgcontent.getAttribute("height"); + // imported content should be 1/3 of the canvas on its largest dimension + + if (innerh > innerw) { + var ts = "scale(" + (canvash/3)/vb[3] + ")"; + } + else { + var ts = "scale(" + (canvash/3)/vb[2] + ")"; + } + + // Hack to make recalculateDimensions understand how to scale + ts = "translate(0) " + ts + " translate(0)"; + + var symbol = svgdoc.createElementNS(svgns, "symbol"); + var defs = findDefs(); + + if(svgedit.browser.isGecko()) { + // Move all gradients into root for Firefox, workaround for this bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 + // TODO: Make this properly undo-able. + $(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); + } + + while (svg.firstChild) { + var first = svg.firstChild; + symbol.appendChild(first); + } + var attrs = svg.attributes; + for(var i=0; i < attrs.length; i++) { + var attr = attrs[i]; + symbol.setAttribute(attr.nodeName, attr.nodeValue); + } + symbol.id = getNextId(); + + // Store data + import_ids[uid] = { + symbol: symbol, + xform: ts + } + + findDefs().appendChild(symbol); + batchCmd.addSubCommand(new InsertElementCommand(symbol)); + } + + + var use_el = svgdoc.createElementNS(svgns, "use"); + use_el.id = getNextId(); + setHref(use_el, "#" + symbol.id); + + (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(use_el); + batchCmd.addSubCommand(new InsertElementCommand(use_el)); + clearSelection(); + + use_el.setAttribute("transform", ts); + recalculateDimensions(use_el); + $(use_el).data('symbol', symbol).data('ref', symbol); + addToSelection([use_el]); + + // TODO: Find way to add this in a recalculateDimensions-parsable way +// if (vb[0] != 0 || vb[1] != 0) +// ts = "translate(" + (-vb[0]) + "," + (-vb[1]) + ") " + ts; + addCommandToHistory(batchCmd); + call("changed", [svgcontent]); + + } catch(e) { + console.log(e); + return false; + } + + return true; +}; + +// TODO(codedread): Move all layer/context functions in draw.js +// Layer API Functions + +// Group: Layers + +// Function: identifyLayers +// Updates layer system +var identifyLayers = canvas.identifyLayers = function() { + leaveContext(); + getCurrentDrawing().identifyLayers(); +}; + +// Function: createLayer +// Creates a new top-level layer in the drawing with the given name, sets the current layer +// to it, and then clears the selection This function then calls the 'changed' handler. +// This is an undoable action. +// +// Parameters: +// name - The given name +this.createLayer = function(name) { + var batchCmd = new BatchCommand("Create Layer"); + var new_layer = getCurrentDrawing().createLayer(name); + batchCmd.addSubCommand(new InsertElementCommand(new_layer)); + addCommandToHistory(batchCmd); + clearSelection(); + call("changed", [new_layer]); +}; + +// Function: cloneLayer +// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents +// to it, and then clears the selection This function then calls the 'changed' handler. +// This is an undoable action. +// +// Parameters: +// name - The given name +this.cloneLayer = function(name) { + var batchCmd = new BatchCommand("Duplicate Layer"); + var new_layer = svgdoc.createElementNS(svgns, "g"); + var layer_title = svgdoc.createElementNS(svgns, "title"); + layer_title.textContent = name; + new_layer.appendChild(layer_title); + var current_layer = getCurrentDrawing().getCurrentLayer(); + $(current_layer).after(new_layer); + var childs = current_layer.childNodes; + for(var i = 0; i < childs.length; i++) { + var ch = childs[i]; + if(ch.localName == 'title') continue; + new_layer.appendChild(copyElem(ch)); + } + + clearSelection(); + identifyLayers(); + + batchCmd.addSubCommand(new InsertElementCommand(new_layer)); + addCommandToHistory(batchCmd); + canvas.setCurrentLayer(name); + call("changed", [new_layer]); +}; + +// Function: deleteCurrentLayer +// Deletes the current layer from the drawing and then clears the selection. This function +// then calls the 'changed' handler. This is an undoable action. +this.deleteCurrentLayer = function() { + var current_layer = getCurrentDrawing().getCurrentLayer(); + var nextSibling = current_layer.nextSibling; + var parent = current_layer.parentNode; + current_layer = getCurrentDrawing().deleteCurrentLayer(); + if (current_layer) { + var batchCmd = new BatchCommand("Delete Layer"); + // store in our Undo History + batchCmd.addSubCommand(new RemoveElementCommand(current_layer, nextSibling, parent)); + addCommandToHistory(batchCmd); + clearSelection(); + call("changed", [parent]); + return true; + } + return false; +}; + +// Function: setCurrentLayer +// Sets the current layer. If the name is not a valid layer name, then this function returns +// false. Otherwise it returns true. This is not an undo-able action. +// +// Parameters: +// name - the name of the layer you want to switch to. +// +// Returns: +// true if the current layer was switched, otherwise false +this.setCurrentLayer = function(name) { + var result = getCurrentDrawing().setCurrentLayer(svgedit.utilities.toXml(name)); + if (result) { + clearSelection(); + } + return result; +}; + +// Function: renameCurrentLayer +// Renames the current layer. If the layer name is not valid (i.e. unique), then this function +// does nothing and returns false, otherwise it returns true. This is an undo-able action. +// +// Parameters: +// newname - the new name you want to give the current layer. This name must be unique +// among all layer names. +// +// Returns: +// true if the rename succeeded, false otherwise. +this.renameCurrentLayer = function(newname) { + var drawing = getCurrentDrawing(); + if (drawing.current_layer) { + var oldLayer = drawing.current_layer; + // setCurrentLayer will return false if the name doesn't already exist + // this means we are free to rename our oldLayer + if (!canvas.setCurrentLayer(newname)) { + var batchCmd = new BatchCommand("Rename Layer"); + // find the index of the layer + for (var i = 0; i < drawing.getNumLayers(); ++i) { + if (drawing.all_layers[i][1] == oldLayer) break; + } + var oldname = drawing.getLayerName(i); + drawing.all_layers[i][0] = svgedit.utilities.toXml(newname); + + // now change the underlying title element contents + var len = oldLayer.childNodes.length; + for (var i = 0; i < len; ++i) { + var child = oldLayer.childNodes.item(i); + // found the element, now append all the + if (child && child.tagName == "title") { + // wipe out old name + while (child.firstChild) { child.removeChild(child.firstChild); } + child.textContent = newname; + + batchCmd.addSubCommand(new ChangeElementCommand(child, {"#text":oldname})); + addCommandToHistory(batchCmd); + call("changed", [oldLayer]); + return true; + } + } + } + drawing.current_layer = oldLayer; + } + return false; +}; + +// Function: setCurrentLayerPosition +// Changes the position of the current layer to the new value. If the new index is not valid, +// this function does nothing and returns false, otherwise it returns true. This is an +// undo-able action. +// +// Parameters: +// newpos - The zero-based index of the new position of the layer. This should be between +// 0 and (number of layers - 1) +// +// Returns: +// true if the current layer position was changed, false otherwise. +this.setCurrentLayerPosition = function(newpos) { + var drawing = getCurrentDrawing(); + if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) { + for (var oldpos = 0; oldpos < drawing.getNumLayers(); ++oldpos) { + if (drawing.all_layers[oldpos][1] == drawing.current_layer) break; + } + // some unknown error condition (current_layer not in all_layers) + if (oldpos == drawing.getNumLayers()) { return false; } + + if (oldpos != newpos) { + // if our new position is below us, we need to insert before the node after newpos + var refLayer = null; + var oldNextSibling = drawing.current_layer.nextSibling; + if (newpos > oldpos ) { + if (newpos < drawing.getNumLayers()-1) { + refLayer = drawing.all_layers[newpos+1][1]; + } + } + // if our new position is above us, we need to insert before the node at newpos + else { + refLayer = drawing.all_layers[newpos][1]; + } + svgcontent.insertBefore(drawing.current_layer, refLayer); + addCommandToHistory(new MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent)); + + identifyLayers(); + canvas.setCurrentLayer(drawing.getLayerName(newpos)); + + return true; + } + } + + return false; +}; + +// Function: setLayerVisibility +// Sets the visibility of the layer. If the layer name is not valid, this function return +// false, otherwise it returns true. This is an undo-able action. +// +// Parameters: +// layername - the name of the layer to change the visibility +// bVisible - true/false, whether the layer should be visible +// +// Returns: +// true if the layer's visibility was set, false otherwise +this.setLayerVisibility = function(layername, bVisible) { + var drawing = getCurrentDrawing(); + var prevVisibility = drawing.getLayerVisibility(layername); + var layer = drawing.setLayerVisibility(layername, bVisible); + if (layer) { + var oldDisplay = prevVisibility ? 'inline' : 'none'; + addCommandToHistory(new ChangeElementCommand(layer, {'display':oldDisplay}, 'Layer Visibility')); + } else { + return false; + } + + if (layer == drawing.getCurrentLayer()) { + clearSelection(); + pathActions.clear(); + } +// call("changed", [selected]); + return true; +}; + +// Function: moveSelectedToLayer +// Moves the selected elements to layername. If the name is not a valid layer name, then false +// is returned. Otherwise it returns true. This is an undo-able action. +// +// Parameters: +// layername - the name of the layer you want to which you want to move the selected elements +// +// Returns: +// true if the selected elements were moved to the layer, false otherwise. +this.moveSelectedToLayer = function(layername) { + // find the layer + var layer = null; + var drawing = getCurrentDrawing(); + for (var i = 0; i < drawing.getNumLayers(); ++i) { + if (drawing.getLayerName(i) == layername) { + layer = drawing.all_layers[i][1]; + break; + } + } + if (!layer) return false; + + var batchCmd = new BatchCommand("Move Elements to Layer"); + + // loop for each selected element and move it + var selElems = selectedElements; + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (!elem) continue; + var oldNextSibling = elem.nextSibling; + // TODO: this is pretty brittle! + var oldLayer = elem.parentNode; + layer.appendChild(elem); + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); + } + + addCommandToHistory(batchCmd); + + return true; +}; + +this.mergeLayer = function(skipHistory) { + var batchCmd = new BatchCommand("Merge Layer"); + var drawing = getCurrentDrawing(); + var prev = $(drawing.current_layer).prev()[0]; + if(!prev) return; + var childs = drawing.current_layer.childNodes; + var len = childs.length; + var layerNextSibling = drawing.current_layer.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand(drawing.current_layer, layerNextSibling, svgcontent)); + + while(drawing.current_layer.firstChild) { + var ch = drawing.current_layer.firstChild; + if(ch.localName == 'title') { + var chNextSibling = ch.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand(ch, chNextSibling, drawing.current_layer)); + drawing.current_layer.removeChild(ch); + continue; + } + var oldNextSibling = ch.nextSibling; + prev.appendChild(ch); + batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer)); + } + + // Remove current layer + svgcontent.removeChild(drawing.current_layer); + + if(!skipHistory) { + clearSelection(); + identifyLayers(); + + call("changed", [svgcontent]); + + addCommandToHistory(batchCmd); + } + + drawing.current_layer = prev; + return batchCmd; +} + +this.mergeAllLayers = function() { + var batchCmd = new BatchCommand("Merge all Layers"); + var drawing = getCurrentDrawing(); + drawing.current_layer = drawing.all_layers[drawing.getNumLayers()-1][1]; + while($(svgcontent).children('g').length > 1) { + batchCmd.addSubCommand(canvas.mergeLayer(true)); + } + + clearSelection(); + identifyLayers(); + call("changed", [svgcontent]); + addCommandToHistory(batchCmd); +} + +// Function: leaveContext +// Return from a group context to the regular kind, make any previously +// disabled elements enabled again +var leaveContext = this.leaveContext = function() { + var len = disabled_elems.length; + if(len) { + for(var i = 0; i < len; i++) { + var elem = disabled_elems[i]; + + var orig = elData(elem, 'orig_opac'); + if(orig !== 1) { + elem.setAttribute('opacity', orig); + } else { + elem.removeAttribute('opacity'); + } + elem.setAttribute('style', 'pointer-events: inherit'); + } + disabled_elems = []; + clearSelection(true); + call("contextset", null); + } + current_group = null; +} + +// Function: setContext +// Set the current context (for in-group editing) +var setContext = this.setContext = function(elem) { + leaveContext(); + if(typeof elem === 'string') { + elem = getElem(elem); + } + + // Edit inside this group + current_group = elem; + + // Disable other elements + $(elem).parentsUntil('#svgcontent').addBack().siblings().each(function() { + var opac = this.getAttribute('opacity') || 1; + // Store the original's opacity + elData(this, 'orig_opac', opac); + this.setAttribute('opacity', opac * .33); + this.setAttribute('style', 'pointer-events: none'); + disabled_elems.push(this); + }); + + clearSelection(); + call("contextset", current_group); +} + +// Group: Document functions + +// Function: clear +// Clears the current document. This is not an undoable action. +this.clear = function() { + pathActions.clear(); + + clearSelection(); + + // clear the svgcontent node + canvas.clearSvgContentElement(); + + // create new document + canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent); + + // create empty first layer + canvas.createLayer("Layer 1"); + + // clear the undo stack + canvas.undoMgr.resetUndoStack(); + + // reset the selector manager + selectorManager.initGroup(); + + // reset the rubber band box + rubberBox = selectorManager.getRubberBandBox(); + + call("cleared"); +}; + +// Function: linkControlPoints +// Alias function +this.linkControlPoints = pathActions.linkControlPoints; + +// Function: getContentElem +// Returns the content DOM element +this.getContentElem = function() { return svgcontent; }; + +// Function: getRootElem +// Returns the root DOM element +this.getRootElem = function() { return svgroot; }; + +// Function: getSelectedElems +// Returns the array with selected DOM elements +this.getSelectedElems = function() { return selectedElements; }; + +// Function: getResolution +// Returns the current dimensions and zoom level in an object +var getResolution = this.getResolution = function() { +// var vb = svgcontent.getAttribute("viewBox").split(' '); +// return {'w':vb[2], 'h':vb[3], 'zoom': current_zoom}; + + var width = svgcontent.getAttribute("width")/current_zoom; + var height = svgcontent.getAttribute("height")/current_zoom; + + return { + 'w': width, + 'h': height, + 'zoom': current_zoom + }; +}; + +// Function: getZoom +// Returns the current zoom level +this.getZoom = function(){return current_zoom;}; + +// Function: getVersion +// Returns a string which describes the revision number of SvgCanvas. +this.getVersion = function() { + return "svgcanvas.js ($Rev: 2082 $)"; +}; + +// Function: setConfig +// Update configuration options with given values +// +// Parameters: +// opts - Object with options (see curConfig for examples) +this.setConfig = function(opts) { + $.extend(curConfig, opts); +} + +// Function: getTitle +// Returns the current group/SVG's title contents +this.getTitle = function(elem) { + elem = elem || selectedElements[0]; + if(!elem) return; + elem = $(elem).data('gsvg') || $(elem).data('symbol') || elem; + var childs = elem.childNodes; + for (var i=0; i<childs.length; i++) { + if(childs[i].nodeName == 'title') { + return childs[i].textContent; + } + } + return ''; +} + +// Function: setGroupTitle +// Sets the group/SVG's title content +// TODO: Combine this with setDocumentTitle +this.setGroupTitle = function(val) { + var elem = selectedElements[0]; + elem = $(elem).data('gsvg') || elem; + + var ts = $(elem).children('title'); + + var batchCmd = new BatchCommand("Set Label"); + + if(!val.length) { + // Remove title element + var tsNextSibling = ts.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); + ts.remove(); + } else if(ts.length) { + // Change title contents + var title = ts[0]; + batchCmd.addSubCommand(new ChangeElementCommand(title, {'#text': title.textContent})); + title.textContent = val; + } else { + // Add title element + title = svgdoc.createElementNS(svgns, "title"); + title.textContent = val; + $(elem).prepend(title); + batchCmd.addSubCommand(new InsertElementCommand(title)); + } + + addCommandToHistory(batchCmd); +} + +// Function: getDocumentTitle +// Returns the current document title or an empty string if not found +this.getDocumentTitle = function() { + return canvas.getTitle(svgcontent); +} + +// Function: setDocumentTitle +// Adds/updates a title element for the document with the given name. +// This is an undoable action +// +// Parameters: +// newtitle - String with the new title +this.setDocumentTitle = function(newtitle) { + var childs = svgcontent.childNodes, doc_title = false, old_title = ''; + + var batchCmd = new BatchCommand("Change Image Title"); + + for (var i=0; i<childs.length; i++) { + if(childs[i].nodeName == 'title') { + doc_title = childs[i]; + old_title = doc_title.textContent; + break; + } + } + if(!doc_title) { + doc_title = svgdoc.createElementNS(svgns, "title"); + svgcontent.insertBefore(doc_title, svgcontent.firstChild); + } + + if(newtitle.length) { + doc_title.textContent = newtitle; + } else { + // No title given, so element is not necessary + doc_title.parentNode.removeChild(doc_title); + } + batchCmd.addSubCommand(new ChangeElementCommand(doc_title, {'#text': old_title})); + addCommandToHistory(batchCmd); +} + +// Function: getEditorNS +// Returns the editor's namespace URL, optionally adds it to root element +// +// Parameters: +// add - Boolean to indicate whether or not to add the namespace value +this.getEditorNS = function(add) { + if(add) { + svgcontent.setAttribute('xmlns:se', se_ns); + } + return se_ns; +} + +// Function: setResolution +// Changes the document's dimensions to the given size +// +// Parameters: +// x - Number with the width of the new dimensions in user units. +// Can also be the string "fit" to indicate "fit to content" +// y - Number with the height of the new dimensions in user units. +// +// Returns: +// Boolean to indicate if resolution change was succesful. +// It will fail on "fit to content" option with no content to fit to. +this.setResolution = function(x, y) { + var res = getResolution(); + var w = res.w, h = res.h; + var batchCmd; + + if(x == 'fit') { + // Get bounding box + var bbox = getStrokedBBox(); + + if(bbox) { + batchCmd = new BatchCommand("Fit Canvas to Content"); + var visEls = getVisibleElements(); + addToSelection(visEls); + var dx = [], dy = []; + $.each(visEls, function(i, item) { + dx.push(bbox.x*-1); + dy.push(bbox.y*-1); + }); + + var cmd = canvas.moveSelectedElements(dx, dy, true); + batchCmd.addSubCommand(cmd); + clearSelection(); + + x = Math.round(bbox.width); + y = Math.round(bbox.height); + } else { + return false; + } + } + if (x != w || y != h) { + if(!batchCmd) { + batchCmd = new BatchCommand("Change Image Dimensions"); + } + + x = convertToNum('width', x); + y = convertToNum('height', y); + + svgcontent.setAttribute('width', x); + svgcontent.setAttribute('height', y); + + this.contentW = x; + this.contentH = y; + batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"width":w, "height":h})); + + svgcontent.setAttribute("viewBox", [0, 0, x/current_zoom, y/current_zoom].join(' ')); + batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"viewBox": ["0 0", w, h].join(' ')})); + + addCommandToHistory(batchCmd); + background = document.getElementById("canvas_background"); + if (background) { + background.setAttribute("x", -1) + background.setAttribute("y", -1) + background.setAttribute("width", x+2) + background.setAttribute("height", y+2) + } + call("changed", [svgcontent]); + } + return [x,y]; +}; + +// Function: getOffset +// Returns an object with x, y values indicating the svgcontent element's +// position in the editor's canvas. +this.getOffset = function() { + return $(svgcontent).attr(['x', 'y']); +} + +// Function: setBBoxZoom +// Sets the zoom level on the canvas-side based on the given value +// +// Parameters: +// val - Bounding box object to zoom to or string indicating zoom option +// editor_w - Integer with the editor's workarea box's width +// editor_h - Integer with the editor's workarea box's height +this.setBBoxZoom = function(val, editor_w, editor_h) { + var spacer = .85; + var bb; + var calcZoom = function(bb) { + if(!bb) return false; + var w_zoom = Math.round((editor_w / bb.width)*100 * spacer)/100; + var h_zoom = Math.round((editor_h / bb.height)*100 * spacer)/100; + var zoomlevel = Math.min(w_zoom,h_zoom); + canvas.setZoom(zoomlevel); + return {'zoom': zoomlevel, 'bbox': bb}; + } + + if(typeof val == 'object') { + bb = val; + if(bb.width == 0 || bb.height == 0) { + var newzoom = bb.zoom?bb.zoom:current_zoom * bb.factor; + canvas.setZoom(newzoom); + return {'zoom': current_zoom, 'bbox': bb}; + } + return calcZoom(bb); + } + + switch (val) { + case 'selection': + if(!selectedElements[0]) return; + var sel_elems = $.map(selectedElements, function(n){ if(n) return n; }); + bb = getStrokedBBox(sel_elems); + break; + case 'canvas': + var res = getResolution(); + spacer = .95; + bb = {width:res.w, height:res.h ,x:0, y:0}; + break; + case 'content': + bb = getStrokedBBox(); + break; + case 'layer': + bb = getStrokedBBox(getVisibleElements(getCurrentDrawing().getCurrentLayer())); + break; + default: + return; + } + return calcZoom(bb); +} + +// Function: setZoom +// Sets the zoom to the given level +// +// Parameters: +// zoomlevel - Float indicating the zoom level to change to +this.setZoom = function(zoomlevel) { + var res = getResolution(); + svgcontent.setAttribute("viewBox", "0 0 " + res.w/zoomlevel + " " + res.h/zoomlevel); + current_zoom = zoomlevel; + $.each(selectedElements, function(i, elem) { + if(!elem) return; + selectorManager.requestSelector(elem).resize(); + }); + pathActions.zoomChange(); + runExtensions("zoomChanged", zoomlevel); +} + +// Function: getMode +// Returns the current editor mode string +this.getMode = function() { + return current_mode; +}; + +// Function: setMode +// Sets the editor's mode to the given string +// +// Parameters: +// name - String with the new mode to change to +this.setMode = function(name) { + + pathActions.clear(); + textActions.clear(); + $("#workarea").attr("class", name); + cur_properties = (selectedElements[0] && selectedElements[0].nodeName == 'text') ? cur_text : cur_shape; + current_mode = name; +}; + +// Group: Element Styling + +// Function: getColor +// Returns the current fill/stroke option +this.getColor = function(type) { + return cur_properties[type]; +}; + +// Function: setColor +// Change the current stroke/fill color/gradient value +// +// Parameters: +// type - String indicating fill or stroke +// val - The value to set the stroke attribute to +// preventUndo - Boolean indicating whether or not this should be and undoable option +this.setColor = function(type, val, preventUndo) { + cur_shape[type] = val; + cur_properties[type + '_paint'] = {type:"solidColor"}; + var elems = []; + var i = selectedElements.length; + while (i--) { + var elem = selectedElements[i]; + if (elem) { + if (elem.tagName == "g") + svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); + else { + if(type == 'fill') { + if(elem.tagName != "polyline" && elem.tagName != "line") { + elems.push(elem); + } + } else { + elems.push(elem); + } + } + } + } + if (elems.length > 0) { + if (!preventUndo) { + changeSelectedAttribute(type, val, elems); + call("changed", elems); + } else + changeSelectedAttributeNoUndo(type, val, elems); + } +} + + +// Function: findDefs +// Return the document's <defs> element, create it first if necessary +var findDefs = function() { + var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); + if (defs.length > 0) { + defs = defs[0]; + } + else { + defs = svgdoc.createElementNS(svgns, "defs" ); + if(svgcontent.firstChild) { + // first child is a comment, so call nextSibling + svgcontent.insertBefore( defs, svgcontent.firstChild.nextSibling); + } else { + svgcontent.appendChild(defs); + } + } + return defs; +}; + +// Function: setGradient +// Apply the current gradient to selected element's fill or stroke +// +// Parameters +// type - String indicating "fill" or "stroke" to apply to an element +var setGradient = this.setGradient = function(type) { + if(!cur_properties[type + '_paint'] || cur_properties[type + '_paint'].type == "solidColor") return; + var grad = canvas[type + 'Grad']; + // find out if there is a duplicate gradient already in the defs + var duplicate_grad = findDuplicateGradient(grad); + var defs = findDefs(); + // no duplicate found, so import gradient into defs + if (!duplicate_grad) { + var orig_grad = grad; + grad = defs.appendChild( svgdoc.importNode(grad, true) ); + // get next id and set it on the grad + grad.id = getNextId(); + } + else { // use existing gradient + grad = duplicate_grad; + } + canvas.setColor(type, "url(#" + grad.id + ")"); + if (type == "canvas") { + var background = document.getElementById("canvas_background"); + if (background) { + background.setAttribute('fill', "url(#" + grad.id + ")") + } + } +} + +// Function: findDuplicateGradient +// Check if exact gradient already exists +// +// Parameters: +// grad - The gradient DOM element to compare to others +// +// Returns: +// The existing gradient if found, null if not +var findDuplicateGradient = function(grad) { + var defs = findDefs(); + var existing_grads = $(defs).find("linearGradient, radialGradient"); + var i = existing_grads.length; + var rad_attrs = ['r','cx','cy','fx','fy']; + while (i--) { + var og = existing_grads[i]; + if(grad.tagName == "linearGradient") { + if (grad.getAttribute('x1') != og.getAttribute('x1') || + grad.getAttribute('y1') != og.getAttribute('y1') || + grad.getAttribute('x2') != og.getAttribute('x2') || + grad.getAttribute('y2') != og.getAttribute('y2')) + { + continue; + } + } else { + var grad_attrs = $(grad).attr(rad_attrs); + var og_attrs = $(og).attr(rad_attrs); + + var diff = false; + $.each(rad_attrs, function(i, attr) { + if(grad_attrs[attr] != og_attrs[attr]) diff = true; + }); + + if(diff) continue; + } + + // else could be a duplicate, iterate through stops + var stops = grad.getElementsByTagNameNS(svgns, "stop"); + var ostops = og.getElementsByTagNameNS(svgns, "stop"); + + if (stops.length != ostops.length) { + continue; + } + + var j = stops.length; + while(j--) { + var stop = stops[j]; + var ostop = ostops[j]; + + if (stop.getAttribute('offset') != ostop.getAttribute('offset') || + stop.getAttribute('stop-opacity') != ostop.getAttribute('stop-opacity') || + stop.getAttribute('stop-color') != ostop.getAttribute('stop-color')) + { + break; + } + } + + if (j == -1) { + return og; + } + } // for each gradient in defs + + return null; +}; + +function reorientGrads(elem, m) { + var bb = svgedit.utilities.getBBox(elem); + for(var i = 0; i < 2; i++) { + var type = i === 0 ? 'fill' : 'stroke'; + var attrVal = elem.getAttribute(type); + if(attrVal && attrVal.indexOf('url(') === 0) { + var grad = getRefElem(attrVal); + if(grad.tagName === 'linearGradient') { + var x1 = grad.getAttribute('x1') || 0; + var y1 = grad.getAttribute('y1') || 0; + var x2 = grad.getAttribute('x2') || 1; + var y2 = grad.getAttribute('y2') || 0; + + // Convert to USOU points + x1 = (bb.width * x1) + bb.x; + y1 = (bb.height * y1) + bb.y; + x2 = (bb.width * x2) + bb.x; + y2 = (bb.height * y2) + bb.y; + + // Transform those points + var pt1 = transformPoint(x1, y1, m); + var pt2 = transformPoint(x2, y2, m); + + // Convert back to BB points + var g_coords = {}; + + g_coords.x1 = (pt1.x - bb.x) / bb.width; + g_coords.y1 = (pt1.y - bb.y) / bb.height; + g_coords.x2 = (pt2.x - bb.x) / bb.width; + g_coords.y2 = (pt2.y - bb.y) / bb.height; + + var newgrad = grad.cloneNode(true); + $(newgrad).attr(g_coords); + + newgrad.id = getNextId(); + findDefs().appendChild(newgrad); + elem.setAttribute(type, 'url(#' + newgrad.id + ')'); + } + } + } +} + +// Function: setPaint +// Set a color/gradient to a fill/stroke +// +// Parameters: +// type - String with "fill" or "stroke" +// paint - The jGraduate paint object to apply +this.setPaint = function(type, paint) { + // make a copy + var p = new $.jGraduate.Paint(paint); + this.setPaintOpacity(type, p.alpha/100, true); + // now set the current paint object + cur_properties[type + '_paint'] = p; + switch ( p.type ) { + case "solidColor": + + if (p.solidColor != "none" && p.solidColor != "#none") { + this.setColor(type, "#"+p.solidColor) + } + else { + this.setColor(type, "none"); + var selector = (type == "fill") ? "#fill_color rect" : "#stroke_color rect" + document.querySelector(selector).setAttribute('fill', 'none'); + } + break; + case "linearGradient": + case "radialGradient": + canvas[type + 'Grad'] = p[p.type]; + setGradient(type); + break; + default: +// console.log("none!"); + } +}; + + +// this.setStrokePaint = function(p) { +// // make a copy +// var p = new $.jGraduate.Paint(p); +// this.setStrokeOpacity(p.alpha/100); +// +// // now set the current paint object +// cur_properties.stroke_paint = p; +// switch ( p.type ) { +// case "solidColor": +// this.setColor('stroke', p.solidColor != "none" ? "#"+p.solidColor : "none");; +// break; +// case "linearGradient" +// case "radialGradient" +// canvas.strokeGrad = p[p.type]; +// setGradient(type); +// default: +// // console.log("none!"); +// } +// }; +// +// this.setFillPaint = function(p, addGrad) { +// // make a copy +// var p = new $.jGraduate.Paint(p); +// this.setFillOpacity(p.alpha/100, true); +// +// // now set the current paint object +// cur_properties.fill_paint = p; +// if (p.type == "solidColor") { +// this.setColor('fill', p.solidColor != "none" ? "#"+p.solidColor : "none"); +// } +// else if(p.type == "linearGradient") { +// canvas.fillGrad = p.linearGradient; +// if(addGrad) setGradient(); +// } +// else if(p.type == "radialGradient") { +// canvas.fillGrad = p.radialGradient; +// if(addGrad) setGradient(); +// } +// else { +// // console.log("none!"); +// } +// }; + +// Function: getStrokeWidth +// Returns the current stroke-width value +this.getStrokeWidth = function() { + return cur_properties.stroke_width; +}; + +// Function: setStrokeWidth +// Sets the stroke width for the current selected elements +// When attempting to set a line's width to 0, this changes it to 1 instead +// +// Parameters: +// val - A Float indicating the new stroke width value +this.setStrokeWidth = function(val) { + if(val == 0 && ['line', 'path'].indexOf(current_mode) >= 0) { + canvas.setStrokeWidth(1); + return; + } + cur_properties.stroke_width = val; + + var elems = []; + var i = selectedElements.length; + while (i--) { + var elem = selectedElements[i]; + if (elem) { + if (elem.tagName == "g") + svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); + else + elems.push(elem); + } + } + if (elems.length > 0) { + changeSelectedAttribute("stroke-width", val, elems); + call("changed", selectedElements); + } +}; + +// Function: setStrokeAttr +// Set the given stroke-related attribute the given value for selected elements +// +// Parameters: +// attr - String with the attribute name +// val - String or number with the attribute value +this.setStrokeAttr = function(attr, val) { + cur_shape[attr.replace('-','_')] = val; + var elems = []; + var i = selectedElements.length; + while (i--) { + var elem = selectedElements[i]; + if (elem) { + if (elem.tagName == "g") + svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); + else + elems.push(elem); + } + } + if (elems.length > 0) { + changeSelectedAttribute(attr, val, elems); + call("changed", selectedElements); + } +}; + +// Function: getStyle +// Returns current style options +this.getStyle = function() { + return cur_shape; +} + +// Function: getOpacity +// Returns the current opacity +this.getOpacity = function() { + return cur_shape.opacity; +}; + +// Function: setOpacity +// Sets the given opacity to the current selected elements +this.setOpacity = function(val) { + cur_shape.opacity = val; + changeSelectedAttribute("opacity", val); +}; + +// Function: getOpacity +// Returns the current fill opacity +this.getFillOpacity = function() { + return cur_shape.fill_opacity; +}; + +// Function: getStrokeOpacity +// Returns the current stroke opacity +this.getStrokeOpacity = function() { + return cur_shape.stroke_opacity; +}; + +// Function: setPaintOpacity +// Sets the current fill/stroke opacity +// +// Parameters: +// type - String with "fill" or "stroke" +// val - Float with the new opacity value +// preventUndo - Boolean indicating whether or not this should be an undoable action +this.setPaintOpacity = function(type, val, preventUndo) { + cur_shape[type + '_opacity'] = val; + if (!preventUndo) + changeSelectedAttribute(type + "-opacity", val); + else + changeSelectedAttributeNoUndo(type + "-opacity", val); +}; + +// Function: getBlur +// Gets the stdDeviation blur value of the given element +// +// Parameters: +// elem - The element to check the blur value for +this.getBlur = function(elem) { + var val = 0; +// var elem = selectedElements[0]; + + if(elem) { + var filter_url = elem.getAttribute('filter'); + if(filter_url) { + var blur = getElem(elem.id + '_blur'); + if(blur) { + val = blur.firstChild.getAttribute('stdDeviation'); + } + } + } + return val; +}; + +(function() { + var cur_command = null; + var filter = null; + var filterHidden = false; + + // Function: setBlurNoUndo + // Sets the stdDeviation blur value on the selected element without being undoable + // + // Parameters: + // val - The new stdDeviation value + canvas.setBlurNoUndo = function(val) { + if(!filter) { + canvas.setBlur(val); + return; + } + if(val === 0) { + // Don't change the StdDev, as that will hide the element. + // Instead, just remove the value for "filter" + changeSelectedAttributeNoUndo("filter", ""); + filterHidden = true; + } else { + var elem = selectedElements[0]; + if(filterHidden) { + changeSelectedAttributeNoUndo("filter", 'url(#' + elem.id + '_blur)'); + } + if(svgedit.browser.isWebkit()) { + elem.removeAttribute('filter'); + elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); + } + changeSelectedAttributeNoUndo("stdDeviation", val, [filter.firstChild]); + canvas.setBlurOffsets(filter, val); + } + } + + function finishChange() { + var bCmd = canvas.undoMgr.finishUndoableChange(); + cur_command.addSubCommand(bCmd); + addCommandToHistory(cur_command); + cur_command = null; + filter = null; + } + + // Function: setBlurOffsets + // Sets the x, y, with, height values of the filter element in order to + // make the blur not be clipped. Removes them if not neeeded + // + // Parameters: + // filter - The filter DOM element to update + // stdDev - The standard deviation value on which to base the offset size + canvas.setBlurOffsets = function(filter, stdDev) { + if(stdDev > 3) { + // TODO: Create algorithm here where size is based on expected blur + assignAttributes(filter, { + x: '-50%', + y: '-50%', + width: '200%', + height: '200%' + }, 100); + } else { + // Removing these attributes hides text in Chrome (see Issue 579) + if(!svgedit.browser.isWebkit()) { + filter.removeAttribute('x'); + filter.removeAttribute('y'); + filter.removeAttribute('width'); + filter.removeAttribute('height'); + } + } + } + + // Function: setBlur + // Adds/updates the blur filter to the selected element + // + // Parameters: + // val - Float with the new stdDeviation blur value + // complete - Boolean indicating whether or not the action should be completed (to add to the undo manager) + canvas.setBlur = function(val, complete) { + if(cur_command) { + finishChange(); + return; + } + + // Looks for associated blur, creates one if not found + var elem = selectedElements[0]; + var elem_id = elem.id; + filter = getElem(elem_id + '_blur'); + + val -= 0; + + var batchCmd = new BatchCommand(); + + // Blur found! + if(filter) { + if(val === 0) { + filter = null; + } + } else { + // Not found, so create + var newblur = addSvgElementFromJson({ "element": "feGaussianBlur", + "attr": { + "in": 'SourceGraphic', + "stdDeviation": val + } + }); + + filter = addSvgElementFromJson({ "element": "filter", + "attr": { + "id": elem_id + '_blur' + } + }); + + filter.appendChild(newblur); + findDefs().appendChild(filter); + + batchCmd.addSubCommand(new InsertElementCommand(filter)); + } + + var changes = {filter: elem.getAttribute('filter')}; + + if(val === 0) { + elem.removeAttribute("filter"); + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); + return; + } else { + changeSelectedAttribute("filter", 'url(#' + elem_id + '_blur)'); + + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); + + canvas.setBlurOffsets(filter, val); + } + + cur_command = batchCmd; + canvas.undoMgr.beginUndoableChange("stdDeviation", [filter?filter.firstChild:null]); + if(complete) { + canvas.setBlurNoUndo(val); + finishChange(); + } + }; +}()); + +// Function: getBold +// Check whether selected element is bold or not +// +// Returns: +// Boolean indicating whether or not element is bold +this.getBold = function() { + var selectedElems = selectedElements.filter(Boolean) + var isBold = true + selectedElems.forEach(function(el){ + if (el.getAttribute("font-weight") != "bold") isBold = false; + }); + return isBold; +}; + +// Function: setBold +// Make the selected element bold or normal +// +// Parameters: +// b - Boolean indicating bold (true) or normal (false) +this.setBold = function(b) { + var selectedElems = selectedElements.filter(Boolean) + selectedElems.forEach(function(selected){ + if (selected != null && selected.tagName == "text") changeSelectedAttribute("font-weight", b ? "bold" : "normal"); + }); + if (!selectedElems[0].textContent) textActions.setCursor(); +}; + +// Function: getItalic +// Check whether selected element is italic or not +// +// Returns: +// Boolean indicating whether or not element is italic +this.getItalic = function() { + var selectedElems = selectedElements.filter(Boolean) + var isItalic = true + selectedElems.forEach(function(el){ + if (el.getAttribute("font-style") != "italic") isItalic = false; + }); + return isItalic; +}; + +// Function: setItalic +// Make the selected element italic or normal +// +// Parameters: +// b - Boolean indicating italic (true) or normal (false) +this.setItalic = function(i) { + var selectedElems = selectedElements.filter(Boolean) + selectedElems.forEach(function(selected){ + if (selected != null && selected.tagName == "text") changeSelectedAttribute("font-style", i ? "italic" : "normal"); + }); + if (!selectedElems[0].textContent) textActions.setCursor(); +}; + +// Function: getFontFamily +// Returns the current font family +this.getFontFamily = function() { + return cur_text.font_family; +}; + +// Function: setFontFamily +// Set the new font family +// +// Parameters: +// val - String with the new font family +this.setFontFamily = function(val) { + cur_text.font_family = val; + changeSelectedAttribute("font-family", val); + if(selectedElements[0] && !selectedElements[0].textContent) { + textActions.setCursor(); + } +}; + + +// Function: setFontColor +// Set the new font color +// +// Parameters: +// val - String with the new font color +this.setFontColor = function(val) { + cur_text.fill = val; + changeSelectedAttribute("fill", val); +}; + +// Function: getFontColor +// Returns the current font color +this.getFontSize = function() { + return cur_text.fill; +}; + +// Function: getFontSize +// Returns the current font size +this.getFontSize = function() { + return cur_text.font_size; +}; + +// Function: setFontSize +// Applies the given font size to the selected element +// +// Parameters: +// val - Float with the new font size +this.setFontSize = function(val) { + cur_text.font_size = val; + changeSelectedAttribute("font-size", val); + if(!selectedElements[0].textContent) { + textActions.setCursor(); + } +}; + +// Function: getText +// Returns the current text (textContent) of the selected element +this.getText = function() { + var selected = selectedElements[0]; + if (selected == null) { return ""; } + return selected.textContent; +}; + +// Function: setTextContent +// Updates the text element with the given string +// +// Parameters: +// val - String with the new text +this.setTextContent = function(val) { + changeSelectedAttribute("#text", val); + textActions.init(val); + textActions.setCursor(); +}; + +// Function: setImageURL +// Sets the new image URL for the selected image element. Updates its size if +// a new URL is given +// +// Parameters: +// val - String with the image URL/path +this.setImageURL = function(val) { + var elem = selectedElements[0]; + if(!elem) return; + + var attrs = $(elem).attr(['width', 'height']); + var setsize = (!attrs.width || !attrs.height); + + var cur_href = getHref(elem); + + // Do nothing if no URL change or size change + if(cur_href !== val) { + setsize = true; + } else if(!setsize) return; + + var batchCmd = new BatchCommand("Change Image URL"); + + setHref(elem, val); + batchCmd.addSubCommand(new ChangeElementCommand(elem, { + "#href": cur_href + })); + + if(setsize) { + $(new Image()).load(function() { + var changes = $(elem).attr(['width', 'height']); + + $(elem).attr({ + width: this.width, + height: this.height + }); + + selectorManager.requestSelector(elem).resize(); + + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); + addCommandToHistory(batchCmd); + call("changed", [elem]); + }).attr('src',val); + } else { + addCommandToHistory(batchCmd); + } +}; + +// Function: setLinkURL +// Sets the new link URL for the selected anchor element. +// +// Parameters: +// val - String with the link URL/path +this.setLinkURL = function(val) { + var elem = selectedElements[0]; + if(!elem) return; + if(elem.tagName !== 'a') { + // See if parent is an anchor + var parents_a = $(elem).parents('a'); + if(parents_a.length) { + elem = parents_a[0]; + } else { + return; + } + } + + var cur_href = getHref(elem); + + if(cur_href === val) return; + + var batchCmd = new BatchCommand("Change Link URL"); + + setHref(elem, val); + batchCmd.addSubCommand(new ChangeElementCommand(elem, { + "#href": cur_href + })); + + addCommandToHistory(batchCmd); +}; + + +// Function elementAreSame +// Checks if all the selected Elements are the same type +// +// Parameters: +// None + +this.elementsAreSame = function(elements) { + if (!elements.length || elements[0] == null) return null + else { + var isSameElement = function(el) { + if (el && selectedElements[0]) + return (el.nodeName == selectedElements[0].nodeName); + else return null; + } + return selectedElements.every(isSameElement); + } +} + + +// Function: setRectRadius +// Sets the rx & ry values to the selected rect element to change its corner radius +// +// Parameters: +// val - The new radius +this.setRectRadius = function(val) { + if (canvas.elementsAreSame(selectedElements) && selectedElements[0].tagName == "rect") { + var assign_rr = function(selected){ + var r = selected.getAttribute("rx"); + if (r != val) { + selected.setAttribute("rx", val); + selected.setAttribute("ry", val); + addCommandToHistory(new ChangeElementCommand(selected, {"rx":r, "ry":r}, "Radius")); + call("changed", [selected]); + } + } + selectedElements.forEach(assign_rr) + } +}; + +// Function: makeHyperlink +// Wraps the selected element(s) in an anchor element or converts group to one +this.makeHyperlink = function(url) { + canvas.groupSelectedElements('a', url); + + // TODO: If element is a single "g", convert to "a" + // if(selectedElements.length > 1 && selectedElements[1]) { + +} + +// Function: removeHyperlink +this.removeHyperlink = function() { + canvas.ungroupSelectedElement(); +} + +// Group: Element manipulation + +// Function: setSegType +// Sets the new segment type to the selected segment(s). +// +// Parameters: +// new_type - Integer with the new segment type +// See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list +this.setSegType = function(new_type) { + pathActions.setSegType(new_type); +} + +// TODO(codedread): Remove the getBBox argument and split this function into two. +// Function: convertToPath +// Convert selected element to a path, or get the BBox of an element-as-path +// +// Parameters: +// elem - The DOM element to be converted +// getBBox - Boolean on whether or not to only return the path's BBox +// +// Returns: +// If the getBBox flag is true, the resulting path's bounding box object. +// Otherwise the resulting path element is returned. +this.convertToPath = function(elem, getBBox) { + if(elem == null) { + var elems = selectedElements; + $.each(selectedElements, function(i, elem) { + if(elem) canvas.convertToPath(elem); + }); + return; + } + + if(!getBBox) { + var batchCmd = new BatchCommand("Convert element to Path"); + } + + var attrs = getBBox?{}:{ + "fill": cur_shape.fill, + "fill-opacity": cur_shape.fill_opacity, + "stroke": cur_shape.stroke, + "stroke-width": cur_shape.stroke_width, + "stroke-dasharray": cur_shape.stroke_dasharray, + "stroke-linejoin": cur_shape.stroke_linejoin, + "stroke-linecap": cur_shape.stroke_linecap, + "stroke-opacity": cur_shape.stroke_opacity, + "opacity": cur_shape.opacity, + "visibility":"hidden" + }; + + // any attribute on the element not covered by the above + // TODO: make this list global so that we can properly maintain it + // TODO: what about @transform, @clip-rule, @fill-rule, etc? + $.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function() { + if (elem.getAttribute(this)) { + attrs[this] = elem.getAttribute(this); + } + }); + + var path = addSvgElementFromJson({ + "element": "path", + "attr": attrs + }); + + var eltrans = elem.getAttribute("transform"); + if(eltrans) { + path.setAttribute("transform",eltrans); + } + + var id = elem.id; + var parent = elem.parentNode; + if(elem.nextSibling) { + parent.insertBefore(path, elem); + } else { + parent.appendChild(path); + } + + var d = ''; + + var joinSegs = function(segs) { + $.each(segs, function(j, seg) { + var l = seg[0], pts = seg[1]; + d += l; + for(var i=0; i < pts.length; i+=2) { + d += (pts[i] +','+pts[i+1]) + ' '; + } + }); + } + + // Possibly the cubed root of 6, but 1.81 works best + var num = 1.81; + + switch (elem.tagName) { + case 'ellipse': + case 'circle': + var a = $(elem).attr(['rx', 'ry', 'cx', 'cy']); + var cx = a.cx, cy = a.cy, rx = a.rx, ry = a.ry; + if(elem.tagName == 'circle') { + rx = ry = $(elem).attr('r'); + } + + joinSegs([ + ['M',[(cx-rx),(cy)]], + ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]], + ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]], + ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]], + ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]], + ['Z',[]] + ]); + break; + case 'path': + d = elem.getAttribute('d'); + break; + case 'line': + var a = $(elem).attr(["x1", "y1", "x2", "y2"]); + d = "M"+a.x1+","+a.y1+"L"+a.x2+","+a.y2; + break; + case 'polyline': + case 'polygon': + d = "M" + elem.getAttribute('points'); + break; + case 'rect': + var r = $(elem).attr(['rx', 'ry']); + var rx = r.rx, ry = r.ry; + var b = elem.getBBox(); + var x = b.x, y = b.y, w = b.width, h = b.height; + var num = 4-num; // Why? Because! + if(!rx && !ry) { + // Regular rect + joinSegs([ + ['M',[x, y]], + ['L',[x+w, y]], + ['L',[x+w, y+h]], + ['L',[x, y+h]], + ['L',[x, y]], + ['Z',[]] + ]); + } else { + if (!ry) ry = rx + joinSegs([ + ['M',[x, y+ry]], + ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]], + ['L',[x+w-rx, y]], + ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]], + ['L',[x+w, y+h-ry]], + ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]], + ['L',[x+rx, y+h]], + ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]], + ['L',[x, y+ry]], + ['Z',[]] + ]); + } + break; + default: + path.parentNode.removeChild(path); + break; + } + + if(d) { + path.setAttribute('d',d); + } + + if(!getBBox) { + // Replace the current element with the converted one + + // Reorient if it has a matrix + if(eltrans) { + var tlist = getTransformList(path); + if(hasMatrixTransform(tlist)) { + pathActions.resetOrientation(path); + } + } + + var nextSibling = elem.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + batchCmd.addSubCommand(new InsertElementCommand(path)); + + clearSelection(); + elem.parentNode.removeChild(elem) + path.setAttribute('id', id); + path.removeAttribute("visibility"); + addToSelection([path], true); + + addCommandToHistory(batchCmd); + + } else { + // Get the correct BBox of the new path, then discard it + pathActions.resetOrientation(path); + var bb = false; + try { + bb = path.getBBox(); + } catch(e) { + // Firefox fails + } + path.parentNode.removeChild(path); + return bb; + } +}; + + +// Function: changeSelectedAttributeNoUndo +// This function makes the changes to the elements. It does not add the change +// to the history stack. +// +// Parameters: +// attr - String with the attribute name +// newValue - String or number with the new attribute value +// elems - The DOM elements to apply the change to +var changeSelectedAttributeNoUndo = this.changeSelectedAttributeNoUndo = function(attr, newValue, elems) { + if(current_mode == 'pathedit') { + // Editing node + pathActions.moveNode(attr, newValue); + } + var elems = elems || selectedElements; + var i = elems.length; + var no_xy_elems = ['g', 'polyline', 'path']; + var good_g_attrs = ['transform', 'opacity', 'filter']; + while (i--) { + var elem = elems[i]; + if (elem == null) continue; + // Go into "select" mode for text changes + if(current_mode === "textedit" && attr !== "#text" && elem.textContent.length) { + textActions.toSelectMode(elem); + } + + // Set x,y vals on elements that don't have them + if((attr === 'x' || attr === 'y') && no_xy_elems.indexOf(elem.tagName) >= 0) { + var bbox = getStrokedBBox([elem]); + var diff_x = attr === 'x' ? newValue - bbox.x : 0; + var diff_y = attr === 'y' ? newValue - bbox.y : 0; + canvas.moveSelectedElements(diff_x*current_zoom, diff_y*current_zoom, true); + continue; + } + + var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr); + if (oldval == null) oldval = ""; + if (oldval !== String(newValue)) { + if (attr == "#text") { + var old_w = svgedit.utilities.getBBox(elem).width; + elem.textContent = newValue; + + } else if (attr == "#href") { + setHref(elem, newValue); + } + else elem.setAttribute(attr, newValue); + + // Timeout needed for Opera & Firefox + // codedread: it is now possible for this function to be called with elements + // that are not in the selectedElements array, we need to only request a + // selector if the element is in that array + if (selectedElements.indexOf(elem) >= 0) { + setTimeout(function() { + // Due to element replacement, this element may no longer + // be part of the DOM + if(!elem.parentNode) return; + selectorManager.requestSelector(elem).resize(); + },0); + } + // if this element was rotated, and we changed the position of this element + // we need to update the rotational transform attribute + var angle = getRotationAngle(elem); + if (angle != 0 && attr != "transform") { + var tlist = getTransformList(elem); + var n = tlist.numberOfItems; + while (n--) { + var xform = tlist.getItem(n); + if (xform.type == 4) { + // remove old rotate + tlist.removeItem(n); + + var box = svgedit.utilities.getBBox(elem); + var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix); + var cx = center.x, + cy = center.y; + var newrot = svgroot.createSVGTransform(); + newrot.setRotate(angle, cx, cy); + tlist.insertItemBefore(newrot, n); + break; + } + } + } + } // if oldValue != newValue + } // for each elem +}; + +// Function: changeSelectedAttribute +// Change the given/selected element and add the original value to the history stack +// If you want to change all selectedElements, ignore the elems argument. +// If you want to change only a subset of selectedElements, then send the +// subset to this function in the elems argument. +// +// Parameters: +// attr - String with the attribute name +// newValue - String or number with the new attribute value +// elems - The DOM elements to apply the change to +var changeSelectedAttribute = this.changeSelectedAttribute = function(attr, val, elems) { + var elems = elems || selectedElements; + canvas.undoMgr.beginUndoableChange(attr, elems); + var i = elems.length; + + changeSelectedAttributeNoUndo(attr, val, elems); + + var batchCmd = canvas.undoMgr.finishUndoableChange(); + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + } +}; + +// Function: deleteSelectedElements +// Removes all selected elements from the DOM and adds the change to the +// history stack +this.deleteSelectedElements = function() { + var batchCmd = new BatchCommand("Delete Elements"); + var len = selectedElements.length; + var selectedCopy = []; //selectedElements is being deleted + for (var i = 0; i < len; ++i) { + var selected = selectedElements[i]; + if (selected == null) break; + + var parent = selected.parentNode; + var t = selected; + + // this will unselect the element and remove the selectedOutline + selectorManager.releaseSelector(t); + + // Remove the path if present. + svgedit.path.removePath_(t.id); + + // Get the parent if it's a single-child anchor + if(parent.tagName === 'a' && parent.childNodes.length === 1) { + t = parent; + parent = parent.parentNode; + } + + var nextSibling = t.nextSibling; + var elem = parent.removeChild(t); + selectedCopy.push(selected); //for the copy + selectedElements[i] = null; + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + } + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + call("changed", selectedCopy); + clearSelection(); +}; + +// Function: cutSelectedElements +// Removes all selected elements from the DOM and adds the change to the +// history stack. Remembers removed elements on the clipboard + +// TODO: Combine similar code with deleteSelectedElements +this.cutSelectedElements = function() { + var batchCmd = new BatchCommand("Cut Elements"); + var len = selectedElements.length; + var selectedCopy = []; //selectedElements is being deleted + for (var i = 0; i < len; ++i) { + var selected = selectedElements[i]; + if (selected == null) break; + + var parent = selected.parentNode; + var t = selected; + + // this will unselect the element and remove the selectedOutline + selectorManager.releaseSelector(t); + + // Remove the path if present. + svgedit.path.removePath_(t.id); + + var nextSibling = t.nextSibling; + var elem = parent.removeChild(t); + selectedCopy.push(selected); //for the copy + selectedElements[i] = null; + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + } + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + call("changed", selectedCopy); + clearSelection(); + + canvas.clipBoard = selectedCopy; +}; + +// Function: copySelectedElements +// Remembers the current selected elements on the clipboard +this.copySelectedElements = function() { + canvas.clipBoard = $.merge([], selectedElements); +}; + +this.pasteElements = function(type, x, y) { + var cb = canvas.clipBoard; + var len = cb.length; + if(!len) return; + + var pasted = []; + var batchCmd = new BatchCommand('Paste elements'); + + // Move elements to lastClickPoint + + while (len--) { + var elem = cb[len]; + if(!elem) continue; + var copy = copyElem(elem); + + // See if elem with elem ID is in the DOM already + if(!getElem(elem.id)) copy.id = elem.id; + pasted.push(copy); + (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy); + batchCmd.addSubCommand(new InsertElementCommand(copy)); + } + svgCanvas.clearSelection(); + setTimeout(function(){selectOnly(pasted)},100); + + + + addCommandToHistory(batchCmd); + call("changed", pasted); +} + +// Function: groupSelectedElements +// Wraps all the selected elements in a group (g) element + +// Parameters: +// type - type of element to group into, defaults to <g> +this.groupSelectedElements = function(type) { + if(!type) type = 'g'; + var cmd_str = ''; + + switch ( type ) { + case "a": + cmd_str = "Make hyperlink"; + var url = ''; + if(arguments.length > 1) { + url = arguments[1]; + } + break; + default: + type = 'g'; + cmd_str = "Group Elements"; + break; + } + + var batchCmd = new BatchCommand(cmd_str); + + // create and insert the group element + var g = addSvgElementFromJson({ + "element": type, + "attr": { + "id": getNextId() + } + }); + if(type === 'a') { + setHref(g, url); + } + batchCmd.addSubCommand(new InsertElementCommand(g)); + + // now move all children into the group + var i = selectedElements.length; + while (i--) { + var elem = selectedElements[i]; + if (elem == null) continue; + + if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { + elem = elem.parentNode; + } + + var oldNextSibling = elem.nextSibling; + var oldParent = elem.parentNode; + g.appendChild(elem); + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); + } + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + + // update selection + selectOnly([g], true); +}; + + +// Function: pushGroupProperties +// Pushes all appropriate parent group properties down to its children, then +// removes them from the group +var pushGroupProperties = this.pushGroupProperties = function(g, undoable) { + + var children = g.childNodes; + var len = children.length; + var xform = g.getAttribute("transform"); + + var glist = getTransformList(g); + var m = transformListToTransform(glist).matrix; + + var batchCmd = new BatchCommand("Push group properties"); + + // TODO: get all fill/stroke properties from the group that we are about to destroy + // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", + // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", + // "stroke-width" + // and then for each child, if they do not have the attribute (or the value is 'inherit') + // then set the child's attribute + + var i = 0; + var gangle = getRotationAngle(g); + + var gattrs = $(g).attr(['filter', 'opacity']); + var gfilter, gblur; + + for(var i = 0; i < len; i++) { + var elem = children[i]; + + if(elem.nodeType !== 1) continue; + + if(gattrs.opacity !== null && gattrs.opacity !== 1) { + var c_opac = elem.getAttribute('opacity') || 1; + var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100; + changeSelectedAttribute('opacity', new_opac, [elem]); + } + + if(gattrs.filter) { + var cblur = this.getBlur(elem); + var orig_cblur = cblur; + if(!gblur) gblur = this.getBlur(g); + if(cblur) { + // Is this formula correct? + cblur = (gblur-0) + (cblur-0); + } else if(cblur === 0) { + cblur = gblur; + } + + // If child has no current filter, get group's filter or clone it. + if(!orig_cblur) { + // Set group's filter to use first child's ID + if(!gfilter) { + gfilter = getRefElem(gattrs.filter); + } else { + // Clone the group's filter + gfilter = copyElem(gfilter); + findDefs().appendChild(gfilter); + } + } else { + gfilter = getRefElem(elem.getAttribute('filter')); + } + + // Change this in future for different filters + var suffix = (gfilter.firstChild.tagName === 'feGaussianBlur')?'blur':'filter'; + gfilter.id = elem.id + '_' + suffix; + changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); + + // Update blur value + if(cblur) { + changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); + canvas.setBlurOffsets(gfilter, cblur); + } + } + + var chtlist = getTransformList(elem); + + // Don't process gradient transforms + if(~elem.tagName.indexOf('Gradient')) chtlist = null; + + // Hopefully not a problem to add this. Necessary for elements like <desc/> + if(!chtlist) continue; + + // Apparently <defs> can get get a transformlist, but we don't want it to have one! + if(elem.tagName === 'defs') continue; + + if (glist.numberOfItems) { + // TODO: if the group's transform is just a rotate, we can always transfer the + // rotate() down to the children (collapsing consecutive rotates and factoring + // out any translates) + if (gangle && glist.numberOfItems == 1) { + // [Rg] [Rc] [Mc] + // we want [Tr] [Rc2] [Mc] where: + // - [Rc2] is at the child's current center but has the + // sum of the group and child's rotation angles + // - [Tr] is the equivalent translation that this child + // undergoes if the group wasn't there + + // [Tr] = [Rg] [Rc] [Rc2_inv] + + // get group's rotation matrix (Rg) + var rgm = glist.getItem(0).matrix; + + // get child's rotation matrix (Rc) + var rcm = svgroot.createSVGMatrix(); + var cangle = getRotationAngle(elem); + if (cangle) { + rcm = chtlist.getItem(0).matrix; + } + + // get child's old center of rotation + var cbox = svgedit.utilities.getBBox(elem); + var ceqm = transformListToTransform(chtlist).matrix; + var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm); + + // sum group and child's angles + var sangle = gangle + cangle; + + // get child's rotation at the old center (Rc2_inv) + var r2 = svgroot.createSVGTransform(); + r2.setRotate(sangle, coldc.x, coldc.y); + + // calculate equivalent translate + var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); + + // set up tlist + if (cangle) { + chtlist.removeItem(0); + } + + if (sangle) { + if(chtlist.numberOfItems) { + chtlist.insertItemBefore(r2, 0); + } else { + chtlist.appendItem(r2); + } + } + + if (trm.e || trm.f) { + var tr = svgroot.createSVGTransform(); + tr.setTranslate(trm.e, trm.f); + if(chtlist.numberOfItems) { + chtlist.insertItemBefore(tr, 0); + } else { + chtlist.appendItem(tr); + } + } + } + else { // more complicated than just a rotate + + // transfer the group's transform down to each child and then + // call recalculateDimensions() + var oldxform = elem.getAttribute("transform"); + var changes = {}; + changes["transform"] = oldxform ? oldxform : ""; + + var newxform = svgroot.createSVGTransform(); + + // [ gm ] [ chm ] = [ chm ] [ gm' ] + // [ gm' ] = [ chm_inv ] [ gm ] [ chm ] + var chm = transformListToTransform(chtlist).matrix, + chm_inv = chm.inverse(); + var gm = matrixMultiply( chm_inv, m, chm ); + newxform.setMatrix(gm); + chtlist.appendItem(newxform); + } + var cmd = recalculateDimensions(elem); + if(cmd) batchCmd.addSubCommand(cmd); + } + } + + + // remove transform and make it undo-able + if (xform) { + var changes = {}; + changes["transform"] = xform; + g.setAttribute("transform", ""); + g.removeAttribute("transform"); + batchCmd.addSubCommand(new ChangeElementCommand(g, changes)); + } + + if (undoable && !batchCmd.isEmpty()) { + return batchCmd; + } +} + + +// Function: ungroupSelectedElement +// Unwraps all the elements in a selected group (g) element. This requires +// significant recalculations to apply group's transforms, etc to its children +this.ungroupSelectedElement = function() { + var g = selectedElements[0]; + if($(g).data('gsvg') || $(g).data('symbol')) { + // Is svg, so actually convert to group + + convertToGroup(g); + return; + } else if(g.tagName === 'use') { + // Somehow doesn't have data set, so retrieve + var symbol = getElem(getHref(g).substr(1)); + $(g).data('symbol', symbol).data('ref', symbol); + convertToGroup(g); + return; + } + var parents_a = $(g).parents('a'); + if(parents_a.length) { + g = parents_a[0]; + } + + // Look for parent "a" + if (g.tagName === "g" || g.tagName === "a") { + + var batchCmd = new BatchCommand("Ungroup Elements"); + var cmd = pushGroupProperties(g, true); + if(cmd) batchCmd.addSubCommand(cmd); + + var parent = g.parentNode; + var anchor = g.nextSibling; + var children = new Array(g.childNodes.length); + + var i = 0; + + while (g.firstChild) { + var elem = g.firstChild; + var oldNextSibling = elem.nextSibling; + var oldParent = elem.parentNode; + + // Remove child title elements + if(elem.tagName === 'title') { + var nextSibling = elem.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)); + oldParent.removeChild(elem); + continue; + } + + children[i++] = elem = parent.insertBefore(elem, anchor); + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); + } + + // remove the group from the selection + clearSelection(); + + // delete the group element (but make undo-able) + var gNextSibling = g.nextSibling; + g = parent.removeChild(g); + batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); + + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + + // update selection + addToSelection(children); + } +}; + +// Function: moveToTopSelectedElement +// Repositions the selected element to the bottom in the DOM to appear on top of +// other elements +this.moveToTopSelectedElement = function() { + var selected = selectedElements.filter(Boolean).reverse(); + var batchCmd = new BatchCommand("Move to top"); + selected.forEach(function(element){ + var t = element; + var oldParent = t.parentNode; + var oldNextSibling = t.nextSibling; + t = t.parentNode.appendChild(t); + // If the element actually moved position, add the command and fire the changed + // event handler. + if (oldNextSibling != t.nextSibling) { + batchCmd.addSubCommand(new MoveElementCommand(t, oldNextSibling, oldParent, "top")); + call("changed", [t]); + } + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + }) +}; + +// Function: moveToBottomSelectedElement +// Repositions the selected element to the top in the DOM to appear under +// other elements +this.moveToBottomSelectedElement = function() { + var selected = selectedElements.filter(Boolean).reverse(); + var batchCmd = new BatchCommand("Move to top"); + selected.forEach(function(element){ + var t = element; + var oldParent = t.parentNode; + var oldNextSibling = t.nextSibling; + var firstChild = t.parentNode.firstChild; + if (firstChild.tagName == 'title') { + firstChild = firstChild.nextSibling; + } + // This can probably be removed, as the defs should not ever apppear + // inside a layer group + if (firstChild.tagName == 'defs') { + firstChild = firstChild.nextSibling; + } + t = t.parentNode.insertBefore(t, firstChild); + // If the element actually moved position, add the command and fire the changed + // event handler. + if (oldNextSibling != t.nextSibling) { + batchCmd.addSubCommand(new MoveElementCommand(t, oldNextSibling, oldParent, "bottom")); + call("changed", [t]); + } + }) + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); +}; + +// Function: moveUpDownSelected +// Moves the select element up or down the stack, based on the visibly +// intersecting elements +// +// Parameters: +// dir - String that's either 'Up' or 'Down' +this.moveUpDownSelected = function(dir) { + var selected = selectedElements.filter(Boolean); + if(dir == 'Down') selected.reverse(); + var batchCmd = new BatchCommand("Move " + dir); + selected.forEach(function(selected){ + curBBoxes = []; + var closest, found_cur; + // jQuery sorts this list + var list = $(getIntersectionList(getStrokedBBox([selected]))).toArray(); + if(dir == 'Down') list.reverse(); + + $.each(list, function() { + if(!found_cur) { + if(this == selected) { + found_cur = true; + } + return; + } + closest = this; + return false; + }); + if(!closest) return; + + var t = selected; + var oldParent = t.parentNode; + var oldNextSibling = t.nextSibling; + $(closest)[dir == 'Down'?'before':'after'](t); + // If the element actually moved position, add the command and fire the changed + // event handler. + if (oldNextSibling != t.nextSibling) { + batchCmd.addSubCommand(new MoveElementCommand(t, oldNextSibling, oldParent, "Move " + dir)); + call("changed", [t]); + } + }); + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); +}; + +// Function: moveSelectedElements +// Moves selected elements on the X/Y axis +// +// Parameters: +// dx - Float with the distance to move on the x-axis +// dy - Float with the distance to move on the y-axis +// undoable - Boolean indicating whether or not the action should be undoable +// +// Returns: +// Batch command for the move +this.moveSelectedElements = function(dx, dy, undoable) { + // if undoable is not sent, default to true + // if single values, scale them to the zoom + if (dx.constructor != Array) { + dx /= current_zoom; + dy /= current_zoom; + } + var undoable = undoable || true; + var batchCmd = new BatchCommand("position"); + var i = selectedElements.length; + while (i--) { + var selected = selectedElements[i]; + if (selected != null) { +// if (i==0) +// selectedBBoxes[0] = svgedit.utilities.getBBox(selected); + +// var b = {}; +// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; +// selectedBBoxes[i] = b; + + var xform = svgroot.createSVGTransform(); + var tlist = getTransformList(selected); + + // dx and dy could be arrays + if (dx.constructor == Array) { +// if (i==0) { +// selectedBBoxes[0].x += dx[0]; +// selectedBBoxes[0].y += dy[0]; +// } + xform.setTranslate(dx[i],dy[i]); + } else { +// if (i==0) { +// selectedBBoxes[0].x += dx; +// selectedBBoxes[0].y += dy; +// } + xform.setTranslate(dx,dy); + } + + if(tlist.numberOfItems) { + tlist.insertItemBefore(xform, 0); + } else { + tlist.appendItem(xform); + } + + var cmd = recalculateDimensions(selected); + if (cmd) { + batchCmd.addSubCommand(cmd); + } + + selectorManager.requestSelector(selected).resize(); + } + } + if (!batchCmd.isEmpty()) { + if (undoable) + addCommandToHistory(batchCmd); + call("changed", selectedElements); + return batchCmd; + } +}; + +// Function: cloneSelectedElements +// Create deep DOM copies (clones) of all selected elements and move them slightly +// from their originals +this.cloneSelectedElements = function(x,y, drag) { + var batchCmd = new BatchCommand("Clone Elements"); + // find all the elements selected (stop at first null) + var len = selectedElements.length; + for (var i = 0; i < len; ++i) { + var elem = selectedElements[i]; + if (elem == null) break; + } + // use slice to quickly get the subset of elements we need + var copiedElements = selectedElements.slice(0,i); + this.clearSelection(true); + // note that we loop in the reverse way because of the way elements are added + // to the selectedElements array (top-first) + var i = copiedElements.length; + clones = [] + while (i--) { + // clone each element and replace it within copiedElements + var elem = copiedElements[i] + var clone = copyElem(copiedElements[i]); + var parent = (current_group || getCurrentDrawing().getCurrentLayer()) + if (drag) { + //removed the dragged transform until that moment + tlist = getTransformList(clone) + tlist.removeItem(0) + recalculateDimensions(clone) + parent.insertBefore(clone, elem); + } + else { + parent.appendChild(clone); + } + clones.push(clone) + batchCmd.addSubCommand(new InsertElementCommand(clone)); + } + + if (!batchCmd.isEmpty()) { + addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding + if (!drag) this.moveSelectedElements(x,y,false); + addCommandToHistory(batchCmd); + } + return clones +}; + +// Function: alignSelectedElements +// Aligns selected elements +// +// Parameters: +// type - String with single character indicating the alignment type +// relative_to - String that must be one of the following: +// "selected", "largest", "smallest", "page" +this.alignSelectedElements = function(type, relative_to) { + var bboxes = [], angles = []; + var minx = Number.MAX_VALUE, maxx = Number.MIN_VALUE, miny = Number.MAX_VALUE, maxy = Number.MIN_VALUE; + var curwidth = Number.MIN_VALUE, curheight = Number.MIN_VALUE; + var len = selectedElements.length; + if (!len) return; + for (var i = 0; i < len; ++i) { + if (selectedElements[i] == null) break; + var elem = selectedElements[i]; + bboxes[i] = getStrokedBBox([elem]); + + // now bbox is axis-aligned and handles rotation + switch (relative_to) { + case 'smallest': + if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth > bboxes[i].width) || + (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight > bboxes[i].height) ) { + minx = bboxes[i].x; + miny = bboxes[i].y; + maxx = bboxes[i].x + bboxes[i].width; + maxy = bboxes[i].y + bboxes[i].height; + curwidth = bboxes[i].width; + curheight = bboxes[i].height; + } + break; + case 'largest': + if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth < bboxes[i].width) || + (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight < bboxes[i].height) ) { + minx = bboxes[i].x; + miny = bboxes[i].y; + maxx = bboxes[i].x + bboxes[i].width; + maxy = bboxes[i].y + bboxes[i].height; + curwidth = bboxes[i].width; + curheight = bboxes[i].height; + } + break; + default: // 'selected' + if (bboxes[i].x < minx) minx = bboxes[i].x; + if (bboxes[i].y < miny) miny = bboxes[i].y; + if (bboxes[i].x + bboxes[i].width > maxx) maxx = bboxes[i].x + bboxes[i].width; + if (bboxes[i].y + bboxes[i].height > maxy) maxy = bboxes[i].y + bboxes[i].height; + break; + } + } // loop for each element to find the bbox and adjust min/max + + if (relative_to == 'page') { + minx = 0; + miny = 0; + maxx = canvas.contentW; + maxy = canvas.contentH; + } + + var dx = new Array(len); + var dy = new Array(len); + for (var i = 0; i < len; ++i) { + if (selectedElements[i] == null) break; + var elem = selectedElements[i]; + var bbox = bboxes[i]; + dx[i] = 0; + dy[i] = 0; + switch (type) { + case 'l': // left (horizontal) + dx[i] = minx - bbox.x; + break; + case 'c': // center (horizontal) + dx[i] = (minx+maxx)/2 - (bbox.x + bbox.width/2); + break; + case 'r': // right (horizontal) + dx[i] = maxx - (bbox.x + bbox.width); + break; + case 't': // top (vertical) + dy[i] = miny - bbox.y; + break; + case 'm': // middle (vertical) + dy[i] = (miny+maxy)/2 - (bbox.y + bbox.height/2); + break; + case 'b': // bottom (vertical) + dy[i] = maxy - (bbox.y + bbox.height); + break; + } + } + this.moveSelectedElements(dx,dy); +}; + +// Group: Additional editor tools + +this.contentW = getResolution().w; +this.contentH = getResolution().h; + +// Function: updateCanvas +// Updates the editor canvas width/height/position after a zoom has occurred +// +// Parameters: +// w - Float with the new width +// h - Float with the new height +// +// Returns: +// Object with the following values: +// * x - The canvas' new x coordinate +// * y - The canvas' new y coordinate +// * old_x - The canvas' old x coordinate +// * old_y - The canvas' old y coordinate +// * d_x - The x position difference +// * d_y - The y position difference +this.updateCanvas = function(w, h) { + svgroot.setAttribute("width", w); + svgroot.setAttribute("height", h); + var bg = $('#canvasBackground')[0]; + var old_x = svgcontent.getAttribute('x'); + var old_y = svgcontent.getAttribute('y'); + var x = (w/2 - this.contentW*current_zoom/2); + var y = (h/2 - this.contentH*current_zoom/2); + + assignAttributes(svgcontent, { + width: this.contentW*current_zoom, + height: this.contentH*current_zoom, + 'x': x, + 'y': y, + "viewBox" : "0 0 " + this.contentW + " " + this.contentH + }); + + assignAttributes(bg, { + width: svgcontent.getAttribute('width'), + height: svgcontent.getAttribute('height'), + x: x, + y: y + }); + + var bg_img = getElem('background_image'); + if (bg_img) { + assignAttributes(bg_img, { + 'width': '100%', + 'height': '100%' + }); + } + + selectorManager.selectorParentGroup.setAttribute("transform","translate(" + x + "," + y + ")"); + + return {x:x, y:y, old_x:old_x, old_y:old_y, d_x:x - old_x, d_y:y - old_y}; +} + +// Function: setBackground +// Set the background of the editor (NOT the actual document) +// +// Parameters: +// color - String with fill color to apply +// url - URL or path to image to use +this.setBackground = function(color, url) { + var bg = getElem('canvasBackground'); + var border = $(bg).find('rect')[0]; + var bg_img = getElem('background_image'); + border.setAttribute('fill',color); + if(url) { + if(!bg_img) { + bg_img = svgdoc.createElementNS(svgns, "image"); + assignAttributes(bg_img, { + 'id': 'background_image', + 'width': '100%', + 'height': '100%', + 'preserveAspectRatio': 'xMinYMin', + 'style':'pointer-events:none' + }); + } + setHref(bg_img, url); + bg.appendChild(bg_img); + } else if(bg_img) { + bg_img.parentNode.removeChild(bg_img); + } +} + +// Function: cycleElement +// Select the next/previous element within the current layer +// +// Parameters: +// next - Boolean where true = next and false = previous element +this.cycleElement = function(next) { + var cur_elem = selectedElements[0]; + var elem = false; + var all_elems = getVisibleElements(current_group || getCurrentDrawing().getCurrentLayer()); + if(!all_elems.length) return; + if (cur_elem == null) { + var num = next?all_elems.length-1:0; + elem = all_elems[num]; + } else { + var i = all_elems.length; + while(i--) { + if(all_elems[i] == cur_elem) { + var num = next?i-1:i+1; + if(num >= all_elems.length) { + num = 0; + } else if(num < 0) { + num = all_elems.length-1; + } + elem = all_elems[num]; + break; + } + } + } + selectOnly([elem], true); + call("selected", selectedElements); +} + +this.clear(); + + +// DEPRECATED: getPrivateMethods +// Since all methods are/should be public somehow, this function should be removed + +// Being able to access private methods publicly seems wrong somehow, +// but currently appears to be the best way to allow testing and provide +// access to them to plugins. +this.getPrivateMethods = function() { + var obj = { + addCommandToHistory: addCommandToHistory, + setGradient: setGradient, + addSvgElementFromJson: addSvgElementFromJson, + assignAttributes: assignAttributes, + BatchCommand: BatchCommand, + call: call, + ChangeElementCommand: ChangeElementCommand, + copyElem: copyElem, + ffClone: ffClone, + findDefs: findDefs, + findDuplicateGradient: findDuplicateGradient, + getElem: getElem, + getId: getId, + getIntersectionList: getIntersectionList, + getMouseTarget: getMouseTarget, + getNextId: getNextId, + getPathBBox: getPathBBox, + getUrlFromAttr: getUrlFromAttr, + hasMatrixTransform: hasMatrixTransform, + identifyLayers: identifyLayers, + InsertElementCommand: InsertElementCommand, + isIdentity: svgedit.math.isIdentity, + logMatrix: logMatrix, + matrixMultiply: matrixMultiply, + MoveElementCommand: MoveElementCommand, + preventClickDefault: preventClickDefault, + recalculateAllSelectedDimensions: recalculateAllSelectedDimensions, + recalculateDimensions: recalculateDimensions, + remapElement: remapElement, + RemoveElementCommand: RemoveElementCommand, + removeUnusedDefElems: removeUnusedDefElems, + round: round, + runExtensions: runExtensions, + sanitizeSvg: sanitizeSvg, + SVGEditTransformList: svgedit.transformlist.SVGTransformList, + toString: toString, + transformBox: svgedit.math.transformBox, + transformListToTransform: transformListToTransform, + transformPoint: transformPoint, + walkTree: svgedit.utilities.walkTree + } + return obj; +}; + +} + +/* +* svg-editor.js +* +* Licensed under the MIT License +* +* Copyright(c) 2010 Alexis Deveria +* Copyright(c) 2010 Pavol Rusnak +* Copyright(c) 2010 Jeff Schiller +* Copyright(c) 2010 Narendra Sisodiya +* Copyright(c) 2012 Mark MacKay +* +*/ + +// Dependencies: +// 1) units.js +// 2) browser.js +// 3) svgcanvas.js + + +if(!window.methodDraw) window.methodDraw = function($) { + var svgCanvas; + var Editor = {}; + var is_ready = false; + var curConfig = { + canvas_expansion: 1, + dimensions: [800,600], + initFill: {color: 'fff', opacity: 1}, + initStroke: {width: 1.5, color: '000', opacity: 1}, + initOpacity: 1, + imgPath: 'images/', + extPath: 'extensions/', + jGraduatePath: 'images/', + extensions: [], + initTool: 'select', + wireframe: false, + colorPickerCSS: false, + gridSnapping: false, + gridColor: "#000", + baseUnit: 'px', + snappingStep: 10, + showRulers: (svgedit.browser.isTouch()) ? false : true, + show_outside_canvas: false, + no_save_warning: true, + initFont: 'Helvetica, Arial, sans-serif' + }; + console.log(curConfig); + var curPrefs = {}; //$.extend({}, defaultPrefs); + var customHandlers = {}; + Editor.curConfig = curConfig; + Editor.tool_scale = 1; + + Editor.setConfig = function(opts) { + $.extend(true, curConfig, opts); + if(opts.extensions) { + curConfig.extensions = opts.extensions; + } + } + + // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save + // opts.open's responsibilities are: + // - invoke a file chooser dialog in 'open' mode + // - let user pick a SVG file + // - calls setCanvas.setSvgString() with the string contents of that file + // opts.save's responsibilities are: + // - accept the string contents of the current document + // - invoke a file chooser dialog in 'save' mode + // - save the file to location chosen by the user + Editor.setCustomHandlers = function(opts) { + Editor.ready(function() { + if(opts.open) { + $('#tool_open > input[type="file"]').remove(); + $('#tool_open').show(); + svgCanvas.open = opts.open; + } + if(opts.save) { + Editor.show_save_warning = false; + svgCanvas.bind("saved", opts.save); + } + if(opts.pngsave) { + svgCanvas.bind("exported", opts.pngsave); + } + customHandlers = opts; + }); + } + + Editor.randomizeIds = function() { + svgCanvas.randomizeIds(arguments) + } + + Editor.init = function() { + // For external openers + (function() { + // let the opener know SVG Edit is ready + var w = window.opener; + if (w) { + try { + var methodDrawReadyEvent = w.document.createEvent("Event"); + methodDrawReadyEvent.initEvent("methodDrawReady", true, true); + w.document.documentElement.dispatchEvent(methodDrawReadyEvent); + } + catch(e) {} + } + })(); + + + $("body").toggleClass("touch", svgedit.browser.isTouch()); + $("#canvas_width").val(curConfig.dimensions[0]); + $("#canvas_height").val(curConfig.dimensions[1]); + + var extFunc = function() { + $.each(curConfig.extensions, function() { + var extname = this; + $.getScript(curConfig.extPath + extname, function(d) { + // Fails locally in Chrome 5 + if(!d) { + var s = document.createElement('script'); + s.src = curConfig.extPath + extname; + document.querySelector('head').appendChild(s); + } + }); + }); + } + + // Load extensions + // Bit of a hack to run extensions in local Opera/IE9 + if(document.location.protocol === 'file:') { + setTimeout(extFunc, 100); + } else { + extFunc(); + } + $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { + w:27, h:27, + id_match: false, + no_img: true, // Opera & Firefox 4 gives odd behavior w/images + fallback_path: curConfig.imgPath, + fallback:{ + 'logo':'logo.png', + 'select':'select.png', + 'select_node':'select_node.png', + 'pencil':'pencil.png', + 'pen':'line.png', + 'rect':'square.png', + 'ellipse':'ellipse.png', + 'path':'path.png', + 'text':'text.png', + 'image':'image.png', + 'zoom':'zoom.png', + 'delete':'delete.png', + 'spapelib':'shapelib.png', + 'node_delete':'node_delete.png', + 'align_left':'align-left.png', + 'align_center':'align-center.png', + 'align_right':'align-right.png', + 'align_top':'align-top.png', + 'align_middle':'align-middle.png', + 'align_bottom':'align-bottom.png', + 'arrow_right':'flyouth.png', + 'arrow_down':'dropdown.gif' + }, + placement: { + '#logo':'logo', + '#tool_select':'select', + '#tool_fhpath':'pencil', + '#tool_line':'pen', + '#tool_rect,#tools_rect_show':'rect', + '#tool_ellipse,#tools_ellipse_show':'ellipse', + '#tool_path':'path', + '#tool_text,#layer_rename':'text', + '#tool_image':'image', + '#tool_zoom':'zoom', + '#tool_node_clone':'node_clone', + '#tool_node_delete':'node_delete', + '#tool_add_subpath':'add_subpath', + '#tool_openclose_path':'open_path', + '#tool_alignleft, #tool_posleft':'align_left', + '#tool_aligncenter, #tool_poscenter':'align_center', + '#tool_alignright, #tool_posright':'align_right', + '#tool_aligntop, #tool_postop':'align_top', + '#tool_alignmiddle, #tool_posmiddle':'align_middle', + '#tool_alignbottom, #tool_posbottom':'align_bottom', + '#cur_position':'align', + '#zoomLabel':'zoom' + }, + resize: { + '#logo .svg_icon': 15, + '.flyout_arrow_horiz .svg_icon': 5, + '#fill_bg .svg_icon, #stroke_bg .svg_icon': svgedit.browser.isTouch() ? 24 : 24, + '.palette_item:first .svg_icon': svgedit.browser.isTouch() ? 30 : 16, + '#zoomLabel .svg_icon': 16, + '#zoom_dropdown .svg_icon': 7 + }, + callback: function(icons) { + $('.toolbar_button button > svg, .toolbar_button button > img').each(function() { + $(this).parent().prepend(this); + }); + $('.tool_button, .tool_button_current').addClass("loaded") + var tleft = $('#tools_left'); + if (tleft.length != 0) { + var min_height = tleft.offset().top + tleft.outerHeight(); + } + + // Look for any missing flyout icons from plugins + $('.tools_flyout').each(function() { + var shower = $('#' + this.id + '_show'); + var sel = shower.attr('data-curopt'); + // Check if there's an icon here + if(!shower.children('svg, img').length) { + var clone = $(sel).children().clone(); + if(clone.length) { + clone[0].removeAttribute('style'); //Needed for Opera + shower.append(clone); + } + } + }); + methodDraw.runCallbacks(); + + setTimeout(function() { + $('.flyout_arrow_horiz:empty').each(function() { + $(this).append($.getSvgIcon('arrow_right').width(5).height(5)); + }); + }, 1); + } + }); + + $('#rulers').on("dblclick", function(e){ + $("#base_unit_container").css({ + top: e.pageY-10, + left: e.pageX-50, + display: 'block' + }) + }) + $("#base_unit_container") + .on("mouseleave mouseenter", function(e){ + t = setTimeout(function(){$("#base_unit_container").fadeOut(500)}, 200) + if(event.type == "mouseover") clearTimeout(t) + }) + $("#base_unit") + .on("change", function(e) { + savePreferences(); + }); + + Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig); + Editor.show_save_warning = false; + Editor.paintBox = {fill: null, stroke:null, canvas:null}; + var palette = ["#444444", "#482816", "#422C10", "#3B2F0E", "#32320F", + "#293414", "#1F361B", "#153723", "#0C372C", + "#083734", "#0E353B", "#1A333F", "#273141", + "#332D40", "#3E2A3C", "#462735", "#4B252D", + "#4D2425", "#4C261D", "#666666", "#845335", "#7B572D", + "#6F5C2A", "#62612C", "#546433", "#46673D", + "#396849", "#306856", "#2D6862", "#33666C", + "#426373", "#535F75", "#645A73", "#74556D", + "#805064", "#884D58", "#8B4D4B", "#894F3F", + "#999999", "#C48157", "#B8874D", "#A98E49", "#97944B", + "#849854", "#729C62", "#619E73", "#559E84", + "#529D94", "#5B9BA2", "#6D97AB", "#8391AE", + "#9A8AAB", "#AF84A3", "#BF7E96", "#C97A86", + "#CE7975", "#CC7C65", "#BBBBBB", "#FFB27C", "#FABA6F", + "#E6C36A", "#CFCA6D", "#B8D078", "#A0D58A", + "#8CD79F", "#7DD8B5", "#7AD6CA", "#84D3DB", + "#9ACEE6", "#B6C7EA", "#D3BEE7", "#EDB6DC", + "#FFAFCC", "#FFAAB8", "#FFA9A2", "#FFAC8D", + "#DDDDDD", "#FFE7A2", "#FFF093", "#FFFA8D", "#FFFF91", + "#EEFF9F", "#D1FFB4", "#B9FFCE", "#A8FFE9", + "#A4FFFF", "#B1FFFF", "#CBFFFF", "#EDFFFF", + "#FFF5FF", "#FFEBFF", "#FFE2FF", "#FFDCEC", + "#FFDBD2", "#FFDFB8" + ], + isMac = (navigator.platform.indexOf("Mac") >= 0), + isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0), + modKey = (isMac ? "meta+" : "ctrl+"), // ⌘ + path = svgCanvas.pathActions, + undoMgr = svgCanvas.undoMgr, + Utils = svgedit.utilities, + default_img_url = curConfig.imgPath + "placeholder.svg", + workarea = $("#workarea"), + canv_menu = $("#cmenu_canvas"), + exportWindow = null, + tool_scale = 1, + ui_context = 'toolbars', + orig_source = ''; + + + // This puts the correct shortcuts in the menus + if (!isMac) { + $('.shortcut').each(function(){ + var text = $(this).text(); + $(this).text(text.split("⌘").join("Ctrl+")) + }); + } + + // This sets up alternative dialog boxes. They mostly work the same way as + // their UI counterparts, expect instead of returning the result, a callback + // needs to be included that returns the result as its first parameter. + // In the future we may want to add additional types of dialog boxes, since + // they should be easy to handle this way. + (function() { + $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'}); + var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); + + var dbox = function(type, msg, callback, defText) { + $('#dialog_content').html('<p>'+msg.replace(/\n/g,'</p><p>')+'</p>') + .toggleClass('prompt',(type=='prompt')); + btn_holder.empty(); + + var ok = $('<input type="button" value="OK">').appendTo(btn_holder); + + if(type != 'alert') { + $('<input type="button" value="Cancel">') + .appendTo(btn_holder) + .on("click touchstart", function() { box.hide();callback(false)}); + } + + if(type == 'prompt') { + var input = $('<input type="text">').prependTo(btn_holder); + input.val(defText || ''); + input.bind('keydown', 'return', function() {ok.trigger("click touchstart");}); + } + + if(type == 'process') { + ok.hide(); + } + + box.show(); + + ok.on("click touchstart", function() { + box.hide(); + var resp = (type == 'prompt')?input.val():true; + if(callback) callback(resp); + }).focus(); + + if(type == 'prompt') input.focus(); + } + + $.alert = function(msg, cb) { dbox('alert', msg, cb);}; + $.confirm = function(msg, cb) { dbox('confirm', msg, cb);}; + $.process_cancel = function(msg, cb) { dbox('process', msg, cb);}; + $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);}; + }()); + + var setSelectMode = function() { + var curr = $('.tool_button_current'); + if(curr.length && curr[0].id !== 'tool_select') { + curr.removeClass('tool_button_current').addClass('tool_button'); + $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); + } + svgCanvas.setMode('select'); + }; + + var setEyedropperMode = function() { + var curr = $('.tool_button_current'); + if(curr.length && curr[0].id !== 'tool_eyedropper') { + curr.removeClass('tool_button_current').addClass('tool_button'); + $('#tool_eyedropper').addClass('tool_button_current').removeClass('tool_button'); + } + svgCanvas.setMode('eyedropper'); + } + + var togglePathEditMode = function(editmode, elems) { + $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); + if(editmode) { + // Change select icon + $('.context_panel').hide(); + $('#path_node_panel').show(); + $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); + $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); + setIcon('#tool_select', 'select_node'); + multiselected = false; + } else { + if (elems[0]) { + var selector = svgCanvas.selectorManager.requestSelector(elems[0]) + selector.reset(elems[0]); + selector.selectorRect.setAttribute('display', 'inline'); + } + + setIcon('#tool_select', 'select'); + } + } + + // used to make the flyouts stay on the screen longer the very first time + var flyoutspeed = 1250; + var textBeingEntered = false; + var selectedElement = null; + var multiselected = false; + var editingsource = false; + var docprops = false; + var preferences = false; + var cur_context = ''; + + var saveHandler = function(window,svg) { + + }; + + var exportHandler = function(window, data) { + var issues = data.issues; + + if(!$('#export_canvas').length) { + $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); + } + var c = $('#export_canvas')[0]; + + c.width = svgCanvas.contentW; + c.height = svgCanvas.contentH; + canvg(c, data.svg, {renderCallback: function() { + var datauri = c.toDataURL('image/png'); + if (!datauri) return false; + var filename = "Method Draw Image"; + var type = 'image/png'; + var file = svgedit.utilities.dataURItoBlob(datauri, type); + if (window.navigator.msSaveOrOpenBlob) // IE10+ + window.navigator.msSaveOrOpenBlob(file, filename); + else { // Others + var a = document.createElement("a"), + url = URL.createObjectURL(file); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + setTimeout(function() { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); + } + }}); + }; + + // called when we've selected a different element + var selectedChanged = function(window,elems) { + var mode = svgCanvas.getMode(); + if(mode === "select") setSelectMode(); + if (mode === "pathedit") return updateContextPanel(); + // if elems[1] is present, then we have more than one element + selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null); + elems = elems.filter(Boolean) + multiselected = (elems.length >= 2) ? elems : false; + if (svgCanvas.elementsAreSame(multiselected)) selectedElement = multiselected[0] + if (selectedElement != null) { + $('#multiselected_panel').hide() + updateToolbar(); + if (multiselected.length) {//multiselected elements are the same + $('#tools_top').addClass('multiselected') + } + } + else if (multiselected.length) { + $('.context_panel').hide() + $('#tools_top').removeClass('multiselected') + $('#multiselected_panel').show() + } + else { + $('.context_panel').hide() + $('#canvas_panel').show() + $('#tools_top').removeClass('multiselected') + } + svgCanvas.runExtensions("selectedChanged", { + elems: elems, + selectedElement: selectedElement, + multiselected: multiselected + }); + }; + + // Call when part of element is in process of changing, generally + // on mousemove actions like rotate, move, etc. + var elementTransition = function(window,elems) { + var mode = svgCanvas.getMode(); + var elem = elems[0]; + + if(!elem) return; + + multiselected = (elems.length >= 2 && elems[1] != null) ? elems : null; + // Only updating fields for single elements for now + if(!multiselected) { + switch ( mode ) { + case "rotate": + var ang = svgCanvas.getRotationAngle(elem); + $('#angle').val(Math.round(ang)); + rotateCursor(ang); + $('#tool_reorient').toggleClass('disabled', ang == 0); + break; + + // TODO: Update values that change on move/resize, etc +// case "select": +// case "resize": +// break; + } + } + svgCanvas.runExtensions("elementTransition", { + elems: elems + }); + }; + + // called when any element has changed + var elementChanged = function(window,elems) { + var mode = svgCanvas.getMode(); + if(mode === "select") { + setSelectMode(); + } + + for (var i = 0; i < elems.length; ++i) { + var elem = elems[i]; + + // if the element changed was the svg, then it could be a resolution change + if (elem && elem.tagName === "svg") { + //populateLayers(); + updateCanvas(); + } + // Update selectedElement if element is no longer part of the image. + // This occurs for the text elements in Firefox + else if(elem && selectedElement && selectedElement.parentNode == null) { +// || elem && elem.tagName == "path" && !multiselected) { // This was added in r1430, but not sure why + selectedElement = elem; + } + } + + Editor.show_save_warning = true; + + // we update the contextual panel with potentially new + // positional/sizing information (we DON'T want to update the + // toolbar here as that creates an infinite loop) + // also this updates the history buttons + + // we tell it to skip focusing the text control if the + // text element was previously in focus + updateContextPanel(); + + // In the event a gradient was flipped: + if(selectedElement && mode === "select") { + Editor.paintBox.fill.update(); + Editor.paintBox.stroke.update(); + } + + svgCanvas.runExtensions("elementChanged", { + elems: elems + }); + }; + + var zoomChanged = function(window, bbox, autoCenter) { + var scrbar = 15, + res = svgCanvas.getResolution(), + w_area = workarea, + canvas_pos = $('#svgcanvas').position(); + var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); + if(!z_info) return; + var zoomlevel = z_info.zoom, + bb = z_info.bbox; + + if(zoomlevel < .001) { + changeZoom({value: .1}); + return; + } + if (typeof animatedZoom != 'undefined') window.cancelAnimationFrame(animatedZoom) + // zoom duration 500ms + var start = Date.now(); + var duration = 500; + var diff = (zoomlevel) - (res.zoom) + var zoom = $('#zoom')[0] + var current_zoom = res.zoom + var animateZoom = function(timestamp) { + var progress = Date.now() - start + var tick = progress / duration + tick = (Math.pow((tick-1), 3) +1); + svgCanvas.setZoom(current_zoom + (diff*tick)); + updateCanvas(); + if (tick < 1 && tick > -.90) { + window.animatedZoom = requestAnimationFrame(animateZoom) + } + else { + $("#zoom").val(parseInt(zoomlevel*100)) + $("option", "#zoom_select").removeAttr("selected") + $("option[value="+ parseInt(zoomlevel*100) +"]", "#zoom_select").attr("selected", "selected") + } + } + animateZoom() + + + if(svgCanvas.getMode() == 'zoom' && bb.width) { + // Go to select if a zoom box was drawn + setSelectMode(); + } + + zoomDone(); + } + + $('#cur_context_panel').delegate('a', 'click', function() { + var link = $(this); + if(link.attr('data-root')) { + svgCanvas.leaveContext(); + } else { + svgCanvas.setContext(link.text()); + } + svgCanvas.clearSelection(); + return false; + }); + + var contextChanged = function(win, context) { + + var link_str = ''; + if(context) { + var str = ''; + link_str = '<a href="#" data-root="y">' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + '</a>'; + + $(context).parentsUntil('#svgcontent > g').addBack().each(function() { + if(this.id) { + str += ' > ' + this.id; + if(this !== context) { + link_str += ' > <a href="#">' + this.id + '</a>'; + } else { + link_str += ' > ' + this.id; + } + } + }); + + cur_context = str; + } else { + cur_context = null; + } + $('#cur_context_panel').toggle(!!context).html(link_str); + + } + + // Makes sure the current selected paint is available to work with + var prepPaints = function() { + Editor.paintBox.fill.prep(); + Editor.paintBox.stroke.prep(); + } + + var flyout_funcs = {}; + + var setupFlyouts = function(holders) { + $.each(holders, function(hold_sel, btn_opts) { + var buttons = $(hold_sel).children(); + var show_sel = hold_sel + '_show'; + var shower = $(show_sel); + var def = false; + buttons.addClass('tool_button') + .unbind('click mousedown mouseup') // may not be necessary + .each(function(i) { + // Get this buttons options + var opts = btn_opts[i]; + + // Remember the function that goes with this ID + flyout_funcs[opts.sel] = opts.fn; + + if(opts.isDefault) def = i; + + // Clicking the icon in flyout should set this set's icon + var func = function(event) { + var options = opts; + //find the currently selected tool if comes from keystroke + if (event.type === "keydown") { + var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current'); + var currentOperation = $(options.parent + "_show").attr("data-curopt"); + $.each(holders[opts.parent], function(i, tool){ + if (tool.sel == currentOperation) { + if(!event.shiftKey || !flyoutIsSelected) { + options = tool; + } + else { + options = holders[opts.parent][i+1] || holders[opts.parent][0]; + } + } + }); + } + if($(this).hasClass('disabled')) return false; + if (toolButtonClick(show_sel)) { + options.fn(); + } + if(options.icon) { + var icon = $.getSvgIcon(options.icon, true); + } else { + var icon = $(options.sel).children().eq(0).clone(); + } + + icon[0].setAttribute('width',shower.width()); + icon[0].setAttribute('height',shower.height()); + shower.children(':not(.flyout_arrow_horiz)').remove(); + shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode + } + + $(this).mouseup(func); + + if(opts.key) { + $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func); + } + }); + + if(def) { + shower.attr('data-curopt', btn_opts[def].sel); + } else if(!shower.attr('data-curopt')) { + // Set first as default + shower.attr('data-curopt', btn_opts[0].sel); + } + + var timer; + + var pos = $(show_sel).position(); + $(hold_sel).css({'left': pos.left+34, 'top': pos.top+77}); + + // Clicking the "show" icon should set the current mode + shower.mousedown(function(evt) { + $('#workarea').one("mousedown", function(){$('#tools_shapelib').hide()}) + if ($('#tools_shapelib').is(":visible")) toolButtonClick(show_sel, false); + if(shower.hasClass('disabled')) return false; + var holder = $(hold_sel); + var l = pos.left+34; + var w = holder.width()*-1; + var time = holder.data('shown_popop')?200:0; + timer = setTimeout(function() { + // Show corresponding menu + if(!shower.data('isLibrary')) { + holder.css('left', w).show().animate({ + left: l + },50); + } else { + holder.css('left', l).show(); + } + holder.data('shown_popop',true); + },time); + evt.preventDefault(); + }).mouseup(function(evt) { + clearTimeout(timer); + var opt = $(this).attr('data-curopt'); + // Is library and popped up, so do nothing + if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) { + toolButtonClick(show_sel, true); + return; + } + if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { + flyout_funcs[opt](); + } + }); + + // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); + }); + + setFlyoutTitles(); + } + + var makeFlyoutHolder = function(id, child) { + var div = $('<div>',{ + 'class': 'tools_flyout', + id: id + }).appendTo('#svg_editor').append(child); + + return div; + } + + var setFlyoutPositions = function() { + $('.tools_flyout').each(function() { + var shower = $('#' + this.id + '_show'); + var pos = shower.offset(); + var w = shower.outerWidth(); + $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); + }); + } + + var setFlyoutTitles = function() { + $('.tools_flyout').each(function() { + var shower = $('#' + this.id + '_show'); + if(shower.data('isLibrary')) return; + + var tooltips = []; + $(this).children().each(function() { + tooltips.push(this.title); + }); + shower[0].title = tooltips.join(' / '); + }); + } + + var resize_timer; + + var extAdded = function(window, ext) { + + var cb_called = false; + var resize_done = false; + var cb_ready = true; // Set to false to delay callback (e.g. wait for $.svgIcons) + + function prepResize() { + if(resize_timer) { + clearTimeout(resize_timer); + resize_timer = null; + } + if(!resize_done) { + resize_timer = setTimeout(function() { + resize_done = true; + setIconSize(curPrefs.iconsize); + }, 50); + } + } + + + var runCallback = function() { + if(ext.callback && !cb_called && cb_ready) { + cb_called = true; + ext.callback(); + } + } + + var btn_selects = []; + + if(ext.context_tools) { + $.each(ext.context_tools, function(i, tool) { + // Add select tool + var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):""; + + var panel = $('#' + tool.panel); + + // create the panel if it doesn't exist + if(!panel.length) + panel = $('<div>', {id: tool.panel}).appendTo("#tools_top").hide(); + + // TODO: Allow support for other types, or adding to existing tool + switch (tool.type) { + case 'tool_button': + var html = '<div class="tool_button">' + tool.id + '</div>'; + var div = $(html).appendTo(panel); + if (tool.events) { + $.each(tool.events, function(evt, func) { + $(div).bind(evt, func); + }); + } + break; + case 'select': + var html = '<label' + cont_id + '>' + + '<select id="' + tool.id + '">'; + $.each(tool.options, function(val, text) { + var sel = (val == tool.defval) ? " selected":""; + html += '<option value="'+val+'"' + sel + '>' + text + '</option>'; + }); + html += "</select></label>"; + // Creates the tool, hides & adds it, returns the select element + var sel = $(html).appendTo(panel).find('select'); + + $.each(tool.events, function(evt, func) { + $(sel).bind(evt, func); + }); + break; + case 'button-select': + var html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">' + + '<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>'; + + var list = $('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists'); + if(tool.colnum) { + list.addClass('optcols' + tool.colnum); + } + + // Creates the tool, hides & adds it, returns the select element + var dropdown = $(html).appendTo(panel).children(); + + btn_selects.push({ + elem: ('#' + tool.id), + list: ('#' + tool.id + '_opts'), + title: tool.title, + callback: tool.events.change, + cur: ('#cur_' + tool.id) + }); + + break; + case 'input': + var html = '<label' + cont_id + '>' + + '<span id="' + tool.id + '_label">' + + tool.label + ':</span>' + + '<input id="' + tool.id + '" title="' + tool.title + + '" size="' + (tool.size || "4") + '" value="' + (tool.defval || "") + '" type="text"/></label>' + + // Creates the tool, hides & adds it, returns the select element + + // Add to given tool.panel + var inp = $(html).appendTo(panel).find('input'); + + if(tool.spindata) { + inp.SpinButton(tool.spindata); + } + + if(tool.events) { + $.each(tool.events, function(evt, func) { + inp.bind(evt, func); + }); + } + break; + + default: + break; + } + }); + } + + if(ext.buttons) { + var fallback_obj = {}, + placement_obj = {}, + svgicons = ext.svgicons; + var holders = {}; + + + // Add buttons given by extension + $.each(ext.buttons, function(i, btn) { + var icon; + var id = btn.id; + var num = i; + // Give button a unique ID + while($('#'+id).length) { + id = btn.id + '_' + (++num); + } + if(!svgicons) { + icon = (btn.type == "menu") ? "" : $('<img src="' + btn.icon + '">'); + } else { + fallback_obj[id] = btn.icon; + var svgicon = btn.svgicon ? btn.svgicon : btn.id; + if(btn.type == 'app_menu') { + placement_obj['#' + id + ' > div'] = svgicon; + } else { + placement_obj['#' + id] = svgicon; + } + } + + var cls, parent; + + + + // Set button up according to its type + switch ( btn.type ) { + case 'mode_flyout': + case 'mode': + cls = 'tool_button'; + if(btn.cls) { + cls += " " + btn.cls; + } + parent = "#tools_left"; + break; + case 'context': + cls = 'tool_button'; + parent = "#" + btn.panel; + // create the panel if it doesn't exist + if(!$(parent).length) + $('<div>', {id: btn.panel}).appendTo("#tools_top"); + break; + case 'menu': + cls = 'menu_item tool_button'; + parent = "#" + (btn.after || btn.panel); + break; + case 'app_menu': + cls = ''; + parent = btn.parent || '#main_menu ul'; + // create the panel if it doesn't exist + if(!$(parent).length) + $('<div>', {id: btn.panel}).appendTo("#tools_top"); + break; + } + + var button = $((btn.list || btn.type == 'app_menu')?'<li/>':'<div/>') + .attr("id", id) + .attr("title", btn.title) + .addClass(cls); + if(!btn.includeWith && !btn.list) { + if("position" in btn) { + $(parent).children().eq(btn.position).before(button); + } else { + if (btn.type != "menu" || !btn.after) button.appendTo(parent); + else $(parent).after(button); + } + + if(btn.type =='mode_flyout') { + // Add to flyout menu / make flyout menu +// var opts = btn.includeWith; +// // opts.button, default, position + var ref_btn = $(button); + + var flyout_holder = ref_btn.parent(); + // Create a flyout menu if there isn't one already + if(!ref_btn.parent().hasClass('tools_flyout')) { + // Create flyout placeholder + var tls_id = ref_btn[0].id.replace('tool_','tools_') + var show_btn = ref_btn.clone() + .attr('id',tls_id + '_show') + .append($('<div>',{'class':'flyout_arrow_horiz'})); + + ref_btn.before(show_btn); + + // Create a flyout div + flyout_holder = makeFlyoutHolder(tls_id, ref_btn); + flyout_holder.data('isLibrary', true); + show_btn.data('isLibrary', true); + } + + + +// var ref_data = Actions.getButtonData(opts.button); + + placement_obj['#' + tls_id + '_show'] = btn.id; + // TODO: Find way to set the current icon using the iconloader if this is not default + + // Include data for extension button as well as ref button + var cur_h = holders['#'+flyout_holder[0].id] = [{ + sel: '#'+id, + fn: btn.events.click, + icon: btn.id, + //key: btn.key, + isDefault: true + }, ref_data]; + + } else if(btn.type == 'app_menu' || btn.type == 'menu') { + button.append(btn.title); + } + + } else if(btn.list) { + // Add button to list + button.addClass('push_button'); + $('#' + btn.list + '_opts').append(button); + if(btn.isDefault) { + $('#cur_' + btn.list).append(button.children().clone()); + var svgicon = btn.svgicon?btn.svgicon:btn.id; + placement_obj['#cur_' + btn.list] = svgicon; + } + } else if(btn.includeWith) { + // Add to flyout menu / make flyout menu + var opts = btn.includeWith; + // opts.button, default, position + var ref_btn = $(opts.button); + + var flyout_holder = ref_btn.parent(); + // Create a flyout menu if there isn't one already + if(!ref_btn.parent().hasClass('tools_flyout')) { + // Create flyout placeholder + var tls_id = ref_btn[0].id.replace('tool_','tools_') + var show_btn = ref_btn.clone() + .attr('id',tls_id + '_show') + .append($('<div>',{'class':'flyout_arrow_horiz'})); + + ref_btn.before(show_btn); + + // Create a flyout div + flyout_holder = makeFlyoutHolder(tls_id, ref_btn); + } + + var ref_data = Actions.getButtonData(opts.button); + + if(opts.isDefault) { + placement_obj['#' + tls_id + '_show'] = btn.id; + } + // TODO: Find way to set the current icon using the iconloader if this is not default + + // Include data for extension button as well as ref button + var cur_h = holders['#'+flyout_holder[0].id] = [{ + sel: '#'+id, + fn: btn.events.click, + icon: btn.id, + key: btn.key, + isDefault: btn.includeWith?btn.includeWith.isDefault:0 + }, ref_data]; + + // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} + + var pos = ("position" in opts)?opts.position:'last'; + var len = flyout_holder.children().length; + + // Add at given position or end + if(!isNaN(pos) && pos >= 0 && pos < len) { + flyout_holder.children().eq(pos).before(button); + } else { + flyout_holder.append(button); + cur_h.reverse(); + } + } + + if(!svgicons) { + button.append(icon); + } + + if(!btn.list) { + // Add given events to button + $.each(btn.events, function(name, func) { + if(name == "click") { + if(btn.type == 'mode') { + if(btn.includeWith) { + button.bind(name, func); + } else { + button.bind(name, function() { + if(toolButtonClick(button)) { + func(); + } + }); + } + if(btn.key) { + $(document).bind('keydown', btn.key, func); + if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']'); + } + } else { + button.bind(name, func); + } + } else { + button.bind(name, func); + } + }); + } + setupFlyouts(holders); + }); + + $.each(btn_selects, function() { + addAltDropDown(this.elem, this.list, this.callback, {seticon: true}); + }); + + if (svgicons) + cb_ready = false; // Delay callback + + $.svgIcons(svgicons, { + w:27, h:27, + id_match: false, + no_img: (!isWebkit), + fallback: fallback_obj, + placement: placement_obj, + callback: function(icons) { + // Non-ideal hack to make the icon match the current size + if(curPrefs.iconsize && curPrefs.iconsize != 'm') { + prepResize(); + } + cb_ready = true; // Ready for callback + runCallback(); + } + + }); + } + + runCallback(); + }; + + var getPaint = function(color, opac, type) { + // update the editor's fill paint + var opts = null; + if (color.indexOf("url(#") === 0) { + var refElem = svgCanvas.getRefElem(color); + if(refElem) { + refElem = refElem.cloneNode(true); + } else { + refElem = $("#" + type + "_color defs *")[0]; + } + + opts = { alpha: opac }; + opts[refElem.tagName] = refElem; + } + else if (color.indexOf("#") === 0) { + opts = { + alpha: opac, + solidColor: color.substr(1) + }; + } + else { + opts = { + alpha: opac, + solidColor: 'none' + }; + } + return new $.jGraduate.Paint(opts); + }; + + // set the canvas properties at init + var res = svgCanvas.getResolution(); + if(curConfig.baseUnit !== "px") { + res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; + res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; + } + + var createBackground = function(fill) { + svgCanvas.createLayer("background") + cur_shape = svgCanvas.addSvgElementFromJson({ + "element": "rect", + "attr": { + "x": -1, + "y": -1, + "width": res.w+2, + "height": res.h+2, + "stroke": "none", + "id": "canvas_background", + "opacity": 1, + "fill": fill || "#fff", + "style": "pointer-events:none" + } + }); + svgCanvas.setCurrentLayer("Layer 1") + svgCanvas.setCurrentLayerPosition("1") + } + + // create a new layer background if it doesn't exist + if (!document.getElementById('canvas_background')) createBackground(); + var fill = document.getElementById('canvas_background').getAttribute("fill"); + + // updates the toolbar (colors, opacity, etc) based on the selected element + // This function also updates the opacity and id elements that are in the context panel + var updateToolbar = function() { + if (selectedElement != null) { + switch ( selectedElement.tagName ) { + case 'use': + $(".context_panel").hide(); + $("#use_panel").show(); + break; + case 'image': + $(".context_panel").hide(); + $("#image_panel").show(); + break; + case 'foreignObject': + $(".context_panel").hide(); + break; + case 'g': + case 'a': + // Look for common styles + var gWidth = null; + + var childs = selectedElement.getElementsByTagName('*'); + for(var i = 0, len = childs.length; i < len; i++) { + var swidth = childs[i].getAttribute("stroke-width"); + if(i === 0) { + gWidth = swidth; + } else if(gWidth !== swidth) { + gWidth = null; + } + } + + $('#stroke_width').val(gWidth === null ? "0" : gWidth); + updateContextPanel(); + break; + default: + //removed because multiselect shouldnt set color + //Editor.paintBox.fill.update(false); + //Editor.paintBox.stroke.update(false); + + $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 0); + var dash = selectedElement.getAttribute("stroke-dasharray") || "none" + $('option', '#stroke_style').removeAttr('selected'); + $('#stroke_style option[value="'+ dash +'"]').attr("selected", "selected"); + $('#stroke_style').trigger('change'); + + $.fn.dragInput.updateCursor($('#stroke_width')[0]) + $.fn.dragInput.updateCursor($('#blur')[0]) + } + + } + + // All elements including image and group have opacity + if(selectedElement != null) { + var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100); + $('#group_opacity').val(opac_perc); + $.fn.dragInput.updateCursor($('#group_opacity')[0]) + } + }; + + var setImageURL = Editor.setImageURL = function(url) { + if(!url) url = default_img_url; + + svgCanvas.setImageURL(url); + $('#image_url').val(url); + } + + var setInputWidth = function(elem) { + var w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300); + $(elem).width(w); + } + + // updates the context panel tools based on the selected element + var updateContextPanel = function(e) { + var elem = selectedElement; + // If element has just been deleted, consider it null + if(elem != null && !elem.parentNode) elem = null; + if (multiselected && multiselected[0] != null && !multiselected[0].parentNode) multiselected = false; + + var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); + var currentMode = svgCanvas.getMode(); + var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; + var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; + + if (is_node) { + $('.context_panel').hide(); + $('#path_node_panel').show(); + $('#stroke_panel').hide(); + var point = path.getNodePoint(); + $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); + $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); + + // Show open/close button based on selected point + setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); + + if(point) { + var seg_type = $('#seg_type'); + if(unit) { + point.x = svgedit.units.convertUnit(point.x); + point.y = svgedit.units.convertUnit(point.y); + } + $('#path_node_x').val(Math.round(point.x)); + $('#path_node_y').val(Math.round(point.y)); + if(point.type) { + seg_type.val(point.type).removeAttr('disabled'); + $("#seg_type_label").html(point.type == 4 ? "Straight" : "Curve") + } else { + seg_type.val(4).attr('disabled','disabled'); + } + } + $("#tools_top").removeClass("multiselected") + $("#stroke_panel").hide(); + $("#canvas_panel").hide(); + return; + } + + var menu_items = $('#cmenu_canvas li'); + $('.context_panel').hide(); + $('.menu_item', '#edit_menu').addClass('disabled'); + $('.menu_item', '#object_menu').addClass('disabled'); + + + //hack to show the proper multialign box + if (multiselected) { + multiselected = multiselected.filter(Boolean); + elem = (svgCanvas.elementsAreSame(multiselected)) ? multiselected[0] : null + if (elem) $("#tools_top").addClass("multiselected") + } + + if (!elem && !multiselected) { + $("#tools_top").removeClass("multiselected") + $("#stroke_panel").hide(); + $("#canvas_panel").show(); + } + + if (elem != null) { + $("#stroke_panel").show(); + var elname = elem.nodeName; + var angle = svgCanvas.getRotationAngle(elem); + $('#angle').val(Math.round(angle)); + + var blurval = svgCanvas.getBlur(elem); + $('#blur').val(blurval); + if(!is_node && currentMode != 'pathedit') { + $('#selected_panel').show(); + $('.action_selected').removeClass('disabled'); + // Elements in this array already have coord fields + var x, y + if(['g', 'polyline', 'path'].indexOf(elname) >= 0) { + var bb = svgCanvas.getStrokedBBox([elem]); + if(bb) { + x = bb.x; + y = bb.y; + } + } + + if(unit) { + x = svgedit.units.convertUnit(x); + y = svgedit.units.convertUnit(y); + } + + $("#" + elname +"_x").val(Math.round(x)) + $("#" + elname +"_y").val(Math.round(y)) + if (elname === "polyline") { + //we're acting as if polylines were paths + $("#path_x").val(Math.round(x)) + $("#path_y").val(Math.round(y)) + } + + // Elements in this array cannot be converted to a path + var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1; + if (no_path) $('.action_path_convert_selected').removeClass('disabled'); + if (elname === "path") $('.action_path_selected').removeClass('disabled'); + + } + + var link_href = null; + if (el_name === 'a') { + link_href = svgCanvas.getHref(elem); + $('#g_panel').show(); + } + + if(elem.parentNode.tagName === 'a') { + if(!$(elem).siblings().length) { + $('#a_panel').show(); + link_href = svgCanvas.getHref(elem.parentNode); + } + } + + // Hide/show the make_link buttons + $('#tool_make_link, #tool_make_link').toggle(!link_href); + + if(link_href) { + $('#link_url').val(link_href); + } + + // update contextual tools here + var panels = { + g: [], + a: [], + rect: ['rx','width','height', 'x', 'y'], + image: ['width','height', 'x', 'y'], + circle: ['cx','cy','r'], + ellipse: ['cx','cy','rx','ry'], + line: ['x1','y1','x2','y2'], + text: ['x', 'y'], + 'use': [], + path : [] + }; + + var el_name = elem.tagName; + + if($(elem).data('gsvg')) { + $('#g_panel').show(); + } + + if (el_name == "path" || el_name == "polyline") { + $('#path_panel').show(); + } + + if(panels[el_name]) { + var cur_panel = panels[el_name]; + $('#' + el_name + '_panel').show(); + + // corner radius has to live in a different panel + // because otherwise it changes the position of the + // of the elements + if(el_name == "rect") $("#cornerRadiusLabel").show() + else $("#cornerRadiusLabel").hide() + + $.each(cur_panel, function(i, item) { + var attrVal = elem.getAttribute(item); + if(curConfig.baseUnit !== 'px' && elem[item]) { + var bv = elem[item].baseVal.value; + attrVal = svgedit.units.convertUnit(bv); + } + + //update the draginput cursors + var name_item = document.getElementById(el_name + '_' + item); + name_item.value = Math.round(attrVal) || 0; + if (name_item.getAttribute("data-cursor") === "true") { + $.fn.dragInput.updateCursor(name_item ); + } + }); + + if(el_name == 'text') { + var font_family = elem.getAttribute("font-family"); + var select = document.getElementById("font_family_dropdown"); + select.selectedIndex = 3 + + $('#text_panel').css("display", "inline"); + $('#tool_italic').toggleClass('active', svgCanvas.getItalic()) + $('#tool_bold').toggleClass('active', svgCanvas.getBold()) + $('#font_family').val(font_family); + $('#font_size').val(elem.getAttribute("font-size")); + $('#text').val(elem.textContent); + $('#preview_font').text(font_family.split(",")[0].replace(/'/g, "")).css('font-family', font_family); + if (svgCanvas.addedNew) { + // Timeout needed for IE9 + setTimeout(function() { + $('#text').focus().select(); + },100); + } + } // text + else if(el_name == 'image') { + setImageURL(svgCanvas.getHref(elem)); + } // image + else if(el_name === 'g' || el_name === 'use') { + $('#container_panel').show(); + $('.action_group_selected').removeClass('disabled'); + var title = svgCanvas.getTitle(); + } + } + menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup'); + menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group'); + } + + if (multiselected) { + $('#multiselected_panel').show(); + $('.action_multi_selected').removeClass('disabled'); + menu_items + .enableContextMenuItems('#group') + .disableContextMenuItems('#ungroup'); + } + + if (!elem) { + menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); + } + + // update history buttons + if (undoMgr.getUndoStackSize() > 0) { + $('#tool_undo').removeClass( 'disabled'); + } + else { + $('#tool_undo').addClass( 'disabled'); + } + if (undoMgr.getRedoStackSize() > 0) { + $('#tool_redo').removeClass( 'disabled'); + } + else { + $('#tool_redo').addClass( 'disabled'); + } + + svgCanvas.addedNew = false; + + if ( (elem && !is_node) || multiselected) { + // update the selected elements' layer + $('#selLayerNames').removeAttr('disabled').val(currentLayerName); + + // Enable regular menu options + canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); + } + }; + + $('#text').on("focus", function(e){ textBeingEntered = true; } ); + $('#text').on("blur", function(){ textBeingEntered = false; } ); + + // bind the selected event to our function that handles updates to the UI + svgCanvas.bind("selected", selectedChanged); + svgCanvas.bind("transition", elementTransition); + svgCanvas.bind("changed", elementChanged); + svgCanvas.bind("exported", exportHandler); + svgCanvas.bind("zoomed", zoomChanged); + svgCanvas.bind("contextset", contextChanged); + svgCanvas.bind("extension_added", extAdded); + svgCanvas.textActions.setInputElem($("#text")[0]); + + var str = '<div class="palette_item transparent" data-rgb="none"></div>\ + <div class="palette_item black" data-rgb="#000000"></div>\ + <div class="palette_item white" data-rgb="#ffffff"></div>' + palette.forEach(function(item, i){ + str += '<div class="palette_item" style="background-color: ' + item + ';" data-rgb="' + item + '"></div>'; + }); + $('#palette').append(str); + + var changeFontSize = function(ctl) { + svgCanvas.setFontSize(ctl.value); + } + + var changeStrokeWidth = function(ctl) { + var val = ctl.value; + if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) { + val = ctl.value = 1; + } + svgCanvas.setStrokeWidth(val); + } + + //cache + var $indicator = $('#tool_angle_indicator') + var $reorient = $('#tool_reorient') + + rotateCursor = function(angle){ + var rotate_string = 'rotate('+ angle + 'deg)' + $indicator.css({ + '-webkit-transform': rotate_string, + '-moz-transform': rotate_string, + '-o-transform': rotate_string, + '-ms-transform': rotate_string, + 'transform': rotate_string + }); + } + + var changeRotationAngle = function(ctl) { + var preventUndo = true; + svgCanvas.setRotationAngle(ctl.value, preventUndo); + rotateCursor(ctl.value) + $('#tool_reorient').toggleClass('disabled', ctl.value == 0); + } + + var changeZoom = function(ctl) { + var zoomlevel = ctl.value / 100; + if(zoomlevel < .001) { + ctl.value = .1; + return; + } + var zoom = svgCanvas.getZoom(); + var w_area = workarea; + zoomChanged(window, { + width: 0, + height: 0, + // center pt of scroll position + x: (w_area[0].scrollLeft + w_area.width()/2)/zoom, + y: (w_area[0].scrollTop + w_area.height()/2)/zoom, + zoom: zoomlevel + }, true); + } + + var changeBlur = function(ctl, completed) { + val = ctl.value; + $('#blur').val(val); + if (completed) { + svgCanvas.setBlur(val, true); + } + else { + svgCanvas.setBlurNoUndo(val); + } + } + + var operaRepaint = function() { + // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change + if(!window.opera) return; + $('<p/>').hide().appendTo('body').remove(); + } + + $('#stroke_style').change(function(){ + svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val()); + $("#stroke_style_label").html(this.options[this.selectedIndex].text) + operaRepaint(); + }); + + $('#seg_type').change(function() { + svgCanvas.setSegType($(this).val()); + $("#seg_type_label").html(this.options[this.selectedIndex].text) + }); + + // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) + $('select').change(function(){$(this).blur();}); + + $('#font_family').change(function() { + svgCanvas.setFontFamily(this.value); + }); + + $('#text').keyup(function(){ + svgCanvas.setTextContent(this.value); + }); + + changeAttribute = function(el, completed) { + var attr = el.getAttribute("data-attr"); + var multiplier = el.getAttribute("data-multiplier") || 1; + multiplier = parseFloat(multiplier); + var val = el.value * multiplier; + var valid = svgedit.units.isValidUnit(attr, val, selectedElement); + if(!valid) { + $.alert("Invalid value given"); + el.value = selectedElement.getAttribute(attr); + return false; + } + //if (!noUndo) svgCanvas.changeSelectedAttribute(attr, val); + svgCanvas.changeSelectedAttributeNoUndo(attr, val); + }; + + picking = false; + $(document).on("mouseup", function(){picking = false;}) + + $('#palette').on("mousemove mousedown touchstart touchmove", ".palette_item", function(evt){ + evt.preventDefault(); + + if (evt.type == "mousedown") picking = true; + if (picking) { + var isStroke = $('#tool_stroke').hasClass('active'); + var picker = isStroke ? "stroke" : "fill"; + var color = $(this).attr('data-rgb'); + var paint = null; + var noUndo = true; + if (evt.type == "mousedown") noUndo = false + // Webkit-based browsers returned 'initial' here for no stroke + if (color === 'transparent' || color === 'initial' || color === '#none') { + color = 'none'; + paint = new $.jGraduate.Paint(); + } + else { + paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)}); + } + + Editor.paintBox[picker].setPaint(paint); + + if (isStroke) { + svgCanvas.setColor('stroke', color, noUndo); + if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) { + svgCanvas.setPaintOpacity('stroke', 1.0); + } + } else { + svgCanvas.setColor('fill', color, noUndo); + if (color != 'none' && svgCanvas.getFillOpacity() != 1) { + svgCanvas.setPaintOpacity('fill', 1.0); + } + } + } + }).bind('contextmenu', function(e) {e.preventDefault()}); + + $("#toggle_stroke_tools").toggle(function() { + $(".stroke_tool").css('display','table-cell'); + $(this).addClass('expanded'); + resetScrollPos(); + }, function() { + $(".stroke_tool").css('display','none'); + $(this).removeClass('expanded'); + resetScrollPos(); + }); + + // This is a common function used when a tool has been clicked (chosen) + // It does several common things: + // - removes the tool_button_current class from whatever tool currently has it + // - hides any flyouts + // - adds the tool_button_current class to the button passed in + var toolButtonClick = function(button, noHiding) { + if ($(button).hasClass('disabled')) return false; + if($(button).parent().hasClass('tools_flyout')) return true; + var fadeFlyouts = fadeFlyouts || 'normal'; + if(!noHiding) { + $('.tools_flyout').fadeOut(fadeFlyouts); + } + $('#styleoverrides').text(''); + $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); + $(button).addClass('tool_button_current').removeClass('tool_button'); + return true; + }; + + (function() { + var last_x = null, last_y = null, w_area = workarea[0], + panning = false, keypan = false; + + var move_pan = function(evt) { + if(panning === false) return; + + w_area.scrollLeft -= (evt.clientX - last_x); + w_area.scrollTop -= (evt.clientY - last_y); + last_x = evt.clientX; + last_y = evt.clientY; + if(evt.type === 'mouseup' || evt.type === 'touchend') panning = false; + return false; + } + + var start_pan = function(evt) { + if(evt.button === 1 || keypan === true || (evt.originalEvent.touches && evt.originalEvent.touches.length >= 2)) { + panning = true; + last_x = evt.clientX; + last_y = evt.clientY; + return false; + } + } + + $('#svgcanvas') + .on('mousemove mouseup touchend', move_pan) + .on("mousedown touchmove", start_pan) + + $(window).mouseup(function() { + panning = false; + }); + + $(document).bind('keydown', 'space', function(evt) { + evt.preventDefault(); + svgCanvas.spaceKey = keypan = true; + + }).bind('keyup', 'space', function(evt) { + evt.preventDefault(); + svgCanvas.spaceKey = keypan = false; + }).bind('keydown', 'alt', function(evt) { + if(svgCanvas.getMode() === 'zoom') { + workarea.addClass('out'); + } + }).bind('keyup', 'alt', function(evt) { + if(svgCanvas.getMode() === 'zoom') { + workarea.removeClass('out'); + } + }) + }()); + + + function setStrokeOpt(opt, changeElem) { + var id = opt.id; + var bits = id.split('_'); + var pre = bits[0]; + var val = bits[1]; + + if(changeElem) { + svgCanvas.setStrokeAttr('stroke-' + pre, val); + } + operaRepaint(); + setIcon('#cur_' + pre , id, 20); + $(opt).addClass('current').siblings().removeClass('current'); + } + + //menu handling + var menus = $('.menu'); + var blinker = function(e) { + e.target.style.background = "#fff"; + setTimeout(function(){e.target.style.background = "#ddd";}, 50); + setTimeout(function(){e.target.style.background = "#fff";}, 150); + setTimeout(function(){e.target.style.background = "#ddd";}, 200); + setTimeout(function(){e.target.style.background = "";}, 200); + setTimeout(function(){$('#menu_bar').removeClass('active')}, 220); + return false; + } + var closer = function(e){ + if (e.target.nodeName && e.target.nodeName.toLowerCase() === "input") return false; + if (!$(e.target).hasClass("menu_title") && !$(e.target).parent().hasClass("menu_title")) { + if(!$(e.target).hasClass("disabled") && $(e.target).hasClass("menu_item")) blinker(e) + else $('#menu_bar').removeClass('active') + + } + } + + $('.menu_item').on('mousedown touchstart', function(e){blinker(e)}); + $("svg, body").on('mousedown touchstart', function(e){closer(e)}); + + var accumulatedDelta = 0 + $('#workarea').on('mousewheel', function(e, delta, deltaX, deltaY){ + if (e.altKey || e.ctrlKey) { + e.preventDefault(); + zoom = parseInt($("#zoom").val()) + $("#zoom").val(parseInt(zoom + deltaY*(e.altKey ? 10 : 5))).change() + } + }); + + $('.menu_title') + .on('mousedown', function() { + $("#tools_shapelib").hide() + $("#menu_bar").toggleClass('active'); + menus.removeClass('open'); + $(this).parent().addClass('open'); + }) + .on('mouseover', function() { + menus.removeClass('open'); + $(this).parent().addClass('open'); + }); + + + // Made public for UI customization. + // TODO: Group UI functions into a public methodDraw.ui interface. + Editor.addDropDown = function(elem, callback, dropUp) { + if ($(elem).length == 0) return; // Quit if called on non-existant element + var button = $(elem).find('button'); + + var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list'); + + if(!dropUp) { + // Move list to place where it can overflow container + $('#option_lists').append(list); + } + + var on_button = false; + if(dropUp) { + $(elem).addClass('dropup'); + } + + list.find('li').bind('mouseup', callback); + + $(window).mouseup(function(evt) { + if(!on_button) { + button.removeClass('down'); + list.hide(); + } + on_button = false; + }); + + button.bind('mousedown',function() { + if (!button.hasClass('down')) { + button.addClass('down'); + + if(!dropUp) { + var pos = $(elem).offset(); + // position slider + list.css({ + top: pos.top, + left: pos.left - 110 + }); + } + list.show(); + + on_button = true; + } else { + button.removeClass('down'); + list.hide(); + } + }).hover(function() { + on_button = true; + }).mouseout(function() { + on_button = false; + }); + } + + // TODO: Combine this with addDropDown or find other way to optimize + var addAltDropDown = function(elem, list, callback, opts) { + var button = $(elem); + var list = $(list); + var on_button = false; + var dropUp = opts.dropUp; + if(dropUp) { + $(elem).addClass('dropup'); + } + list.find('li').bind('mouseup', function() { + if(opts.seticon) { + setIcon('#cur_' + button[0].id , $(this).children()); + $(this).addClass('current').siblings().removeClass('current'); + } + callback.apply(this, arguments); + + }); + + $(window).mouseup(function(evt) { + if(!on_button) { + button.removeClass('down'); + list.hide(); + list.css({top:0, left:0}); + } + on_button = false; + }); + + var height = list.height(); + $(elem).bind('mousedown',function() { + var off = $(elem).offset(); + if(dropUp) { + off.top -= list.height(); + off.left += 8; + } else { + off.top += $(elem).height(); + } + $(list).offset(off); + + if (!button.hasClass('down')) { + button.addClass('down'); + list.show(); + on_button = true; + return false; + } else { + button.removeClass('down'); + // CSS position must be reset for Webkit + list.hide(); + list.css({top:0, left:0}); + } + }).hover(function() { + on_button = true; + }).mouseout(function() { + on_button = false; + }); + + if(opts.multiclick) { + list.mousedown(function() { + on_button = true; + }); + } + } + + $('#font_family_dropdown').change(function() { + var fam = this.options[this.selectedIndex].value + var fam_display = this.options[this.selectedIndex].text + $('#preview_font').html(fam_display).css("font-family", fam); + $('#font_family').val(fam).change(); + }); + + $('div', '#position_opts').each(function(){ + this.addEventListener("mouseup", function(){ + var letter = this.id.replace('tool_pos','').charAt(0); + svgCanvas.alignSelectedElements(letter, 'page'); + }) + }); + + /* + + When a flyout icon is selected + (if flyout) { + - Change the icon + - Make pressing the button run its stuff + } + - Run its stuff + + When its shortcut key is pressed + - If not current in list, do as above + , else: + - Just run its stuff + + */ + + // Unfocus text input when workarea is mousedowned. + (function() { + var inp; + var unfocus = function() { + $(inp).blur(); + } + + $('#svg_editor').find('button, select, input:not(#text)').focus(function() { + inp = this; + ui_context = 'toolbars'; + workarea.mousedown(unfocus); + }).blur(function() { + ui_context = 'canvas'; + workarea.unbind('mousedown', unfocus); + // Go back to selecting text if in textedit mode + if(svgCanvas.getMode() == 'textedit') { + $('#text').focus(); + } + }); + + }()); + + var clickSelect = function() { + if (toolButtonClick('#tool_select')) { + svgCanvas.setMode('select'); + } + }; + + var clickFHPath = function() { + if (toolButtonClick('#tool_fhpath')) { + svgCanvas.setMode('fhpath'); + } + }; + + var clickLine = function() { + if (toolButtonClick('#tool_line')) { + svgCanvas.setMode('line'); + } + }; + + var clickSquare = function(){ + if (toolButtonClick('#tool_square')) { + svgCanvas.setMode('square'); + } + }; + + var clickRect = function(){ + if (toolButtonClick('#tool_rect')) { + svgCanvas.setMode('rect'); + } + }; + + var clickFHRect = function(){ + if (toolButtonClick('#tool_fhrect')) { + svgCanvas.setMode('fhrect'); + } + }; + + var clickCircle = function(){ + if (toolButtonClick('#tool_circle')) { + svgCanvas.setMode('circle'); + } + }; + + var clickEllipse = function(){ + if (toolButtonClick('#tool_ellipse')) { + svgCanvas.setMode('ellipse'); + } + }; + + var clickFHEllipse = function(){ + if (toolButtonClick('#tool_fhellipse')) { + svgCanvas.setMode('fhellipse'); + } + }; + + var clickImage = function(){ + if (toolButtonClick('#tool_image')) { + svgCanvas.setMode('image'); + } + }; + + var clickZoom = function(){ + if (toolButtonClick('#tool_zoom')) { + svgCanvas.setMode('zoom'); + } + }; + + var dblclickZoom = function(){ + if (toolButtonClick('#tool_zoom')) { + zoomImage(); + setSelectMode(); + } + }; + + var clickText = function(){ + if (toolButtonClick('#tool_text')) { + svgCanvas.setMode('text'); + } + }; + + var clickPath = function(){ + if (toolButtonClick('#tool_path')) { + svgCanvas.setMode('path'); + } + }; + + // Delete is a contextual tool that only appears in the ribbon if + // an element has been selected + var deleteSelected = function() { + if (selectedElement != null || multiselected) { + svgCanvas.deleteSelectedElements(); + } + if (path.getNodePoint()) { + path.deletePathNode(); + } + }; + + var cutSelected = function() { + if (selectedElement != null || multiselected) { + flash($('#edit_menu')); + svgCanvas.cutSelectedElements(); + } + }; + + var copySelected = function() { + if (selectedElement != null || multiselected) { + flash($('#edit_menu')); + svgCanvas.copySelectedElements(); + } + }; + + var pasteSelected = function() { + flash($('#edit_menu')); + var zoom = svgCanvas.getZoom(); + var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW; + var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH; + svgCanvas.pasteElements('point', x, y); + } + + var moveToTopSelected = function() { + if (selectedElement != null) { + flash($('#object_menu')); + svgCanvas.moveToTopSelectedElement(); + } + }; + + var moveToBottomSelected = function() { + if (selectedElement != null) { + flash($('#object_menu')); + svgCanvas.moveToBottomSelectedElement(); + } + }; + + var moveUpSelected = function() { + if (selectedElement != null) { + flash($('#object_menu')); + svgCanvas.moveUpDownSelected("Up"); + } + }; + + var moveDownSelected = function() { + if (selectedElement != null) { + flash($('#object_menu')); + svgCanvas.moveUpDownSelected("Down"); + } + }; + + var moveUpDownSelected = function(dir) { + if (selectedElement != null) { + flash($('#object_menu')); + svgCanvas.moveUpDownSelected(dir); + } + }; + + var convertToPath = function() { + if (selectedElement != null) { + svgCanvas.convertToPath(); + var elems = svgCanvas.getSelectedElems() + svgCanvas.selectorManager.requestSelector(elems[0]).reset(elems[0]) + svgCanvas.selectorManager.requestSelector(elems[0]).selectorRect.setAttribute("display", "none"); + svgCanvas.setMode("pathedit") + path.toEditMode(elems[0]); + svgCanvas.clearSelection(); + updateContextPanel(); + } + } + + var reorientPath = function() { + if (selectedElement != null) { + path.reorient(); + } + } + + var makeHyperlink = function() { + if (selectedElement != null || multiselected) { + $.prompt("Enter the new hyperlink URL", "http://", function(url) { + if(url) svgCanvas.makeHyperlink(url); + }); + } + } + + var moveSelected = function(dx,dy) { + if (selectedElement != null || multiselected) { + if(curConfig.gridSnapping) { + // Use grid snap value regardless of zoom level + var multi = svgCanvas.getZoom() * curConfig.snappingStep; + dx *= multi; + dy *= multi; + } + $('input').blur() + svgCanvas.moveSelectedElements(dx,dy); + } + }; + + var linkControlPoints = function() { + // var linked = document.getElementById('tool_node_link').checked; + // path.linkControlPoints(linked); + } + + var clonePathNode = function() { + if (path.getNodePoint()) { + path.clonePathNode(); + } + }; + + var deletePathNode = function() { + if (path.getNodePoint()) { + path.deletePathNode(); + } + }; + + var addSubPath = function() { + var button = $('#tool_add_subpath'); + var sp = !button.hasClass('push_button_pressed'); + if (sp) { + button.addClass('push_button_pressed').removeClass('tool_button'); + } else { + button.removeClass('push_button_pressed').addClass('tool_button'); + } + + path.addSubPath(sp); + + }; + + var opencloseSubPath = function() { + path.opencloseSubPath(); + } + + var selectNext = function() { + svgCanvas.cycleElement(1); + }; + + var selectPrev = function() { + svgCanvas.cycleElement(0); + }; + + var rotateSelected = function(cw,step) { + if (selectedElement == null || multiselected) return; + if(!cw) step *= -1; + var new_angle = $('#angle').val()*1 + step; + svgCanvas.setRotationAngle(new_angle); + updateContextPanel(); + }; + + var clickClear = function(){ + var dims = curConfig.dimensions; + $.confirm("<strong>Do you want to clear the drawing?</strong>\nThis will also erase your undo history", function(ok) { + if(!ok) return; + setSelectMode(); + svgCanvas.deleteSelectedElements(); + svgCanvas.clear(); + svgCanvas.setResolution(dims[0], dims[1]); + updateCanvas(true); + createBackground(); + zoomImage(); + updateContextPanel(); + prepPaints(); + svgCanvas.runExtensions('onNewDocument'); + }); + }; + + var clickBold = function(){ + svgCanvas.setBold( !svgCanvas.getBold() ); + updateContextPanel(); + }; + + var clickItalic = function(){ + svgCanvas.setItalic( !svgCanvas.getItalic() ); + updateContextPanel(); + }; + + var clickExport = function() { + if(window.canvg) { + svgCanvas.rasterExport(); + } else { + $.getScript('/js/lib/rgbcolor.js', function() { + $.getScript('/js/lib/canvg.js', function() { + svgCanvas.rasterExport(); + }); + }); + } + } + + // by default, svgCanvas.open() is a no-op. + // it is up to an extension mechanism (opera widget, etc) + // to call setCustomHandlers() which will make it do something + var clickOpen = function(){ + svgCanvas.open(); + }; + var clickImport = function(){ + }; + + var flash = function($menu){ + var menu_title = $menu.prev(); + menu_title.css({ + "background": "white", + "color": "black" + }); + setTimeout(function(){menu_title.removeAttr("style")}, 200); + } + + var clickUndo = function(){ + if (undoMgr.getUndoStackSize() > 0) { + flash($('#edit_menu')); + undoMgr.undo(); + } + }; + + var clickRedo = function(){ + if (undoMgr.getRedoStackSize() > 0) { + flash($('#edit_menu')); + undoMgr.redo(); + } + }; + + var clickGroup = function(){ + // group + if (multiselected) { + flash($('#object_menu')); + svgCanvas.groupSelectedElements(); + } + // ungroup + else if(selectedElement){ + flash($('#object_menu')); + svgCanvas.ungroupSelectedElement(); + } + }; + + var clickClone = function(){ + flash($('#edit_menu')); + svgCanvas.cloneSelectedElements(20,20); + }; + + var clickAlign = function() { + var letter = this.id.replace('tool_align','').charAt(0); + svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val()); + }; + + var clickSwitch = function() { + var stroke_rect = document.querySelector('#tool_stroke rect'); + $("#tool_stroke").toggleClass('active') + $("#tool_fill").toggleClass('active') + var fill_rect = document.querySelector('#tool_fill rect'); + var fill_color = fill_rect.getAttribute("fill"); + var stroke_color = stroke_rect.getAttribute("fill"); + var stroke_opacity = parseFloat(stroke_rect.getAttribute("stroke-opacity")); + if (isNaN(stroke_opacity)) {stroke_opacity = 100;} + var fill_opacity = parseFloat(fill_rect.getAttribute("fill-opacity")); + if (isNaN(fill_opacity)) {fill_opacity = 100;} + var stroke = getPaint(stroke_color, stroke_opacity, "stroke"); + var fill = getPaint(fill_color, fill_opacity, "fill"); + Editor.paintBox.fill.setPaint(stroke, true); + Editor.paintBox.stroke.setPaint(fill, true); + + }; + + var zoomImage = function(multiplier) { + var res = svgCanvas.getResolution(); + multiplier = multiplier?res.zoom * multiplier:1; + // setResolution(res.w * multiplier, res.h * multiplier, true); + $('#zoom').val(multiplier * 100); + svgCanvas.setZoom(multiplier); + zoomDone(); + updateCanvas(true); + }; + + var zoomDone = function() { + // updateBgImage(); + updateWireFrame(); + //updateCanvas(); // necessary? + } + + var clickWireframe = function() { + flash($('#view_menu')); + var wf = !$('#tool_wireframe').hasClass('push_button_pressed'); + if (wf) + $('#tool_wireframe').addClass('push_button_pressed'); + else + $('#tool_wireframe').removeClass('push_button_pressed'); + workarea.toggleClass('wireframe'); + + if(supportsNonSS) return; + var wf_rules = $('#wireframe_rules'); + if(!wf_rules.length) { + wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head'); + } else { + wf_rules.empty(); + } + + updateWireFrame(); + } + + var clickSnapGrid = function() { + flash($('#view_menu')); + var sg = !$('#tool_snap').hasClass('push_button_pressed'); + if (sg) + $('#tool_snap').addClass('push_button_pressed'); + else + $('#tool_snap').removeClass('push_button_pressed'); + curConfig.gridSnapping = sg; + } + + var minimizeModal = function() { + + if (window.self != window.top) { //we're in an iframe + top.exit_fullscreen(); + } + } + + var clickRulers = function() { + flash($('#view_menu')); + var rulers = !$('#tool_rulers').hasClass('push_button_pressed'); + if (rulers) { + $('#tool_rulers').addClass('push_button_pressed'); + $('#show_rulers').attr("checked", true); + curConfig.showRulers = true; + } + else { + $('#tool_rulers').removeClass('push_button_pressed'); + $('#show_rulers').attr("checked", false); + curConfig.showRulers = false; + } + $('#rulers').toggle(!!curConfig.showRulers) + } + + var updateWireFrame = function() { + // Test support + if(supportsNonSS) return; + + var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }"; + $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); + } + + var showSourceEditor = function(e, forSaving){ + if (editingsource) return; + flash($('#view_menu')); + editingsource = true; + + $('#save_output_btns').toggle(!!forSaving); + $('#tool_source_back').toggle(!forSaving); + + var str = orig_source = svgCanvas.getSvgString(); + $('#svg_source_textarea').val(str); + $('#svg_source_editor').fadeIn(); + $('#svg_source_textarea').focus().select(); + }; + + var clickSave = function(){ + flash($('#file_menu')); + // In the future, more options can be provided here + var saveOpts = { + 'images': curPrefs.img_save, + 'round_digits': 6 + } + svgCanvas.save(saveOpts); + }; + + var saveSourceEditor = function(){ + if (!editingsource) return; + + var saveChanges = function() { + svgCanvas.clearSelection(); + hideSourceEditor(); + zoomImage(); + prepPaints(); + } + + if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { + $.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?", function(ok) { + if(!ok) return false; + saveChanges(); + }); + } else { + saveChanges(); + } + setSelectMode(); + }; + + function setBackground(color, url) { +// if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; + $.pref('bkgd_color', color); + $.pref('bkgd_url', url); + + // This should be done in svgcanvas.js for the borderRect fill + svgCanvas.setBackground(color, url); + } + + var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { + var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone(); + if(!icon) { + console.log('NOTE: Icon image missing: ' + icon_id); + return; + } + + $(elem).find("img").replaceWith(icon); + } + + var ua_prefix; + (ua_prefix = function() { + var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/; + var someScript = document.getElementsByTagName('script')[0]; + for(var prop in someScript.style) { + if(regex.test(prop)) { + // test is faster than match, so it's better to perform + // that on the lot and match only when necessary + return prop.match(regex)[0]; + } + } + + // Nothing found so far? + if('WebkitOpacity' in someScript.style) return 'Webkit'; + if('KhtmlOpacity' in someScript.style) return 'Khtml'; + + return ''; + }()); + + var scaleElements = function(elems, scale) { + var prefix = '-' + ua_prefix.toLowerCase() + '-'; + + var sides = ['top', 'left', 'bottom', 'right']; + + elems.each(function() { +// console.log('go', scale); + + // Handled in CSS + // this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')'; + + var el = $(this); + + var w = el.outerWidth() * (scale - 1); + var h = el.outerHeight() * (scale - 1); + var margins = {}; + + for(var i = 0; i < 4; i++) { + var s = sides[i]; + + var cur = el.data('orig_margin-' + s); + if(cur == null) { + cur = parseInt(el.css('margin-' + s)); + // Cache the original margin + el.data('orig_margin-' + s, cur); + } + var val = cur * scale; + if(s === 'right') { + val += w; + } else if(s === 'bottom') { + val += h; + } + + el.css('margin-' + s, val); +// el.css('outline', '1px solid red'); + } + }); + } + + var setIconSize = Editor.setIconSize = function(size, force) { + if(size == curPrefs.size && !force) return; +// return; +// var elems = $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open'); + + var sel_toscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,\ + #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\ + #g_panel > *, #tool_font_size > *, .tools_flyout'; + + var elems = $(sel_toscale); + + var scale = 1; + + if(typeof size == 'number') { + scale = size; + } else { + var icon_sizes = { s:.75, m:1, l:1.25, xl:1.5 }; + scale = icon_sizes[size]; + } + + Editor.tool_scale = tool_scale = scale; + + setFlyoutPositions(); + var hidden_ps = elems.parents(':hidden'); + hidden_ps.css('visibility', 'hidden').show(); + scaleElements(elems, scale); + hidden_ps.css('visibility', 'visible').hide(); + + var rule_elem = $('#tool_size_rules'); + if(!rule_elem.length) { + rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head'); + } else { + rule_elem.empty(); + } + + if(size != 'm') { + var style_str = ''; + $.each(cssResizeRules, function(selector, rules) { + selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); + style_str += selector + '{'; + $.each(rules, function(prop, values) { + if(typeof values === 'number') { + var val = (values * scale) + 'px'; + } else if(values[size] || values.all) { + var val = (values[size] || values.all); + } + style_str += (prop + ':' + val + ';'); + }); + style_str += '}'; + }); + //this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')'; + var prefix = '-' + ua_prefix.toLowerCase() + '-'; + style_str += (sel_toscale + '{' + prefix + 'transform: scale(' + scale + ');}' + + ' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' // Hack for markers + + ' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + (1/scale) + ');}' // Hack for sliders + ); + rule_elem.text(style_str); + } + + setFlyoutPositions(); + } + + var cancelOverlays = function() { + $('#dialog_box').hide(); + if (!editingsource && !docprops && !preferences) { + if(cur_context) { + svgCanvas.leaveContext(); + } + return; + }; + + if (editingsource) { + if (orig_source !== $('#svg_source_textarea').val()) { + $.confirm("Ignore changes made to SVG source?", function(ok) { + if(ok) hideSourceEditor(); + }); + } else { + hideSourceEditor(); + } + } + else if (docprops) { + hideDocProperties(); + } else if (preferences) { + hidePreferences(); + } + resetScrollPos(); + }; + + var hideSourceEditor = function(){ + $('#svg_source_editor').hide(); + editingsource = false; + $('#svg_source_textarea').blur(); + }; + + var win_wh = {width:$(window).width(), height:$(window).height()}; + + var resetScrollPos = $.noop, curScrollPos; + + /* Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) + if(svgedit.browser.isIE()) { + (function() { + resetScrollPos = function() { + if(workarea[0].scrollLeft === 0 + && workarea[0].scrollTop === 0) { + workarea[0].scrollLeft = curScrollPos.left; + workarea[0].scrollTop = curScrollPos.top; + } + } + + curScrollPos = { + left: workarea[0].scrollLeft, + top: workarea[0].scrollTop + }; + + $(window).resize(resetScrollPos); + methodDraw.ready(function() { + // TODO: Find better way to detect when to do this to minimize + // flickering effect + setTimeout(function() { + resetScrollPos(); + }, 500); + }); + + workarea.scroll(function() { + curScrollPos = { + left: workarea[0].scrollLeft, + top: workarea[0].scrollTop + }; + }); + }()); + }*/ + + $(window).resize(function(evt) { + updateCanvas(); + }); + + (function() { + workarea.scroll(function() { + // TODO: jQuery's scrollLeft/Top() wouldn't require a null check + if ($('#ruler_x').length != 0) { + $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; + } + if ($('#ruler_y').length != 0) { + $('#ruler_y')[0].scrollTop = workarea[0].scrollTop; + } + }); + + }()); + + $('#url_notice').click(function() { + $.alert(this.title); + }); + + $('#change_image_url').click(promptImgURL); + + function promptImgURL() { + var curhref = svgCanvas.getHref(selectedElement); + curhref = curhref.indexOf("data:") === 0?"":curhref; + $.prompt("Enter the new image URL", curhref, function(url) { + if(url) setImageURL(url); + }); + } + + // TODO: go back to the color boxes having white background-color and then setting + // background-image to none.png (otherwise partially transparent gradients look weird) + var colorPicker = function(elem) { + var picker = elem[0].id == 'stroke_color' ? 'stroke' : 'fill'; + var is_background = elem[0].id == "canvas_color" + if (is_background) picker = 'canvas' +// var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); + var paint = Editor.paintBox[picker].paint; + + var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity'); + var was_none = false; + var pos = is_background ? {'right': 175, 'top': 50} : {'left': 50, 'bottom': 50} + + $("#color_picker") + .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'}) + .removeAttr("style") + .css(pos) + .jGraduate( + { + paint: paint, + window: { pickerTitle: title }, + images: { clientPath: curConfig.jGraduatePath }, + newstop: 'inverse' + }, + function(p) { + paint = new $.jGraduate.Paint(p); + + Editor.paintBox[picker].setPaint(paint); + svgCanvas.setPaint(picker, paint); + + $('#color_picker').hide(); + }, + function(p) { + $('#color_picker').hide(); + }); + }; + + var PaintBox = function(container, type) { + var background = document.getElementById("canvas_background"); + var cur = {color: "fff", opacity: 1} + if (type == "stroke") cur = curConfig['initStroke']; + if (type == "fill") cur = curConfig['initFill']; + if (type == "canvas" && background) { + var rgb = background.getAttribute("fill").match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); + if (rgb) { + var hex = ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) + + ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) + + ("0" + parseInt(rgb[3],10).toString(16)).slice(-2); + cur = {color: hex, opacity: 1} + } + } + + // set up gradients to be used for the buttons + var svgdocbox = new DOMParser().parseFromString( + '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\ + fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\ + <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml'); + var docElem = svgdocbox.documentElement; + + docElem = $(container)[0].appendChild(document.importNode(docElem, true)); + if (type === 'canvas') docElem.setAttribute('width',60.5); + else docElem.setAttribute('width',"100%"); + + this.rect = docElem.firstChild; + this.defs = docElem.getElementsByTagName('defs')[0]; + this.grad = this.defs.firstChild; + this.paint = new $.jGraduate.Paint({solidColor: cur.color}); + this.type = type; + + this.setPaint = function(paint, apply, noUndo) { + this.paint = paint; + var fillAttr = "none"; + var ptype = paint.type; + var opac = paint.alpha / 100; + switch ( ptype ) { + case 'solidColor': + fillAttr = (paint[ptype] == 'none' || paint[ptype] == 'one') ? 'none' : "#" + paint[ptype]; + break; + case 'linearGradient': + case 'radialGradient': + this.defs.removeChild(this.grad); + this.grad = this.defs.appendChild(paint[ptype]); + var id = this.grad.id = 'gradbox_' + this.type; + fillAttr = "url(#" + id + ')'; + } + this.rect.setAttribute('fill', fillAttr); + this.rect.setAttribute('opacity', opac); + + if (this.type == "canvas") { + //recache background in case it changed + var background = document.getElementById("canvas_background"); + if (background) { + res = svgCanvas.getResolution() + background.setAttribute("x", -1); + background.setAttribute("y", -1); + background.setAttribute("width", res.w+2); + background.setAttribute("height", res.h+2); + if (fillAttr.indexOf("url") == -1) background.setAttribute('fill', fillAttr) + } + else createBackground(fillAttr) + } + + if(apply) { + svgCanvas.setColor(this.type, fillAttr, true); + svgCanvas.setPaintOpacity(this.type, opac, true); + } + + } + + this.update = function(apply) { + if(!selectedElement) return; + var type = this.type; + switch ( selectedElement.tagName ) { + case 'use': + case 'image': + case 'foreignObject': + // These elements don't have fill or stroke, so don't change + // the current value + return; + case 'g': + case 'a': + var gPaint = null; + + var childs = selectedElement.getElementsByTagName('*'); + for(var i = 0, len = childs.length; i < len; i++) { + var elem = childs[i]; + var p = elem.getAttribute(type); + if(i === 0) { + gPaint = p; + } else if(gPaint !== p) { + gPaint = null; + break; + } + } + if(gPaint === null) { + // No common color, don't update anything + var paintColor = null; + return; + } + var paintColor = gPaint; + + var paintOpacity = 1; + break; + default: + var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity")); + if (isNaN(paintOpacity)) { + paintOpacity = 1.0; + } + + var defColor = type === "fill" ? "black" : "none"; + var paintColor = selectedElement.getAttribute(type) || defColor; + } + if(apply) { + svgCanvas.setColor(type, paintColor, true); + svgCanvas.setPaintOpacity(type, paintOpacity, true); + } + + paintOpacity *= 100; + + var paint = getPaint(paintColor, paintOpacity, type); + // update the rect inside #fill_color/#stroke_color + this.setPaint(paint); + } + + this.prep = function() { + var ptype = this.paint.type; + + switch ( ptype ) { + case 'linearGradient': + case 'radialGradient': + var paint = new $.jGraduate.Paint({copy: this.paint}); + svgCanvas.setPaint(type, paint); + } + } + }; + + Editor.paintBox.fill = new PaintBox('#fill_color', 'fill'); + Editor.paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); + Editor.paintBox.canvas = new PaintBox('#canvas_color', 'canvas'); + + $('#stroke_width').val(curConfig.initStroke.width); + $('#group_opacity').val(curConfig.initOpacity * 100); + + // Use this SVG elem to test vectorEffect support + var test_el = Editor.paintBox.fill.rect.cloneNode(false); + test_el.setAttribute('style','vector-effect:non-scaling-stroke'); + var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); + test_el.removeAttribute('style'); + var svgdocbox = Editor.paintBox.fill.rect.ownerDocument; + // Use this to test support for blur element. Seems to work to test support in Webkit + var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); + if(typeof blur_test.stdDeviationX === "undefined") { + $('#tool_blur').hide(); + } + $(blur_test).remove(); + + + + // Test for embedImage support (use timeout to not interfere with page load) + setTimeout(function() { + svgCanvas.embedImage('images/placeholder.svg', function(datauri) { + if(!datauri) { + // Disable option + $('#image_save_opts [value=embed]').attr('disabled','disabled'); + $('#image_save_opts input').val(['ref']); + curPrefs.img_save = 'ref'; + $('#image_opt_embed').css('color','#666').attr('title', "Feature not supported"); + } + }); + },1000); + + $('#tool_fill').click(function(){ + if ($('#tool_fill').hasClass('active')) { + colorPicker($('#fill_color')); + } + else { + $('#tool_fill').addClass('active'); + $("#tool_stroke").removeClass('active'); + } + }); + + $('#tool_stroke').on("click", function(){ + if ($('#tool_stroke').hasClass('active')) { + colorPicker($('#stroke_color')); + } + else { + $('#tool_stroke').addClass('active'); + $("#tool_fill").removeClass('active'); + } + }); + + $('#tool_canvas').on("click touchstart", function(){ + colorPicker($('#canvas_color')); + }); + + $('#tool_stroke').on("touchstart", function(){ + $('#tool_stroke').addClass('active'); + $("#tool_fill").removeClass('active'); + colorPicker($('#stroke_color')); + }); + + $('#tool_fill').on("touchstart", function(){ + $('#tool_fill').addClass('active'); + $("#tool_stroke").removeClass('active'); + colorPicker($('#fill_color')); + }); + + $('#zoom_select').on("change", function() { + var val = this.options[this.selectedIndex].text + val = val.split("%")[0] + $("#zoom").val(val).trigger("change") + }); + + $('.push_button').mousedown(function() { + if (!$(this).hasClass('disabled')) { + $(this).addClass('push_button_pressed').removeClass('push_button'); + } + }).mouseout(function() { + $(this).removeClass('push_button_pressed').addClass('push_button'); + }).mouseup(function() { + $(this).removeClass('push_button_pressed').addClass('push_button'); + }); + + + // function changeResolution(x,y) { + // var zoom = svgCanvas.getResolution().zoom; + // setResolution(x * zoom, y * zoom); + // } + + var centerCanvas = function() { + // this centers the canvas vertically in the workarea (horizontal handled in CSS) + workarea.css('line-height', workarea.height() + 'px'); + }; + + $(window).bind('load resize', centerCanvas); + + function stepFontSize(elem, step) { + var orig_val = elem.value-0; + var sug_val = orig_val + step; + var increasing = sug_val >= orig_val; + if(step === 0) return orig_val; + + if(orig_val >= 24) { + if(increasing) { + return Math.round(orig_val * 1.1); + } else { + return Math.round(orig_val / 1.1); + } + } else if(orig_val <= 1) { + if(increasing) { + return orig_val * 2; + } else { + return orig_val / 2; + } + } else { + return sug_val; + } + } + + function stepZoom(elem, step) { + var orig_val = elem.value-0; + if(orig_val === 0) return 100; + var sug_val = orig_val + step; + if(step === 0) return orig_val; + + if(orig_val >= 100) { + return sug_val; + } else { + if(sug_val >= orig_val) { + return orig_val * 2; + } else { + return orig_val / 2; + } + } + } + + var changeCanvasSize = function(ctl){ + var width = $("#canvas_width"); + var height = $("#canvas_height"); + var w = width.val(); + var h = height.val() + + if(w != "fit" && !svgedit.units.isValidUnit('width', w)) { + $.alert("Invalid value given"); + width.parent().addClass('error'); + return false; + } + + width.parent().removeClass('error'); + + if(h != "fit" && !svgedit.units.isValidUnit('height', h)) { + $.alert("Invalid value given"); + height.parent().addClass('error'); + return false; + } + height.parent().removeClass('error'); + if(!svgCanvas.setResolution(w, h)) { + $.alert("No content to fit to"); + var dims = svgCanvas.getResolution() + width.val(dims.w) + height.val(dims.h) + return false; + } + updateCanvas(); + } + + + $('#resolution').change(function(){ + var w = $('#canvas_width')[0]; + var h = $('#canvas_height')[0]; + if(!this.selectedIndex) { + $('#resolution_label').html("Custom"); + w.removeAttribute("readonly"); + w.focus(); + w.select(); + if(w.value == 'fit') { + w.value = 100 + h.value = 100 + } + } else if(this.value == 'content') { + w.value = 'fit' + h.value = 'fit' + changeCanvasSize(); + var res = svgCanvas.getResolution() + w.value = res.w + h.value = res.h + + } else { + var dims = this.value.split('x'); + dims[0] = parseInt(dims[0]); + dims[1] = parseInt(dims[1]); + var diff_w = dims[0] - w.value; + var diff_h = dims[1] - h.value; + //animate + var start = Date.now(); + var duration = 1000; + var animateCanvasSize = function(timestamp) { + var progress = Date.now() - start; + var tick = progress / duration; + tick = (Math.pow((tick-1), 3) +1); + w.value = (dims[0] - diff_w + (tick*diff_w)).toFixed(0); + h.value = (dims[1] - diff_h + (tick*diff_h)).toFixed(0); + changeCanvasSize(); + if (tick >= 1) { + var res = svgCanvas.getResolution() + $('#canvas_width').val(res.w.toFixed()) + $('#canvas_height').val(res.h.toFixed()) + $('#resolution_label').html("<div class='pull'>" + res.w + "<span>×</span></br>" + res.h + "</div>"); + } + else { + requestAnimationFrame(animateCanvasSize) + } + } + animateCanvasSize() + + } + }); + + $('#zoom').change(function(){ + changeZoom(this) + }) + + //Prevent browser from erroneously repopulating fields + $('input,select').attr("autocomplete","off"); + + // Associate all button actions as well as non-button keyboard shortcuts + var Actions = function() { + // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput] + var tool_buttons = [ + {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]}, + {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]}, + {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]}, + {sel:'#tool_rect', fn: clickRect, evt: 'click', key: ['R', true], icon: 'rect'}, + {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['C', true], icon: 'ellipse'}, + //{sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', icon: 'circle'}, + //{sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'}, + {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]}, + {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]}, + {sel:'#tool_image', fn: clickImage, evt: 'mouseup'}, + {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]}, + {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey + 'N', true]}, + {sel:'#tool_save', fn: function() { editingsource ? saveSourceEditor(): clickSave() }, evt: 'mouseup', key: [modKey + 'S', true]}, + {sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, + {sel:'#tool_open', fn: clickOpen, evt: 'mouseup'}, + {sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, + {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: [modKey + 'U', true]}, + {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click'}, + {sel:'#tool_snap', fn: clickSnapGrid, evt: 'click'}, + {sel:'#tool_rulers', fn: clickRulers, evt: 'click'}, + {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, + {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, + {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, + {sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, + {sel:'#tool_node_link', fn: linkControlPoints, evt: 'change'}, + {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'}, + {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, + {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, + {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, + {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: modKey + 'shift+up'}, + {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: modKey + 'shift+down'}, + {sel:'#tool_move_up', fn: moveUpSelected, evt:'click', key: [modKey+'up', true]}, + {sel:'#tool_move_down', fn: moveDownSelected, evt:'click', key: [modKey+'down', true]}, + {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, + {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'}, + {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey + 'D', true]}, + {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey + 'G', true]}, + {sel:'#tool_ungroup', fn: clickGroup, evt: 'click', key: modKey + 'shift+G'}, + {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, + {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, + {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: modKey + 'z'}, + {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['y', true]}, + {sel:'#tool_cut', fn: cutSelected, evt: 'click', key: [modKey+'x', true]}, + {sel:'#tool_copy', fn: copySelected, evt: 'click', key: modKey+'c'}, + {sel:'#tool_paste', fn: pasteSelected, evt: 'click', key: modKey+'v'}, + {sel:'#tool_switch', fn: clickSwitch, evt: 'click', key: ['x', true]}, + {sel:'#tool_bold', fn: clickBold, evt: 'mousedown', key: [modKey + 'B', true]}, + {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown', key: [modKey + 'I', true]}, + //{sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']}, + {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'}, + + // Shortcuts not associated with buttons + + {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}}, + {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}}, + {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}}, + {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}}, + {key: 'shift+O', fn: selectPrev}, + {key: 'shift+P', fn: selectNext}, + {key: [modKey+'+', true], fn: function(){zoomImage(2);}}, + {key: [modKey+'-', true], fn: function(){zoomImage(.5);}}, + {key: ['up', true], fn: function(){moveSelected(0,-1);}}, + {key: ['down', true], fn: function(){moveSelected(0,1);}}, + {key: ['left', true], fn: function(){moveSelected(-1,0);}}, + {key: ['right', true], fn: function(){moveSelected(1,0);}}, + {key: 'shift+up', fn: function(){moveSelected(0,-10)}}, + {key: 'shift+down', fn: function(){moveSelected(0,10)}}, + {key: 'shift+left', fn: function(){moveSelected(-10,0)}}, + {key: 'shift+right', fn: function(){moveSelected(10,0)}}, + {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}}, + {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}}, + {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}}, + {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}}, + {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}}, + {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}}, + {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}}, + {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}}, + {key: modKey + 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}}, + {key: 'I', fn: function(){setEyedropperMode()}}, + + // Standard shortcuts + {key: modKey + 'shift+z', fn: clickRedo}, + {key: 'esc', fn: minimizeModal} + ]; + + // Tooltips not directly associated with a single function + var key_assocs = { + '4/Shift+4': '#tools_rect_show', + '5/Shift+5': '#tools_ellipse_show' + }; + + return { + setAll: function() { + var flyouts = {}; + + $.each(tool_buttons, function(i, opts) { + // Bind function to button + if(opts.sel) { + var btn = $(opts.sel); + if (btn.length == 0) return true; // Skip if markup does not exist + if(opts.evt) { + if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown" + btn[opts.evt](opts.fn); + } + + // Add to parent flyout menu, if able to be displayed + if(opts.parent && $(opts.parent + '_show').length != 0) { + var f_h = $(opts.parent); + if(!f_h.length) { + f_h = makeFlyoutHolder(opts.parent.substr(1)); + } + + f_h.append(btn); + + if(!$.isArray(flyouts[opts.parent])) { + flyouts[opts.parent] = []; + } + flyouts[opts.parent].push(opts); + } + } + + + // Bind function to shortcut key + if(opts.key) { + // Set shortcut based on options + var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false; + if($.isArray(opts.key)) { + keyval = opts.key[0]; + if(opts.key.length > 1) pd = opts.key[1]; + if(opts.key.length > 2) disInInp = opts.key[2]; + } else { + keyval = opts.key; + } + keyval += ''; + if (svgedit.browser.isMac && keyval.indexOf("+") != -1) { + var modifier_key = keyval.split("+")[0]; + if (modifier_key == "ctrl") keyval.replace("ctrl", "cmd") + } + + $.each(keyval.split('/'), function(i, key) { + $(document).bind('keydown', key, function(e) { + fn(); + if(pd) { + e.preventDefault(); + } + // Prevent default on ALL keys? + return false; + }); + }); + + // Put shortcut in title + if(opts.sel && !opts.hidekey && btn.attr('title')) { + var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')'; + key_assocs[keyval] = opts.sel; + // Disregard for menu items + if(!btn.parents('#main_menu').length) { + btn.attr('title', new_title); + } + } + } + }); + + // Setup flyouts + setupFlyouts(flyouts); + + $(window).bind('keydown', 'tab', function(e) { + if(ui_context === 'canvas') { + e.preventDefault(); + selectNext(); + } + }).bind('keydown', 'shift+tab', function(e) { + if(ui_context === 'canvas') { + e.preventDefault(); + selectPrev(); + } + }); + + $('#tool_zoom').dblclick(dblclickZoom); + }, + setTitles: function() { + $.each(key_assocs, function(keyval, sel) { + var menu = ($(sel).parents('#main_menu').length); + + $(sel).each(function() { + if(menu) { + var t = $(this).text().split(' [')[0]; + } else { + var t = this.title.split(' [')[0]; + } + var key_str = ''; + // Shift+Up + $.each(keyval.split('/'), function(i, key) { + var mod_bits = key.split('+'), mod = ''; + if(mod_bits.length > 1) { + mod = mod_bits[0] + '+'; + key = mod_bits[1]; + } + key_str += (i?'/':'') + mod + (key); + }); + if(menu) { + this.lastChild.textContent = t +' ['+key_str+']'; + } else { + this.title = t +' ['+key_str+']'; + } + }); + }); + }, + getButtonData: function(sel) { + var b; + $.each(tool_buttons, function(i, btn) { + if(btn.sel === sel) b = btn; + }); + return b; + } + }; + }(); + + Actions.setAll(); + + // Select given tool + Editor.ready(function() { + var tool, + itool = curConfig.initTool, + container = $("#tools_left, #svg_editor .tools_flyout"), + pre_tool = container.find("#tool_" + itool), + reg_tool = container.find("#" + itool); + if(pre_tool.length) { + tool = pre_tool; + } else if(reg_tool.length){ + tool = reg_tool; + } else { + tool = $("#tool_select"); + } + tool.click().mouseup(); + + if(curConfig.wireframe) { + $('#tool_wireframe').click(); + } + + if(curConfig.showlayers) { + toggleSidePanel(); + } + + $('#rulers').toggle(!!curConfig.showRulers); + }); + + + $('#canvas_height').dragInput({ min: 10, max: null, step: 10, callback: changeCanvasSize, cursor: false, dragAdjust: .1 }); + $('#canvas_width') .dragInput({ min: 10, max: null, step: 10, callback: changeCanvasSize, cursor: false, dragAdjust: .1 }); + $('#rect_width') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#rect_height') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#ellipse_cx') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#ellipse_cy') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#ellipse_rx') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#ellipse_ry') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $("#image_height") .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#circle_cx') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#circle_cy') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#circle_r') .dragInput({ min: 1, max: null, step: 1, callback: changeAttribute, cursor: false }); + $("#image_height") .dragInput({ min: 0, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#selected_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#selected_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $("#path_node_x") .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $("#path_node_y") .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $("#image_width") .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#line_x1') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#line_x2') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#line_y1') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#line_y2') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#path_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#path_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#rect_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#rect_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#g_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#g_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#image_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#text_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#text_x') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#image_y') .dragInput({ min: null, max: null, step: 1, callback: changeAttribute, cursor: false }); + $('#rect_rx') .dragInput({ min: 0, max: 100, step: 1, callback: changeAttribute, cursor: true }); + $('#stroke_width') .dragInput({ min: 0, max: 99, step: 1, callback: changeStrokeWidth, cursor: true, smallStep: 0.1, start: 1.5 }); + $('#angle') .dragInput({ min: -180, max: 180, step: 1, callback: changeRotationAngle, cursor: false, dragAdjust: 0.5 }); + $('#font_size') .dragInput({ min: 1, max: 250, step: 1, callback: changeFontSize, cursor: true, stepfunc: stepFontSize, dragAdjust: .15 }); + $('#group_opacity').dragInput({ min: 0, max: 100, step: 5, callback: changeAttribute, cursor: true, start: 100 }); + $('#blur') .dragInput({ min: 0, max: 10, step: .1, callback: changeBlur, cursor: true, start: 0 }); + // Set default zoom + $('#zoom').val(svgCanvas.getZoom() * 100); + + $("#workarea").contextMenu({ + menu: 'cmenu_canvas', + inSpeed: 0 + }, + function(action, el, pos) { + switch ( action ) { + case 'delete': + deleteSelected(); + break; + case 'cut': + cutSelected(); + break; + case 'copy': + copySelected(); + break; + case 'paste': + svgCanvas.pasteElements(); + break; + case 'paste_in_place': + svgCanvas.pasteElements('in_place'); + break; + case 'group': + svgCanvas.groupSelectedElements(); + break; + case 'ungroup': + svgCanvas.ungroupSelectedElement(); + break; + case 'move_front': + moveToTopSelected(); + break; + case 'move_up': + moveUpDownSelected('Up'); + break; + case 'move_down': + moveUpDownSelected('Down'); + break; + case 'move_back': + moveToBottomSelected(); + break; + default: + if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){ + svgedit.contextmenu.getCustomHandler(action).call(); + } + break; + } + + }); + + $('.contextMenu li').mousedown(function(ev) { + ev.preventDefault(); + }) + + $('#cmenu_canvas li').disableContextMenu(); + canv_menu.enableContextMenuItems('#delete,#cut,#copy'); + + window.onbeforeunload = function() { + // Suppress warning if page is empty + if(undoMgr.getUndoStackSize() === 0) { + Editor.show_save_warning = false; + } + + // show_save_warning is set to "false" when the page is saved. + if(!curConfig.no_save_warning && Editor.show_save_warning) { + // Browser already asks question about closing the page + return "There are unsaved changes."; + } + }; + + Editor.openPrep = function(func) { + $('#main_menu').hide(); + if(undoMgr.getUndoStackSize() === 0) { + func(true); + } else { + $.confirm("Do you want to open a new file?\nThis will also erase your undo history", func); + } + } + + if (window.FileReader) { + + var import_image = function(e) { + e.stopPropagation(); + e.preventDefault(); + $("#workarea").removeAttr("style"); + $('#main_menu').hide(); + var file = null; + if (e.type == "drop") file = e.dataTransfer.files[0] + else file = this.files[0]; + if (file) { + if(file.type.indexOf("image") != -1) { + //detected an image + + //svg handing + if(file.type.indexOf("svg") != -1) { + var reader = new FileReader(); + reader.onloadend = function(e) { + svgCanvas.importSvgString(e.target.result, true); + svgCanvas.ungroupSelectedElement() + svgCanvas.ungroupSelectedElement() + svgCanvas.groupSelectedElements() + svgCanvas.alignSelectedElements("m", "page") + svgCanvas.alignSelectedElements("c", "page") + }; + reader.readAsText(file); + } + + //image handling + else { + var reader = new FileReader(); + reader.onloadend = function(e) { + // lets insert the new image until we know its dimensions + insertNewImage = function(img_width, img_height){ + var newImage = svgCanvas.addSvgElementFromJson({ + "element": "image", + "attr": { + "x": 0, + "y": 0, + "width": img_width, + "height": img_height, + "id": svgCanvas.getNextId(), + "style": "pointer-events:inherit" + } + }); + svgCanvas.setHref(newImage, e.target.result); + svgCanvas.selectOnly([newImage]) + svgCanvas.alignSelectedElements("m", "page") + svgCanvas.alignSelectedElements("c", "page") + updateContextPanel(); + } + // put a placeholder img so we know the default dimensions + var img_width = 100; + var img_height = 100; + var img = new Image() + img.src = e.target.result + document.body.appendChild(img); + img.onload = function() { + img_width = img.offsetWidth + img_height = img.offsetHeight + insertNewImage(img_width, img_height); + document.body.removeChild(img); + } + }; + reader.readAsDataURL(file) + } + } + } + } + + var workarea = $("#workarea") + + function onDragEnter(e) { + e.stopPropagation(); + e.preventDefault(); + workarea.css({ + "-webkit-transform": "scale3d(1.1,1.1,1)", + "-moz-transform": "scale3d(1.1,1.1,1)", + "-o-transform": "scale(1.1)", + "-ms-transform": "scale3d(1.1,1.1,1)", + "transform": "scale3d(1.1,1.1,1)" + }) + + } + + function onDragOver(e) { + e.stopPropagation(); + e.preventDefault(); + } + + function onDragLeave(e) { + workarea.removeAttr("style") + e.stopPropagation(); + e.preventDefault(); + } + + workarea[0].addEventListener('dragenter', onDragEnter, false); + workarea[0].addEventListener('dragover', onDragOver, false); + workarea[0].addEventListener('dragleave', onDragLeave, false); + workarea[0].addEventListener('drop', import_image, false); + + var open = $('<input type="file">').change(function() { + var f = this; + Editor.openPrep(function(ok) { + if(!ok) return; + svgCanvas.clear(); + if(f.files.length==1) { + var reader = new FileReader(); + reader.onloadend = function(e) { + loadSvgString(e.target.result); + updateCanvas(); + }; + reader.readAsText(f.files[0]); + } + }); + }); + $("#tool_open").show().prepend(open); + + var img_import = $('<input type="file">').change(import_image); + $("#tool_import").show().prepend(img_import); + } + + + var updateCanvas = Editor.updateCanvas = function(center, new_ctr) { + var w = workarea.width(), h = workarea.height(); + var w_orig = w, h_orig = h; + var zoom = svgCanvas.getZoom(); + var w_area = workarea; + var cnvs = $("#svgcanvas"); + + var old_ctr = { + x: w_area[0].scrollLeft + w_orig/2, + y: w_area[0].scrollTop + h_orig/2 + }; + + var multi = curConfig.canvas_expansion; + w = Math.max(w_orig, svgCanvas.contentW * zoom * multi); + h = Math.max(h_orig, svgCanvas.contentH * zoom * multi); + + if(w == w_orig && h == h_orig) { + workarea.css('overflow','hidden'); + } else { + workarea.css('overflow','scroll'); + } + + var old_can_y = cnvs.height()/2; + var old_can_x = cnvs.width()/2; + cnvs.width(w).height(h); + var new_can_y = h/2; + var new_can_x = w/2; + var offset = svgCanvas.updateCanvas(w, h); + + var ratio = new_can_x / old_can_x; + + var scroll_x = w/2 - w_orig/2; + var scroll_y = h/2 - h_orig/2; + + if(!new_ctr) { + + var old_dist_x = old_ctr.x - old_can_x; + var new_x = new_can_x + old_dist_x * ratio; + + var old_dist_y = old_ctr.y - old_can_y; + var new_y = new_can_y + old_dist_y * ratio; + + new_ctr = { + x: new_x, + y: new_y + }; + + } else { + new_ctr.x += offset.x, + new_ctr.y += offset.y; + } + + //width.val(offset.x) + //height.val(offset.y) + + if(center) { + // Go to top-left for larger documents + if(svgCanvas.contentW > w_area.width()) { + // Top-left + workarea[0].scrollLeft = offset.x - 10; + workarea[0].scrollTop = offset.y - 10; + } else { + // Center + w_area[0].scrollLeft = scroll_x; + w_area[0].scrollTop = scroll_y; + } + } else { + w_area[0].scrollLeft = new_ctr.x - w_orig/2; + w_area[0].scrollTop = new_ctr.y - h_orig/2; + } + if(curConfig.showRulers) { + updateRulers(cnvs, zoom); + workarea.scroll(); + } + } + + // Make [1,2,5] array + var r_intervals = []; + for(var i = .1; i < 1E5; i *= 10) { + r_intervals.push(1 * i); + r_intervals.push(2 * i); + r_intervals.push(5 * i); + } + + function updateRulers(scanvas, zoom) { + var workarea = document.getElementById("workarea"); + var title_show = document.getElementById("title_show"); + var offset_x = 66; + var offset_y = 48; + if(!zoom) zoom = svgCanvas.getZoom(); + if(!scanvas) scanvas = $("#svgcanvas"); + + var limit = 30000; + + var c_elem = svgCanvas.getContentElem(); + + var units = svgedit.units.getTypeMap(); + var unit = units[curConfig.baseUnit]; // 1 = 1px + + for(var d = 0; d < 2; d++) { + var is_x = (d === 0); + var dim = is_x ? 'x' : 'y'; + var lentype = is_x?'width':'height'; + var content_d = c_elem.getAttribute(dim)-0; + + var $hcanv_orig = $('#ruler_' + dim + ' canvas:first'); + + // Bit of a hack to fully clear the canvas in Safari & IE9 + $hcanv = $hcanv_orig.clone(); + $hcanv_orig.replaceWith($hcanv); + + var hcanv = $hcanv[0]; + + // Set the canvas size to the width of the container + var ruler_len = scanvas[lentype]()*2; + var total_len = ruler_len; + hcanv.parentNode.style[lentype] = total_len + 'px'; + + var canv_count = 1; + var ctx_num = 0; + var ctx_arr; + var ctx = hcanv.getContext("2d"); + + ctx.fillStyle = "rgb(200,0,0)"; + ctx.fillRect(0,0,hcanv.width,hcanv.height); + + // Remove any existing canvasses + $hcanv.siblings().remove(); + + // Create multiple canvases when necessary (due to browser limits) + if(ruler_len >= limit) { + var num = parseInt(ruler_len / limit) + 1; + ctx_arr = Array(num); + ctx_arr[0] = ctx; + for(var i = 1; i < num; i++) { + hcanv[lentype] = limit; + var copy = hcanv.cloneNode(true); + hcanv.parentNode.appendChild(copy); + ctx_arr[i] = copy.getContext('2d'); + } + + copy[lentype] = ruler_len % limit; + + // set copy width to last + ruler_len = limit; + } + + hcanv[lentype] = ruler_len; + + var u_multi = unit * zoom; + + // Calculate the main number interval + var raw_m = 50 / u_multi; + var multi = 1; + for(var i = 0; i < r_intervals.length; i++) { + var num = r_intervals[i]; + multi = num; + if(raw_m <= num) { + break; + } + } + + var big_int = multi * u_multi; + ctx.font = "normal 9px 'Lucida Grande', sans-serif"; + ctx.fillStyle = "#777"; + + var ruler_d = ((content_d / u_multi) % multi) * u_multi; + var label_pos = ruler_d - big_int; + for (; ruler_d < total_len; ruler_d += big_int) { + label_pos += big_int; + var real_d = ruler_d - content_d; + + var cur_d = Math.round(ruler_d) + .5; + if(is_x) { + ctx.moveTo(cur_d, 15); + ctx.lineTo(cur_d, 0); + } else { + ctx.moveTo(15, cur_d); + ctx.lineTo(0, cur_d); + } + + var num = (label_pos - content_d) / u_multi; + var label; + if(multi >= 1) { + label = Math.round(num); + } else { + var decs = (multi+'').split('.')[1].length; + label = num.toFixed(decs)-0; + } + + // Do anything special for negative numbers? +// var is_neg = label < 0; +// real_d2 = Math.abs(real_d2); + + // Change 1000s to Ks + if(label !== 0 && label !== 1000 && label % 1000 === 0) { + label = (label / 1000) + 'K'; + } + + if(is_x) { + ctx.fillText(label, ruler_d+2, 8); + ctx.fillStyle = "#777"; + } else { + var str = (label+'').split(''); + for(var i = 0; i < str.length; i++) { + ctx.fillText(str[i], 1, (ruler_d+9) + i*9); + ctx.fillStyle = "#777"; + } + } + + var part = big_int / 10; + for(var i = 1; i < 10; i++) { + var sub_d = Math.round(ruler_d + part * i) + .5; + if(ctx_arr && sub_d > ruler_len) { + ctx_num++; + ctx.stroke(); + if(ctx_num >= ctx_arr.length) { + i = 10; + ruler_d = total_len; + continue; + } + ctx = ctx_arr[ctx_num]; + ruler_d -= limit; + sub_d = Math.round(ruler_d + part * i) + .5; + } + + var line_num = (i % 2)?12:10; + if(is_x) { + ctx.moveTo(sub_d, 15); + ctx.lineTo(sub_d, line_num); + } else { + ctx.moveTo(15, sub_d); + ctx.lineTo(line_num ,sub_d); + } + } + } + ctx.strokeStyle = "#666"; + ctx.stroke(); + } + } + +// $(function() { + updateCanvas(true); +// }); + + // var revnums = "svg-editor.js ($Rev: 2083 $) "; + // revnums += svgCanvas.getVersion(); + // $('#copyright')[0].setAttribute("title", revnums); + + // Callback handler for embedapi.js + try{ + var json_encode = function(obj){ + //simple partial JSON encoder implementation + if(window.JSON && JSON.stringify) return JSON.stringify(obj); + var enc = arguments.callee; //for purposes of recursion + if(typeof obj == "boolean" || typeof obj == "number"){ + return obj+'' //should work... + }else if(typeof obj == "string"){ + //a large portion of this is stolen from Douglas Crockford's json2.js + return '"'+ + obj.replace( + /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g + , function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + +'"'; //note that this isn't quite as purtyful as the usualness + }else if(obj.length){ //simple hackish test for arrayish-ness + for(var i = 0; i < obj.length; i++){ + obj[i] = enc(obj[i]); //encode every sub-thingy on top + } + return "["+obj.join(",")+"]"; + }else{ + var pairs = []; //pairs will be stored here + for(var k in obj){ //loop through thingys + pairs.push(enc(k)+":"+enc(obj[k])); //key: value + } + return "{"+pairs.join(",")+"}" //wrap in the braces + } + } + window.addEventListener("message", function(e){ + var cbid = parseInt(e.data.substr(0, e.data.indexOf(";"))); + try{ + e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*"); + }catch(err){ + e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*"); + } + }, false) + }catch(err){ + window.embed_error = err; + } + + + + // For Compatibility with older extensions + $(function() { + window.svgCanvas = svgCanvas; + svgCanvas.ready = methodDraw.ready; + }); + + + Editor.setLang = function(lang, allStrings) { + $.pref('lang', lang); + $('#lang_select').val(lang); + if(allStrings) { + + var notif = allStrings.notification; + + svgCanvas.runExtensions("langChanged", lang); + + // Update flyout tooltips + setFlyoutTitles(); + + // Copy title for certain tool elements + var elems = { + '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', + '#fill_color': '#tool_fill label, #tool_fill .color_block', + '#linejoin_miter': '#cur_linejoin', + '#linecap_butt': '#cur_linecap' + } + + $.each(elems, function(source, dest) { + $(dest).attr('title', $(source)[0].title); + }); + + // Copy alignment titles + $('#multiselected_panel div[id^=tool_align]').each(function() { + $('#tool_pos' + this.id.substr(10))[0].title = this.title; + }); + + } + }; + }; + + var callbacks = []; + + function loadSvgString(str, callback) { + var success = svgCanvas.setSvgString(str) !== false; + callback = callback || $.noop; + if(success) { + callback(true); + } else { + $.alert("Error: Unable to load SVG data", function() { + callback(false); + }); + } + } + + Editor.ready = function(cb) { + if(!is_ready) { + callbacks.push(cb); + } else { + cb(); + } + }; + + Editor.runCallbacks = function() { + $.each(callbacks, function() { + this(); + }); + is_ready = true; + }; + + Editor.loadFromString = function(str) { + Editor.ready(function() { + loadSvgString(str); + }); + }; + + Editor.loadFromURL = function(url, opts) { + if(!opts) opts = {}; + + var cache = opts.cache; + var cb = opts.callback; + + Editor.ready(function() { + $.ajax({ + 'url': url, + 'dataType': 'text', + cache: !!cache, + success: function(str) { + loadSvgString(str, cb); + }, + error: function(xhr, stat, err) { + if(xhr.status != 404 && xhr.responseText) { + loadSvgString(xhr.responseText, cb); + } else { + $.alert("Unable to load from URL" + ": \n"+err+'', cb); + } + } + }); + }); + }; + + Editor.loadFromDataURI = function(str) { + Editor.ready(function() { + var pre = 'data:image/svg+xml;base64,'; + var src = str.substring(pre.length); + loadSvgString(svgedit.utilities.decode64(src)); + }); + }; + + Editor.addExtension = function() { + var args = arguments; + + // Note that we don't want this on Editor.ready since some extensions + // may want to run before then (like server_opensave). + $(function() { + if(svgCanvas) svgCanvas.addExtension.apply(this, args); + }); + }; + + return Editor; +}(jQuery); + +// Run init once DOM is loaded +$(methodDraw.init); + + + +// Mark MacKay http://method.ac MIT License + + +$.fn.dragInput = function(cfg){ + return this.each(function(){ + + this.repeating = false; + // Apply specified options or defaults: + // (Ought to refactor this some day to use $.extend() instead) + this.dragCfg = { + min: cfg && !isNaN(parseFloat(cfg.min)) ? Number(cfg.min) : null, // Fixes bug with min:0 + max: cfg && !isNaN(parseFloat(cfg.max)) ? Number(cfg.max) : null, + step: cfg && Number(cfg.step) ? cfg.step : 1, + stepfunc: cfg && cfg.stepfunc ? cfg.stepfunc : false, + dragAdjust: cfg && cfg.dragAdjust ? cfg.dragAdjust : 1, + height: 70, + cursor: cfg && cfg.cursor ? Boolean(cfg.cursor) : false, + start: cfg && cfg.start ? Number(cfg.start) : 0, + _btn_width: 20, + _direction: null, + _delay: null, + _repeat: null, + callback: cfg && cfg.callback ? cfg.callback : null + }; + // if a smallStep isn't supplied, use half the regular step + this.dragCfg.smallStep = cfg && cfg.smallStep ? cfg.smallStep : this.dragCfg.step/2; + var dragAdjust = this.dragCfg.dragAdjust; + var $label = $(this).parent(); + var $input = $(this); + var cursorHeight = this.dragCfg.height; + var min = this.dragCfg.min; + var max = this.dragCfg.max + var step = this.dragCfg.step + var area = (max - min > 0) ? (max - min) / step : 200; + var scale = area/cursorHeight * step; + var lastY = 0; + var attr = this.getAttribute("data-attr"); + var canvas = methodDraw.canvas + var isTouch = svgedit.browser.isTouch(); + var completed = true //for mousewheel + var $cursor = (area && this.dragCfg.cursor) + ? $("<div class='draginput_cursor' />").appendTo($label) + : false + $input.attr("readonly", "readonly") + if ($cursor && !isNaN(this.dragCfg.start)) $cursor.css("top", (this.dragCfg.start*-1)/scale+cursorHeight) + + //this is where all the magic happens + this.adjustValue = function(i, completed){ + var v; + i = parseFloat(i); + if(isNaN(this.value)) { + v = this.dragCfg.reset; + } else if($.isFunction(this.dragCfg.stepfunc)) { + v = this.dragCfg.stepfunc(this, i); + } else { + v = Number((Number(this.value) + Number(i)).toFixed(5)); + } + if (max !== null) v = Math.min(v, max); + if (min !== null) v = Math.max(v, min); + if ($cursor) this.updateCursor(v); + this.value = v; + $label.attr("data-value", v) + if ($.isFunction(this.dragCfg.callback)) this.dragCfg.callback(this, completed) + }; + + $label.toggleClass("draginput", $label.is("label")) + + // when the mouse is down and moving + this.move = function(e, oy, val) { + if (isTouch) { + e = e.originalEvent.touches[0] + } + // just got started let's save for undo purposes + if (lastY === 0) { + lastY = oy; + } + var deltaY = (e.pageY - lastY) *-1 + lastY = e.pageY; + val = (deltaY * scale) * dragAdjust + var fixed = (step < 1) ? 1 : 0 + this.adjustValue(val.toFixed(fixed)) //no undo true + }; + + //when the mouse is released + this.stop = function() { + var selectedElems = canvas.getSelectedElems(); + $('body').removeClass('dragging'); + $label.removeClass("active"); + completed = true; + $(window).unbind("mousemove.draginput touchmove.draginput mouseup.draginput touchend.draginput"); + lastY = 0; + if (selectedElems[0]) { + var batchCmd = canvas.undoMgr.finishUndoableChange(); + if (!batchCmd.isEmpty()) canvas.undoMgr.addCommandToHistory(batchCmd); + } + this.adjustValue(0, completed) + } + + this.updateCursor = function(){ + var value = parseFloat(this.value); + var pos = (value*-1)/scale+cursorHeight; + $cursor.css("top", pos); + } + + this.launch = function(e) { + var selectedElems = canvas.getSelectedElems(); + if (isTouch) e = e.originalEvent.touches[0]; + var oy = e.pageY; + var val = this.value; + var el = this; + canvas.undoMgr.beginUndoableChange(attr, selectedElems) + $('body').addClass('dragging'); + $label.addClass('active'); + $(window).bind("mousemove.draginput touchmove.draginput", function(e){el.move(e, oy, parseFloat(val))}) + $(window).bind("mouseup.draginput touchend.draginput", function(e){el.stop()}) + } + + $(this) + .attr("readonly", "readonly") + .attr("data-scale", scale) + .attr("data-domain", cursorHeight) + .attr("data-cursor", ($cursor != false)) + + .bind("mousedown touchstart", function(e){ + this.blur(); + this.launch(e); + }) + + .bind("dblclick taphold", function(e) { + this.removeAttribute("readonly", "readonly"); + this.focus(); + this.select(); + }) + + .keydown(function(e){ + // Respond to up/down arrow keys. + switch(e.keyCode){ + case 13: this.adjustValue(0); this.blur(); break; // Enter + } + }) + + .focus(function(e){ + if (this.getAttribute("readonly") === "readonly") this.blur() + }) + + .blur(function(e){ + this.setAttribute("readonly", "readonly") + }) + + .bind("mousewheel", function(e, delta, deltaX, deltaY){ + var selectedElems = canvas.getSelectedElems(); + if (completed) canvas.undoMgr.beginUndoableChange(attr, selectedElems) + completed = false + clearTimeout(window.undoTimeout) + window.undoTimeout = setTimeout(function(){ + wheel_input.stop() + },200) + + var wheel_input = this; + if (deltaY > 0) + this.adjustValue(this.dragCfg.step); + else if (deltaY < 0) + this.adjustValue(-this.dragCfg.step); + e.preventDefault(); + + }) + + }); + +}; + +// public function +$.fn.dragInput.updateCursor = function(el){ + var value = parseFloat(el.value); + var scale = parseFloat(el.getAttribute("data-scale")); + var domain = parseFloat(el.getAttribute("data-domain")); + var pos = ((value*-1)/scale+domain) + "px"; + var cursor = el.parentNode.lastChild + if (cursor.className == "draginput_cursor") cursor.style.top = pos; +} + + +/** + * Package: svgedit.contextmenu + * + * Licensed under the Apache License, Version 2 + * + * Author: Adam Bender + */ +// Dependencies: +// 1) jQuery (for dom injection of context menus)\ + +var svgedit = svgedit || {}; +(function() { + var self = this; + if (!svgedit.contextmenu) { + svgedit.contextmenu = {}; + } + self.contextMenuExtensions = {} + var addContextMenuItem = function(menuItem) { + // menuItem: {id, label, shortcut, action} + if (!menuItemIsValid(menuItem)) { + console + .error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); + return; + } + if (menuItem.id in self.contextMenuExtensions) { + console.error('Cannot add extension "' + menuItem.id + + '", an extension by that name already exists"'); + return; + } + // Register menuItem action, see below for deferred menu dom injection + console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); + self.contextMenuExtensions[menuItem.id] = menuItem; + //TODO: Need to consider how to handle custom enable/disable behavior + } + var hasCustomHandler = function(handlerKey) { + return self.contextMenuExtensions[handlerKey] && true; + } + var getCustomHandler = function(handlerKey) { + return self.contextMenuExtensions[handlerKey].action; + } + var injectExtendedContextMenuItemIntoDom = function(menuItem) { + if (Object.keys(self.contextMenuExtensions).length == 0) { + // all menuItems appear at the bottom of the menu in their own container. + // if this is the first extension menu we need to add the separator. + $("#cmenu_canvas").append("<li class='separator'>"); + } + var shortcut = menuItem.shortcut || ""; + $("#cmenu_canvas").append("<li class='disabled'><a href='#" + menuItem.id + "'>" + + menuItem.label + "<span class='shortcut'>" + + shortcut + "</span></a></li>"); + } + + var menuItemIsValid = function(menuItem) { + return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; + } + + // Defer injection to wait out initial menu processing. This probably goes away once all context + // menu behavior is brought here. + methodDraw.ready(function() { + for (menuItem in contextMenuExtensions) { + injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]); + } + }); + svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}} + svgedit.contextmenu.add = addContextMenuItem; + svgedit.contextmenu.hasCustomHandler = hasCustomHandler; + svgedit.contextmenu.getCustomHandler = getCustomHandler; +})(); + +/* + * jPicker 1.1.6 + * + * jQuery Plugin for Photoshop style color picker + * + * Copyright (c) 2010 Christopher T. Tillman + * Digital Magic Productions, Inc. (http://www.digitalmagicpro.com/) + * MIT style license, FREE to use, alter, copy, sell, and especially ENHANCE + * + * Painstakingly ported from John Dyers' excellent work on his own color picker based on the Prototype framework. + * + * John Dyers' website: (http://johndyer.name) + * Color Picker page: (http://johndyer.name/post/2007/09/PhotoShop-like-JavaScript-Color-Picker.aspx) + * + */ +(function($, version) +{ + Math.precision = function(value, precision) + { + if (precision === undefined) precision = 0; + return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision); + }; + var Slider = // encapsulate slider functionality for the ColorMap and ColorBar - could be useful to use a jQuery UI draggable for this with certain extensions + function(bar, options) + { + var $this = this, // private properties, methods, and events - keep these variables and classes invisible to outside code + arrow = bar.find('img:first'), // the arrow image to drag + minX = 0, + maxX = 100, + rangeX = 100, + minY = 0, + maxY = 100, + rangeY = 100, + x = 0, + y = 0, + offset, + timeout, + changeEvents = new Array(), + fireChangeEvents = + function(context) + { + for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); + }, + mouseDown = // bind the mousedown to the bar not the arrow for quick snapping to the clicked location + function(e) + { + var off = bar.offset(); + offset = { l: off.left | 0, t: off.top | 0 }; + clearTimeout(timeout); + timeout = setTimeout( // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run + function() + { + setValuesFromMousePosition.call($this, e); + }, 0); + // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing + $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); + e.preventDefault(); // don't try to select anything or drag the image to the desktop + }, + mouseMove = // set the values as the mouse moves + function(e) + { + clearTimeout(timeout); + timeout = setTimeout( + function() + { + setValuesFromMousePosition.call($this, e); + }, 0); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + mouseUp = // unbind the document events - they aren't needed when not dragging + function(e) + { + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + setValuesFromMousePosition = // calculate mouse position and set value within the current range + function(e) + { + var locX = e.pageX - offset.l, + locY = e.pageY - offset.t, + barW = bar.w, // local copies for YUI compressor + barH = bar.h; + // keep the arrow within the bounds of the bar + if (locX < 0) locX = 0; + else if (locX > barW) locX = barW; + if (locY < 0) locY = 0; + else if (locY > barH) locY = barH; + val.call($this, 'xy', { x: ((locX / barW) * rangeX) + minX, y: ((locY / barH) * rangeY) + minY }); + }, + draw = + function() + { + var arrowOffsetX = 0, + arrowOffsetY = 0, + barW = bar.w, + barH = bar.h, + arrowW = arrow.w, + arrowH = arrow.h; + setTimeout( + function() + { + if (rangeX > 0) // range is greater than zero + { + // constrain to bounds + if (x == maxX) arrowOffsetX = barW; + else arrowOffsetX = ((x / rangeX) * barW) | 0; + } + if (rangeY > 0) // range is greater than zero + { + // constrain to bounds + if (y == maxY) arrowOffsetY = barH; + else arrowOffsetY = ((y / rangeY) * barH) | 0; + } + // if arrow width is greater than bar width, center arrow and prevent horizontal dragging + if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) + else arrowOffsetX -= arrowW >> 1; + // if arrow height is greater than bar height, center arrow and prevent vertical dragging + if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1); + else arrowOffsetY -= arrowH >> 1; + // set the arrow position based on these offsets + arrow.css({ left: arrowOffsetX + 'px', top: arrowOffsetY + 'px' }); + }, 0); + }, + val = + function(name, value, context) + { + var set = value !== undefined; + if (!set) + { + if (name === undefined || name == null) name = 'xy'; + switch (name.toLowerCase()) + { + case 'x': return x; + case 'y': return y; + case 'xy': + default: return { x: x, y: y }; + } + } + if (context != null && context == $this) return; + var changed = false, + newX, + newY; + if (name == null) name = 'xy'; + switch (name.toLowerCase()) + { + case 'x': + newX = value && (value.x && value.x | 0 || value | 0) || 0; + break; + case 'y': + newY = value && (value.y && value.y | 0 || value | 0) || 0; + break; + case 'xy': + default: + newX = value && value.x && value.x | 0 || 0; + newY = value && value.y && value.y | 0 || 0; + break; + } + if (newX != null) + { + if (newX < minX) newX = minX; + else if (newX > maxX) newX = maxX; + if (x != newX) + { + x = newX; + changed = true; + } + } + if (newY != null) + { + if (newY < minY) newY = minY; + else if (newY > maxY) newY = maxY; + if (y != newY) + { + y = newY; + changed = true; + } + } + changed && fireChangeEvents.call($this, context || $this); + }, + range = + function (name, value) + { + var set = value !== undefined; + if (!set) + { + if (name === undefined || name == null) name = 'all'; + switch (name.toLowerCase()) + { + case 'minx': return minX; + case 'maxx': return maxX; + case 'rangex': return { minX: minX, maxX: maxX, rangeX: rangeX }; + case 'miny': return minY; + case 'maxy': return maxY; + case 'rangey': return { minY: minY, maxY: maxY, rangeY: rangeY }; + case 'all': + default: return { minX: minX, maxX: maxX, rangeX: rangeX, minY: minY, maxY: maxY, rangeY: rangeY }; + } + } + var changed = false, + newMinX, + newMaxX, + newMinY, + newMaxY; + if (name == null) name = 'all'; + switch (name.toLowerCase()) + { + case 'minx': + newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0; + break; + case 'maxx': + newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0; + break; + case 'rangex': + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + break; + case 'miny': + newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0; + break; + case 'maxy': + newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0; + break; + case 'rangey': + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; + case 'all': + default: + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; + } + if (newMinX != null && minX != newMinX) + { + minX = newMinX; + rangeX = maxX - minX; + } + if (newMaxX != null && maxX != newMaxX) + { + maxX = newMaxX; + rangeX = maxX - minX; + } + if (newMinY != null && minY != newMinY) + { + minY = newMinY; + rangeY = maxY - minY; + } + if (newMaxY != null && maxY != newMaxY) + { + maxY = newMaxY; + rangeY = maxY - minY; + } + }, + bind = + function (callback) + { + if ($.isFunction(callback)) changeEvents.push(callback); + }, + unbind = + function (callback) + { + if (!$.isFunction(callback)) return; + var i; + while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1); + }, + destroy = + function() + { + // unbind all possible events and null objects + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + bar.unbind('mousedown', mouseDown); + bar = null; + arrow = null; + changeEvents = null; + }; + $.extend(true, $this, // public properties, methods, and event bindings - these we need to access from other controls + { + val: val, + range: range, + bind: bind, + unbind: unbind, + destroy: destroy + }); + // initialize this control + arrow.src = options.arrow && options.arrow.image; + arrow.w = options.arrow && options.arrow.width || arrow.width(); + arrow.h = options.arrow && options.arrow.height || arrow.height(); + bar.w = options.map && options.map.width || bar.width(); + bar.h = options.map && options.map.height || bar.height(); + // bind mousedown event + bar.bind('mousedown', mouseDown); + bind.call($this, draw); + }, + ColorValuePicker = // controls for all the input elements for the typing in color values + function(picker, color, bindedHex, alphaPrecision) + { + var $this = this, // private properties and methods + inputs = picker.find('td.Text input'), + red = inputs.eq(3), + green = inputs.eq(4), + blue = inputs.eq(5), + alpha = inputs.length > 7 ? inputs.eq(6) : null, + hue = inputs.eq(0), + saturation = inputs.eq(1), + value = inputs.eq(2), + hex = inputs.eq(inputs.length > 7 ? 7 : 6), + ahex = inputs.length > 7 ? inputs.eq(8) : null, + keyDown = // input box key down - use arrows to alter color + function(e) + { + if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return; + if (!validateKey(e)) return e; + switch (e.target) + { + case red.get(0): + switch (e.keyCode) + { + case 38: + red.val(setValueInRange.call($this, (red.val() << 0) + 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + case 40: + red.val(setValueInRange.call($this, (red.val() << 0) - 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + } + break; + case green.get(0): + switch (e.keyCode) + { + case 38: + green.val(setValueInRange.call($this, (green.val() << 0) + 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + case 40: + green.val(setValueInRange.call($this, (green.val() << 0) - 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + } + break; + case blue.get(0): + switch (e.keyCode) + { + case 38: + blue.val(setValueInRange.call($this, (blue.val() << 0) + 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + case 40: + blue.val(setValueInRange.call($this, (blue.val() << 0) - 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + } + break; + case alpha && alpha.get(0): + switch (e.keyCode) + { + case 38: + alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) + 1, 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + case 40: + alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) - 1, 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + } + break; + case hue.get(0): + switch (e.keyCode) + { + case 38: + hue.val(setValueInRange.call($this, (hue.val() << 0) + 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + case 40: + hue.val(setValueInRange.call($this, (hue.val() << 0) - 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + } + break; + case saturation.get(0): + switch (e.keyCode) + { + case 38: + saturation.val(setValueInRange.call($this, (saturation.val() << 0) + 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + case 40: + saturation.val(setValueInRange.call($this, (saturation.val() << 0) - 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + } + break; + case value.get(0): + switch (e.keyCode) + { + case 38: + value.val(setValueInRange.call($this, (value.val() << 0) + 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + case 40: + value.val(setValueInRange.call($this, (value.val() << 0) - 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + } + break; + } + }, + keyUp = // input box key up - validate value and set color + function(e) + { + if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return; + if (!validateKey(e)) return e; + switch (e.target) + { + case red.get(0): + red.val(setValueInRange.call($this, red.val(), 0, 255)); + color.val('r', red.val(), e.target); + break; + case green.get(0): + green.val(setValueInRange.call($this, green.val(), 0, 255)); + color.val('g', green.val(), e.target); + break; + case blue.get(0): + blue.val(setValueInRange.call($this, blue.val(), 0, 255)); + color.val('b', blue.val(), e.target); + break; + case alpha && alpha.get(0): + alpha.val(setValueInRange.call($this, alpha.val(), 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + break; + case hue.get(0): + hue.val(setValueInRange.call($this, hue.val(), 0, 360)); + color.val('h', hue.val(), e.target); + break; + case saturation.get(0): + saturation.val(setValueInRange.call($this, saturation.val(), 0, 100)); + color.val('s', saturation.val(), e.target); + break; + case value.get(0): + value.val(setValueInRange.call($this, value.val(), 0, 100)); + color.val('v', value.val(), e.target); + break; + case hex.get(0): + hex.val(hex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); + bindedHex && bindedHex.val(hex.val()); + color.val('hex', hex.val() != '' ? hex.val() : null, e.target); + break; + case bindedHex && bindedHex.get(0): + bindedHex.val(bindedHex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); + hex.val(bindedHex.val()); + color.val('hex', bindedHex.val() != '' ? bindedHex.val() : null, e.target); + break; + case ahex && ahex.get(0): + ahex.val(ahex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 2)); + color.val('a', ahex.val() != null ? parseInt(ahex.val(), 16) : null, e.target); + break; + } + }, + blur = // input box blur - reset to original if value empty + function(e) + { + if (color.val() != null) + { + switch (e.target) + { + case red.get(0): red.val(color.val('r')); break; + case green.get(0): green.val(color.val('g')); break; + case blue.get(0): blue.val(color.val('b')); break; + case alpha && alpha.get(0): alpha.val(Math.precision((color.val('a') * 100) / 255, alphaPrecision)); break; + case hue.get(0): hue.val(color.val('h')); break; + case saturation.get(0): saturation.val(color.val('s')); break; + case value.get(0): value.val(color.val('v')); break; + case hex.get(0): + case bindedHex && bindedHex.get(0): + hex.val(color.val('hex')); + bindedHex && bindedHex.val(color.val('hex')); + break; + case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; + } + } + }, + validateKey = // validate key + function(e) + { + switch(e.keyCode) + { + case 9: + case 16: + case 29: + case 37: + case 39: + return false; + case 'c'.charCodeAt(): + case 'v'.charCodeAt(): + if (e.ctrlKey) return false; + } + return true; + }, + setValueInRange = // constrain value within range + function(value, min, max) + { + if (value == '' || isNaN(value)) return min; + if (value > max) return max; + if (value < min) return min; + return value; + }, + colorChanged = + function(ui, context) + { + var all = ui.val('all'); + if (context != red.get(0)) red.val(all != null ? all.r : ''); + if (context != green.get(0)) green.val(all != null ? all.g : ''); + if (context != blue.get(0)) blue.val(all != null ? all.b : ''); + if (alpha && context != alpha.get(0)) alpha.val(all != null ? Math.precision((all.a * 100) / 255, alphaPrecision) : ''); + if (context != hue.get(0)) hue.val(all != null ? all.h : ''); + if (context != saturation.get(0)) saturation.val(all != null ? all.s : ''); + if (context != value.get(0)) value.val(all != null ? all.v : ''); + if (context != hex.get(0) && (bindedHex && context != bindedHex.get(0) || !bindedHex)) hex.val(all != null ? all.hex : ''); + if (bindedHex && context != bindedHex.get(0) && context != hex.get(0)) bindedHex.val(all != null ? all.hex : ''); + if (ahex && context != ahex.get(0)) ahex.val(all != null ? all.ahex.substring(6) : ''); + }, + destroy = + function() + { + // unbind all events and null objects + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); + color.unbind(colorChanged); + red = null; + green = null; + blue = null; + alpha = null; + hue = null; + saturation = null; + value = null; + hex = null; + ahex = null; + }; + $.extend(true, $this, // public properties and methods + { + destroy: destroy + }); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); + color.bind(colorChanged); + }; + $.jPicker = + { + List: [], // array holding references to each active instance of the control + Color: // color object - we will be able to assign by any color space type or retrieve any color space info + // we want this public so we can optionally assign new color objects to initial values using inputs other than a string hex value (also supported) + function(init) + { + var $this = this, + r, + g, + b, + a, + h, + s, + v, + changeEvents = new Array(), + fireChangeEvents = + function(context) + { + for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); + }, + val = + function(name, value, context) + { + var set = value !== undefined; + if (!set) + { + if (name === undefined || name == null || name == '') name = 'all'; + if (r == null) return null; + switch (name.toLowerCase()) + { + case 'ahex': return ColorMethods.rgbaToHex({ r: r, g: g, b: b, a: a }); + case 'hex': return val('ahex').substring(0, 6); + case 'all': return { r: r, g: g, b: b, a: a, h: h, s: s, v: v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') }; + default: + var ret={}; + for (var i = 0; i < name.length; i++) + { + switch (name.charAt(i)) + { + case 'r': + if (name.length == 1) ret = r; + else ret.r = r; + break; + case 'g': + if (name.length == 1) ret = g; + else ret.g = g; + break; + case 'b': + if (name.length == 1) ret = b; + else ret.b = b; + break; + case 'a': + if (name.length == 1) ret = a; + else ret.a = a; + break; + case 'h': + if (name.length == 1) ret = h; + else ret.h = h; + break; + case 's': + if (name.length == 1) ret = s; + else ret.s = s; + break; + case 'v': + if (name.length == 1) ret = v; + else ret.v = v; + break; + } + } + return ret == {} ? val.call($this, 'all') : ret; + break; + } + } + if (context != null && context == $this) return; + var changed = false; + if (name == null) name = ''; + if (value == null) + { + if (r != null) + { + r = null; + changed = true; + } + if (g != null) + { + g = null; + changed = true; + } + if (b != null) + { + b = null; + changed = true; + } + if (a != null) + { + a = null; + changed = true; + } + if (h != null) + { + h = null; + changed = true; + } + if (s != null) + { + s = null; + changed = true; + } + if (v != null) + { + v = null; + changed = true; + } + changed && fireChangeEvents.call($this, context || $this); + return; + } + switch (name.toLowerCase()) + { + case 'ahex': + case 'hex': + var ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || '00000000'); + val.call($this, 'rgba', { r: ret.r, g: ret.g, b: ret.b, a: name == 'ahex' ? ret.a : a != null ? a : 255 }, context); + break; + default: + if (value && (value.ahex != null || value.hex != null)) + { + val.call($this, 'ahex', value.ahex || value.hex || '00000000', context); + return; + } + var newV = {}, rgb = false, hsv = false; + if (value.r !== undefined && !name.indexOf('r') == -1) name += 'r'; + if (value.g !== undefined && !name.indexOf('g') == -1) name += 'g'; + if (value.b !== undefined && !name.indexOf('b') == -1) name += 'b'; + if (value.a !== undefined && !name.indexOf('a') == -1) name += 'a'; + if (value.h !== undefined && !name.indexOf('h') == -1) name += 'h'; + if (value.s !== undefined && !name.indexOf('s') == -1) name += 's'; + if (value.v !== undefined && !name.indexOf('v') == -1) name += 'v'; + for (var i = 0; i < name.length; i++) + { + switch (name.charAt(i)) + { + case 'r': + if (hsv) continue; + rgb = true; + newV.r = value && value.r && value.r | 0 || value && value | 0 || 0; + if (newV.r < 0) newV.r = 0; + else if (newV.r > 255) newV.r = 255; + if (r != newV.r) + { + r = newV.r; + changed = true; + } + break; + case 'g': + if (hsv) continue; + rgb = true; + newV.g = value && value.g && value.g | 0 || value && value | 0 || 0; + if (newV.g < 0) newV.g = 0; + else if (newV.g > 255) newV.g = 255; + if (g != newV.g) + { + g = newV.g; + changed = true; + } + break; + case 'b': + if (hsv) continue; + rgb = true; + newV.b = value && value.b && value.b | 0 || value && value | 0 || 0; + if (newV.b < 0) newV.b = 0; + else if (newV.b > 255) newV.b = 255; + if (b != newV.b) + { + b = newV.b; + changed = true; + } + break; + case 'a': + newV.a = value && value.a != null ? value.a | 0 : value != null ? value | 0 : 255; + if (newV.a < 0) newV.a = 0; + else if (newV.a > 255) newV.a = 255; + if (a != newV.a) + { + a = newV.a; + changed = true; + } + break; + case 'h': + if (rgb) continue; + hsv = true; + newV.h = value && value.h && value.h | 0 || value && value | 0 || 0; + if (newV.h < 0) newV.h = 0; + else if (newV.h > 360) newV.h = 360; + if (h != newV.h) + { + h = newV.h; + changed = true; + } + break; + case 's': + if (rgb) continue; + hsv = true; + newV.s = value && value.s != null ? value.s | 0 : value != null ? value | 0 : 100; + if (newV.s < 0) newV.s = 0; + else if (newV.s > 100) newV.s = 100; + if (s != newV.s) + { + s = newV.s; + changed = true; + } + break; + case 'v': + if (rgb) continue; + hsv = true; + newV.v = value && value.v != null ? value.v | 0 : value != null ? value | 0 : 100; + if (newV.v < 0) newV.v = 0; + else if (newV.v > 100) newV.v = 100; + if (v != newV.v) + { + v = newV.v; + changed = true; + } + break; + } + } + if (changed) + { + if (rgb) + { + r = r || 0; + g = g || 0; + b = b || 0; + var ret = ColorMethods.rgbToHsv({ r: r, g: g, b: b }); + h = ret.h; + s = ret.s; + v = ret.v; + } + else if (hsv) + { + h = h || 0; + s = s != null ? s : 100; + v = v != null ? v : 100; + var ret = ColorMethods.hsvToRgb({ h: h, s: s, v: v }); + r = ret.r; + g = ret.g; + b = ret.b; + } + a = a != null ? a : 255; + fireChangeEvents.call($this, context || $this); + } + break; + } + }, + bind = + function(callback) + { + if ($.isFunction(callback)) changeEvents.push(callback); + }, + unbind = + function(callback) + { + if (!$.isFunction(callback)) return; + var i; + while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1); + }, + destroy = + function() + { + changeEvents = null; + } + $.extend(true, $this, // public properties and methods + { + val: val, + bind: bind, + unbind: unbind, + destroy: destroy + }); + if (init) + { + if (init.ahex != null) val('ahex', init); + else if (init.hex != null) val((init.a != null ? 'a' : '') + 'hex', init.a != null ? { ahex: init.hex + ColorMethods.intToHex(init.a) } : init); + else if (init.r != null && init.g != null && init.b != null) val('rgb' + (init.a != null ? 'a' : ''), init); + else if (init.h != null && init.s != null && init.v != null) val('hsv' + (init.a != null ? 'a' : ''), init); + } + }, + ColorMethods: // color conversion methods - make public to give use to external scripts + { + hexToRgba: + function(hex) + { + hex = this.validateHex(hex); + if (hex == '') return { r: null, g: null, b: null, a: null }; + var r = '00', g = '00', b = '00', a = '255'; + if (hex.length == 6) hex += 'ff'; + if (hex.length > 6) + { + r = hex.substring(0, 2); + g = hex.substring(2, 4); + b = hex.substring(4, 6); + a = hex.substring(6, hex.length); + } + else + { + if (hex.length > 4) + { + r = hex.substring(4, hex.length); + hex = hex.substring(0, 4); + } + if (hex.length > 2) + { + g = hex.substring(2, hex.length); + hex = hex.substring(0, 2); + } + if (hex.length > 0) b = hex.substring(0, hex.length); + } + return { r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) }; + }, + validateHex: + function(hex) + { + if (typeof hex == "object") return ''; + hex = hex.toLowerCase().replace(/[^a-f0-9]/g, ''); + if (hex.length > 8) hex = hex.substring(0, 8); + return hex; + }, + rgbaToHex: + function(rgba) + { + return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); + }, + intToHex: + function(dec) + { + var result = (dec | 0).toString(16); + if (result.length == 1) result = ('0' + result); + return result.toLowerCase(); + }, + hexToInt: + function(hex) + { + return parseInt(hex, 16); + }, + rgbToHsv: + function(rgb) + { + var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = { h: 0, s: 0, v: 0 }, min = 0, max = 0, delta; + if (r >= g && r >= b) + { + max = r; + min = g > b ? b : g; + } + else if (g >= b && g >= r) + { + max = g; + min = r > b ? b : r; + } + else + { + max = b; + min = g > r ? r : g; + } + hsv.v = max; + hsv.s = max ? (max - min) / max : 0; + if (!hsv.s) hsv.h = 0; + else + { + delta = max - min; + if (r == max) hsv.h = (g - b) / delta; + else if (g == max) hsv.h = 2 + (b - r) / delta; + else hsv.h = 4 + (r - g) / delta; + hsv.h = parseInt(hsv.h * 60); + if (hsv.h < 0) hsv.h += 360; + } + hsv.s = (hsv.s * 100) | 0; + hsv.v = (hsv.v * 100) | 0; + return hsv; + }, + hsvToRgb: + function(hsv) + { + var rgb = { r: 0, g: 0, b: 0, a: 100 }, h = hsv.h, s = hsv.s, v = hsv.v; + if (s == 0) + { + if (v == 0) rgb.r = rgb.g = rgb.b = 0; + else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0; + } + else + { + if (h == 360) h = 0; + h /= 60; + s = s / 100; + v = v / 100; + var i = h | 0, + f = h - i, + p = v * (1 - s), + q = v * (1 - (s * f)), + t = v * (1 - (s * (1 - f))); + switch (i) + { + case 0: + rgb.r = v; + rgb.g = t; + rgb.b = p; + break; + case 1: + rgb.r = q; + rgb.g = v; + rgb.b = p; + break; + case 2: + rgb.r = p; + rgb.g = v; + rgb.b = t; + break; + case 3: + rgb.r = p; + rgb.g = q; + rgb.b = v; + break; + case 4: + rgb.r = t; + rgb.g = p; + rgb.b = v; + break; + case 5: + rgb.r = v; + rgb.g = p; + rgb.b = q; + break; + } + rgb.r = (rgb.r * 255) | 0; + rgb.g = (rgb.g * 255) | 0; + rgb.b = (rgb.b * 255) | 0; + } + return rgb; + } + } + }; + var Color = $.jPicker.Color, List = $.jPicker.List, ColorMethods = $.jPicker.ColorMethods; // local copies for YUI compressor + $.fn.jPicker = + function(options) + { + var $arguments = arguments; + return this.each( + function() + { + var $this = this, settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor + if ($($this).get(0).nodeName.toLowerCase() == 'input') // Add color picker icon if binding to an input element and bind the events to the input + { + $.extend(true, settings, + { + window: + { + bindToInput: true, + expandable: true, + input: $($this) + } + }); + if($($this).val()=='') + { + settings.color.active = new Color({ hex: null }); + settings.color.current = new Color({ hex: null }); + } + else if (ColorMethods.validateHex($($this).val())) + { + settings.color.active = new Color({ hex: $($this).val(), a: settings.color.active.val('a') }); + settings.color.current = new Color({ hex: $($this).val(), a: settings.color.active.val('a') }); + } + } + if (settings.window.expandable) + $($this).after('<span class="jPicker"><span class="Icon"><span class="Color"> </span><span class="Alpha"> </span><span class="Image" title="Click To Open Color Picker"> </span><span class="Container"> </span></span></span>'); + else settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results + var isLessThanIE7 = parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters, // needed to run the AlphaImageLoader function for IE6 + container = null, + colorMapDiv = null, + colorBarDiv = null, + colorMapL1 = null, // different layers of colorMap and colorBar + colorMapL2 = null, + colorMapL3 = null, + colorBarL1 = null, + colorBarL2 = null, + colorBarL3 = null, + colorBarL4 = null, + colorBarL5 = null, + colorBarL6 = null, + colorMap = null, // color maps + colorBar = null, + colorPicker = null, + elementStartX = null, // Used to record the starting css positions for dragging the control + elementStartY = null, + pageStartX = null, // Used to record the mousedown coordinates for dragging the control + pageStartY = null, + activePreview = null, // color boxes above the radio buttons + currentPreview = null, + okButton = null, + cancelButton = null, + grid = null, // preset colors grid + iconColor = null, // iconColor for popup icon + iconAlpha = null, // iconAlpha for popup icon + iconImage = null, // iconImage popup icon + moveBar = null, // drag bar + setColorMode = // set color mode and update visuals for the new color mode + function(colorMode) + { + var active = color.active, // local copies for YUI compressor + clientPath = images.clientPath, + hex = active.val('hex'), + rgbMap, + rgbBar; + settings.color.mode = colorMode; + switch (colorMode) + { + case 'h': + setTimeout( + function() + { + setBG.call($this, colorMapDiv, 'transparent'); + setImgLoc.call($this, colorMapL1, 0); + setAlpha.call($this, colorMapL1, 100); + setImgLoc.call($this, colorMapL2, 260); + setAlpha.call($this, colorMapL2, 100); + setBG.call($this, colorBarDiv, 'transparent'); + setImgLoc.call($this, colorBarL1, 0); + setAlpha.call($this, colorBarL1, 100); + setImgLoc.call($this, colorBarL2, 260); + setAlpha.call($this, colorBarL2, 100); + setImgLoc.call($this, colorBarL3, 260); + setAlpha.call($this, colorBarL3, 100); + setImgLoc.call($this, colorBarL4, 260); + setAlpha.call($this, colorBarL4, 100); + setImgLoc.call($this, colorBarL6, 260); + setAlpha.call($this, colorBarL6, 100); + }, 0); + colorMap.range('all', { minX: 0, maxX: 100, minY: 0, maxY: 100 }); + colorBar.range('rangeY', { minY: 0, maxY: 360 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('s'), y: 100 - active.val('v') }, colorMap); + colorBar.val('y', 360 - active.val('h'), colorBar); + break; + case 's': + setTimeout( + function() + { + setBG.call($this, colorMapDiv, 'transparent'); + setImgLoc.call($this, colorMapL1, -260); + setImgLoc.call($this, colorMapL2, -520); + setImgLoc.call($this, colorBarL1, -260); + setImgLoc.call($this, colorBarL2, -520); + setImgLoc.call($this, colorBarL6, 260); + setAlpha.call($this, colorBarL6, 100); + }, 0); + colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); + colorBar.range('rangeY', { minY: 0, maxY: 100 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap); + colorBar.val('y', 100 - active.val('s'), colorBar); + break; + case 'v': + setTimeout( + function() + { + setBG.call($this, colorMapDiv, '000000'); + setImgLoc.call($this, colorMapL1, -780); + setImgLoc.call($this, colorMapL2, 260); + setBG.call($this, colorBarDiv, hex); + setImgLoc.call($this, colorBarL1, -520); + setImgLoc.call($this, colorBarL2, 260); + setAlpha.call($this, colorBarL2, 100); + setImgLoc.call($this, colorBarL6, 260); + setAlpha.call($this, colorBarL6, 100); + }, 0); + colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); + colorBar.range('rangeY', { minY: 0, maxY: 100 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('s') }, colorMap); + colorBar.val('y', 100 - active.val('v'), colorBar); + break; + case 'r': + rgbMap = -1040; + rgbBar = -780; + colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); + colorBar.range('rangeY', { minY: 0, maxY: 255 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('g') }, colorMap); + colorBar.val('y', 255 - active.val('r'), colorBar); + break; + case 'g': + rgbMap = -1560; + rgbBar = -1820; + colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); + colorBar.range('rangeY', { minY: 0, maxY: 255 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('r') }, colorMap); + colorBar.val('y', 255 - active.val('g'), colorBar); + break; + case 'b': + rgbMap = -2080; + rgbBar = -2860; + colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); + colorBar.range('rangeY', { minY: 0, maxY: 255 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('r'), y: 255 - active.val('g') }, colorMap); + colorBar.val('y', 255 - active.val('b'), colorBar); + break; + case 'a': + setTimeout( + function() + { + setBG.call($this, colorMapDiv, 'transparent'); + setImgLoc.call($this, colorMapL1, -260); + setImgLoc.call($this, colorMapL2, -520); + setImgLoc.call($this, colorBarL1, 260); + setImgLoc.call($this, colorBarL2, 260); + setAlpha.call($this, colorBarL2, 100); + setImgLoc.call($this, colorBarL6, 0); + setAlpha.call($this, colorBarL6, 100); + }, 0); + colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); + colorBar.range('rangeY', { minY: 0, maxY: 255 }); + if (active.val('ahex') == null) break; + colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap); + colorBar.val('y', 255 - active.val('a'), colorBar); + break; + default: + throw ('Invalid Mode'); + break; + } + switch (colorMode) + { + case 'h': + break; + case 's': + case 'v': + case 'a': + setTimeout( + function() + { + setAlpha.call($this, colorMapL1, 100); + setAlpha.call($this, colorBarL1, 100); + setImgLoc.call($this, colorBarL3, 260); + setAlpha.call($this, colorBarL3, 100); + setImgLoc.call($this, colorBarL4, 260); + setAlpha.call($this, colorBarL4, 100); + }, 0); + break; + case 'r': + case 'g': + case 'b': + setTimeout( + function() + { + setBG.call($this, colorMapDiv, 'transparent'); + setBG.call($this, colorBarDiv, 'transparent'); + setAlpha.call($this, colorBarL1, 100); + setAlpha.call($this, colorMapL1, 100); + setImgLoc.call($this, colorMapL1, rgbMap); + setImgLoc.call($this, colorMapL2, rgbMap - 260); + setImgLoc.call($this, colorBarL1, rgbBar - 780); + setImgLoc.call($this, colorBarL2, rgbBar - 520); + setImgLoc.call($this, colorBarL3, rgbBar); + setImgLoc.call($this, colorBarL4, rgbBar - 260); + setImgLoc.call($this, colorBarL6, 260); + setAlpha.call($this, colorBarL6, 100); + }, 0); + break; + } + if (active.val('ahex') == null) return; + activeColorChanged.call($this, active); + }, + activeColorChanged = // Update color when user changes text values + function(ui, context) + { + if (context == null || (context != colorBar && context != colorMap)) positionMapAndBarArrows.call($this, ui, context); + setTimeout( + function() + { + updatePreview.call($this, ui); + updateMapVisuals.call($this, ui); + updateBarVisuals.call($this, ui); + }, 0); + }, + mapValueChanged = // user has dragged the ColorMap pointer + function(ui, context) + { + var active = color.active; + if (context != colorMap && active.val() == null) return; + var xy = ui.val('all'); + switch (settings.color.mode) + { + case 'h': + active.val('sv', { s: xy.x, v: 100 - xy.y }, context); + break; + case 's': + case 'a': + active.val('hv', { h: xy.x, v: 100 - xy.y }, context); + break; + case 'v': + active.val('hs', { h: xy.x, s: 100 - xy.y }, context); + break; + case 'r': + active.val('gb', { g: 255 - xy.y, b: xy.x }, context); + break; + case 'g': + active.val('rb', { r: 255 - xy.y, b: xy.x }, context); + break; + case 'b': + active.val('rg', { r: xy.x, g: 255 - xy.y }, context); + break; + } + }, + colorBarValueChanged = // user has dragged the ColorBar slider + function(ui, context) + { + var active = color.active; + if (context != colorBar && active.val() == null) return; + switch (settings.color.mode) + { + case 'h': + active.val('h', { h: 360 - ui.val('y') }, context); + break; + case 's': + active.val('s', { s: 100 - ui.val('y') }, context); + break; + case 'v': + active.val('v', { v: 100 - ui.val('y') }, context); + break; + case 'r': + active.val('r', { r: 255 - ui.val('y') }, context); + break; + case 'g': + active.val('g', { g: 255 - ui.val('y') }, context); + break; + case 'b': + active.val('b', { b: 255 - ui.val('y') }, context); + break; + case 'a': + active.val('a', 255 - ui.val('y'), context); + break; + } + }, + positionMapAndBarArrows = // position map and bar arrows to match current color + function(ui, context) + { + if (context != colorMap) + { + switch (settings.color.mode) + { + case 'h': + var sv = ui.val('sv'); + colorMap.val('xy', { x: sv != null ? sv.s : 100, y: 100 - (sv != null ? sv.v : 100) }, context); + break; + case 's': + case 'a': + var hv = ui.val('hv'); + colorMap.val('xy', { x: hv && hv.h || 0, y: 100 - (hv != null ? hv.v : 100) }, context); + break; + case 'v': + var hs = ui.val('hs'); + colorMap.val('xy', { x: hs && hs.h || 0, y: 100 - (hs != null ? hs.s : 100) }, context); + break; + case 'r': + var bg = ui.val('bg'); + colorMap.val('xy', { x: bg && bg.b || 0, y: 255 - (bg && bg.g || 0) }, context); + break; + case 'g': + var br = ui.val('br'); + colorMap.val('xy', { x: br && br.b || 0, y: 255 - (br && br.r || 0) }, context); + break; + case 'b': + var rg = ui.val('rg'); + colorMap.val('xy', { x: rg && rg.r || 0, y: 255 - (rg && rg.g || 0) }, context); + break; + } + } + if (context != colorBar) + { + switch (settings.color.mode) + { + case 'h': + colorBar.val('y', 360 - (ui.val('h') || 0), context); + break; + case 's': + var s = ui.val('s'); + colorBar.val('y', 100 - (s != null ? s : 100), context); + break; + case 'v': + var v = ui.val('v'); + colorBar.val('y', 100 - (v != null ? v : 100), context); + break; + case 'r': + colorBar.val('y', 255 - (ui.val('r') || 0), context); + break; + case 'g': + colorBar.val('y', 255 - (ui.val('g') || 0), context); + break; + case 'b': + colorBar.val('y', 255 - (ui.val('b') || 0), context); + break; + case 'a': + var a = ui.val('a'); + colorBar.val('y', 255 - (a != null ? a : 255), context); + break; + } + } + }, + updatePreview = + function(ui) + { + try + { + var all = ui.val('all'); + activePreview.css({ backgroundColor: all && '#' + all.hex || 'transparent' }); + setAlpha.call($this, activePreview, all && Math.precision((all.a * 100) / 255, 4) || 0); + } + catch (e) { } + }, + updateMapVisuals = + function(ui) + { + switch (settings.color.mode) + { + case 'h': + setBG.call($this, colorMapDiv, new Color({ h: ui.val('h') || 0, s: 100, v: 100 }).val('hex')); + break; + case 's': + case 'a': + var s = ui.val('s'); + setAlpha.call($this, colorMapL2, 100 - (s != null ? s : 100)); + break; + case 'v': + var v = ui.val('v'); + setAlpha.call($this, colorMapL1, v != null ? v : 100); + break; + case 'r': + setAlpha.call($this, colorMapL2, Math.precision((ui.val('r') || 0) / 255 * 100, 4)); + break; + case 'g': + setAlpha.call($this, colorMapL2, Math.precision((ui.val('g') || 0) / 255 * 100, 4)); + break; + case 'b': + setAlpha.call($this, colorMapL2, Math.precision((ui.val('b') || 0) / 255 * 100)); + break; + } + var a = ui.val('a'); + setAlpha.call($this, colorMapL3, Math.precision(((255 - (a || 0)) * 100) / 255, 4)); + }, + updateBarVisuals = + function(ui) + { + switch (settings.color.mode) + { + case 'h': + var a = ui.val('a'); + setAlpha.call($this, colorBarL5, Math.precision(((255 - (a || 0)) * 100) / 255, 4)); + break; + case 's': + var hva = ui.val('hva'), + saturatedColor = new Color({ h: hva && hva.h || 0, s: 100, v: hva != null ? hva.v : 100 }); + setBG.call($this, colorBarDiv, saturatedColor.val('hex')); + setAlpha.call($this, colorBarL2, 100 - (hva != null ? hva.v : 100)); + setAlpha.call($this, colorBarL5, Math.precision(((255 - (hva && hva.a || 0)) * 100) / 255, 4)); + break; + case 'v': + var hsa = ui.val('hsa'), + valueColor = new Color({ h: hsa && hsa.h || 0, s: hsa != null ? hsa.s : 100, v: 100 }); + setBG.call($this, colorBarDiv, valueColor.val('hex')); + setAlpha.call($this, colorBarL5, Math.precision(((255 - (hsa && hsa.a || 0)) * 100) / 255, 4)); + break; + case 'r': + case 'g': + case 'b': + var hValue = 0, vValue = 0, rgba = ui.val('rgba'); + if (settings.color.mode == 'r') + { + hValue = rgba && rgba.b || 0; + vValue = rgba && rgba.g || 0; + } + else if (settings.color.mode == 'g') + { + hValue = rgba && rgba.b || 0; + vValue = rgba && rgba.r || 0; + } + else if (settings.color.mode == 'b') + { + hValue = rgba && rgba.r || 0; + vValue = rgba && rgba.g || 0; + } + var middle = vValue > hValue ? hValue : vValue; + setAlpha.call($this, colorBarL2, hValue > vValue ? Math.precision(((hValue - vValue) / (255 - vValue)) * 100, 4) : 0); + setAlpha.call($this, colorBarL3, vValue > hValue ? Math.precision(((vValue - hValue) / (255 - hValue)) * 100, 4) : 0); + setAlpha.call($this, colorBarL4, Math.precision((middle / 255) * 100, 4)); + setAlpha.call($this, colorBarL5, Math.precision(((255 - (rgba && rgba.a || 0)) * 100) / 255, 4)); + break; + case 'a': + var a = ui.val('a'); + setBG.call($this, colorBarDiv, ui.val('hex') || '000000'); + setAlpha.call($this, colorBarL5, a != null ? 0 : 100); + setAlpha.call($this, colorBarL6, a != null ? 100 : 0); + break; + } + }, + setBG = + function(el, c) + { + el.css({ backgroundColor: c && c.length == 6 && '#' + c || 'transparent' }); + }, + setImg = + function(img, src) + { + if (isLessThanIE7 && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) + { + img.attr('pngSrc', src); + img.css({ backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' }); + } + else img.css({ backgroundImage: 'url(\'' + src + '\')' }); + }, + setImgLoc = + function(img, y) + { + img.css({ top: y + 'px' }); + }, + setAlpha = + function(obj, alpha) + { + obj.css({ visibility: alpha > 0 ? 'visible' : 'hidden' }); + if (alpha > 0 && alpha < 100) + { + if (isLessThanIE7) + { + var src = obj.attr('pngSrc'); + if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) + obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' }); + else obj.css({ opacity: Math.precision(alpha / 100, 4) }); + } + else obj.css({ opacity: Math.precision(alpha / 100, 4) }); + } + else if (alpha == 0 || alpha == 100) + { + if (isLessThanIE7) + { + var src = obj.attr('pngSrc'); + if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) + obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' }); + else obj.css({ opacity: '' }); + } + else obj.css({ opacity: '' }); + } + }, + revertColor = // revert color to original color when opened + function() + { + color.active.val('ahex', color.current.val('ahex')); + }, + commitColor = // commit the color changes + function() + { + color.current.val('ahex', color.active.val('ahex')); + }, + radioClicked = + function(e) + { + $(this).parents('tbody:first').find('input:radio[value!="'+e.target.value+'"]').removeAttr('checked'); + setColorMode.call($this, e.target.value); + }, + currentClicked = + function() + { + revertColor.call($this); + }, + cancelClicked = + function() + { + revertColor.call($this); + settings.window.expandable && hide.call($this); + $.isFunction(cancelCallback) && cancelCallback.call($this, color.active, cancelButton); + }, + okClicked = + function() + { + commitColor.call($this); + settings.window.expandable && hide.call($this); + $.isFunction(commitCallback) && commitCallback.call($this, color.active, okButton); + }, + iconImageClicked = + function() + { + show.call($this); + }, + currentColorChanged = + function(ui, context) + { + var hex = ui.val('hex'); + currentPreview.css({ backgroundColor: hex && '#' + hex || 'transparent' }); + setAlpha.call($this, currentPreview, Math.precision(((ui.val('a') || 0) * 100) / 255, 4)); + }, + expandableColorChanged = + function(ui, context) + { + var hex = ui.val('hex'); + var va = ui.val('va'); + iconColor.css({ backgroundColor: hex && '#' + hex || 'transparent' }); + setAlpha.call($this, iconAlpha, Math.precision(((255 - (va && va.a || 0)) * 100) / 255, 4)); + if (settings.window.bindToInput&&settings.window.updateInputColor) + settings.window.input.css( + { + backgroundColor: hex && '#' + hex || 'transparent', + color: va == null || va.v > 75 ? '#000000' : '#ffffff' + }); + }, + moveBarMouseDown = + function(e) + { + var element = settings.window.element, // local copies for YUI compressor + page = settings.window.page; + elementStartX = parseInt(container.css('left')); + elementStartY = parseInt(container.css('top')); + pageStartX = e.pageX; + pageStartY = e.pageY; + // bind events to document to move window - we will unbind these on mouseup + $(document).bind('mousemove', documentMouseMove).bind('mouseup', documentMouseUp); + e.preventDefault(); // prevent attempted dragging of the column + }, + documentMouseMove = + function(e) + { + container.css({ left: elementStartX - (pageStartX - e.pageX) + 'px', top: elementStartY - (pageStartY - e.pageY) + 'px' }); + if (settings.window.expandable && !$.support.boxModel) container.prev().css({ left: container.css("left"), top: container.css("top") }); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + documentMouseUp = + function(e) + { + $(document).unbind('mousemove', documentMouseMove).unbind('mouseup', documentMouseUp); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + quickPickClicked = + function(e) + { + e.preventDefault(); + e.stopPropagation(); + color.active.val('ahex', $(this).attr('title') || null, e.target); + return false; + }, + commitCallback = $.isFunction($arguments[1]) && $arguments[1] || null, + liveCallback = $.isFunction($arguments[2]) && $arguments[2] || null, + cancelCallback = $.isFunction($arguments[3]) && $arguments[3] || null, + show = + function() + { + color.current.val('ahex', color.active.val('ahex')); + var attachIFrame = function() + { + if (!settings.window.expandable || $.support.boxModel) return; + var table = container.find('table:first'); + container.before('<iframe/>'); + container.prev().css({ width: table.width(), height: container.height(), opacity: 0, position: 'absolute', left: container.css("left"), top: container.css("top") }); + }; + if (settings.window.expandable) + { + $(document.body).children('div.jPicker.Container').css({zIndex:10}); + container.css({zIndex:20}); + } + switch (settings.window.effects.type) + { + case 'fade': + container.fadeIn(settings.window.effects.speed.show, attachIFrame); + break; + case 'slide': + container.slideDown(settings.window.effects.speed.show, attachIFrame); + break; + case 'show': + default: + container.show(settings.window.effects.speed.show, attachIFrame); + break; + } + }, + hide = + function() + { + var removeIFrame = function() + { + if (settings.window.expandable) container.css({ zIndex: 10 }); + if (!settings.window.expandable || $.support.boxModel) return; + container.prev().remove(); + }; + switch (settings.window.effects.type) + { + case 'fade': + container.fadeOut(settings.window.effects.speed.hide, removeIFrame); + break; + case 'slide': + container.slideUp(settings.window.effects.speed.hide, removeIFrame); + break; + case 'show': + default: + container.hide(settings.window.effects.speed.hide, removeIFrame); + break; + } + }, + initialize = + function() + { + var win = settings.window, + popup = win.expandable ? $($this).next().find('.Container:first') : null; + container = win.expandable ? $('<div/>') : $($this); + container.addClass('jPicker Container'); + if (win.expandable) container.hide(); + container.get(0).onselectstart = function(event){ if (event.target.nodeName.toLowerCase() !== 'input') return false; }; + // inject html source code - we are using a single table for this control - I know tables are considered bad, but it takes care of equal height columns and + // this control really is tabular data, so I believe it is the right move + var all = color.active.val('all'); + if (win.alphaPrecision < 0) win.alphaPrecision = 0; + else if (win.alphaPrecision > 2) win.alphaPrecision = 2; + var controlHtml='<table class="jPicker" cellpadding="0" cellspacing="0"><tbody>' + (win.expandable ? '<tr><td class="Move" colspan="5"> </td></tr>' : '') + '<tr><td rowspan="9"><h2 class="Title">' + (win.title || localization.text.title) + '</h2><div class="Map"><span class="Map1"> </span><span class="Map2"> </span><span class="Map3"> </span><img src="' + images.clientPath + images.colorMap.arrow.file + '" class="Arrow"/></div></td><td rowspan="9"><div class="Bar"><span class="Map1"> </span><span class="Map2"> </span><span class="Map3"> </span><span class="Map4"> </span><span class="Map5"> </span><span class="Map6"> </span><img src="' + images.clientPath + images.colorBar.arrow.file + '" class="Arrow"/></div></td><td colspan="2" class="Preview"><div class="prev_div">' + localization.text.newColor + '<div class="color_preview"><span class="Active" title="' + localization.tooltips.colors.newColor + '"> </span><span class="Current" title="' + localization.tooltips.colors.currentColor + '"> </span></div></div>' + localization.text.currentColor + '</td><td rowspan="9" class="Button"><input type="button" class="Ok" value="' + localization.text.ok + '" title="' + localization.tooltips.buttons.ok + '"/><input type="button" class="Cancel" value="' + localization.text.cancel + '" title="' + localization.tooltips.buttons.cancel + '"/><div class="Grid"> </div></td></tr><tr class="Hue"><td class="Radio"><label title="' + localization.tooltips.hue.radio + '"><input type="radio" value="h"' + (settings.color.mode == 'h' ? ' checked="checked"' : '') + '/>H:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.h : '') + '" title="' + localization.tooltips.hue.textbox + '"/> Âº</td></tr><tr class="Saturation"><td class="Radio"><label title="' + localization.tooltips.saturation.radio + '"><input type="radio" value="s"' + (settings.color.mode == 's' ? ' checked="checked"' : '') + '/>S:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.s : '') + '" title="' + localization.tooltips.saturation.textbox + '"/> %</td></tr><tr class="Value"><td class="Radio"><label title="' + localization.tooltips.value.radio + '"><input type="radio" value="v"' + (settings.color.mode == 'v' ? ' checked="checked"' : '') + '/>V:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.v : '') + '" title="' + localization.tooltips.value.textbox + '"/> %<br/><br/></td></tr><tr class="Red"><td class="Radio"><label title="' + localization.tooltips.red.radio + '"><input type="radio" value="r"' + (settings.color.mode == 'r' ? ' checked="checked"' : '') + '/>R:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.r : '') + '" title="' + localization.tooltips.red.textbox + '"/></td></tr><tr class="Green"><td class="Radio"><label title="' + localization.tooltips.green.radio + '"><input type="radio" value="g"' + (settings.color.mode == 'g' ? ' checked="checked"' : '') + '/>G:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.g : '') + '" title="' + localization.tooltips.green.textbox + '"/></td></tr><tr class="Blue"><td class="Radio"><label title="' + localization.tooltips.blue.radio + '"><input type="radio" value="b"' + (settings.color.mode == 'b' ? ' checked="checked"' : '') + '/>B:</label></td><td class="Text"><input type="text" maxlength="3" value="' + (all != null ? all.b : '') + '" title="' + localization.tooltips.blue.textbox + '"/></td></tr><tr class="Alpha"><td class="Radio">' + (win.alphaSupport ? '<label title="' + localization.tooltips.alpha.radio + '"><input type="radio" value="a"' + (settings.color.mode == 'a' ? ' checked="checked"' : '') + '/>A:</label>' : ' ') + '</td><td class="Text">' + (win.alphaSupport ? '<input type="text" maxlength="' + (3 + win.alphaPrecision) + '" value="' + (all != null ? Math.precision((all.a * 100) / 255, win.alphaPrecision) : '') + '" title="' + localization.tooltips.alpha.textbox + '"/> %' : ' ') + '</td></tr><tr class="Hex"><td colspan="2" class="Text"><label title="' + localization.tooltips.hex.textbox + '">#:<input type="text" maxlength="6" class="Hex" value="' + (all != null ? all.hex : '') + '"/></label>' + (win.alphaSupport ? '<input type="text" maxlength="2" class="AHex" value="' + (all != null ? all.ahex.substring(6) : '') + '" title="' + localization.tooltips.hex.alpha + '"/></td>' : ' ') + '</tr></tbody></table>'; + if (win.expandable) + { + container.html(controlHtml); + if($(document.body).children('div.jPicker.Container').length==0)$(document.body).prepend(container); + else $(document.body).children('div.jPicker.Container:last').after(container); + container.mousedown( + function() + { + $(document.body).children('div.jPicker.Container').css({zIndex:10}); + container.css({zIndex:20}); + }); + container.css( // positions must be set and display set to absolute before source code injection or IE will size the container to fit the window + { + left: + win.position.x == 'left' ? (popup.offset().left - 530 - (win.position.y == 'center' ? 25 : 0)) + 'px' : + win.position.x == 'center' ? (popup.offset().left - 260) + 'px' : + win.position.x == 'right' ? (popup.offset().left - 10 + (win.position.y == 'center' ? 25 : 0)) + 'px' : + win.position.x == 'screenCenter' ? (($(document).width() >> 1) - 260) + 'px' : (popup.offset().left + parseInt(win.position.x)) + 'px', + position: 'absolute', + top: win.position.y == 'top' ? (popup.offset().top - 312) + 'px' : + win.position.y == 'center' ? (popup.offset().top - 156) + 'px' : + win.position.y == 'bottom' ? (popup.offset().top + 25) + 'px' : (popup.offset().top + parseInt(win.position.y)) + 'px' + }); + } + else + { + container = $($this); + container.html(controlHtml); + } + // initialize the objects to the source code just injected + var tbody = container.find('tbody:first'); + colorMapDiv = tbody.find('div.Map:first'); + colorBarDiv = tbody.find('div.Bar:first'); + var MapMaps = colorMapDiv.find('span'), + BarMaps = colorBarDiv.find('span'); + colorMapL1 = MapMaps.filter('.Map1:first'); + colorMapL2 = MapMaps.filter('.Map2:first'); + colorMapL3 = MapMaps.filter('.Map3:first'); + colorBarL1 = BarMaps.filter('.Map1:first'); + colorBarL2 = BarMaps.filter('.Map2:first'); + colorBarL3 = BarMaps.filter('.Map3:first'); + colorBarL4 = BarMaps.filter('.Map4:first'); + colorBarL5 = BarMaps.filter('.Map5:first'); + colorBarL6 = BarMaps.filter('.Map6:first'); + // create color pickers and maps + colorMap = new Slider(colorMapDiv, + { + map: + { + width: images.colorMap.width, + height: images.colorMap.height + }, + arrow: + { + image: images.clientPath + images.colorMap.arrow.file, + width: images.colorMap.arrow.width, + height: images.colorMap.arrow.height + } + }); + colorMap.bind(mapValueChanged); + colorBar = new Slider(colorBarDiv, + { + map: + { + width: images.colorBar.width, + height: images.colorBar.height + }, + arrow: + { + image: images.clientPath + images.colorBar.arrow.file, + width: images.colorBar.arrow.width, + height: images.colorBar.arrow.height + } + }); + colorBar.bind(colorBarValueChanged); + colorPicker = new ColorValuePicker(tbody, color.active, win.expandable && win.bindToInput ? win.input : null, win.alphaPrecision); + var hex = all != null ? all.hex : null, + preview = tbody.find('.Preview'), + button = tbody.find('.Button'); + activePreview = preview.find('.Active:first').css({ backgroundColor: hex && '#' + hex || 'transparent' }); + currentPreview = preview.find('.Current:first').css({ backgroundColor: hex && '#' + hex || 'transparent' }).bind('click', currentClicked); + setAlpha.call($this, currentPreview, Math.precision(color.current.val('a') * 100) / 255, 4); + okButton = button.find('.Ok:first').bind('click touchstart', okClicked); + cancelButton = button.find('.Cancel:first').bind('click touchstart', cancelClicked); + grid = button.find('.Grid:first'); + setTimeout( + function() + { + setImg.call($this, colorMapL1, images.clientPath + 'Maps.png'); + setImg.call($this, colorMapL2, images.clientPath + 'Maps.png'); + setImg.call($this, colorMapL3, images.clientPath + 'map-opacity.png'); + setImg.call($this, colorBarL1, images.clientPath + 'Bars.png'); + setImg.call($this, colorBarL2, images.clientPath + 'Bars.png'); + setImg.call($this, colorBarL3, images.clientPath + 'Bars.png'); + setImg.call($this, colorBarL4, images.clientPath + 'Bars.png'); + setImg.call($this, colorBarL5, images.clientPath + 'bar-opacity.png'); + setImg.call($this, colorBarL6, images.clientPath + 'AlphaBar.png'); + setImg.call($this, preview.find('div:last'), images.clientPath + 'preview-opacity.png'); + }, 0); + tbody.find('td.Radio input').bind('click touchstart', radioClicked); + // initialize quick list + if (color.quickList && color.quickList.length > 0) + { + var html = ''; + for (i = 0; i < color.quickList.length; i++) + { + /* if default colors are hex strings, change them to color objects */ + if ((typeof (color.quickList[i])).toString().toLowerCase() == 'string') color.quickList[i] = new Color({ hex: color.quickList[i] }); + var alpha = color.quickList[i].val('a'); + var ahex = color.quickList[i].val('ahex'); + if (!win.alphaSupport && ahex) ahex = ahex.substring(0, 6) + 'ff'; + var quickHex = color.quickList[i].val('hex'); + html+='<span class="QuickColor"' + (ahex && ' title="#' + ahex + '"' || '') + ' style="background-color:' + (quickHex && '#' + quickHex || '') + ';' + (quickHex ? '' : 'background-image:url(' + images.clientPath + 'NoColor.svg)') + (win.alphaSupport && alpha && alpha < 255 ? ';opacity:' + Math.precision(alpha / 255, 4) + ';filter:Alpha(opacity=' + Math.precision(alpha / 2.55, 4) + ')' : '') + '"> </span>'; + } + setImg.call($this, grid, images.clientPath + 'bar-opacity.png'); + grid.html(html); + grid.find('.QuickColor').click(quickPickClicked); + } + setColorMode.call($this, settings.color.mode); + color.active.bind(activeColorChanged); + $.isFunction(liveCallback) && color.active.bind(liveCallback); + color.current.bind(currentColorChanged); + // bind to input + if (win.expandable) + { + $this.icon = popup.parents('.Icon:first'); + iconColor = $this.icon.find('.Color:first').css({ backgroundColor: hex && '#' + hex || 'transparent' }); + iconAlpha = $this.icon.find('.Alpha:first'); + setImg.call($this, iconAlpha, images.clientPath + 'bar-opacity.png'); + setAlpha.call($this, iconAlpha, Math.precision(((255 - (all != null ? all.a : 0)) * 100) / 255, 4)); + iconImage = $this.icon.find('.Image:first').css( + { + backgroundImage: 'url(\'' + images.clientPath + images.picker.file + '\')' + }).bind('click', iconImageClicked); + if (win.bindToInput&&win.updateInputColor) + win.input.css( + { + backgroundColor: hex && '#' + hex || 'transparent', + color: all == null || all.v > 75 ? '#000000' : '#ffffff' + }); + moveBar = tbody.find('.Move:first').bind('mousedown', moveBarMouseDown); + color.active.bind(expandableColorChanged); + } + else show.call($this); + }, + destroy = + function() + { + container.find('td.Radio input touchstart').unbind('click', radioClicked); + currentPreview.unbind('click touchstart', currentClicked); + cancelButton.unbind('click touchstart', cancelClicked); + okButton.unbind('click touchstart', okClicked); + if (settings.window.expandable) + { + iconImage.unbind('click', iconImageClicked); + moveBar.unbind('mousedown', moveBarMouseDown); + $this.icon = null; + } + container.find('.QuickColor').unbind('click', quickPickClicked); + colorMapDiv = null; + colorBarDiv = null; + colorMapL1 = null; + colorMapL2 = null; + colorMapL3 = null; + colorBarL1 = null; + colorBarL2 = null; + colorBarL3 = null; + colorBarL4 = null; + colorBarL5 = null; + colorBarL6 = null; + colorMap.destroy(); + colorMap = null; + colorBar.destroy(); + colorBar = null; + colorPicker.destroy(); + colorPicker = null; + activePreview = null; + currentPreview = null; + okButton = null; + cancelButton = null; + grid = null; + commitCallback = null; + cancelCallback = null; + liveCallback = null; + container.html(''); + for (i = 0; i < List.length; i++) if (List[i] == $this) List.splice(i, 1); + }, + images = settings.images, // local copies for YUI compressor + localization = settings.localization, + color = + { + active: (typeof(settings.color.active)).toString().toLowerCase() == 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') }), + current: (typeof(settings.color.active)).toString().toLowerCase() == 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') }), + quickList: settings.color.quickList + }; + $.extend(true, $this, // public properties, methods, and callbacks + { + commitCallback: commitCallback, // commitCallback function can be overridden to return the selected color to a method you specify when the user clicks "OK" + liveCallback: liveCallback, // liveCallback function can be overridden to return the selected color to a method you specify in live mode (continuous update) + cancelCallback: cancelCallback, // cancelCallback function can be overridden to a method you specify when the user clicks "Cancel" + color: color, + show: show, + hide: hide, + destroy: destroy // destroys this control entirely, removing all events and objects, and removing itself from the List + }); + List.push($this); + setTimeout( + function() + { + initialize.call($this); + }, 0); + }); + }; + $.fn.jPicker.defaults = /* jPicker defaults - you can change anything in this section (such as the clientPath to your images) without fear of breaking the program */ + { + window: + { + title: null, /* any title for the jPicker window itself - displays "Drag Markers To Pick A Color" if left null */ + effects: + { + type: 'slide', /* effect used to show/hide an expandable picker. Acceptable values "slide", "show", "fade" */ + speed: + { + show: 'slow', /* duration of "show" effect. Acceptable values are "fast", "slow", or time in ms */ + hide: 'fast' /* duration of "hide" effect. Acceptable values are "fast", "slow", or time in ms */ + } + }, + position: + { + x: 'screenCenter', /* acceptable values "left", "center", "right", "screenCenter", or relative px value */ + y: 'top' /* acceptable values "top", "bottom", "center", or relative px value */ + }, + expandable: false, /* default to large static picker - set to true to make an expandable picker (small icon with popup) - set automatically when binded to input element */ + liveUpdate: true, /* set false if you want the user to have to click "OK" before the binded input box updates values (always "true" for expandable picker) */ + alphaSupport: false, /* set to true to enable alpha picking */ + alphaPrecision: 0, /* set decimal precision for alpha percentage display - hex codes do not map directly to percentage integers - range 0-2 */ + updateInputColor: true /* set to false to prevent binded input colors from changing */ + }, + color: + { + mode: 'h', /* acceptabled values "h" (hue), "s" (saturation), "v" (value), "r" (red), "g" (green), "b" (blue), "a" (alpha) */ + active: new Color({ ahex: '#ffcc00ff' }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */ + quickList: /* the quick pick color list */ + [ + new Color({ h: 360, s: 33, v: 100 }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */ + new Color({ h: 360, s: 66, v: 100 }), + new Color({ h: 360, s: 100, v: 100 }), + new Color({ h: 360, s: 100, v: 75 }), + new Color({ h: 360, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 100 }), + new Color({ h: 30, s: 33, v: 100 }), + new Color({ h: 30, s: 66, v: 100 }), + new Color({ h: 30, s: 100, v: 100 }), + new Color({ h: 30, s: 100, v: 75 }), + new Color({ h: 30, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 90 }), + new Color({ h: 60, s: 33, v: 100 }), + new Color({ h: 60, s: 66, v: 100 }), + new Color({ h: 60, s: 100, v: 100 }), + new Color({ h: 60, s: 100, v: 75 }), + new Color({ h: 60, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 80 }), + new Color({ h: 90, s: 33, v: 100 }), + new Color({ h: 90, s: 66, v: 100 }), + new Color({ h: 90, s: 100, v: 100 }), + new Color({ h: 90, s: 100, v: 75 }), + new Color({ h: 90, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 70 }), + new Color({ h: 120, s: 33, v: 100 }), + new Color({ h: 120, s: 66, v: 100 }), + new Color({ h: 120, s: 100, v: 100 }), + new Color({ h: 120, s: 100, v: 75 }), + new Color({ h: 120, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 60 }), + new Color({ h: 150, s: 33, v: 100 }), + new Color({ h: 150, s: 66, v: 100 }), + new Color({ h: 150, s: 100, v: 100 }), + new Color({ h: 150, s: 100, v: 75 }), + new Color({ h: 150, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 50 }), + new Color({ h: 180, s: 33, v: 100 }), + new Color({ h: 180, s: 66, v: 100 }), + new Color({ h: 180, s: 100, v: 100 }), + new Color({ h: 180, s: 100, v: 75 }), + new Color({ h: 180, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 40 }), + new Color({ h: 210, s: 33, v: 100 }), + new Color({ h: 210, s: 66, v: 100 }), + new Color({ h: 210, s: 100, v: 100 }), + new Color({ h: 210, s: 100, v: 75 }), + new Color({ h: 210, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 30 }), + new Color({ h: 240, s: 33, v: 100 }), + new Color({ h: 240, s: 66, v: 100 }), + new Color({ h: 240, s: 100, v: 100 }), + new Color({ h: 240, s: 100, v: 75 }), + new Color({ h: 240, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 20 }), + new Color({ h: 270, s: 33, v: 100 }), + new Color({ h: 270, s: 66, v: 100 }), + new Color({ h: 270, s: 100, v: 100 }), + new Color({ h: 270, s: 100, v: 75 }), + new Color({ h: 270, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 10 }), + new Color({ h: 300, s: 33, v: 100 }), + new Color({ h: 300, s: 66, v: 100 }), + new Color({ h: 300, s: 100, v: 100 }), + new Color({ h: 300, s: 100, v: 75 }), + new Color({ h: 300, s: 100, v: 50 }), + new Color({ h: 180, s: 0, v: 0 }), + new Color({ h: 330, s: 33, v: 100 }), + new Color({ h: 330, s: 66, v: 100 }), + new Color({ h: 330, s: 100, v: 100 }), + new Color({ h: 330, s: 100, v: 75 }), + new Color({ h: 330, s: 100, v: 50 }), + new Color() + ] + }, + images: + { + clientPath: '/jPicker/images/', /* Path to image files */ + colorMap: + { + width: 256, + height: 256, + arrow: + { + file: 'mappoint.gif', /* ColorMap arrow icon */ + width: 15, + height: 15 + } + }, + colorBar: + { + width: 20, + height: 256, + arrow: + { + file: 'rangearrows.svg', /* ColorBar arrow icon */ + width: 20, + height: 7 + } + }, + picker: + { + file: 'picker.gif', /* Color Picker icon */ + width: 25, + height: 24 + } + }, + localization: /* alter these to change the text presented by the picker (e.g. different language) */ + { + text: + { + title: 'Drag Markers To Pick A Color', + newColor: 'new', + currentColor: 'current', + ok: 'OK', + cancel: 'Cancel' + }, + tooltips: + { + colors: + { + newColor: 'New Color - Press “OK” To Commit', + currentColor: 'Click To Revert To Original Color' + }, + buttons: + { + ok: 'Commit To This Color Selection', + cancel: 'Cancel And Revert To Original Color' + }, + hue: + { + radio: 'Set To “Hue” Color Mode', + textbox: 'Enter A “Hue” Value (0-360°)' + }, + saturation: + { + radio: 'Set To “Saturation” Color Mode', + textbox: 'Enter A “Saturation” Value (0-100%)' + }, + value: + { + radio: 'Set To “Value” Color Mode', + textbox: 'Enter A “Value” Value (0-100%)' + }, + red: + { + radio: 'Set To “Red” Color Mode', + textbox: 'Enter A “Red” Value (0-255)' + }, + green: + { + radio: 'Set To “Green” Color Mode', + textbox: 'Enter A “Green” Value (0-255)' + }, + blue: + { + radio: 'Set To “Blue” Color Mode', + textbox: 'Enter A “Blue” Value (0-255)' + }, + alpha: + { + radio: 'Set To “Alpha” Color Mode', + textbox: 'Enter A “Alpha” Value (0-100)' + }, + hex: + { + textbox: 'Enter A “Hex” Color Value (#000000-#ffffff)', + alpha: 'Enter A “Alpha” Value (#00-#ff)' + } + } + } + }; +})(jQuery, '1.1.6'); +/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.0.6 + * + * Requires: 1.2.2+ + */ + +(function($) { + +var types = ['DOMMouseScroll', 'mousewheel']; + +if ($.event.fixHooks) { + for ( var i=types.length; i; ) { + $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; + } +} + +$.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) { + for ( var i=types.length; i; ) { + this.addEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = handler; + } + }, + + teardown: function() { + if ( this.removeEventListener ) { + for ( var i=types.length; i; ) { + this.removeEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = null; + } + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + + +function handler(event) { + var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; + event = $.event.fix(orgEvent); + event.type = "mousewheel"; + + // Old school scrollwheel delta + if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } + if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } + + // New school multidimensional scroll (touchpads) deltas + deltaY = delta; + + // Gecko + if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = -1*delta; + } + + // Webkit + if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } + if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } + + // Add event and delta to the front of the arguments + args.unshift(event, delta, deltaX, deltaY); + + return ($.event.dispatch || $.event.handle).apply(this, args); +} + +})(jQuery); +/* + * ext-eyedropper.js + * + * Licensed under the Apache License, Version 2 + * + * Copyright(c) 2010 Jeff Schiller + * + */ + +// Dependencies: +// 1) jQuery +// 2) history.js +// 3) svg_editor.js +// 4) svgcanvas.js + +methodDraw.addExtension("eyedropper", function(S) { + var svgcontent = S.svgcontent, + svgns = "http://www.w3.org/2000/svg", + svgdoc = S.svgroot.parentNode.ownerDocument, + svgCanvas = methodDraw.canvas, + ChangeElementCommand = svgedit.history.ChangeElementCommand, + addToHistory = function(cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, + currentStyle = {fillPaint: "red", fillOpacity: 1.0, + strokePaint: "black", strokeOpacity: 1.0, + strokeWidth: 5, strokeDashArray: null, + opacity: 1.0, + strokeLinecap: 'butt', + strokeLinejoin: 'miter' + }; + function getStyle(opts) { + // if we are in eyedropper mode, we don't want to disable the eye-dropper tool + var mode = svgCanvas.getMode(); + if (mode == "eyedropper") return; + var tool = $('#tool_eyedropper'); + + } + + var getPaint = function(color, opac, type) { + // update the editor's fill paint + var opts = null; + if (color.indexOf("url(#") === 0) { + var refElem = svgCanvas.getRefElem(color); + if(refElem) { + refElem = refElem.cloneNode(true); + } else { + refElem = $("#" + type + "_color defs *")[0]; + } + + opts = { alpha: opac }; + opts[refElem.tagName] = refElem; + } + else if (color.indexOf("#") === 0) { + opts = { + alpha: opac, + solidColor: color.substr(1) + }; + } + else { + opts = { + alpha: opac, + solidColor: 'none' + }; + } + return new $.jGraduate.Paint(opts); + }; + + return { + name: "eyedropper", + svgicons: "extensions/eyedropper-icon.xml", + buttons: [{ + id: "tool_eyedropper", + type: "mode", + title: "Eye Dropper Tool", + position: 8, + key: "I", + icon: "extensions/eyedropper.png", + events: { + "click": function() { + svgCanvas.setMode("eyedropper"); + } + } + }], + + mouseDown: function(opts) { + var mode = svgCanvas.getMode(); + var e = opts.event; + var target = (e.target.id === "svgroot") ? document.getElementById('canvas_background') : e.target; + if (mode == "eyedropper" && target) { + currentStyle.fillPaint = target.getAttribute("fill") || "white"; + currentStyle.fillOpacity = target.getAttribute("fill-opacity") || 1.0; + currentStyle.strokePaint = target.getAttribute("stroke") || 'none'; + currentStyle.strokeOpacity = target.getAttribute("stroke-opacity") || 1.0; + currentStyle.strokeWidth = target.getAttribute("stroke-width"); + currentStyle.strokeDashArray = target.getAttribute("stroke-dasharray"); + currentStyle.strokeLinecap = target.getAttribute("stroke-linecap"); + currentStyle.strokeLinejoin = target.getAttribute("stroke-linejoin"); + currentStyle.opacity = target.getAttribute("opacity") || 1.0; + opts.selectedElements = opts.selectedElements.filter(Boolean) + if (!opts.selectedElements.length) { //nothing selected, just update colors + var fill = getPaint(currentStyle.fillPaint, currentStyle.fillOpacity*100, "fill"); + var stroke = getPaint(currentStyle.strokePaint, currentStyle.strokeOpacity*100, "stroke"); + methodDraw.paintBox.fill.setPaint(fill) + methodDraw.paintBox.stroke.setPaint(stroke) + return; + } + if ($.inArray(opts.selectedElements.nodeName, ['g', 'use']) == -1) { + var changes = {}; + var change = function(elem, attrname, newvalue) { + changes[attrname] = elem.getAttribute(attrname); + elem.setAttribute(attrname, newvalue); + }; + var batchCmd = new S.BatchCommand(); + opts.selectedElements.forEach(function(element){ + if (currentStyle.fillPaint) change(element, "fill", currentStyle.fillPaint); + if (currentStyle.fillOpacity) change(element, "fill-opacity", currentStyle.fillOpacity); + if (currentStyle.strokePaint) change(element, "stroke", currentStyle.strokePaint); + if (currentStyle.strokeOpacity) change(element, "stroke-opacity", currentStyle.strokeOpacity); + if (currentStyle.strokeWidth) change(element, "stroke-width", currentStyle.strokeWidth); + if (currentStyle.strokeDashArray) change(element, "stroke-dasharray", currentStyle.strokeDashArray); + if (currentStyle.opacity) change(element, "opacity", currentStyle.opacity); + if (currentStyle.strokeLinecap) change(element, "stroke-linecap", currentStyle.strokeLinecap); + if (currentStyle.strokeLinejoin) change(element, "stroke-linejoin", currentStyle.strokeLinejoin); + batchCmd.addSubCommand(new ChangeElementCommand(element, changes)); + changes = {}; + }); + var fill = getPaint(currentStyle.fillPaint, currentStyle.fillOpacity*100, "fill") + var stroke = getPaint(currentStyle.strokePaint, currentStyle.strokeOpacity*100, "stroke") + methodDraw.paintBox.fill.update(true) + methodDraw.paintBox.stroke.update(true) + addToHistory(batchCmd); + } + } + } + }; +}); +/* + * ext-shapes.js + * + * Licensed under the Apache License, Version 2 + * + * Copyright(c) 2010 Christian Tzurcanu + * Copyright(c) 2010 Alexis Deveria + * + */ + +methodDraw.addExtension("shapes", function() { + + + var current_d, cur_shape_id; + var canv = methodDraw.canvas; + var cur_shape; + var start_x, start_y; + var svgroot = canv.getRootElem(); + var lastBBox = {}; + + // This populates the category list + var categories = { + basic: 'Basic', + object: 'Objects', + symbol: 'Symbols', + arrow: 'Arrows', + flowchart: 'Flowchart', + nature: 'Nature', + game: 'Cards & Chess', + dialog_balloon: 'Dialog balloons', + music: 'Music', + weather: 'Weather & Time', + ui: 'User Interface', + social: 'Social Web' + }; + + var library = { + 'basic': { + data: { + "star_points_5": "m1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z", + 'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z', + "triangle": "m1,280.375l149,-260.75l149,260.75z", + "right_triangle": "m1,299l0,-298l298,298z", + "diamond": "m1,150l149,-149l149,149l-149,149l-149,-149z", + "pentagon": "m1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z", + "hexagon": "m1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z", + "septagon1": "m0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z", + "heptagon": "m1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z", + "decagon": "m1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z", + "dodecagon": "m1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z", + "trapezoid": "m1,299l55.875,-298l186.25001,0l55.87498,298z", + "dialog_balloon_1": "m0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z", + 'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z', + "cylinder": "m299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z", + "arrow_up": "m1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z", + "arrow_u_turn": "m1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z", + "arrow_left_up": "m0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z", + "plaque": "m-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z", + "page": "m249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234", + "cross": "m0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z", + "divide": "m150,0.99785l0,0c25.17819,0 45.58916,20.41097 45.58916,45.58916c0,25.17821 -20.41096,45.58916 -45.58916,45.58916c-25.17822,0 -45.58916,-20.41093 -45.58916,-45.58916c0,-25.1782 20.41093,-45.58916 45.58916,-45.58916zm0,296.25203c-25.17822,0 -45.58916,-20.41095 -45.58916,-45.58917c0,-25.17819 20.41093,-45.58916 45.58916,-45.58916c25.17819,0 45.58916,20.41096 45.58916,45.58916c0,25.17822 -20.41096,45.58917 -45.58916,45.58917zm-134.06754,-193.71518l268.13507,0l0,91.17833l-268.13507,0z", + "minus": "m0.99887,102.39503l297.49445,0l0,95.2112l-297.49445,0z", + "times": "m1.00089,73.36786l72.36697,-72.36697l76.87431,76.87368l76.87431,-76.87368l72.36765,72.36697l-76.87433,76.87431l76.87433,76.87431l-72.36765,72.36765l-76.87431,-76.87433l-76.87431,76.87433l-72.36697,-72.36765l76.87368,-76.87431l-76.87368,-76.87431z" + + + }, + buttons: [] + } + }; + + var cur_lib = library.basic; + + var mode_id = 'shapelib'; + + function loadIcons() { + $('#shape_buttons').empty(); + + // Show lib ones + $('#shape_buttons').append(cur_lib.buttons); + } + + function loadLibrary(cat_id) { + + var lib = library[cat_id]; + + if(!lib) { + $('#shape_buttons').html('Loading...'); + $.getJSON('shapelib/' + cat_id + '.json', function(result, textStatus) { + cur_lib = library[cat_id] = { + data: result.data, + size: result.size, + fill: result.fill + } + makeButtons(cat_id, result); + loadIcons(); + }); + return; + } + + cur_lib = lib; + if(!lib.buttons.length) makeButtons(cat_id, lib); + loadIcons(); + } + + function makeButtons(cat, shapes) { + var size = cur_lib.size || 300; + var fill = cur_lib.fill || false; + var off = size * .05; + var vb = [-off, -off, size + off*2, size + off*2].join(' '); + var stroke = fill ? 0: (size/30); + + var shape_icon = new DOMParser().parseFromString( + '<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="#333" stroke="transparent" stroke-width="' + stroke + '" /><\/svg><\/svg>', + 'text/xml'); + + var width = 40; + var height = 40; + shape_icon.documentElement.setAttribute('width', width); + shape_icon.documentElement.setAttribute('height', height); + var svg_elem = $(document.importNode(shape_icon.documentElement,true)); + + var data = shapes.data; + + cur_lib.buttons = []; + + for(var id in data) { + var path_d = data[id]; + var icon = svg_elem.clone(); + icon.find('path').attr('d', path_d); + + var icon_btn = icon.wrap('<div class="tool_button">').parent().attr({ + id: mode_id + '_' + id, + title: id + }); + + + // Store for later use + cur_lib.buttons.push(icon_btn[0]); + } + + } + + + return { + svgicons: "extensions/ext-shapes.xml", + buttons: [{ + id: "tool_shapelib", + type: "mode_flyout", // _flyout + position: 6, + title: "Shape library", + icon: "extensions/ext-shapes.png", + events: { + "click": function() { + canv.setMode(mode_id); + } + } + }], + callback: function() { + + + var btn_div = $('<div id="shape_buttons">'); + $('#tools_shapelib > *').wrapAll(btn_div); + + var shower = $('#tools_shapelib_show'); + + + loadLibrary('basic'); + + // Do mouseup on parent element rather than each button + $('#shape_buttons').mouseup(function(evt) { + var btn = $(evt.target).closest('div.tool_button'); + + if(!btn.length) return; + + var copy = btn.children().clone().attr({width: 24, height: 24}); + shower.children(':not(.flyout_arrow_horiz)').remove(); + shower + .append(copy) + .attr('data-curopt', '#' + btn[0].id) // This sets the current mode + .mouseup(); + canv.setMode(mode_id); + + cur_shape_id = btn[0].id.substr((mode_id+'_').length); + current_d = cur_lib.data[cur_shape_id]; + + $('.tools_flyout').fadeOut(); + + }); + +// + var shape_cats = $('<div id="shape_cats">'); + var cat_str = ''; + + $.each(categories, function(id, label) { + cat_str += '<div data-cat=' + id + '>' + label + '</div>'; + }); + + shape_cats.html(cat_str).children().bind('mouseup', function() { + var catlink = $(this); + catlink.siblings().removeClass('current'); + catlink.addClass('current'); + + loadLibrary(catlink.attr('data-cat')); + // Get stuff + + return false; + }); + + shape_cats.children().eq(0).addClass('current'); + + $('#tools_shapelib').prepend(shape_cats); + + shower.mouseup(function() { + canv.setMode(current_d ? mode_id : 'select'); + }); + + + $('#tool_shapelib').remove(); + + var h = $('#tools_shapelib').height(); + $('#tools_shapelib').css({ + 'margin-top': -(h/2), + 'margin-left': 3 + }); + + + }, + mouseDown: function(opts) { + var mode = canv.getMode(); + if(mode !== mode_id) return; + + var e = opts.event; + var x = start_x = opts.start_x; + var y = start_y = opts.start_y; + var cur_style = canv.getStyle(); + cur_shape = canv.addSvgElementFromJson({ + "element": "path", + "curStyles": true, + "attr": { + "d": current_d, + "id": canv.getNextId(), + "opacity": cur_style.opacity / 2, + "style": "pointer-events:none" + } + }); + cur_shape.setAttribute("d", current_d); + // Make sure shape uses absolute values + if(/[a-z]/.test(current_d)) { + current_d = cur_lib.data[cur_shape_id] = canv.pathActions.convertPath(cur_shape); + cur_shape.setAttribute('d', current_d); + canv.pathActions.fixEnd(cur_shape); + } + + cur_shape.setAttribute('transform', "translate(" + x + "," + y + ") scale(0.005) translate(" + -x + "," + -y + ")"); +// console.time('b'); + canv.recalculateDimensions(cur_shape); + var tlist = canv.getTransformList(cur_shape); + lastBBox = cur_shape.getBBox(); + totalScale = { + sx: 1, + sy: 1 + }; + return { + started: true + } + // current_d + }, + mouseMove: function(opts) { + var mode = canv.getMode(); + if(mode !== mode_id) return; + + var zoom = canv.getZoom(); + var evt = opts.event + + var x = opts.mouse_x/zoom; + var y = opts.mouse_y/zoom; + + var tlist = canv.getTransformList(cur_shape), + box = cur_shape.getBBox(), + left = box.x, top = box.y, width = box.width, + height = box.height; + var dx = (x-start_x), dy = (y-start_y); + + var newbox = { + 'x': Math.min(start_x,x), + 'y': Math.min(start_y,y), + 'width': Math.abs(x-start_x), + 'height': Math.abs(y-start_y) + }; + + var ts = null, + tx = 0, ty = 0, + sy = height ? (height+dy)/height : 1, + sx = width ? (width+dx)/width : 1; + + var sx = newbox.width / lastBBox.width; + var sy = newbox.height / lastBBox.height; + + sx = sx || 1; + sy = sy || 1; + + // Not perfect, but mostly works... + + if(x < start_x) { + tx = lastBBox.width; + } + if(y < start_y) ty = lastBBox.height; + + // update the transform list with translate,scale,translate + var translateOrigin = svgroot.createSVGTransform(), + scale = svgroot.createSVGTransform(), + translateBack = svgroot.createSVGTransform(); + + translateOrigin.setTranslate(-(left+tx), -(top+ty)); + if(evt.shiftKey) { + replaced = true + var max = Math.min(Math.abs(sx), Math.abs(sy)); + sx = max * (sx < 0 ? -1 : 1); + sy = max * (sy < 0 ? -1 : 1); + if (totalScale.sx != totalScale.sy) { + var multiplierX = (totalScale.sx > totalScale.sy) ? 1 : totalScale.sx/totalScale.sy; + var multiplierY = (totalScale.sy > totalScale.sx) ? 1 : totalScale.sy/totalScale.sx; + sx *= multiplierY + sy *= multiplierX + } + } + totalScale.sx *= sx; + totalScale.sy *= sy; + scale.setScale(sx,sy); + translateBack.setTranslate(left+tx, top+ty); + var N = tlist.numberOfItems; + tlist.appendItem(translateBack); + tlist.appendItem(scale); + tlist.appendItem(translateOrigin); + + canv.recalculateDimensions(cur_shape); + lastBBox = cur_shape.getBBox(); + }, + mouseUp: function(opts) { + var mode = canv.getMode(); + if(mode !== mode_id) return; + + if(opts.mouse_x == start_x && opts.mouse_y == start_y) { + return { + keep: false, + element: cur_shape, + started: false + } + } + canv.setMode("select") + return { + keep: true, + element: cur_shape, + started: false + } + } + } +}); + +/* + * ext-grid.js + * + * Licensed under the Apache License, Version 2 + * + * Copyright(c) 2010 Redou Mine + * Copyright(c) 2010 Alexis Deveria + * + */ + +// Dependencies: +// 1) units.js +// 2) everything else + +methodDraw.addExtension("view_grid", function(s) { + if (!document.getElementById("canvasGrid")){ + var svgdoc = document.getElementById("svgcanvas").ownerDocument, + svgns = "http://www.w3.org/2000/svg", + dims = methodDraw.curConfig.dimensions, + svgroot = s.svgroot; + var svgCanvas = methodDraw.canvas; + var showGrid = false; + var assignAttributes = s.assignAttributes; + + var hcanvas = document.createElement('canvas'); + $(hcanvas).hide().appendTo('body'); + + var canvasgrid = svgdoc.createElementNS(svgns, "g"); + assignAttributes(canvasgrid, { + 'id': 'canvasGrid', + 'width': '100%', + 'height': '100%', + 'x': 0, + 'y': 0, + 'overflow': 'visible', + 'display': 'none' + }); + + var canvBG = $('#canvas_background'); + canvBG.after(canvasgrid); + + + + // grid-pattern + var gridPattern = svgdoc.createElementNS(svgns, "pattern"); + assignAttributes(gridPattern, { + 'id': 'gridpattern', + 'patternUnits': 'userSpaceOnUse', + 'x': 0, //-(value.strokeWidth / 2), // position for strokewidth + 'y': 0, //-(value.strokeWidth / 2), // position for strokewidth + 'width': 100, + 'height': 100 + }); + + var gridimg = svgdoc.createElementNS(svgns, "image"); + assignAttributes(gridimg, { + 'x': 0, + 'y': 0, + 'width': 100, + 'height': 100 + }); + + gridPattern.appendChild(gridimg); + $('#svgroot defs').append(gridPattern); + + // grid-box + var gridBox = svgdoc.createElementNS(svgns, "rect"); + assignAttributes(gridBox, { + 'width': '100%', + 'height': '100%', + 'x': 0, + 'y': 0, + 'stroke-width': 0, + 'stroke': 'none', + 'fill': 'url(#gridpattern)', + 'style': 'pointer-events: none; display:visible;' + }); + $('#canvasGrid').append(gridBox); + } +// }); + + function updateGrid(zoom) { + // TODO: Try this with <line> elements, then compare performance difference + + var bgwidth = +canvBG.attr('width'); + var bgheight = +canvBG.attr('height'); + + var units = svgedit.units.getTypeMap(); + var unit = units[methodDraw.curConfig.baseUnit]; // 1 = 1px + var r_intervals = [.01, .1, 1, 10, 100, 1000]; + + var d = 0; + var is_x = (d === 0); + var dim = is_x ? 'x' : 'y'; + var lentype = is_x?'width':'height'; + var c_elem = svgCanvas.getContentElem(); + var content_d = c_elem.getAttribute(dim)-0; + + var hcanv = hcanvas; + + var u_multi = unit * zoom; + + // Calculate the main number interval + var raw_m = 100 / u_multi; + var multi = 1; + for(var i = 0; i < r_intervals.length; i++) { + var num = r_intervals[i]; + multi = num; + if(raw_m <= num) { + break; + } + } + + var big_int = multi * u_multi; + + // Set the canvas size to the width of the container + hcanv.width = big_int; + hcanv.height = big_int; + var ctx = hcanv.getContext("2d"); + + var ruler_d = 0; + var cur_d = .5; + + var part = big_int / 10; + + ctx.globalAlpha = 0.2; + ctx.strokeStyle = "#000"; + for(var i = 1; i < 10; i++) { + var sub_d = Math.round(part * i) + .5; +// var line_num = (i % 2)?12:10; + var line_num = 0; + ctx.moveTo(sub_d, big_int); + ctx.lineTo(sub_d, line_num); + ctx.moveTo(big_int, sub_d); + ctx.lineTo(line_num ,sub_d); + } + ctx.stroke(); + ctx.beginPath(); + ctx.globalAlpha = 0.5; + ctx.moveTo(cur_d, big_int); + ctx.lineTo(cur_d, 0); + + ctx.moveTo(big_int, cur_d); + ctx.lineTo(0, cur_d); + ctx.stroke(); + + var datauri = hcanv.toDataURL('image/png'); + gridimg.setAttribute('width', big_int); + gridimg.setAttribute('height', big_int); + gridimg.parentNode.setAttribute('width', big_int); + gridimg.parentNode.setAttribute('height', big_int); + svgCanvas.setHref(gridimg, datauri); + } + + return { + name: "view_grid", + zoomChanged: function(zoom) { + // update size + if(showGrid) updateGrid(zoom); + }, + + buttons: [{ + id: "view_grid", + type: "menu", + after: "tool_wireframe", + panel: "view_menu", + title: "View Grid", + events: { + 'click': function() { + var gr = !$('#view_grid').hasClass('push_button_pressed'); + if (gr) { + methodDraw.curConfig.showGrid = showGrid = true; + $('#view_grid').addClass('push_button_pressed'); + $('#canvasGrid').attr('display', 'inline'); + updateGrid(svgCanvas.getZoom()); + } + else { + methodDraw.curConfig.showGrid = showGrid = false; + $('#view_grid').removeClass('push_button_pressed'); + $('#canvasGrid').attr('display', 'none'); + } + } + } +}] + }; + }); + +(function() { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; + window.cancelAnimationFrame = + window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function() { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; +}()); + +/** + * Copyright (c) 2011 Zauber S.A. <http://www.zaubersoftware.com/> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Guido Marucci Blas - guido@zaubersoftware.com + * @description Adds a handler for a custom event 'taphold' that handles a + * tap and hold on touch interfaces. + */ +(function($) { + var TAP_AND_HOLD_TRIGGER_TIMER = 1000; + var MAX_DISTANCE_ALLOWED_IN_TAP_AND_HOLD_EVENT = 5; + var TOUCHSTART = "touchstart"; + var TOUCHEND = "touchend"; + var TOUCHMOVE = "touchmove"; + + // For debugging only + // var TOUCHSTART = "mousedown"; + // var TOUCHEND = "mouseup"; + // var TOUCHMOVE = "mousemove"; + + var tapAndHoldTimer = null; + + function calculateEuclideanDistance(x1, y1, x2, y2) { + var diffX = (x2 - x1); + var diffY = (y2 - y1); + return Math.sqrt((diffX * diffX) + (diffY * diffY)); + }; + + function onTouchStart(event) { + var e = event.originalEvent; + + // Only start detector if and only if one finger is over the widget + if (!e.touches || (e.targetTouches.length === 1 && e.touches.length === 1)) { + startTapAndHoldDetector.call(this, event) + var element = $(this); + element.bind(TOUCHMOVE, onTouchMove); + element.bind(TOUCHEND, onTouchEnd); + } else { + stopTapAndHoldDetector.call(this); + } + }; + + function onTouchMove(event) { + if (tapAndHoldTimer == null) { + return; + } + + var e = event.originalEvent; + var x = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX; + var y = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY; + + var tapAndHoldPoint = $(this).data("taphold.point"); + var euclideanDistance = calculateEuclideanDistance(tapAndHoldPoint.x, tapAndHoldPoint.y, x, y); + + if (euclideanDistance > MAX_DISTANCE_ALLOWED_IN_TAP_AND_HOLD_EVENT) { + stopTapAndHoldDetector.call(this); + } + }; + + function onTouchEnd(event) { + stopTapAndHoldDetector.call(this); + }; + + function onTapAndHold(event) { + clear.call(this); + $(this).data("taphold.handler").call(this, event); + }; + + function clear() { + tapAndHoldTimer = null; + $(this).unbind(TOUCHMOVE, onTouchMove); + $(this).unbind(TOUCHEND, onTouchEnd); + }; + + function startTapAndHoldDetector(event) { + if (tapAndHoldTimer != null) { + return; + } + var self = this; + tapAndHoldTimer = setTimeout(function(){ + onTapAndHold.call(self, event) + }, TAP_AND_HOLD_TRIGGER_TIMER); + + // Stores tap x & y + var e = event.originalEvent; + var tapAndHoldPoint = {}; + tapAndHoldPoint.x = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX; + tapAndHoldPoint.y = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY; + $(this).data("taphold.point", tapAndHoldPoint); + }; + + function stopTapAndHoldDetector() { + clearTimeout(tapAndHoldTimer); + clear.call(this); + }; + + $.event.special["taphold"] = { + setup: function() { + + }, + + add: function(handleObj) { + $(this).data("taphold.handler", handleObj.handler); + if (handleObj.data) { + $(this).bind(TOUCHSTART, handleObj.data, onTouchStart); + } else { + $(this).bind(TOUCHSTART, onTouchStart); + } + }, + + remove: function(handleObj) { + stopTapAndHoldDetector.call(this); + if (handleObj.data) { + $(this).unbind(TOUCHSTART, handleObj.data, onTouchStart); + } else { + $(this).unbind(TOUCHSTART, onTouchStart); + } + }, + + teardown: function() { + + } + }; + +})(jQuery); +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.1.20151003 + * + * By Eli Grey, http://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ + +var saveAs = saveAs || (function(view) { + "use strict"; + // IE <10 is explicitly unsupported + if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { + return; + } + var + doc = view.document + // only get URL when necessary in case Blob.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = "download" in save_link + , click = function(node) { + var event = new MouseEvent("click"); + node.dispatchEvent(event); + } + , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent) + , webkit_req_fs = view.webkitRequestFileSystem + , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem + , throw_outside = function(ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + , fs_min_size = 0 + // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and + // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 + // for the reasoning behind the timeout and revocation flow + , arbitrary_revoke_timeout = 500 // in ms + , revoke = function(file) { + var revoker = function() { + if (typeof file === "string") { // file is an object URL + get_URL().revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + }; + if (view.chrome) { + revoker(); + } else { + setTimeout(revoker, arbitrary_revoke_timeout); + } + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob(["\ufeff", blob], {type: blob.type}); + } + return blob; + } + , FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , blob_changed = false + , object_url + , target_view + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + if (target_view && is_safari && typeof FileReader !== "undefined") { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var base64Data = reader.result; + target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/)); + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (blob_changed || !object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (target_view) { + target_view.location.href = object_url; + } else { + var new_tab = view.open(object_url, "_blank"); + if (new_tab == undefined && is_safari) { + //Apple do not allow window.open, see http://bit.ly/1kZffRI + view.location.href = object_url + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + } + , abortable = function(func) { + return function() { + if (filesaver.readyState !== filesaver.DONE) { + return func.apply(this, arguments); + } + }; + } + , create_if_not_found = {create: true, exclusive: false} + , slice + ; + filesaver.readyState = filesaver.INIT; + if (!name) { + name = "download"; + } + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setTimeout(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }); + return; + } + // Object and web filesystem URLs have a problem saving in Google Chrome when + // viewed in a tab, so I force save with application/octet-stream + // http://code.google.com/p/chromium/issues/detail?id=91158 + // Update: Google errantly closed 91158, I submitted it again: + // https://code.google.com/p/chromium/issues/detail?id=389642 + if (view.chrome && type && type !== force_saveable_type) { + slice = blob.slice || blob.webkitSlice; + blob = slice.call(blob, 0, blob.size, force_saveable_type); + blob_changed = true; + } + // Since I can't be sure that the guessed media type will trigger a download + // in WebKit, I append .download to the filename. + // https://bugs.webkit.org/show_bug.cgi?id=65440 + if (webkit_req_fs && name !== "download") { + name += ".download"; + } + if (type === force_saveable_type || webkit_req_fs) { + target_view = view; + } + if (!req_fs) { + fs_error(); + return; + } + fs_min_size += blob.size; + req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { + fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { + var save = function() { + dir.getFile(name, create_if_not_found, abortable(function(file) { + file.createWriter(abortable(function(writer) { + writer.onwriteend = function(event) { + target_view.location.href = file.toURL(); + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "writeend", event); + revoke(file); + }; + writer.onerror = function() { + var error = writer.error; + if (error.code !== error.ABORT_ERR) { + fs_error(); + } + }; + "writestart progress write abort".split(" ").forEach(function(event) { + writer["on" + event] = filesaver["on" + event]; + }); + writer.write(blob); + filesaver.abort = function() { + writer.abort(); + filesaver.readyState = filesaver.DONE; + }; + filesaver.readyState = filesaver.WRITING; + }), fs_error); + }), fs_error); + }; + dir.getFile(name, {create: false}, abortable(function(file) { + // delete file if it already exists + file.remove(); + save(); + }), abortable(function(ex) { + if (ex.code === ex.NOT_FOUND_ERR) { + save(); + } else { + fs_error(); + } + })); + }), fs_error); + }), fs_error); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name, no_auto_bom) { + return new FileSaver(blob, name, no_auto_bom); + } + ; + // IE 10+ (native saveAs) + if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name || "download"); + }; + } + + FS_proto.abort = function() { + var filesaver = this; + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "abort"); + }; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + + return saveAs; +}( + typeof self !== "undefined" && self + || typeof window !== "undefined" && window + || this.content +)); +// `self` is undefined in Firefox for Android content script context +// while `this` is nsIContentFrameMessageManager +// with an attribute `content` that corresponds to the window + +if (typeof module !== "undefined" && module.exports) { + module.exports.saveAs = saveAs; +} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { + define([], function() { + return saveAs; + }); +} \ No newline at end of file diff --git a/editor/extensions/ext-shapes.xml b/dist/extensions/ext-shapes.xml similarity index 100% rename from editor/extensions/ext-shapes.xml rename to dist/extensions/ext-shapes.xml diff --git a/editor/extensions/eyedropper-icon.xml b/dist/extensions/eyedropper-icon.xml similarity index 100% rename from editor/extensions/eyedropper-icon.xml rename to dist/extensions/eyedropper-icon.xml diff --git a/editor/css/font-files/Arvo-Regular-webfont.svg b/dist/font-files/Arvo-Regular-webfont.svg similarity index 100% rename from editor/css/font-files/Arvo-Regular-webfont.svg rename to dist/font-files/Arvo-Regular-webfont.svg diff --git a/editor/css/font-files/Arvo-Regular-webfont.ttf b/dist/font-files/Arvo-Regular-webfont.ttf similarity index 100% rename from editor/css/font-files/Arvo-Regular-webfont.ttf rename to dist/font-files/Arvo-Regular-webfont.ttf diff --git a/editor/css/font-files/Junction-webfont.eot b/dist/font-files/Junction-webfont.eot similarity index 100% rename from editor/css/font-files/Junction-webfont.eot rename to dist/font-files/Junction-webfont.eot diff --git a/editor/css/font-files/Junction-webfont.svg b/dist/font-files/Junction-webfont.svg similarity index 100% rename from editor/css/font-files/Junction-webfont.svg rename to dist/font-files/Junction-webfont.svg diff --git a/editor/css/font-files/Junction-webfont.ttf b/dist/font-files/Junction-webfont.ttf similarity index 100% rename from editor/css/font-files/Junction-webfont.ttf rename to dist/font-files/Junction-webfont.ttf diff --git a/editor/css/font-files/Junction-webfont.woff b/dist/font-files/Junction-webfont.woff similarity index 100% rename from editor/css/font-files/Junction-webfont.woff rename to dist/font-files/Junction-webfont.woff diff --git a/editor/css/font-files/League_Gothic-webfont.eot b/dist/font-files/League_Gothic-webfont.eot similarity index 100% rename from editor/css/font-files/League_Gothic-webfont.eot rename to dist/font-files/League_Gothic-webfont.eot diff --git a/editor/css/font-files/League_Gothic-webfont.svg b/dist/font-files/League_Gothic-webfont.svg similarity index 100% rename from editor/css/font-files/League_Gothic-webfont.svg rename to dist/font-files/League_Gothic-webfont.svg diff --git a/editor/css/font-files/League_Gothic-webfont.ttf b/dist/font-files/League_Gothic-webfont.ttf similarity index 100% rename from editor/css/font-files/League_Gothic-webfont.ttf rename to dist/font-files/League_Gothic-webfont.ttf diff --git a/editor/css/font-files/League_Gothic-webfont.woff b/dist/font-files/League_Gothic-webfont.woff similarity index 100% rename from editor/css/font-files/League_Gothic-webfont.woff rename to dist/font-files/League_Gothic-webfont.woff diff --git a/editor/css/font-files/arvo-bold-webfont.woff b/dist/font-files/arvo-bold-webfont.woff similarity index 100% rename from editor/css/font-files/arvo-bold-webfont.woff rename to dist/font-files/arvo-bold-webfont.woff diff --git a/editor/css/font-files/arvo-bolditalic-webfont.woff b/dist/font-files/arvo-bolditalic-webfont.woff similarity index 100% rename from editor/css/font-files/arvo-bolditalic-webfont.woff rename to dist/font-files/arvo-bolditalic-webfont.woff diff --git a/editor/css/font-files/arvo-italic-webfont.woff b/dist/font-files/arvo-italic-webfont.woff similarity index 100% rename from editor/css/font-files/arvo-italic-webfont.woff rename to dist/font-files/arvo-italic-webfont.woff diff --git a/editor/css/font-files/arvo-regular-webfont.woff b/dist/font-files/arvo-regular-webfont.woff similarity index 100% rename from editor/css/font-files/arvo-regular-webfont.woff rename to dist/font-files/arvo-regular-webfont.woff diff --git a/editor/css/font-files/euphoriascript-regular-webfont.woff b/dist/font-files/euphoriascript-regular-webfont.woff similarity index 100% rename from editor/css/font-files/euphoriascript-regular-webfont.woff rename to dist/font-files/euphoriascript-regular-webfont.woff diff --git a/editor/css/font-files/fanwood-webfont.eot b/dist/font-files/fanwood-webfont.eot similarity index 100% rename from editor/css/font-files/fanwood-webfont.eot rename to dist/font-files/fanwood-webfont.eot diff --git a/editor/css/font-files/fanwood-webfont.svg b/dist/font-files/fanwood-webfont.svg similarity index 100% rename from editor/css/font-files/fanwood-webfont.svg rename to dist/font-files/fanwood-webfont.svg diff --git a/editor/css/font-files/fanwood-webfont.ttf b/dist/font-files/fanwood-webfont.ttf similarity index 100% rename from editor/css/font-files/fanwood-webfont.ttf rename to dist/font-files/fanwood-webfont.ttf diff --git a/editor/css/font-files/fanwood-webfont.woff b/dist/font-files/fanwood-webfont.woff similarity index 100% rename from editor/css/font-files/fanwood-webfont.woff rename to dist/font-files/fanwood-webfont.woff diff --git a/editor/css/font-files/fanwood_italic-webfont.eot b/dist/font-files/fanwood_italic-webfont.eot similarity index 100% rename from editor/css/font-files/fanwood_italic-webfont.eot rename to dist/font-files/fanwood_italic-webfont.eot diff --git a/editor/css/font-files/fanwood_italic-webfont.svg b/dist/font-files/fanwood_italic-webfont.svg similarity index 100% rename from editor/css/font-files/fanwood_italic-webfont.svg rename to dist/font-files/fanwood_italic-webfont.svg diff --git a/editor/css/font-files/fanwood_italic-webfont.ttf b/dist/font-files/fanwood_italic-webfont.ttf similarity index 100% rename from editor/css/font-files/fanwood_italic-webfont.ttf rename to dist/font-files/fanwood_italic-webfont.ttf diff --git a/editor/css/font-files/fanwood_italic-webfont.woff b/dist/font-files/fanwood_italic-webfont.woff similarity index 100% rename from editor/css/font-files/fanwood_italic-webfont.woff rename to dist/font-files/fanwood_italic-webfont.woff diff --git a/editor/css/font-files/shadowsintolight-webfont.woff b/dist/font-files/shadowsintolight-webfont.woff similarity index 100% rename from editor/css/font-files/shadowsintolight-webfont.woff rename to dist/font-files/shadowsintolight-webfont.woff diff --git a/editor/css/font-files/simonetta-black-webfont.woff b/dist/font-files/simonetta-black-webfont.woff similarity index 100% rename from editor/css/font-files/simonetta-black-webfont.woff rename to dist/font-files/simonetta-black-webfont.woff diff --git a/editor/css/font-files/simonetta-blackitalic-webfont.woff b/dist/font-files/simonetta-blackitalic-webfont.woff similarity index 100% rename from editor/css/font-files/simonetta-blackitalic-webfont.woff rename to dist/font-files/simonetta-blackitalic-webfont.woff diff --git a/editor/css/font-files/simonetta-italic-webfont.ttf b/dist/font-files/simonetta-italic-webfont.ttf similarity index 100% rename from editor/css/font-files/simonetta-italic-webfont.ttf rename to dist/font-files/simonetta-italic-webfont.ttf diff --git a/editor/css/font-files/simonetta-regular-webfont.woff b/dist/font-files/simonetta-regular-webfont.woff similarity index 100% rename from editor/css/font-files/simonetta-regular-webfont.woff rename to dist/font-files/simonetta-regular-webfont.woff diff --git a/editor/images/AlphaBar.png b/dist/images/AlphaBar.png similarity index 100% rename from editor/images/AlphaBar.png rename to dist/images/AlphaBar.png diff --git a/editor/images/Bars.png b/dist/images/Bars.png similarity index 100% rename from editor/images/Bars.png rename to dist/images/Bars.png diff --git a/editor/images/Maps.png b/dist/images/Maps.png similarity index 100% rename from editor/images/Maps.png rename to dist/images/Maps.png diff --git a/editor/images/NoColor.png b/dist/images/NoColor.png similarity index 100% rename from editor/images/NoColor.png rename to dist/images/NoColor.png diff --git a/dist/images/NoColor.svg b/dist/images/NoColor.svg new file mode 100644 index 0000000..025ba34 --- /dev/null +++ b/dist/images/NoColor.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 15"> + <g stroke="#F00000" fill="none" fill-rule="evenodd"> + <path d="M.5.5h16v14H.5z"/> + <path d="M1 1l15 13" stroke-linecap="square"/> + <path d="M1 14L16 1" stroke-linecap="square"/> + </g> +</svg> \ No newline at end of file diff --git a/editor/images/README.txt b/dist/images/README.txt similarity index 100% rename from editor/images/README.txt rename to dist/images/README.txt diff --git a/editor/images/align-bottom.png b/dist/images/align-bottom.png similarity index 100% rename from editor/images/align-bottom.png rename to dist/images/align-bottom.png diff --git a/editor/images/align-bottom.svg b/dist/images/align-bottom.svg similarity index 100% rename from editor/images/align-bottom.svg rename to dist/images/align-bottom.svg diff --git a/editor/images/align-center.png b/dist/images/align-center.png similarity index 100% rename from editor/images/align-center.png rename to dist/images/align-center.png diff --git a/editor/images/align-center.svg b/dist/images/align-center.svg similarity index 100% rename from editor/images/align-center.svg rename to dist/images/align-center.svg diff --git a/editor/images/align-left.png b/dist/images/align-left.png similarity index 100% rename from editor/images/align-left.png rename to dist/images/align-left.png diff --git a/editor/images/align-left.svg b/dist/images/align-left.svg similarity index 100% rename from editor/images/align-left.svg rename to dist/images/align-left.svg diff --git a/editor/images/align-middle.png b/dist/images/align-middle.png similarity index 100% rename from editor/images/align-middle.png rename to dist/images/align-middle.png diff --git a/editor/images/align-middle.svg b/dist/images/align-middle.svg similarity index 100% rename from editor/images/align-middle.svg rename to dist/images/align-middle.svg diff --git a/editor/images/align-right.png b/dist/images/align-right.png similarity index 100% rename from editor/images/align-right.png rename to dist/images/align-right.png diff --git a/editor/images/align-right.svg b/dist/images/align-right.svg similarity index 100% rename from editor/images/align-right.svg rename to dist/images/align-right.svg diff --git a/editor/images/align-top.png b/dist/images/align-top.png similarity index 100% rename from editor/images/align-top.png rename to dist/images/align-top.png diff --git a/editor/images/align-top.svg b/dist/images/align-top.svg similarity index 100% rename from editor/images/align-top.svg rename to dist/images/align-top.svg diff --git a/editor/images/bar-opacity.png b/dist/images/bar-opacity.png similarity index 100% rename from editor/images/bar-opacity.png rename to dist/images/bar-opacity.png diff --git a/editor/images/bold.png b/dist/images/bold.png similarity index 100% rename from editor/images/bold.png rename to dist/images/bold.png diff --git a/editor/images/cancel.png b/dist/images/cancel.png similarity index 100% rename from editor/images/cancel.png rename to dist/images/cancel.png diff --git a/editor/images/circle.png b/dist/images/circle.png similarity index 100% rename from editor/images/circle.png rename to dist/images/circle.png diff --git a/editor/images/clear.png b/dist/images/clear.png similarity index 100% rename from editor/images/clear.png rename to dist/images/clear.png diff --git a/editor/images/clone.png b/dist/images/clone.png similarity index 100% rename from editor/images/clone.png rename to dist/images/clone.png diff --git a/editor/images/conn.svg b/dist/images/conn.svg similarity index 100% rename from editor/images/conn.svg rename to dist/images/conn.svg diff --git a/editor/images/copy.png b/dist/images/copy.png similarity index 100% rename from editor/images/copy.png rename to dist/images/copy.png diff --git a/editor/images/cross.png b/dist/images/cross.png similarity index 100% rename from editor/images/cross.png rename to dist/images/cross.png diff --git a/editor/images/cut.png b/dist/images/cut.png similarity index 100% rename from editor/images/cut.png rename to dist/images/cut.png diff --git a/editor/images/delete.png b/dist/images/delete.png similarity index 100% rename from editor/images/delete.png rename to dist/images/delete.png diff --git a/editor/images/document-properties.png b/dist/images/document-properties.png similarity index 100% rename from editor/images/document-properties.png rename to dist/images/document-properties.png diff --git a/editor/images/drag.png b/dist/images/drag.png similarity index 100% rename from editor/images/drag.png rename to dist/images/drag.png diff --git a/editor/images/dragging.png b/dist/images/dragging.png similarity index 100% rename from editor/images/dragging.png rename to dist/images/dragging.png diff --git a/editor/images/dropdown.gif b/dist/images/dropdown.gif similarity index 100% rename from editor/images/dropdown.gif rename to dist/images/dropdown.gif diff --git a/editor/images/ellipse.png b/dist/images/ellipse.png similarity index 100% rename from editor/images/ellipse.png rename to dist/images/ellipse.png diff --git a/editor/images/ellipse.svg b/dist/images/ellipse.svg similarity index 100% rename from editor/images/ellipse.svg rename to dist/images/ellipse.svg diff --git a/editor/images/eye.png b/dist/images/eye.png similarity index 100% rename from editor/images/eye.png rename to dist/images/eye.png diff --git a/editor/images/eye.svg b/dist/images/eye.svg similarity index 100% rename from editor/images/eye.svg rename to dist/images/eye.svg diff --git a/editor/images/eyedropper.png b/dist/images/eyedropper.png similarity index 100% rename from editor/images/eyedropper.png rename to dist/images/eyedropper.png diff --git a/editor/images/eyedropper_tool.png b/dist/images/eyedropper_tool.png similarity index 100% rename from editor/images/eyedropper_tool.png rename to dist/images/eyedropper_tool.png diff --git a/editor/images/fhpath.png b/dist/images/fhpath.png similarity index 100% rename from editor/images/fhpath.png rename to dist/images/fhpath.png diff --git a/editor/images/flyouth.png b/dist/images/flyouth.png similarity index 100% rename from editor/images/flyouth.png rename to dist/images/flyouth.png diff --git a/editor/images/flyup.gif b/dist/images/flyup.gif similarity index 100% rename from editor/images/flyup.gif rename to dist/images/flyup.gif diff --git a/editor/images/freehand-circle.png b/dist/images/freehand-circle.png similarity index 100% rename from editor/images/freehand-circle.png rename to dist/images/freehand-circle.png diff --git a/editor/images/freehand-square.png b/dist/images/freehand-square.png similarity index 100% rename from editor/images/freehand-square.png rename to dist/images/freehand-square.png diff --git a/editor/images/go-down.png b/dist/images/go-down.png similarity index 100% rename from editor/images/go-down.png rename to dist/images/go-down.png diff --git a/editor/images/go-up.png b/dist/images/go-up.png similarity index 100% rename from editor/images/go-up.png rename to dist/images/go-up.png diff --git a/editor/images/image.png b/dist/images/image.png similarity index 100% rename from editor/images/image.png rename to dist/images/image.png diff --git a/editor/images/image.svg b/dist/images/image.svg similarity index 100% rename from editor/images/image.svg rename to dist/images/image.svg diff --git a/editor/images/italic.png b/dist/images/italic.png similarity index 100% rename from editor/images/italic.png rename to dist/images/italic.png diff --git a/editor/images/italic.svg b/dist/images/italic.svg similarity index 100% rename from editor/images/italic.svg rename to dist/images/italic.svg diff --git a/editor/images/line.png b/dist/images/line.png similarity index 100% rename from editor/images/line.png rename to dist/images/line.png diff --git a/editor/images/link_controls.png b/dist/images/link_controls.png similarity index 100% rename from editor/images/link_controls.png rename to dist/images/link_controls.png diff --git a/editor/images/logo.png b/dist/images/logo.png similarity index 100% rename from editor/images/logo.png rename to dist/images/logo.png diff --git a/editor/images/map-opacity.png b/dist/images/map-opacity.png similarity index 100% rename from editor/images/map-opacity.png rename to dist/images/map-opacity.png diff --git a/editor/images/mappoint.gif b/dist/images/mappoint.gif similarity index 100% rename from editor/images/mappoint.gif rename to dist/images/mappoint.gif diff --git a/editor/images/mappoint_c.png b/dist/images/mappoint_c.png similarity index 100% rename from editor/images/mappoint_c.png rename to dist/images/mappoint_c.png diff --git a/editor/images/mappoint_f.png b/dist/images/mappoint_f.png similarity index 100% rename from editor/images/mappoint_f.png rename to dist/images/mappoint_f.png diff --git a/editor/images/move_bottom.png b/dist/images/move_bottom.png similarity index 100% rename from editor/images/move_bottom.png rename to dist/images/move_bottom.png diff --git a/editor/images/move_top.png b/dist/images/move_top.png similarity index 100% rename from editor/images/move_top.png rename to dist/images/move_top.png diff --git a/editor/images/node_clone.png b/dist/images/node_clone.png similarity index 100% rename from editor/images/node_clone.png rename to dist/images/node_clone.png diff --git a/editor/images/node_delete.png b/dist/images/node_delete.png similarity index 100% rename from editor/images/node_delete.png rename to dist/images/node_delete.png diff --git a/editor/images/none.png b/dist/images/none.png similarity index 100% rename from editor/images/none.png rename to dist/images/none.png diff --git a/editor/images/open.png b/dist/images/open.png similarity index 100% rename from editor/images/open.png rename to dist/images/open.png diff --git a/editor/images/paste.png b/dist/images/paste.png similarity index 100% rename from editor/images/paste.png rename to dist/images/paste.png diff --git a/editor/images/path.png b/dist/images/path.png similarity index 100% rename from editor/images/path.png rename to dist/images/path.png diff --git a/editor/images/path.svg b/dist/images/path.svg similarity index 100% rename from editor/images/path.svg rename to dist/images/path.svg diff --git a/editor/images/pencil.png b/dist/images/pencil.png similarity index 100% rename from editor/images/pencil.png rename to dist/images/pencil.png diff --git a/editor/images/pencil.svg b/dist/images/pencil.svg similarity index 100% rename from editor/images/pencil.svg rename to dist/images/pencil.svg diff --git a/editor/images/pencil_cursor.png b/dist/images/pencil_cursor.png similarity index 100% rename from editor/images/pencil_cursor.png rename to dist/images/pencil_cursor.png diff --git a/editor/images/picker.gif b/dist/images/picker.gif similarity index 100% rename from editor/images/picker.gif rename to dist/images/picker.gif diff --git a/editor/images/placeholder.svg b/dist/images/placeholder.svg similarity index 100% rename from editor/images/placeholder.svg rename to dist/images/placeholder.svg diff --git a/editor/images/polygon.png b/dist/images/polygon.png similarity index 100% rename from editor/images/polygon.png rename to dist/images/polygon.png diff --git a/editor/images/polygon.svg b/dist/images/polygon.svg similarity index 100% rename from editor/images/polygon.svg rename to dist/images/polygon.svg diff --git a/editor/images/preview-opacity.png b/dist/images/preview-opacity.png similarity index 100% rename from editor/images/preview-opacity.png rename to dist/images/preview-opacity.png diff --git a/dist/images/rangearrows.svg b/dist/images/rangearrows.svg new file mode 100644 index 0000000..71b63e2 --- /dev/null +++ b/dist/images/rangearrows.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 7"> + <g fill="none" fill-rule="evenodd"> + <path fill="#000" d="M14 3.01v1H6v-1z"/> + <path d="M6.16 3.52L2.96.67a.5.5 0 00-.33-.13h-1.6a.5.5 0 00-.5.5V6c0 .27.22.5.5.5h1.6a.5.5 0 00.34-.13l3.2-2.86z" stroke="#625E57" fill="#FFF"/> + <path d="M13.74 3.48l3.2 2.86c.08.08.2.13.33.13h1.6a.5.5 0 00.5-.5V1a.5.5 0 00-.5-.5h-1.6a.5.5 0 00-.34.13l-3.2 2.85z" stroke="#625E57" fill="#FFF"/> + </g> +</svg> \ No newline at end of file diff --git a/dist/images/rangearrows2.svg b/dist/images/rangearrows2.svg new file mode 100644 index 0000000..b981b71 --- /dev/null +++ b/dist/images/rangearrows2.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 20"> + <g fill="none" fill-rule="evenodd"> + <path fill="#ADADAD" d="M4 7h1v6H4z"/> + <path d="M4.47 7.33l3.86-3.4a.5.5 0 00.17-.38V1A.5.5 0 008 .5H1a.5.5 0 00-.5.5v2.55c0 .15.06.28.17.38l3.8 3.4z" stroke="#625E57" fill="#FFF"/> + <path d="M4.53 12.67l-3.86 3.4a.5.5 0 00-.17.38V19c0 .28.22.5.5.5h7a.5.5 0 00.5-.5v-2.55a.5.5 0 00-.17-.38l-3.8-3.4z" stroke="#625E57" fill="#FFF"/> + </g> +</svg> \ No newline at end of file diff --git a/editor/images/rect.png b/dist/images/rect.png similarity index 100% rename from editor/images/rect.png rename to dist/images/rect.png diff --git a/editor/images/redo.png b/dist/images/redo.png similarity index 100% rename from editor/images/redo.png rename to dist/images/redo.png diff --git a/editor/images/reorient.png b/dist/images/reorient.png similarity index 100% rename from editor/images/reorient.png rename to dist/images/reorient.png diff --git a/editor/images/rotate.png b/dist/images/rotate.png similarity index 100% rename from editor/images/rotate.png rename to dist/images/rotate.png diff --git a/editor/images/save.png b/dist/images/save.png similarity index 100% rename from editor/images/save.png rename to dist/images/save.png diff --git a/editor/images/select.png b/dist/images/select.png similarity index 100% rename from editor/images/select.png rename to dist/images/select.png diff --git a/editor/images/select.svg b/dist/images/select.svg similarity index 100% rename from editor/images/select.svg rename to dist/images/select.svg diff --git a/editor/images/select_node.png b/dist/images/select_node.png similarity index 100% rename from editor/images/select_node.png rename to dist/images/select_node.png diff --git a/editor/images/sep.png b/dist/images/sep.png similarity index 100% rename from editor/images/sep.png rename to dist/images/sep.png diff --git a/editor/images/shape_group.png b/dist/images/shape_group.png similarity index 100% rename from editor/images/shape_group.png rename to dist/images/shape_group.png diff --git a/editor/images/shape_ungroup.png b/dist/images/shape_ungroup.png similarity index 100% rename from editor/images/shape_ungroup.png rename to dist/images/shape_ungroup.png diff --git a/editor/images/source.png b/dist/images/source.png similarity index 100% rename from editor/images/source.png rename to dist/images/source.png diff --git a/editor/images/spinbtn_updn_big.png b/dist/images/spinbtn_updn_big.png similarity index 100% rename from editor/images/spinbtn_updn_big.png rename to dist/images/spinbtn_updn_big.png diff --git a/editor/images/square.png b/dist/images/square.png similarity index 100% rename from editor/images/square.png rename to dist/images/square.png diff --git a/method-draw/images/svg_edit_icons.svg b/dist/images/svg_edit_icons.svg similarity index 99% rename from method-draw/images/svg_edit_icons.svg rename to dist/images/svg_edit_icons.svg index e6a361c..8aebadc 100644 --- a/method-draw/images/svg_edit_icons.svg +++ b/dist/images/svg_edit_icons.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg"> +<svg xmlns="http://www.w3.org/2000/svg"> <!-- All images created with SVG-edit - http://svg-edit.googlecode.com/ --> diff --git a/editor/images/svg_edit_icons.svgz b/dist/images/svg_edit_icons.svgz similarity index 100% rename from editor/images/svg_edit_icons.svgz rename to dist/images/svg_edit_icons.svgz diff --git a/editor/images/text.png b/dist/images/text.png similarity index 100% rename from editor/images/text.png rename to dist/images/text.png diff --git a/editor/images/text.svg b/dist/images/text.svg similarity index 100% rename from editor/images/text.svg rename to dist/images/text.svg diff --git a/editor/images/to_path.png b/dist/images/to_path.png similarity index 100% rename from editor/images/to_path.png rename to dist/images/to_path.png diff --git a/editor/images/undo.png b/dist/images/undo.png similarity index 100% rename from editor/images/undo.png rename to dist/images/undo.png diff --git a/editor/images/view-refresh.png b/dist/images/view-refresh.png similarity index 100% rename from editor/images/view-refresh.png rename to dist/images/view-refresh.png diff --git a/editor/images/wave.png b/dist/images/wave.png similarity index 100% rename from editor/images/wave.png rename to dist/images/wave.png diff --git a/editor/images/wireframe.png b/dist/images/wireframe.png similarity index 100% rename from editor/images/wireframe.png rename to dist/images/wireframe.png diff --git a/editor/images/zoom.png b/dist/images/zoom.png similarity index 100% rename from editor/images/zoom.png rename to dist/images/zoom.png diff --git a/editor/images/zoom.svg b/dist/images/zoom.svg similarity index 100% rename from editor/images/zoom.svg rename to dist/images/zoom.svg diff --git a/method-draw/index.html b/dist/index.html similarity index 88% rename from method-draw/index.html rename to dist/index.html index ae94008..9b670e8 100644 --- a/method-draw/index.html +++ b/dist/index.html @@ -2,67 +2,19 @@ <html> <head> -<meta http-equiv="X-UA-Compatible" content="chrome=1"/> -<link rel="icon" type="image/png" href="images/logo.png"/> - -<!--{if svg_edit_release}--> - <link rel="stylesheet" href="css/method-draw.compiled.css" type="text/css"/> -<!--{else}> - <link rel="stylesheet" href="lib/jgraduate/css/jPicker.css" type="text/css"/> - <link rel="stylesheet" href="lib/jgraduate/css/jgraduate.css" type="text/css"/> - <link rel="stylesheet" href="css/method-draw.css" type="text/css"/> - <link rel="stylesheet" href="css/fonts.css" type="text/css"/> -<!{endif}--> + <meta http-equiv="X-UA-Compatible" content="chrome=1"/> + <link rel="icon" type="image/png" href="images/logo.png"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <meta name="apple-mobile-web-app-capable" content="yes"/> + <title>Method Draw SVG Editor + + - - - - - - - - - -Method Draw SVG Editor - - + -
+
@@ -630,6 +582,9 @@
  • Send to Back⌘⇧↓
  • + + + diff --git a/editor/lib/canvg/canvg.js b/dist/js/lib/canvg.js similarity index 100% rename from editor/lib/canvg/canvg.js rename to dist/js/lib/canvg.js diff --git a/editor/lib/canvg/rgbcolor.js b/dist/js/lib/rgbcolor.js similarity index 100% rename from editor/lib/canvg/rgbcolor.js rename to dist/js/lib/rgbcolor.js diff --git a/editor/extensions/shapelib/arrow.json b/dist/shapelib/arrow.json similarity index 100% rename from editor/extensions/shapelib/arrow.json rename to dist/shapelib/arrow.json diff --git a/editor/extensions/shapelib/dialog_balloon.json b/dist/shapelib/dialog_balloon.json similarity index 100% rename from editor/extensions/shapelib/dialog_balloon.json rename to dist/shapelib/dialog_balloon.json diff --git a/editor/extensions/shapelib/flowchart.json b/dist/shapelib/flowchart.json similarity index 100% rename from editor/extensions/shapelib/flowchart.json rename to dist/shapelib/flowchart.json diff --git a/editor/extensions/shapelib/game.json b/dist/shapelib/game.json similarity index 100% rename from editor/extensions/shapelib/game.json rename to dist/shapelib/game.json diff --git a/editor/extensions/shapelib/math.json b/dist/shapelib/math.json similarity index 100% rename from editor/extensions/shapelib/math.json rename to dist/shapelib/math.json diff --git a/editor/extensions/shapelib/music.json b/dist/shapelib/music.json similarity index 100% rename from editor/extensions/shapelib/music.json rename to dist/shapelib/music.json diff --git a/editor/extensions/shapelib/nature.json b/dist/shapelib/nature.json similarity index 100% rename from editor/extensions/shapelib/nature.json rename to dist/shapelib/nature.json diff --git a/editor/extensions/shapelib/object.json b/dist/shapelib/object.json similarity index 100% rename from editor/extensions/shapelib/object.json rename to dist/shapelib/object.json diff --git a/editor/extensions/shapelib/raphael.txt b/dist/shapelib/raphael.txt similarity index 100% rename from editor/extensions/shapelib/raphael.txt rename to dist/shapelib/raphael.txt diff --git a/editor/extensions/shapelib/social.json b/dist/shapelib/social.json similarity index 100% rename from editor/extensions/shapelib/social.json rename to dist/shapelib/social.json diff --git a/editor/extensions/shapelib/symbol.json b/dist/shapelib/symbol.json similarity index 100% rename from editor/extensions/shapelib/symbol.json rename to dist/shapelib/symbol.json diff --git a/editor/extensions/shapelib/ui.json b/dist/shapelib/ui.json similarity index 99% rename from editor/extensions/shapelib/ui.json rename to dist/shapelib/ui.json index f5b34bd..a148817 100644 --- a/editor/extensions/shapelib/ui.json +++ b/dist/shapelib/ui.json @@ -24,7 +24,7 @@ "raph_key": "M18.386,16.009l0.009-0.006l-0.58-0.912c1.654-2.226,1.876-5.319,0.3-7.8c-2.043-3.213-6.303-4.161-9.516-2.118c-3.212,2.042-4.163,6.302-2.12,9.517c1.528,2.402,4.3,3.537,6.944,3.102l0.424,0.669l0.206,0.045l0.779-0.447l-0.305,1.377l2.483,0.552l-0.296,1.325l1.903,0.424l-0.68,3.06l1.406,0.313l-0.424,1.906l4.135,0.918l0.758-3.392L18.386,16.009z M10.996,8.944c-0.685,0.436-1.593,0.233-2.029-0.452C8.532,7.807,8.733,6.898,9.418,6.463s1.594-0.233,2.028,0.452C11.883,7.6,11.68,8.509,10.996,8.944z", "raph_ruler": "M6.63,21.796l-5.122,5.121h25.743V1.175L6.63,21.796zM18.702,10.48c0.186-0.183,0.48-0.183,0.664,0l1.16,1.159c0.184,0.183,0.186,0.48,0.002,0.663c-0.092,0.091-0.213,0.137-0.332,0.137c-0.121,0-0.24-0.046-0.33-0.137l-1.164-1.159C18.519,10.96,18.519,10.664,18.702,10.48zM17.101,12.084c0.184-0.183,0.48-0.183,0.662,0l2.156,2.154c0.184,0.183,0.184,0.48,0.002,0.661c-0.092,0.092-0.213,0.139-0.334,0.139s-0.24-0.046-0.33-0.137l-2.156-2.154C16.917,12.564,16.917,12.267,17.101,12.084zM15.497,13.685c0.184-0.183,0.48-0.183,0.664,0l1.16,1.161c0.184,0.183,0.182,0.48-0.002,0.663c-0.092,0.092-0.211,0.138-0.33,0.138c-0.121,0-0.24-0.046-0.332-0.138l-1.16-1.16C15.314,14.166,15.314,13.868,15.497,13.685zM13.896,15.288c0.184-0.183,0.48-0.181,0.664,0.002l1.158,1.159c0.183,0.184,0.183,0.48,0,0.663c-0.092,0.092-0.212,0.138-0.332,0.138c-0.119,0-0.24-0.046-0.332-0.138l-1.158-1.161C13.713,15.767,13.713,15.471,13.896,15.288zM12.293,16.892c0.183-0.184,0.479-0.184,0.663,0l2.154,2.153c0.184,0.184,0.184,0.481,0,0.665c-0.092,0.092-0.211,0.138-0.33,0.138c-0.121,0-0.242-0.046-0.334-0.138l-2.153-2.155C12.11,17.371,12.11,17.075,12.293,16.892zM10.302,24.515c-0.091,0.093-0.212,0.139-0.332,0.139c-0.119,0-0.238-0.045-0.33-0.137l-2.154-2.153c-0.184-0.183-0.184-0.479,0-0.663s0.479-0.184,0.662,0l2.154,2.153C10.485,24.036,10.485,24.332,10.302,24.515zM10.912,21.918c-0.093,0.093-0.214,0.139-0.333,0.139c-0.12,0-0.24-0.045-0.33-0.137l-1.162-1.161c-0.184-0.183-0.184-0.479,0-0.66c0.184-0.185,0.48-0.187,0.664-0.003l1.161,1.162C11.095,21.438,11.095,21.735,10.912,21.918zM12.513,20.316c-0.092,0.092-0.211,0.138-0.332,0.138c-0.119,0-0.239-0.046-0.331-0.138l-1.159-1.16c-0.184-0.184-0.184-0.48,0-0.664s0.48-0.182,0.663,0.002l1.159,1.161C12.696,19.838,12.696,20.135,12.513,20.316zM22.25,21.917h-8.67l8.67-8.67V21.917zM22.13,10.7c-0.09,0.092-0.211,0.138-0.33,0.138c-0.121,0-0.242-0.046-0.334-0.138l-1.16-1.159c-0.184-0.183-0.184-0.479,0-0.663c0.182-0.183,0.479-0.183,0.662,0l1.16,1.159C22.312,10.221,22.313,10.517,22.13,10.7zM24.726,10.092c-0.092,0.092-0.213,0.137-0.332,0.137s-0.24-0.045-0.33-0.137l-2.154-2.154c-0.184-0.183-0.184-0.481,0-0.664s0.482-0.181,0.664,0.002l2.154,2.154C24.911,9.613,24.909,9.91,24.726,10.092z", "raph_power": "M21.816,3.999c-0.993-0.481-2.189-0.068-2.673,0.927c-0.482,0.995-0.066,2.191,0.927,2.673c3.115,1.516,5.265,4.705,5.263,8.401c-0.01,5.154-4.18,9.324-9.333,9.333c-5.154-0.01-9.324-4.18-9.334-9.333c-0.002-3.698,2.149-6.89,5.267-8.403c0.995-0.482,1.408-1.678,0.927-2.673c-0.482-0.993-1.676-1.409-2.671-0.927C5.737,6.152,2.667,10.72,2.665,16C2.667,23.364,8.634,29.332,16,29.334c7.365-0.002,13.333-5.97,13.334-13.334C29.332,10.722,26.266,6.157,21.816,3.999z M16,13.833c1.104,0,1.999-0.894,1.999-2V2.499C17.999,1.394,17.104,0.5,16,0.5c-1.106,0-2,0.895-2,1.999v9.333C14,12.938,14.894,13.833,16,13.833z", - "raph_lock": "M22.335,12.833V9.999h-0.001C22.333,6.501,19.498,3.666,16,3.666S9.666,6.502,9.666,10h0v2.833H7.375V25h17.25V12.833H22.335zM11.667,10C11.667,10,11.667,10,11.667,10c0-2.39,1.944-4.334,4.333-4.334c2.391,0,4.335,1.944,4.335,4.333c0,0,0,0,0,0v2.834h-8.668V10zx", + "raph_lock": "M22.335,12.833V9.999h-0.001C22.333,6.501,19.498,3.666,16,3.666S9.666,6.502,9.666,10h0v2.833H7.375V25h17.25V12.833H22.335zM11.667,10C11.667,10,11.667,10,11.667,10c0-2.39,1.944-4.334,4.333-4.334c2.391,0,4.335,1.944,4.335,4.333c0,0,0,0,0,0v2.834h-8.668V10z", "raph_unlock": "M20.375,12.833h-2.209V10c0,0,0,0,0-0.001c0-2.389,1.945-4.333,4.334-4.333c2.391,0,4.335,1.944,4.335,4.333c0,0,0,0,0,0v2.834h2V9.999h-0.001c-0.001-3.498-2.836-6.333-6.334-6.333S16.166,6.502,16.166,10v2.833H3.125V25h17.25V12.833z", "raph_bookmark": "M17.396,1.841L6.076,25.986l7.341-4.566l1.186,8.564l11.32-24.146L17.396,1.841zM19.131,9.234c-0.562-0.264-0.805-0.933-0.541-1.495c0.265-0.562,0.934-0.805,1.496-0.541s0.805,0.934,0.541,1.496S19.694,9.498,19.131,9.234z", "raph_tag": "M14.263,2.826H7.904L2.702,8.028v6.359L18.405,30.09l11.561-11.562L14.263,2.826zM6.495,8.859c-0.619-0.619-0.619-1.622,0-2.24C7.114,6,8.117,6,8.736,6.619c0.62,0.62,0.619,1.621,0,2.241C8.117,9.479,7.114,9.479,6.495,8.859z", diff --git a/editor/extensions/shapelib/weather.json b/dist/shapelib/weather.json similarity index 100% rename from editor/extensions/shapelib/weather.json rename to dist/shapelib/weather.json diff --git a/dist/site.webmanifest b/dist/site.webmanifest new file mode 100644 index 0000000..7ab88a5 --- /dev/null +++ b/dist/site.webmanifest @@ -0,0 +1,15 @@ +{ + "name": "Blank Page", + "short_name": "Blank Page", + "start_url": "/", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + } + ], + "theme_color": "#fafafa", + "display": "fullscreen", + "background_color": "#fafafa" +} diff --git a/docs/files/svgcanvas-js.html b/docs/files/svgcanvas-js.html deleted file mode 100644 index 6f1b0b3..0000000 --- a/docs/files/svgcanvas-js.html +++ /dev/null @@ -1,426 +0,0 @@ - - -SvgCanvas - - - - - - - - - -

    SvgCanvas

    The main SvgCanvas class that manages all SVG-related functions

    Parameters

    containerThe container HTML element that should hold the SVG root element
    configAn object that contains configuration data
    Summary
    SvgCanvasThe main SvgCanvas class that manages all SVG-related functions
    Utils.toXmlConverts characters in a string to XML-friendly entities.
    Utils.fromXmlConverts XML entities in a string to single characters.
    Utils.encode64Converts a string to base64
    Utils.decode64Converts a string from base64
    Utils.convertToXMLReferencesConverts a string to use XML references
    rectsIntersectCheck if two rectangles (BBoxes objects) intersect each other
    snapToAngleReturns a 45 degree angle coordinate associated with the two given coordinates
    text2xmlCross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
    Unit conversion functions
    convertToNumConverts given values to numbers.
    setUnitAttrSets an element’s attribute based on the unit in its current value.
    isValidUnitCheck if an attribute’s value is in a valid format
    Undo/Redo history management
    ChangeElementCommandHistory command to make a change to an element.
    ChangeElementCommand.applyPerforms the stored change action
    ChangeElementCommand.unapplyReverses the stored change action
    ChangeElementCommand.elementsReturns array with element associated with this command
    InsertElementCommandHistory command for an element that was added to the DOM
    InsertElementCommand.applyRe-Inserts the new element
    InsertElementCommand.unapplyRemoves the element
    InsertElementCommand.elementsReturns array with element associated with this command
    RemoveElementCommandHistory command for an element removed from the DOM
    RemoveElementCommand.applyRe-removes the new element
    RemoveElementCommand.unapplyRe-adds the new element
    RemoveElementCommand.elementsReturns array with element associated with this command
    MoveElementCommandHistory command for an element that had its DOM position changed
    MoveElementCommand.unapplyRe-positions the element
    MoveElementCommand.unapplyPositions the element back to its original location
    MoveElementCommand.elementsReturns array with element associated with this command
    BatchCommandHistory command that can contain/execute multiple other commands
    BatchCommand.applyRuns “apply” on all subcommands
    BatchCommand.unapplyRuns “unapply” on all subcommands
    BatchCommand.elementsIterate through all our subcommands and returns all the elements we are changing
    BatchCommand.addSubCommandAdds a given command to the history stack
    BatchCommand.isEmptyReturns a boolean indicating whether or not the batch command is empty
    resetUndoStackResets the undo stack, effectively clearing the undo/redo history
    undoMgr.getUndoStackSizeInteger with the current size of the undo history stack
    undoMgr.getRedoStackSizeInteger with the current size of the redo history stack
    undoMgr.getNextUndoCommandTextString associated with the next undo command
    undoMgr.getNextRedoCommandTextString associated with the next redo command
    undoMgr.undoPerforms an undo step
    undoMgr.redoPerforms a redo step
    addCommandToHistoryAdds a command object to the undo history stack
    beginUndoableChangeThis function tells the canvas to remember the old values of the attrName attribute for each element sent in.
    finishUndoableChangeThis function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
    SelectorPrivate class for DOM element selection boxes
    Functions
    Selector.resetUsed to reset the id and element that the selector is attached to
    Selector.showGripsShow the resize grips of this selector
    Selector.updateGripCursorsUpdates cursors for corner grips on rotation so arrows point the right way
    Selector.resizeUpdates the selector to match the element’s size
    SelectorManagerPublic class to manage all selector objects (selection boxes)
    SelectorManager.initGroupResets the parent selector group element
    SelectorManager.requestSelectorReturns the selector based on the given element
    SelectorManager.releaseSelectorRemoves the selector of the given element (hides selection box)
    SelectorManager.getRubberBandBoxReturns the rubberBandBox DOM element.
    Helper functions
    walkTreeWalks the tree and executes the callback on each element in a top-down fashion
    walkTreePostWalks the tree and executes the callback on each element in a depth-first fashion
    assignAttributesAssigns multiple attributes to an element.
    cleanupElementRemove unneeded (default) attributes, makes resulting SVG smaller
    addSvgElementFromJsonCreate a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
    addExtensionAdd an extension to the editor
    shortFloatRounds a given value to a float with number of digits defined in save_options
    getStrokedBBoxGet the bounding box for one or more stroked and/or transformed elements
    getVisibleElementsGet all elements that have a BBox (excludes <defs>, <title>, etc).
    copyElemCreate a clone of an element, updating its ID and its children’s IDs when needed
    getElemGet a DOM element by ID within the SVG root element.
    getIdReturns the last created DOM element ID string
    getNextIdCreates and returns a unique ID string for a DOM element
    bindAttaches a callback function to an event
    setIdPrefixChanges the ID prefix to the given value
    sanitizeSvgSanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
    getUrlFromAttrExtracts the URL from the url(...)
    getBBoxGet the given/selected element’s bounding box object, convert it to be more usable when necessary
    ffCloneHack for Firefox bugs where text element features aren’t updated.
    getPathBBoxGet correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
    Element Transforms
    getRotationAngleGet the rotation angle of the given/selected DOM element
    setRotationAngleRemoves any old rotations if present, prepends a new rotation at the transformed center
    getTransformListReturns an object that behaves like a SVGTransformList for the given DOM element
    recalculateAllSelectedDimensionsRuns recalculateDimensions on the selected elements, adding the changes to a single batch command
    remapElementApplies coordinate changes to an element based on the given matrix
    recalculateDimensionsDecides the course of action based on the element’s transform list
    transformPointA (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
    isIdentityHelper function to check if the matrix performs no actual transform (i.e.
    matrixMultiplyThis function tries to return a SVGMatrix that is the multiplication m1*m2.
    transformListToTransformThis returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
    hasMatrixTransformSee if the given transformlist includes a non-indentity matrix transform
    getMatrixGet the matrix object for a given element
    transformBoxTransforms a rectangle based on the given matrix
    Selection
    clearSelectionClears the selection.
    addToSelectionAdds a list of elements to the selection.
    removeFromSelectionRemoves elements from the selection.
    selectAllInCurrentLayerClears the selection, then adds all elements in the current layer to the selection.
    smoothControlPointsTakes three points and creates a smoother line based on them
    getMouseTargetGets the desired element from a mouse event
    preventClickDefaultPrevents default browser click behaviour on the given element
    Text edit functionsFunctions relating to editing text elements
    Path edit functionsFunctions relating to editing path elements
    Serialization
    removeUnusedDefElemsLooks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.
    svgCanvasToStringMain function to set up the SVG content for output
    svgToStringSub function ran on each SVG element to convert it to a string as desired
    embedImageConverts a given image file to a data URL when possible, then runs a given callback
    saveSerializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
    rasterExportGenerates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
    getSvgStringReturns the current drawing as raw SVG XML text.
    setSvgStringThis function sets the current drawing as the input SVG XML.
    importSvgStringThis function imports the input SVG XML into the current layer in the drawing
    Layers
    identifyLayersUpdates layer system
    createLayerCreates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
    deleteCurrentLayerDeletes the current layer from the drawing and then clears the selection.
    getNumLayersReturns the number of layers in the current drawing.
    getLayerReturns the name of the ith layer.
    getCurrentLayerReturns the name of the currently selected layer.
    setCurrentLayerSets the current layer.
    renameCurrentLayerRenames the current layer.
    setCurrentLayerPositionChanges the position of the current layer to the new value.
    getLayerVisibilityReturns whether the layer is visible.
    setLayerVisibilitySets the visibility of the layer.
    moveSelectedToLayerMoves the selected elements to layername.
    getLayerOpacityReturns the opacity of the given layer.
    setLayerOpacitySets the opacity of the given layer.
    Document functions
    clearClears the current document.
    linkControlPointsAlias function
    getContentElemReturns the content DOM element
    getRootElemReturns the root DOM element
    getSelectedElemsReturns the array with selected DOM elements
    getResolutionReturns the current dimensions and zoom level in an object
    getZoomReturns the current zoom level
    getVersionReturns a string which describes the revision number of SvgCanvas.
    setUiStringsUpdate interface strings with given values
    setConfigUpdate configuration options with given values
    getDocumentTitleReturns the current document title or an empty string if not found
    setDocumentTitleAdds/updates a title element for the document with the given name.
    getEditorNSReturns the editor’s namespace URL, optionally adds it to root element
    setResolutionChanges the document’s dimensions to the given size
    getOffsetReturns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
    setBBoxZoomSets the zoom level on the canvas-side based on the given value
    setZoomSets the zoom to the given level
    getModeReturns the current editor mode string
    setModeSets the editor’s mode to the given string
    Element Styling
    getColorReturns the current fill/stroke option
    setColorChange the current stroke/fill color/gradient value
    findDefsReturn the document’s <defs> element, create it first if necessary
    setGradientApply the current gradient to selected element’s fill or stroke
    findDuplicateGradientCheck if exact gradient already exists
    setPaintSet a color/gradient to a fill/stroke
    getStrokeWidthReturns the current stroke-width value
    setStrokeWidthSets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
    setStrokeAttrSet the given stroke-related attribute the given value for selected elements
    getOpacityReturns the current opacity
    setOpacitySets the given opacity to the current selected elements
    getOpacityReturns the current fill opacity
    getStrokeOpacityReturns the current stroke opacity
    setPaintOpacitySets the current fill/stroke opacity
    getBlurGets the stdDeviation blur value of the given element
    setBlurNoUndoSets the stdDeviation blur value on the selected element without being undoable
    setBlurOffsetsSets the x, y, with, height values of the filter element in order to make the blur not be clipped.
    setBlurAdds/updates the blur filter to the selected element
    getBoldCheck whether selected element is bold or not
    setBoldMake the selected element bold or normal
    getItalicCheck whether selected element is italic or not
    setItalicMake the selected element italic or normal
    getFontFamilyReturns the current font family
    setFontFamilySet the new font family
    getFontSizeReturns the current font size
    setFontSizeApplies the given font size to the selected element
    getTextReturns the current text (textContent) of the selected element
    setTextContentUpdates the text element with the given string
    setImageURLSets the new image URL for the selected image element.
    setRectRadiusSets the rx & ry values to the selected rect element to change its corner radius
    Element manipulation
    setSegTypeSets the new segment type to the selected segment(s).
    convertToPathConvert selected element to a path, or get the BBox of an element-as-path
    changeSelectedAttributeNoUndoThis function makes the changes to the elements.
    changeSelectedAttributeChange the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
    deleteSelectedElementsRemoves all selected elements from the DOM and adds the change to the history stack
    groupSelectedElementsWraps all the selected elements in a group (g) element
    ungroupSelectedElementUnwraps all the elements in a selected group (g) element.
    moveToTopSelectedElementRepositions the selected element to the bottom in the DOM to appear on top of other elements
    moveToBottomSelectedElementRepositions the selected element to the top in the DOM to appear under other elements
    moveSelectedElementsMoves selected elements on the X/Y axis
    cloneSelectedElementsCreate deep DOM copies (clones) of all selected elements and move them slightly from their originals
    alignSelectedElementsAligns selected elements
    Additional editor tools
    updateCanvasUpdates the editor canvas width/height/position after a zoom has occurred
    setBackgroundSet the background of the editor (NOT the actual document)
    cycleElementSelect the next/previous element within the current layer
    - -

    Utils.toXml

    Converts characters in a string to XML-friendly entities.

    Example: “&” becomes “&amp;”

    Parameters

    strThe string to be converted

    Returns

    The converted string

    - -

    Utils.fromXml

    Converts XML entities in a string to single characters.  Example: “&amp;” becomes “&”

    Parameters

    strThe string to be converted

    Returns

    The converted string

    - -

    Utils.encode64

    Converts a string to base64

    - -

    Utils.decode64

    Converts a string from base64

    - -

    Utils.convertToXMLReferences

    Converts a string to use XML references

    - -

    rectsIntersect

    "rectsIntersect": function(r1,
    r2)

    Check if two rectangles (BBoxes objects) intersect each other

    Paramaters

    r1The first BBox-like object
    r2The second BBox-like object

    Returns

    Boolean that’s true if rectangles intersect

    - -

    snapToAngle

    "snapToAngle": function(x1,
    y1,
    x2,
    y2)

    Returns a 45 degree angle coordinate associated with the two given coordinates

    Parameters

    x1First coordinate’s x value
    x2Second coordinate’s x value
    y1First coordinate’s y value
    y2Second coordinate’s y value

    Returns

    Object with the following values: x - The angle-snapped x value y - The angle-snapped y value snapangle - The angle at which to snap

    - -

    text2xml

    "text2xml": function(sXML)

    Cross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f

    - -

    Unit conversion functions

    - -

    convertToNum

    convertToNum = function(attr,
    val)

    Converts given values to numbers.  Attributes must be supplied in case a percentage is given

    Parameters

    attrString with the name of the attribute associated with the value
    valString with the attribute value to convert
    - -

    setUnitAttr

    setUnitAttr = function(elem,
    attr,
    val)

    Sets an element’s attribute based on the unit in its current value.

    Parameters

    elemDOM element to be changed
    attrString with the name of the attribute associated with the value
    valString with the attribute value to convert
    - -

    isValidUnit

    canvas.isValidUnit = function(attr,
    val)

    Check if an attribute’s value is in a valid format

    Parameters

    attrString with the name of the attribute associated with the value
    valString with the attribute value to check
    - -

    Undo/Redo history management

    - -

    ChangeElementCommand

    var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
    attrs,
    text)

    History command to make a change to an element.  Usually an attribute change, but can also be textcontent.

    Parameters

    elemThe DOM element that was changed
    attrsAn object with the attributes to be changed and the values they had before the change
    textAn optional string visible to user related to this change
    - -

    ChangeElementCommand.apply

    Performs the stored change action

    - -

    ChangeElementCommand.unapply

    Reverses the stored change action

    - -

    ChangeElementCommand.elements

    Returns array with element associated with this command

    - -

    InsertElementCommand

    var InsertElementCommand = this.undoCmd.insertElement = function(elem,
    text)

    History command for an element that was added to the DOM

    Parameters

    elemThe newly added DOM element
    textAn optional string visible to user related to this change
    - -

    InsertElementCommand.apply

    Re-Inserts the new element

    - -

    InsertElementCommand.unapply

    Removes the element

    - -

    InsertElementCommand.elements

    Returns array with element associated with this command

    - -

    RemoveElementCommand

    var RemoveElementCommand = this.undoCmd.removeElement = function(elem,
    parent,
    text)

    History command for an element removed from the DOM

    Parameters

    elemThe removed DOM element
    parentThe DOM element’s parent
    textAn optional string visible to user related to this change
    - -

    RemoveElementCommand.apply

    Re-removes the new element

    - -

    RemoveElementCommand.unapply

    Re-adds the new element

    - -

    RemoveElementCommand.elements

    Returns array with element associated with this command

    - -

    MoveElementCommand

    var MoveElementCommand = this.undoCmd.moveElement = function(elem,
    oldNextSibling,
    oldParent,
    text)

    History command for an element that had its DOM position changed

    Parameters

    elemThe DOM element that was moved
    oldNextSiblingThe element’s next sibling before it was moved
    oldParentThe element’s parent before it was moved
    textAn optional string visible to user related to this change
    - -

    MoveElementCommand.unapply

    Re-positions the element

    - -

    MoveElementCommand.unapply

    Positions the element back to its original location

    - -

    MoveElementCommand.elements

    Returns array with element associated with this command

    - -

    BatchCommand

    var BatchCommand = this.undoCmd.batch = function(text)

    History command that can contain/execute multiple other commands

    Parameters

    textAn optional string visible to user related to this change
    - -

    BatchCommand.apply

    Runs “apply” on all subcommands

    - -

    BatchCommand.unapply

    Runs “unapply” on all subcommands

    - -

    BatchCommand.elements

    Iterate through all our subcommands and returns all the elements we are changing

    - -

    BatchCommand.addSubCommand

    Adds a given command to the history stack

    Parameters

    cmdThe undo command object to add
    - -

    BatchCommand.isEmpty

    Returns a boolean indicating whether or not the batch command is empty

    - -

    resetUndoStack

    resetUndoStack = function()

    Resets the undo stack, effectively clearing the undo/redo history

    - -

    undoMgr.getUndoStackSize

    Returns

    Integer with the current size of the undo history stack

    - -

    undoMgr.getRedoStackSize

    Returns

    Integer with the current size of the redo history stack

    - -

    undoMgr.getNextUndoCommandText

    Returns

    String associated with the next undo command

    - -

    undoMgr.getNextRedoCommandText

    Returns

    String associated with the next redo command

    - -

    undoMgr.undo

    Performs an undo step

    - -

    undoMgr.redo

    Performs a redo step

    - -

    addCommandToHistory

    addCommandToHistory = c.undoCmd.add = function(cmd)

    Adds a command object to the undo history stack

    Parameters

    cmdThe command object to add
    - -

    beginUndoableChange

    c.beginUndoableChange = function(attrName,
    elems)

    This function tells the canvas to remember the old values of the attrName attribute for each element sent in.  The elements and values are stored on a stack, so the next call to finishUndoableChange() will pop the elements and old values off the stack, gets the current values from the DOM and uses all of these to construct the undo-able command.

    Parameters

    attrNameThe name of the attribute being changed
    elemsArray of DOM elements being changed
    - -

    finishUndoableChange

    c.finishUndoableChange = function()

    This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.  The command can then be added to the command history

    Returns

    Batch command object with resulting changes

    - -

    Selector

    Private class for DOM element selection boxes

    Parameters

    idinteger to internally indentify the selector
    elemDOM element associated with this selector
    Summary
    Functions
    Selector.resetUsed to reset the id and element that the selector is attached to
    Selector.showGripsShow the resize grips of this selector
    Selector.updateGripCursorsUpdates cursors for corner grips on rotation so arrows point the right way
    Selector.resizeUpdates the selector to match the element’s size
    - -

    Functions

    - -

    Selector.reset

    Used to reset the id and element that the selector is attached to

    Parameters

    eDOM element associated with this selector
    - -

    Selector.showGrips

    Show the resize grips of this selector

    Parameters

    showboolean indicating whether grips should be shown or not
    - -

    Selector.updateGripCursors

    Updates cursors for corner grips on rotation so arrows point the right way

    Parameters

    angleFloat indicating current rotation angle in degrees
    - -

    Selector.resize

    Updates the selector to match the element’s size

    - -

    SelectorManager

    Public class to manage all selector objects (selection boxes)

    Summary
    SelectorManager.initGroupResets the parent selector group element
    SelectorManager.requestSelectorReturns the selector based on the given element
    SelectorManager.releaseSelectorRemoves the selector of the given element (hides selection box)
    SelectorManager.getRubberBandBoxReturns the rubberBandBox DOM element.
    Helper functions
    walkTreeWalks the tree and executes the callback on each element in a top-down fashion
    walkTreePostWalks the tree and executes the callback on each element in a depth-first fashion
    assignAttributesAssigns multiple attributes to an element.
    cleanupElementRemove unneeded (default) attributes, makes resulting SVG smaller
    addSvgElementFromJsonCreate a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
    addExtensionAdd an extension to the editor
    shortFloatRounds a given value to a float with number of digits defined in save_options
    getStrokedBBoxGet the bounding box for one or more stroked and/or transformed elements
    getVisibleElementsGet all elements that have a BBox (excludes <defs>, <title>, etc).
    copyElemCreate a clone of an element, updating its ID and its children’s IDs when needed
    getElemGet a DOM element by ID within the SVG root element.
    getIdReturns the last created DOM element ID string
    getNextIdCreates and returns a unique ID string for a DOM element
    bindAttaches a callback function to an event
    setIdPrefixChanges the ID prefix to the given value
    sanitizeSvgSanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
    getUrlFromAttrExtracts the URL from the url(...)
    getBBoxGet the given/selected element’s bounding box object, convert it to be more usable when necessary
    ffCloneHack for Firefox bugs where text element features aren’t updated.
    getPathBBoxGet correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
    Element Transforms
    getRotationAngleGet the rotation angle of the given/selected DOM element
    setRotationAngleRemoves any old rotations if present, prepends a new rotation at the transformed center
    getTransformListReturns an object that behaves like a SVGTransformList for the given DOM element
    recalculateAllSelectedDimensionsRuns recalculateDimensions on the selected elements, adding the changes to a single batch command
    remapElementApplies coordinate changes to an element based on the given matrix
    recalculateDimensionsDecides the course of action based on the element’s transform list
    transformPointA (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
    isIdentityHelper function to check if the matrix performs no actual transform (i.e.
    matrixMultiplyThis function tries to return a SVGMatrix that is the multiplication m1*m2.
    transformListToTransformThis returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
    hasMatrixTransformSee if the given transformlist includes a non-indentity matrix transform
    getMatrixGet the matrix object for a given element
    transformBoxTransforms a rectangle based on the given matrix
    Selection
    clearSelectionClears the selection.
    addToSelectionAdds a list of elements to the selection.
    removeFromSelectionRemoves elements from the selection.
    selectAllInCurrentLayerClears the selection, then adds all elements in the current layer to the selection.
    smoothControlPointsTakes three points and creates a smoother line based on them
    getMouseTargetGets the desired element from a mouse event
    preventClickDefaultPrevents default browser click behaviour on the given element
    Text edit functionsFunctions relating to editing text elements
    Path edit functionsFunctions relating to editing path elements
    Serialization
    removeUnusedDefElemsLooks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.
    svgCanvasToStringMain function to set up the SVG content for output
    svgToStringSub function ran on each SVG element to convert it to a string as desired
    embedImageConverts a given image file to a data URL when possible, then runs a given callback
    saveSerializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
    rasterExportGenerates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
    getSvgStringReturns the current drawing as raw SVG XML text.
    setSvgStringThis function sets the current drawing as the input SVG XML.
    importSvgStringThis function imports the input SVG XML into the current layer in the drawing
    Layers
    identifyLayersUpdates layer system
    createLayerCreates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
    deleteCurrentLayerDeletes the current layer from the drawing and then clears the selection.
    getNumLayersReturns the number of layers in the current drawing.
    getLayerReturns the name of the ith layer.
    getCurrentLayerReturns the name of the currently selected layer.
    setCurrentLayerSets the current layer.
    renameCurrentLayerRenames the current layer.
    setCurrentLayerPositionChanges the position of the current layer to the new value.
    getLayerVisibilityReturns whether the layer is visible.
    setLayerVisibilitySets the visibility of the layer.
    moveSelectedToLayerMoves the selected elements to layername.
    getLayerOpacityReturns the opacity of the given layer.
    setLayerOpacitySets the opacity of the given layer.
    Document functions
    clearClears the current document.
    linkControlPointsAlias function
    getContentElemReturns the content DOM element
    getRootElemReturns the root DOM element
    getSelectedElemsReturns the array with selected DOM elements
    getResolutionReturns the current dimensions and zoom level in an object
    getZoomReturns the current zoom level
    getVersionReturns a string which describes the revision number of SvgCanvas.
    setUiStringsUpdate interface strings with given values
    setConfigUpdate configuration options with given values
    getDocumentTitleReturns the current document title or an empty string if not found
    setDocumentTitleAdds/updates a title element for the document with the given name.
    getEditorNSReturns the editor’s namespace URL, optionally adds it to root element
    setResolutionChanges the document’s dimensions to the given size
    getOffsetReturns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
    setBBoxZoomSets the zoom level on the canvas-side based on the given value
    setZoomSets the zoom to the given level
    getModeReturns the current editor mode string
    setModeSets the editor’s mode to the given string
    Element Styling
    getColorReturns the current fill/stroke option
    setColorChange the current stroke/fill color/gradient value
    findDefsReturn the document’s <defs> element, create it first if necessary
    setGradientApply the current gradient to selected element’s fill or stroke
    findDuplicateGradientCheck if exact gradient already exists
    setPaintSet a color/gradient to a fill/stroke
    getStrokeWidthReturns the current stroke-width value
    setStrokeWidthSets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
    setStrokeAttrSet the given stroke-related attribute the given value for selected elements
    getOpacityReturns the current opacity
    setOpacitySets the given opacity to the current selected elements
    getOpacityReturns the current fill opacity
    getStrokeOpacityReturns the current stroke opacity
    setPaintOpacitySets the current fill/stroke opacity
    getBlurGets the stdDeviation blur value of the given element
    setBlurNoUndoSets the stdDeviation blur value on the selected element without being undoable
    setBlurOffsetsSets the x, y, with, height values of the filter element in order to make the blur not be clipped.
    setBlurAdds/updates the blur filter to the selected element
    getBoldCheck whether selected element is bold or not
    setBoldMake the selected element bold or normal
    getItalicCheck whether selected element is italic or not
    setItalicMake the selected element italic or normal
    getFontFamilyReturns the current font family
    setFontFamilySet the new font family
    getFontSizeReturns the current font size
    setFontSizeApplies the given font size to the selected element
    getTextReturns the current text (textContent) of the selected element
    setTextContentUpdates the text element with the given string
    setImageURLSets the new image URL for the selected image element.
    setRectRadiusSets the rx & ry values to the selected rect element to change its corner radius
    Element manipulation
    setSegTypeSets the new segment type to the selected segment(s).
    convertToPathConvert selected element to a path, or get the BBox of an element-as-path
    changeSelectedAttributeNoUndoThis function makes the changes to the elements.
    changeSelectedAttributeChange the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
    deleteSelectedElementsRemoves all selected elements from the DOM and adds the change to the history stack
    groupSelectedElementsWraps all the selected elements in a group (g) element
    ungroupSelectedElementUnwraps all the elements in a selected group (g) element.
    moveToTopSelectedElementRepositions the selected element to the bottom in the DOM to appear on top of other elements
    moveToBottomSelectedElementRepositions the selected element to the top in the DOM to appear under other elements
    moveSelectedElementsMoves selected elements on the X/Y axis
    cloneSelectedElementsCreate deep DOM copies (clones) of all selected elements and move them slightly from their originals
    alignSelectedElementsAligns selected elements
    Additional editor tools
    updateCanvasUpdates the editor canvas width/height/position after a zoom has occurred
    setBackgroundSet the background of the editor (NOT the actual document)
    cycleElementSelect the next/previous element within the current layer
    - -

    SelectorManager.initGroup

    Resets the parent selector group element

    - -

    SelectorManager.requestSelector

    Returns the selector based on the given element

    Parameters

    elemDOM element to get the selector for
    - -

    SelectorManager.releaseSelector

    Removes the selector of the given element (hides selection box)

    Parameters

    elemDOM element to remove the selector for
    - -

    SelectorManager.getRubberBandBox

    Returns the rubberBandBox DOM element.  This is the rectangle drawn by the user for selecting/zooming

    - -

    Helper functions

    - -

    walkTree

    function walkTree(elem,
    cbFn)

    Walks the tree and executes the callback on each element in a top-down fashion

    Parameters

    elemDOM element to traverse
    cbFnCallback function to run on each element
    - -

    walkTreePost

    function walkTreePost(elem,
    cbFn)

    Walks the tree and executes the callback on each element in a depth-first fashion

    Parameters

    elemDOM element to traverse
    cbFnCallback function to run on each element
    - -

    assignAttributes

    var assignAttributes = this.assignAttributes = function(node,
    attrs,
    suspendLength,
    unitCheck)

    Assigns multiple attributes to an element.

    Parameters

    nodeDOM element to apply new attribute values to
    attrsObject with attribute keys/values
    suspendLengthOptional integer of milliseconds to suspend redraw
    unitCheckBoolean to indicate the need to use setUnitAttr
    - -

    cleanupElement

    var cleanupElement = this.cleanupElement = function(element)

    Remove unneeded (default) attributes, makes resulting SVG smaller

    Parameters

    elementDOM element to clean up
    - -

    addSvgElementFromJson

    var addSvgElementFromJson = this.addSvgElementFromJson = function(data)

    Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned

    Parameters

    dataObject with the following keys/values:
    • element - DOM element to create
    • attr - Object with attributes/values to assign to the new element
    • curStyles - Boolean indicating that current style attributes should be applied first

    Returns: The new element

    - -

    addExtension

    this.addExtension = function(name,
    ext_func)

    Add an extension to the editor

    Parameters

    nameString with the ID of the extension
    ext_funcFunction supplied by the extension with its data
    - -

    shortFloat

    var shortFloat = function(val)

    Rounds a given value to a float with number of digits defined in save_options

    Parameters

    valThe value as a String, Number or Array of two numbers to be rounded

    Returns

    If a string/number was given, returns a Float.  If an array, return a string with comma-seperated floats

    - -

    getStrokedBBox

    var getStrokedBBox = this.getStrokedBBox = function(elems)

    Get the bounding box for one or more stroked and/or transformed elements

    Parameters

    elemsArray with DOM elements to check

    Returns

    A single bounding box object

    - -

    getVisibleElements

    var getVisibleElements = this.getVisibleElements = function(parent,
    includeBBox)

    Get all elements that have a BBox (excludes <defs>, <title>, etc).  Note that 0-opacity, off-screen etc elements are still considered “visible” for this function

    Parameters

    parentThe parent DOM element to search within
    includeBBoxBoolean to indicate that an object should return with the element and its bbox

    Returns

    An array with all “visible” elements, or if includeBBox is true, an array with objects that include:

    • elem - The element
    • bbox - The element’s BBox as retrieved from getStrokedBBox
    - -

    copyElem

    var copyElem = function(el)

    Create a clone of an element, updating its ID and its children’s IDs when needed

    Parameters

    elDOM element to clone

    Returns: The cloned element

    - -

    getElem

    function getElem(id)

    Get a DOM element by ID within the SVG root element.

    Parameters

    idString with the element’s new ID
    - -

    getId

    getId = c.getId = function()

    Returns the last created DOM element ID string

    - -

    getNextId

    getNextId = c.getNextId = function()

    Creates and returns a unique ID string for a DOM element

    - -

    bind

    c.bind = function(event,
    f)

    Attaches a callback function to an event

    Parameters

    eventString indicating the name of the event
    fThe callback function to bind to the event

    Return

    The previous event

    - -

    setIdPrefix

    c.setIdPrefix = function(p)

    Changes the ID prefix to the given value

    Parameters

    pString with the new prefix
    - -

    sanitizeSvg

    var sanitizeSvg = this.sanitizeSvg = function(node)

    Sanitizes the input node and its children It only keeps what is allowed from our whitelist defined above

    Parameters

    nodeThe DOM element to be checked, will also check its children
    - -

    getUrlFromAttr

    var getUrlFromAttr = this.getUrlFromAttr = function(attrVal)

    Extracts the URL from the url(...) syntax of some attributes.  Three variants:

    • <circle fill=”url(someFile.svg#foo)” />
    • <circle fill=”url(‘someFile.svg#foo’)” />
    • <circle fill=’url(“someFile.svg#foo”)’ />

    Parameters

    attrValThe attribute value as a string

    Returns

    String with just the URL, like someFile.svg#foo

    - -

    getBBox

    var getBBox = this.getBBox = function(elem)

    Get the given/selected element’s bounding box object, convert it to be more usable when necessary

    Parameters

    elemOptional DOM element to get the BBox for
    - -

    ffClone

    var ffClone = function(elem)

    Hack for Firefox bugs where text element features aren’t updated.  This function clones the element and re-selects it TODO: Test for this bug on load and add it to “support” object instead of browser sniffing

    Parameters

    elemThe (text) DOM element to clone
    - -

    getPathBBox

    var getPathBBox = function(path)

    Get correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html

    Parameters

    pathThe path DOM element to get the BBox for

    Returns

    A BBox-like object

    - -

    Element Transforms

    - -

    getRotationAngle

    var getRotationAngle = this.getRotationAngle = function(elem,
    to_rad)

    Get the rotation angle of the given/selected DOM element

    Parameters

    elemOptional DOM element to get the angle for
    to_radBoolean that when true returns the value in radians rather than degrees

    Returns

    Float with the angle in degrees or radians

    - -

    setRotationAngle

    this.setRotationAngle = function(val,
    preventUndo)

    Removes any old rotations if present, prepends a new rotation at the transformed center

    Parameters

    valThe new rotation angle in degrees
    preventUndoBoolean indicating whether the action should be undoable or not
    - -

    getTransformList

    var getTransformList = this.getTransformList = function(elem)

    Returns an object that behaves like a SVGTransformList for the given DOM element

    Parameters

    elemDOM element to get a transformlist from
    - -

    recalculateAllSelectedDimensions

    var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function()

    Runs recalculateDimensions on the selected elements, adding the changes to a single batch command

    - -

    remapElement

    var remapElement = this.remapElement = function(selected,
    changes,
    m)

    Applies coordinate changes to an element based on the given matrix

    Parameters

    selectedDOM element to be changed
    changesObject with changes to be remapped
    mMatrix object to use for remapping coordinates
    - -

    recalculateDimensions

    var recalculateDimensions = this.recalculateDimensions = function(selected)

    Decides the course of action based on the element’s transform list

    Parameters

    selectedThe DOM element to recalculate

    Returns

    Undo command object with the resulting change

    - -

    transformPoint

    var transformPoint = function(x,
    y,
    m)

    A (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)

    Parameters

    xFloat representing the x coordinate
    yFloat representing the y coordinate
    mMatrix object to transform the point with Returns a x,y object representing the transformed point
    - -

    isIdentity

    var isIdentity = function(m)

    Helper function to check if the matrix performs no actual transform (i.e. exists for identity purposes)

    Parameters

    mThe matrix object to check

    Returns

    Boolean indicating whether or not the matrix is 1,0,0,1,0,0

    - -

    matrixMultiply

    var matrixMultiply = this.matrixMultiply = function()

    This function tries to return a SVGMatrix that is the multiplication m1*m2.  We also round to zero when it’s near zero

    Parameters

    = 2 Matrix objects to multiply

    Returns

    The matrix object resulting from the calculation

    - -

    transformListToTransform

    var transformListToTransform = this.transformListToTransform = function(tlist,
    min,
    max)

    This returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments

    Parameters

    tlistThe transformlist object
    minOptional integer indicating start transform position
    maxOptional integer indicating end transform position

    Returns

    A single matrix transform object

    - -

    hasMatrixTransform

    var hasMatrixTransform = this.hasMatrixTransform = function(tlist)

    See if the given transformlist includes a non-indentity matrix transform

    Parameters

    tlistThe transformlist to check

    Returns

    Boolean on whether or not a matrix transform was found

    - -

    getMatrix

    var getMatrix = function(elem)

    Get the matrix object for a given element

    Parameters

    elemThe DOM element to check

    Returns

    The matrix object associated with the element’s transformlist

    - -

    transformBox

    var transformBox = this.transformBox = function(l,
    t,
    w,
    h,
    m)

    Transforms a rectangle based on the given matrix

    Parameters

    lFloat with the box’s left coordinate
    tFloat with the box’s top coordinate
    wFloat with the box width
    hFloat with the box height
    mMatrix object to transform the box by

    Returns

    An object with the following values:

    • tl - The top left coordinate (x,y object)
    • tr - The top right coordinate (x,y object)
    • bl - The bottom left coordinate (x,y object)
    • br - The bottom right coordinate (x,y object)
    • aabox - Object with the following values:
    • Float with the axis-aligned x coordinate
    • Float with the axis-aligned y coordinate
    • Float with the axis-aligned width coordinate
    • Float with the axis-aligned height coordinate
    - -

    Selection

    - -

    clearSelection

    var clearSelection = this.clearSelection = function(noCall)

    Clears the selection.  The ‘selected’ handler is then called.  Parameters: noCall - Optional boolean that when true does not call the “selected” handler

    - -

    addToSelection

    var addToSelection = this.addToSelection = function(elemsToAdd,
    showGrips)

    Adds a list of elements to the selection.  The ‘selected’ handler is then called.

    Parameters

    elemsToAddan array of DOM elements to add to the selection
    showGripsa boolean flag indicating whether the resize grips should be shown
    - -

    removeFromSelection

    var removeFromSelection = this.removeFromSelection = function(elemsToRemove)

    Removes elements from the selection.

    Parameters

    elemsToRemovean array of elements to remove from selection
    - -

    selectAllInCurrentLayer

    this.selectAllInCurrentLayer = function()

    Clears the selection, then adds all elements in the current layer to the selection.  This function then fires the selected event.

    - -

    smoothControlPoints

    var smoothControlPoints = this.smoothControlPoints = function(ct1,
    ct2,
    pt)

    Takes three points and creates a smoother line based on them

    Parameters

    ct1Object with x and y values (first control point)
    ct2Object with x and y values (second control point)
    ptObject with x and y values (third point)

    Returns

    Array of two “smoothed” point objects

    - -

    getMouseTarget

    var getMouseTarget = this.getMouseTarget = function(evt)

    Gets the desired element from a mouse event

    Parameters

    evtEvent object from the mouse event

    Returns

    DOM element we want

    - -

    preventClickDefault

    var preventClickDefault = function(img)

    Prevents default browser click behaviour on the given element

    Parameters

    imgThe DOM element to prevent the cilck on
    - -

    Text edit functions

    Functions relating to editing text elements

    - -

    Path edit functions

    Functions relating to editing path elements

    - -

    Serialization

    - -

    removeUnusedDefElems

    var removeUnusedDefElems = this.removeUnusedDefElems = function()

    Looks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.

    Returns

    The amount of elements that were removed

    - -

    svgCanvasToString

    var svgCanvasToString = this.svgCanvasToString = function()

    Main function to set up the SVG content for output

    Returns

    String containing the SVG image for output

    - -

    svgToString

    var svgToString = this.svgToString = function(elem,
    indent)

    Sub function ran on each SVG element to convert it to a string as desired

    Parameters

    elemThe SVG element to convert
    indentInteger with the amount of spaces to indent this tag

    Returns

    String with the given element as an SVG tag

    - -

    embedImage

    this.embedImage = function(val,
    callback)

    Converts a given image file to a data URL when possible, then runs a given callback

    Parameters

    valString with the path/URL of the image
    callbackOptional function to run when image data is found, supplies the result (data URL or false) as first parameter.
    - -

    save

    this.save = function(opts)

    Serializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.  This function also includes the XML prolog.  Clients of the SvgCanvas bind their save function to the ‘saved’ event.

    Returns

    Nothing

    - -

    rasterExport

    this.rasterExport = function()

    Generates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found

    - -

    getSvgString

    this.getSvgString = function()

    Returns the current drawing as raw SVG XML text.

    Returns

    The current drawing as raw SVG XML text.

    - -

    setSvgString

    this.setSvgString = function(xmlString)

    This function sets the current drawing as the input SVG XML.

    Parameters

    xmlStringThe SVG as XML text.

    Returns

    This function returns false if the set was unsuccessful, true otherwise.

    - -

    importSvgString

    this.importSvgString = function(xmlString)

    This function imports the input SVG XML into the current layer in the drawing

    Parameters

    xmlStringThe SVG as XML text.

    Returns

    This function returns false if the import was unsuccessful, true otherwise.  TODO:

    • properly handle if namespace is introduced by imported content (must add to svgcontent and update all prefixes in the imported node)
    • properly handle recalculating dimensions, recalculateDimensions() doesn’t handle arbitrary transform lists, but makes some assumptions about how the transform list was obtained
    • import should happen in top-left of current zoomed viewport
    • create a new layer for the imported SVG
    - -

    Layers

    - -

    identifyLayers

    var identifyLayers = function()

    Updates layer system

    - -

    createLayer

    this.createLayer = function(name)

    Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.  This is an undoable action.

    Parameters

    nameThe given name
    - -

    deleteCurrentLayer

    this.deleteCurrentLayer = function()

    Deletes the current layer from the drawing and then clears the selection.  This function then calls the ‘changed’ handler.  This is an undoable action.

    - -

    getNumLayers

    this.getNumLayers = function()

    Returns the number of layers in the current drawing.

    Returns

    The number of layers in the current drawing.

    - -

    getLayer

    this.getLayer = function(i)

    Returns the name of the ith layer.  If the index is out of range, an empty string is returned.

    Parameters

    ithe zero-based index of the layer you are querying.

    Returns

    The name of the ith layer

    - -

    getCurrentLayer

    this.getCurrentLayer = function()

    Returns the name of the currently selected layer.  If an error occurs, an empty string is returned.

    Returns

    The name of the currently active layer.

    - -

    setCurrentLayer

    this.setCurrentLayer = function(name)

    Sets the current layer.  If the name is not a valid layer name, then this function returns false.  Otherwise it returns true.  This is not an undo-able action.

    Parameters

    namethe name of the layer you want to switch to.

    Returns

    true if the current layer was switched, otherwise false

    - -

    renameCurrentLayer

    this.renameCurrentLayer = function(newname)

    Renames the current layer.  If the layer name is not valid (i.e. unique), then this function does nothing and returns false, otherwise it returns true.  This is an undo-able action.

    Parameters

    newnamethe new name you want to give the current layer.  This name must be unique among all layer names.

    Returns

    true if the rename succeeded, false otherwise.

    - -

    setCurrentLayerPosition

    this.setCurrentLayerPosition = function(newpos)

    Changes the position of the current layer to the new value.  If the new index is not valid, this function does nothing and returns false, otherwise it returns true.  This is an undo-able action.

    Parameters

    newposThe zero-based index of the new position of the layer.  This should be between
    0 and (number of layers1)

    Returns

    true if the current layer position was changed, false otherwise.

    - -

    getLayerVisibility

    this.getLayerVisibility = function(layername)

    Returns whether the layer is visible.  If the layer name is not valid, then this function returns false.

    Parameters

    layernamethe name of the layer which you want to query.

    Returns

    The visibility state of the layer, or false if the layer name was invalid.

    - -

    setLayerVisibility

    this.setLayerVisibility = function(layername,
    bVisible)

    Sets the visibility of the layer.  If the layer name is not valid, this function return false, otherwise it returns true.  This is an undo-able action.

    Parameters

    layernamethe name of the layer to change the visibility
    bVisibletrue/false, whether the layer should be visible

    Returns

    true if the layer’s visibility was set, false otherwise

    - -

    moveSelectedToLayer

    this.moveSelectedToLayer = function(layername)

    Moves the selected elements to layername.  If the name is not a valid layer name, then false is returned.  Otherwise it returns true.  This is an undo-able action.

    Parameters

    layernamethe name of the layer you want to which you want to move the selected elements

    Returns

    true if the selected elements were moved to the layer, false otherwise.

    - -

    getLayerOpacity

    this.getLayerOpacity = function(layername)

    Returns the opacity of the given layer.  If the input name is not a layer, null is returned.

    Parameters

    layernamename of the layer on which to get the opacity

    Returns

    The opacity value of the given layer.  This will be a value between 0.0 and 1.0, or null if layername is not a valid layer

    - -

    setLayerOpacity

    this.setLayerOpacity = function(layername,
    opacity)

    Sets the opacity of the given layer.  If the input name is not a layer, nothing happens.  This is not an undo-able action.  NOTE: this function exists solely to apply a highlighting/de-emphasis effect to a layer, when it is possible for a user to affect the opacity of a layer, we will need to allow this function to produce an undo-able action.  If opacity is not a value between 0.0 and 1.0, then nothing happens.

    Parameters

    layernamename of the layer on which to set the opacity
    opacitya float value in the range 0.0-1.0
    - -

    Document functions

    - -

    clear

    this.clear = function()

    Clears the current document.  This is not an undoable action.

    - -

    linkControlPoints

    Alias function

    - -

    getContentElem

    this.getContentElem = function()

    Returns the content DOM element

    - -

    getRootElem

    this.getRootElem = function()

    Returns the root DOM element

    - -

    getSelectedElems

    this.getSelectedElems = function()

    Returns the array with selected DOM elements

    - -

    getResolution

    var getResolution = this.getResolution = function()

    Returns the current dimensions and zoom level in an object

    - -

    getZoom

    this.getZoom = function()

    Returns the current zoom level

    - -

    getVersion

    this.getVersion = function()

    Returns a string which describes the revision number of SvgCanvas.

    - -

    setUiStrings

    this.setUiStrings = function(strs)

    Update interface strings with given values

    Parameters

    strsObject with strings (see uiStrings for examples)
    - -

    setConfig

    this.setConfig = function(opts)

    Update configuration options with given values

    Parameters

    optsObject with options (see curConfig for examples)
    - -

    getDocumentTitle

    this.getDocumentTitle = function()

    Returns the current document title or an empty string if not found

    - -

    setDocumentTitle

    this.setDocumentTitle = function(newtitle)

    Adds/updates a title element for the document with the given name.  This is an undoable action

    Parameters

    newtitleString with the new title
    - -

    getEditorNS

    this.getEditorNS = function(add)

    Returns the editor’s namespace URL, optionally adds it to root element

    Parameters

    addBoolean to indicate whether or not to add the namespace value
    - -

    setResolution

    this.setResolution = function(x,
    y)

    Changes the document’s dimensions to the given size

    Parameters

    xNumber with the width of the new dimensions in user units.  Can also be the string “fit” to indicate “fit to content”
    yNumber with the height of the new dimensions in user units.

    Returns

    Boolean to indicate if resolution change was succesful.  It will fail on “fit to content” option with no content to fit to.

    - -

    getOffset

    this.getOffset = function()

    Returns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.

    - -

    setBBoxZoom

    this.setBBoxZoom = function(val,
    editor_w,
    editor_h)

    Sets the zoom level on the canvas-side based on the given value

    Parameters

    valBounding box object to zoom to or string indicating zoom option
    editor_wInteger with the editor’s workarea box’s width
    editor_hInteger with the editor’s workarea box’s height
    - -

    setZoom

    this.setZoom = function(zoomlevel)

    Sets the zoom to the given level

    Parameters

    zoomlevelFloat indicating the zoom level to change to
    - -

    getMode

    this.getMode = function()

    Returns the current editor mode string

    - -

    setMode

    this.setMode = function(name)

    Sets the editor’s mode to the given string

    Parameters

    nameString with the new mode to change to
    - -

    Element Styling

    - -

    getColor

    this.getColor = function(type)

    Returns the current fill/stroke option

    - -

    setColor

    this.setColor = function(type,
    val,
    preventUndo)

    Change the current stroke/fill color/gradient value

    Parameters

    typeString indicating fill or stroke
    valThe value to set the stroke attribute to
    preventUndoBoolean indicating whether or not this should be and undoable option
    - -

    findDefs

    var findDefs = function()

    Return the document’s <defs> element, create it first if necessary

    - -

    setGradient

    var setGradient = this.setGradient = function(type)

    Apply the current gradient to selected element’s fill or stroke

    Parameters type - String indicating “fill” or “stroke” to apply to an element

    - -

    findDuplicateGradient

    var findDuplicateGradient = function(grad)

    Check if exact gradient already exists

    Parameters

    gradThe gradient DOM element to compare to others

    Returns

    The existing gradient if found, null if not

    - -

    setPaint

    this.setPaint = function(type,
    paint)

    Set a color/gradient to a fill/stroke

    Parameters

    typeString with “fill” or “stroke”
    paintThe jGraduate paint object to apply
    - -

    getStrokeWidth

    this.getStrokeWidth = function()

    Returns the current stroke-width value

    - -

    setStrokeWidth

    this.setStrokeWidth = function(val)

    Sets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead

    Parameters

    valA Float indicating the new stroke width value
    - -

    setStrokeAttr

    this.setStrokeAttr = function(attr,
    val)

    Set the given stroke-related attribute the given value for selected elements

    Parameters

    attrString with the attribute name
    valString or number with the attribute value
    - -

    getOpacity

    this.getOpacity = function()

    Returns the current opacity

    - -

    setOpacity

    this.setOpacity = function(val)

    Sets the given opacity to the current selected elements

    - -

    getOpacity

    Returns the current fill opacity

    - -

    getStrokeOpacity

    this.getStrokeOpacity = function()

    Returns the current stroke opacity

    - -

    setPaintOpacity

    this.setPaintOpacity = function(type,
    val,
    preventUndo)

    Sets the current fill/stroke opacity

    Parameters

    typeString with “fill” or “stroke”
    valFloat with the new opacity value
    preventUndoBoolean indicating whether or not this should be an undoable action
    - -

    getBlur

    this.getBlur = function(elem)

    Gets the stdDeviation blur value of the given element

    Parameters

    elemThe element to check the blur value for
    - -

    setBlurNoUndo

    canvas.setBlurNoUndo = function(val)

    Sets the stdDeviation blur value on the selected element without being undoable

    Parameters

    valThe new stdDeviation value
    - -

    setBlurOffsets

    canvas.setBlurOffsets = function(filter,
    stdDev)

    Sets the x, y, with, height values of the filter element in order to make the blur not be clipped.  Removes them if not neeeded

    Parameters

    filterThe filter DOM element to update
    stdDevThe standard deviation value on which to base the offset size
    - -

    setBlur

    canvas.setBlur = function(val,
    complete)

    Adds/updates the blur filter to the selected element

    Parameters

    valFloat with the new stdDeviation blur value
    completeBoolean indicating whether or not the action should be completed (to add to the undo manager)
    - -

    getBold

    this.getBold = function()

    Check whether selected element is bold or not

    Returns

    Boolean indicating whether or not element is bold

    - -

    setBold

    this.setBold = function(b)

    Make the selected element bold or normal

    Parameters

    bBoolean indicating bold (true) or normal (false)
    - -

    getItalic

    this.getItalic = function()

    Check whether selected element is italic or not

    Returns

    Boolean indicating whether or not element is italic

    - -

    setItalic

    this.setItalic = function(i)

    Make the selected element italic or normal

    Parameters

    bBoolean indicating italic (true) or normal (false)
    - -

    getFontFamily

    this.getFontFamily = function()

    Returns the current font family

    - -

    setFontFamily

    this.setFontFamily = function(val)

    Set the new font family

    Parameters

    valString with the new font family
    - -

    getFontSize

    this.getFontSize = function()

    Returns the current font size

    - -

    setFontSize

    this.setFontSize = function(val)

    Applies the given font size to the selected element

    Parameters

    valFloat with the new font size
    - -

    getText

    this.getText = function()

    Returns the current text (textContent) of the selected element

    - -

    setTextContent

    this.setTextContent = function(val)

    Updates the text element with the given string

    Parameters

    valString with the new text
    - -

    setImageURL

    this.setImageURL = function(val)

    Sets the new image URL for the selected image element.  Updates its size if a new URL is given

    Parameters

    valString with the image URL/path
    - -

    setRectRadius

    this.setRectRadius = function(val)

    Sets the rx & ry values to the selected rect element to change its corner radius

    Parameters

    valThe new radius
    - -

    Element manipulation

    - -

    setSegType

    this.setSegType = function(new_type)

    Sets the new segment type to the selected segment(s).

    Parameters

    new_typeInteger with the new segment type See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list
    - -

    convertToPath

    this.convertToPath = function(elem,
    getBBox)

    Convert selected element to a path, or get the BBox of an element-as-path

    Parameters

    elemThe DOM element to be converted
    getBBoxBoolean on whether or not to only return the path’s BBox

    Returns

    If the getBBox flag is true, the resulting path’s bounding box object.  Otherwise the resulting path element is returned.

    - -

    changeSelectedAttributeNoUndo

    var changeSelectedAttributeNoUndo = function(attr,
    newValue,
    elems)

    This function makes the changes to the elements.  It does not add the change to the history stack.

    Parameters

    attrString with the attribute name
    newValueString or number with the new attribute value
    elemsThe DOM elements to apply the change to
    - -

    changeSelectedAttribute

    var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
    val,
    elems)

    Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.  If you want to change only a subset of selectedElements, then send the subset to this function in the elems argument.

    Parameters

    attrString with the attribute name
    newValueString or number with the new attribute value
    elemsThe DOM elements to apply the change to
    - -

    deleteSelectedElements

    this.deleteSelectedElements = function()

    Removes all selected elements from the DOM and adds the change to the history stack

    - -

    groupSelectedElements

    this.groupSelectedElements = function()

    Wraps all the selected elements in a group (g) element

    - -

    ungroupSelectedElement

    this.ungroupSelectedElement = function()

    Unwraps all the elements in a selected group (g) element.  This requires significant recalculations to apply group’s transforms, etc to its children

    - -

    moveToTopSelectedElement

    this.moveToTopSelectedElement = function()

    Repositions the selected element to the bottom in the DOM to appear on top of other elements

    - -

    moveToBottomSelectedElement

    this.moveToBottomSelectedElement = function()

    Repositions the selected element to the top in the DOM to appear under other elements

    - -

    moveSelectedElements

    this.moveSelectedElements = function(dx,
    dy,
    undoable)

    Moves selected elements on the X/Y axis

    Parameters

    dxFloat with the distance to move on the x-axis
    dyFloat with the distance to move on the y-axis
    undoableBoolean indicating whether or not the action should be undoable

    Returns

    Batch command for the move

    - -

    cloneSelectedElements

    this.cloneSelectedElements = function()

    Create deep DOM copies (clones) of all selected elements and move them slightly from their originals

    - -

    alignSelectedElements

    this.alignSelectedElements = function(type,
    relative_to)

    Aligns selected elements

    Parameters

    typeString with single character indicating the alignment type
    relative_toString that must be one of the following: “selected”, “largest”, “smallest”, “page”
    - -

    Additional editor tools

    - -

    updateCanvas

    this.updateCanvas = function(w,
    h)

    Updates the editor canvas width/height/position after a zoom has occurred

    Parameters

    wFloat with the new width
    hFloat with the new height

    Returns

    Object with the following values:

    • x - The canvas’ new x coordinate
    • y - The canvas’ new y coordinate
    • old_x - The canvas’ old x coordinate
    • old_y - The canvas’ old y coordinate
    • d_x - The x position difference
    • d_y - The y position difference
    - -

    setBackground

    this.setBackground = function(color,
    url)

    Set the background of the editor (NOT the actual document)

    Parameters

    colorString with fill color to apply
    urlURL or path to image to use
    - -

    cycleElement

    this.cycleElement = function(next)

    Select the next/previous element within the current layer

    Parameters

    nextBoolean where true = next and false = previous element
    - -
    - - - - - - - - - - -
    "rectsIntersect": function(r1,
    r2)
    Check if two rectangles (BBoxes objects) intersect each other
    "snapToAngle": function(x1,
    y1,
    x2,
    y2)
    Returns a 45 degree angle coordinate associated with the two given coordinates
    "text2xml": function(sXML)
    Cross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
    convertToNum = function(attr,
    val)
    Converts given values to numbers.
    setUnitAttr = function(elem,
    attr,
    val)
    Sets an element’s attribute based on the unit in its current value.
    canvas.isValidUnit = function(attr,
    val)
    Check if an attribute’s value is in a valid format
    var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
    attrs,
    text)
    History command to make a change to an element.
    var InsertElementCommand = this.undoCmd.insertElement = function(elem,
    text)
    History command for an element that was added to the DOM
    var RemoveElementCommand = this.undoCmd.removeElement = function(elem,
    parent,
    text)
    History command for an element removed from the DOM
    var MoveElementCommand = this.undoCmd.moveElement = function(elem,
    oldNextSibling,
    oldParent,
    text)
    History command for an element that had its DOM position changed
    var BatchCommand = this.undoCmd.batch = function(text)
    History command that can contain/execute multiple other commands
    resetUndoStack = function()
    Resets the undo stack, effectively clearing the undo/redo history
    addCommandToHistory = c.undoCmd.add = function(cmd)
    Adds a command object to the undo history stack
    c.beginUndoableChange = function(attrName,
    elems)
    This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
    c.finishUndoableChange = function()
    This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
    function walkTree(elem,
    cbFn)
    Walks the tree and executes the callback on each element in a top-down fashion
    function walkTreePost(elem,
    cbFn)
    Walks the tree and executes the callback on each element in a depth-first fashion
    var assignAttributes = this.assignAttributes = function(node,
    attrs,
    suspendLength,
    unitCheck)
    Assigns multiple attributes to an element.
    var cleanupElement = this.cleanupElement = function(element)
    Remove unneeded (default) attributes, makes resulting SVG smaller
    var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
    Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
    this.addExtension = function(name,
    ext_func)
    Add an extension to the editor
    var shortFloat = function(val)
    Rounds a given value to a float with number of digits defined in save_options
    var getStrokedBBox = this.getStrokedBBox = function(elems)
    Get the bounding box for one or more stroked and/or transformed elements
    var getVisibleElements = this.getVisibleElements = function(parent,
    includeBBox)
    Get all elements that have a BBox (excludes defs, title, etc).
    var copyElem = function(el)
    Create a clone of an element, updating its ID and its children’s IDs when needed
    function getElem(id)
    Get a DOM element by ID within the SVG root element.
    getId = c.getId = function()
    Returns the last created DOM element ID string
    getNextId = c.getNextId = function()
    Creates and returns a unique ID string for a DOM element
    c.bind = function(event,
    f)
    Attaches a callback function to an event
    c.setIdPrefix = function(p)
    Changes the ID prefix to the given value
    var sanitizeSvg = this.sanitizeSvg = function(node)
    Sanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
    var getUrlFromAttr = this.getUrlFromAttr = function(attrVal)
    Extracts the URL from the url(...)
    var getBBox = this.getBBox = function(elem)
    Get the given/selected element’s bounding box object, convert it to be more usable when necessary
    var ffClone = function(elem)
    Hack for Firefox bugs where text element features aren’t updated.
    var getPathBBox = function(path)
    Get correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
    var getRotationAngle = this.getRotationAngle = function(elem,
    to_rad)
    Get the rotation angle of the given/selected DOM element
    this.setRotationAngle = function(val,
    preventUndo)
    Removes any old rotations if present, prepends a new rotation at the transformed center
    var getTransformList = this.getTransformList = function(elem)
    Returns an object that behaves like a SVGTransformList for the given DOM element
    var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function()
    Runs recalculateDimensions on the selected elements, adding the changes to a single batch command
    var remapElement = this.remapElement = function(selected,
    changes,
    m)
    Applies coordinate changes to an element based on the given matrix
    var recalculateDimensions = this.recalculateDimensions = function(selected)
    Decides the course of action based on the element’s transform list
    var transformPoint = function(x,
    y,
    m)
    A (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
    var isIdentity = function(m)
    Helper function to check if the matrix performs no actual transform (i.e.
    var matrixMultiply = this.matrixMultiply = function()
    This function tries to return a SVGMatrix that is the multiplication m1*m2.
    var transformListToTransform = this.transformListToTransform = function(tlist,
    min,
    max)
    This returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
    var hasMatrixTransform = this.hasMatrixTransform = function(tlist)
    See if the given transformlist includes a non-indentity matrix transform
    var getMatrix = function(elem)
    Get the matrix object for a given element
    var transformBox = this.transformBox = function(l,
    t,
    w,
    h,
    m)
    Transforms a rectangle based on the given matrix
    var clearSelection = this.clearSelection = function(noCall)
    Clears the selection.
    var addToSelection = this.addToSelection = function(elemsToAdd,
    showGrips)
    Adds a list of elements to the selection.
    var removeFromSelection = this.removeFromSelection = function(elemsToRemove)
    Removes elements from the selection.
    this.selectAllInCurrentLayer = function()
    Clears the selection, then adds all elements in the current layer to the selection.
    var smoothControlPoints = this.smoothControlPoints = function(ct1,
    ct2,
    pt)
    Takes three points and creates a smoother line based on them
    var getMouseTarget = this.getMouseTarget = function(evt)
    Gets the desired element from a mouse event
    var preventClickDefault = function(img)
    Prevents default browser click behaviour on the given element
    var removeUnusedDefElems = this.removeUnusedDefElems = function()
    Looks at DOM elements inside the defs to see if they are referred to, removes them from the DOM if they are not.
    var svgCanvasToString = this.svgCanvasToString = function()
    Main function to set up the SVG content for output
    var svgToString = this.svgToString = function(elem,
    indent)
    Sub function ran on each SVG element to convert it to a string as desired
    this.embedImage = function(val,
    callback)
    Converts a given image file to a data URL when possible, then runs a given callback
    this.save = function(opts)
    Serializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
    this.rasterExport = function()
    Generates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
    this.getSvgString = function()
    Returns the current drawing as raw SVG XML text.
    this.setSvgString = function(xmlString)
    This function sets the current drawing as the input SVG XML.
    this.importSvgString = function(xmlString)
    This function imports the input SVG XML into the current layer in the drawing
    var identifyLayers = function()
    Updates layer system
    this.createLayer = function(name)
    Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
    this.deleteCurrentLayer = function()
    Deletes the current layer from the drawing and then clears the selection.
    this.getNumLayers = function()
    Returns the number of layers in the current drawing.
    this.getLayer = function(i)
    Returns the name of the ith layer.
    this.getCurrentLayer = function()
    Returns the name of the currently selected layer.
    this.setCurrentLayer = function(name)
    Sets the current layer.
    this.renameCurrentLayer = function(newname)
    Renames the current layer.
    this.setCurrentLayerPosition = function(newpos)
    Changes the position of the current layer to the new value.
    this.getLayerVisibility = function(layername)
    Returns whether the layer is visible.
    this.setLayerVisibility = function(layername,
    bVisible)
    Sets the visibility of the layer.
    this.moveSelectedToLayer = function(layername)
    Moves the selected elements to layername.
    this.getLayerOpacity = function(layername)
    Returns the opacity of the given layer.
    this.setLayerOpacity = function(layername,
    opacity)
    Sets the opacity of the given layer.
    this.clear = function()
    Clears the current document.
    this.getContentElem = function()
    Returns the content DOM element
    this.getRootElem = function()
    Returns the root DOM element
    this.getSelectedElems = function()
    Returns the array with selected DOM elements
    var getResolution = this.getResolution = function()
    Returns the current dimensions and zoom level in an object
    this.getZoom = function()
    Returns the current zoom level
    this.getVersion = function()
    Returns a string which describes the revision number of SvgCanvas.
    this.setUiStrings = function(strs)
    Update interface strings with given values
    this.setConfig = function(opts)
    Update configuration options with given values
    this.getDocumentTitle = function()
    Returns the current document title or an empty string if not found
    this.setDocumentTitle = function(newtitle)
    Adds/updates a title element for the document with the given name.
    this.getEditorNS = function(add)
    Returns the editor’s namespace URL, optionally adds it to root element
    this.setResolution = function(x,
    y)
    Changes the document’s dimensions to the given size
    this.getOffset = function()
    Returns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
    this.setBBoxZoom = function(val,
    editor_w,
    editor_h)
    Sets the zoom level on the canvas-side based on the given value
    this.setZoom = function(zoomlevel)
    Sets the zoom to the given level
    this.getMode = function()
    Returns the current editor mode string
    this.setMode = function(name)
    Sets the editor’s mode to the given string
    this.getColor = function(type)
    Returns the current fill/stroke option
    this.setColor = function(type,
    val,
    preventUndo)
    Change the current stroke/fill color/gradient value
    var findDefs = function()
    Return the document’s defs element, create it first if necessary
    var setGradient = this.setGradient = function(type)
    Apply the current gradient to selected element’s fill or stroke
    var findDuplicateGradient = function(grad)
    Check if exact gradient already exists
    this.setPaint = function(type,
    paint)
    Set a color/gradient to a fill/stroke
    this.getStrokeWidth = function()
    Returns the current stroke-width value
    this.setStrokeWidth = function(val)
    Sets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
    this.setStrokeAttr = function(attr,
    val)
    Set the given stroke-related attribute the given value for selected elements
    this.getOpacity = function()
    Returns the current opacity
    this.setOpacity = function(val)
    Sets the given opacity to the current selected elements
    this.getStrokeOpacity = function()
    Returns the current stroke opacity
    this.setPaintOpacity = function(type,
    val,
    preventUndo)
    Sets the current fill/stroke opacity
    this.getBlur = function(elem)
    Gets the stdDeviation blur value of the given element
    canvas.setBlurNoUndo = function(val)
    Sets the stdDeviation blur value on the selected element without being undoable
    canvas.setBlurOffsets = function(filter,
    stdDev)
    Sets the x, y, with, height values of the filter element in order to make the blur not be clipped.
    canvas.setBlur = function(val,
    complete)
    Adds/updates the blur filter to the selected element
    this.getBold = function()
    Check whether selected element is bold or not
    this.setBold = function(b)
    Make the selected element bold or normal
    this.getItalic = function()
    Check whether selected element is italic or not
    this.setItalic = function(i)
    Make the selected element italic or normal
    this.getFontFamily = function()
    Returns the current font family
    this.setFontFamily = function(val)
    Set the new font family
    this.getFontSize = function()
    Returns the current font size
    this.setFontSize = function(val)
    Applies the given font size to the selected element
    this.getText = function()
    Returns the current text (textContent) of the selected element
    this.setTextContent = function(val)
    Updates the text element with the given string
    this.setImageURL = function(val)
    Sets the new image URL for the selected image element.
    this.setRectRadius = function(val)
    Sets the rx & ry values to the selected rect element to change its corner radius
    this.setSegType = function(new_type)
    Sets the new segment type to the selected segment(s).
    this.convertToPath = function(elem,
    getBBox)
    Convert selected element to a path, or get the BBox of an element-as-path
    var changeSelectedAttributeNoUndo = function(attr,
    newValue,
    elems)
    This function makes the changes to the elements.
    var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
    val,
    elems)
    Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
    this.deleteSelectedElements = function()
    Removes all selected elements from the DOM and adds the change to the history stack
    this.groupSelectedElements = function()
    Wraps all the selected elements in a group (g) element
    this.ungroupSelectedElement = function()
    Unwraps all the elements in a selected group (g) element.
    this.moveToTopSelectedElement = function()
    Repositions the selected element to the bottom in the DOM to appear on top of other elements
    this.moveToBottomSelectedElement = function()
    Repositions the selected element to the top in the DOM to appear under other elements
    this.moveSelectedElements = function(dx,
    dy,
    undoable)
    Moves selected elements on the X/Y axis
    this.cloneSelectedElements = function()
    Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
    this.alignSelectedElements = function(type,
    relative_to)
    Aligns selected elements
    this.updateCanvas = function(w,
    h)
    Updates the editor canvas width/height/position after a zoom has occurred
    this.setBackground = function(color,
    url)
    Set the background of the editor (NOT the actual document)
    this.cycleElement = function(next)
    Select the next/previous element within the current layer
    - - - - - - - - \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 635c317..0000000 --- a/docs/index.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/index/Files.html b/docs/index/Files.html deleted file mode 100644 index 9ebbb55..0000000 --- a/docs/index/Files.html +++ /dev/null @@ -1,37 +0,0 @@ - - -File Index - - - - - - - - - -
    File Index
    $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
    M
     my_svgcanvas.js
    S
     svgcanvas-latest copy.js
     svgcanvas-mine.js
     svgcanvas-textanchor-experiment.js
     svgcanvas.js
     svgcanvas_subpaths.js
     svgcanvas_temp.js
    - - - - - - - -
    - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/index/Functions.html b/docs/index/Functions.html deleted file mode 100644 index 9c282c2..0000000 --- a/docs/index/Functions.html +++ /dev/null @@ -1,53 +0,0 @@ - - -Function Index - - - - - - - - - -
    Function Index
    $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
    A
     addCommandToHistory, SvgCanvas
     addExtension, SelectorManager
     addSubCommand, SvgCanvas.BatchCommand
     addSvgElementFromJson, SelectorManager
     addToSelection, SelectorManager
     alignSelectedElements, SelectorManager
     apply
     assignAttributes, SelectorManager
    B
     BatchCommand, SvgCanvas
     beginUndoableChange, SvgCanvas
     bind, SelectorManager
    C
     ChangeElementCommand, SvgCanvas
     changeSelectedAttribute, SelectorManager
     changeSelectedAttributeNoUndo, SelectorManager
     cleanupElement, SelectorManager
     clear, SelectorManager
     clearSelection, SelectorManager
     cloneSelectedElements, SelectorManager
     convertToNum, SvgCanvas
     convertToPath, SelectorManager
     convertToXMLReferences, SvgCanvas.Utils
     copyElem, SelectorManager
     createLayer, SelectorManager
     cycleElement, SelectorManager
    D
     decode64, SvgCanvas.Utils
     deleteCurrentLayer, SelectorManager
     deleteSelectedElements, SelectorManager
    E
     elements
     embedImage, SelectorManager
     encode64, SvgCanvas.Utils
    F
     ffClone, SelectorManager
     findDefs, SelectorManager
     findDuplicateGradient, SelectorManager
     finishUndoableChange, SvgCanvas
     fromXml, SvgCanvas.Utils
    - -
    addCommandToHistory = c.undoCmd.add = function(cmd)
    Adds a command object to the undo history stack
    this.addExtension = function(name,
    ext_func)
    Add an extension to the editor
    Adds a given command to the history stack
    var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
    Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
    var addToSelection = this.addToSelection = function(elemsToAdd,
    showGrips)
    Adds a list of elements to the selection.
    this.alignSelectedElements = function(type,
    relative_to)
    Aligns selected elements
    Runs “apply” on all subcommands
    Performs the stored change action
    Re-Inserts the new element
    Re-removes the new element
    var assignAttributes = this.assignAttributes = function(node,
    attrs,
    suspendLength,
    unitCheck)
    Assigns multiple attributes to an element.
    - - - -
    var BatchCommand = this.undoCmd.batch = function(text)
    History command that can contain/execute multiple other commands
    c.beginUndoableChange = function(attrName,
    elems)
    This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
    c.bind = function(event,
    f)
    Attaches a callback function to an event
    - - - -
    var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
    attrs,
    text)
    History command to make a change to an element.
    var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
    val,
    elems)
    Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
    var changeSelectedAttributeNoUndo = function(attr,
    newValue,
    elems)
    This function makes the changes to the elements.
    var cleanupElement = this.cleanupElement = function(element)
    Remove unneeded (default) attributes, makes resulting SVG smaller
    this.clear = function()
    Clears the current document.
    var clearSelection = this.clearSelection = function(noCall)
    Clears the selection.
    this.cloneSelectedElements = function()
    Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
    convertToNum = function(attr,
    val)
    Converts given values to numbers.
    this.convertToPath = function(elem,
    getBBox)
    Convert selected element to a path, or get the BBox of an element-as-path
    Converts a string to use XML references
    var copyElem = function(el)
    Create a clone of an element, updating its ID and its children’s IDs when needed
    this.createLayer = function(name)
    Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
    this.cycleElement = function(next)
    Select the next/previous element within the current layer
    - - - -
    Converts a string from base64
    this.deleteCurrentLayer = function()
    Deletes the current layer from the drawing and then clears the selection.
    this.deleteSelectedElements = function()
    Removes all selected elements from the DOM and adds the change to the history stack
    - - - -
    Iterate through all our subcommands and returns all the elements we are changing
    Returns array with element associated with this command
    Returns array with element associated with this command
    Returns array with element associated with this command
    Returns array with element associated with this command
    this.embedImage = function(val,
    callback)
    Converts a given image file to a data URL when possible, then runs a given callback
    Converts a string to base64
    - - - -
    var ffClone = function(elem)
    Hack for Firefox bugs where text element features aren’t updated.
    var findDefs = function()
    Return the document’s defs element, create it first if necessary
    var findDuplicateGradient = function(grad)
    Check if exact gradient already exists
    c.finishUndoableChange = function()
    This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
    Converts XML entities in a string to single characters.
    - -
    - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/index/General.html b/docs/index/General.html deleted file mode 100644 index 69d5a0b..0000000 --- a/docs/index/General.html +++ /dev/null @@ -1,53 +0,0 @@ - - -Index - - - - - - - - - -
    Index
    $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
    A
     addCommandToHistory, SvgCanvas
     addExtension, SelectorManager
     Additional editor tools, SelectorManager
     addSubCommand, SvgCanvas.BatchCommand
     addSvgElementFromJson, SelectorManager
     addToSelection, SelectorManager
     alignSelectedElements, SelectorManager
     apply
     assignAttributes, SelectorManager
    B
     BatchCommand, SvgCanvas
     beginUndoableChange, SvgCanvas
     bind, SelectorManager
    C
     ChangeElementCommand, SvgCanvas
     changeSelectedAttribute, SelectorManager
     changeSelectedAttributeNoUndo, SelectorManager
     cleanupElement, SelectorManager
     clear, SelectorManager
     clearSelection, SelectorManager
     cloneSelectedElements, SelectorManager
     convertToNum, SvgCanvas
     convertToPath, SelectorManager
     convertToXMLReferences, SvgCanvas.Utils
     copyElem, SelectorManager
     createLayer, SelectorManager
     cycleElement, SelectorManager
    D
     decode64, SvgCanvas.Utils
     deleteCurrentLayer, SelectorManager
     deleteSelectedElements, SelectorManager
     Document functions, SelectorManager
    E
     Element manipulation, SelectorManager
     Element Styling, SelectorManager
     Element Transforms, SelectorManager
     elements
     embedImage, SelectorManager
     encode64, SvgCanvas.Utils
    F
     ffClone, SelectorManager
     findDefs, SelectorManager
     findDuplicateGradient, SelectorManager
     finishUndoableChange, SvgCanvas
     fromXml, SvgCanvas.Utils
     Functions, Selector
    - -
    addCommandToHistory = c.undoCmd.add = function(cmd)
    Adds a command object to the undo history stack
    this.addExtension = function(name,
    ext_func)
    Add an extension to the editor
    Adds a given command to the history stack
    var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
    Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
    var addToSelection = this.addToSelection = function(elemsToAdd,
    showGrips)
    Adds a list of elements to the selection.
    this.alignSelectedElements = function(type,
    relative_to)
    Aligns selected elements
    Runs “apply” on all subcommands
    Performs the stored change action
    Re-Inserts the new element
    Re-removes the new element
    var assignAttributes = this.assignAttributes = function(node,
    attrs,
    suspendLength,
    unitCheck)
    Assigns multiple attributes to an element.
    - - - -
    var BatchCommand = this.undoCmd.batch = function(text)
    History command that can contain/execute multiple other commands
    c.beginUndoableChange = function(attrName,
    elems)
    This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
    c.bind = function(event,
    f)
    Attaches a callback function to an event
    - - - -
    var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
    attrs,
    text)
    History command to make a change to an element.
    var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
    val,
    elems)
    Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
    var changeSelectedAttributeNoUndo = function(attr,
    newValue,
    elems)
    This function makes the changes to the elements.
    var cleanupElement = this.cleanupElement = function(element)
    Remove unneeded (default) attributes, makes resulting SVG smaller
    this.clear = function()
    Clears the current document.
    var clearSelection = this.clearSelection = function(noCall)
    Clears the selection.
    this.cloneSelectedElements = function()
    Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
    convertToNum = function(attr,
    val)
    Converts given values to numbers.
    this.convertToPath = function(elem,
    getBBox)
    Convert selected element to a path, or get the BBox of an element-as-path
    Converts a string to use XML references
    var copyElem = function(el)
    Create a clone of an element, updating its ID and its children’s IDs when needed
    this.createLayer = function(name)
    Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
    this.cycleElement = function(next)
    Select the next/previous element within the current layer
    - - - -
    Converts a string from base64
    this.deleteCurrentLayer = function()
    Deletes the current layer from the drawing and then clears the selection.
    this.deleteSelectedElements = function()
    Removes all selected elements from the DOM and adds the change to the history stack
    - - - -
    Iterate through all our subcommands and returns all the elements we are changing
    Returns array with element associated with this command
    Returns array with element associated with this command
    Returns array with element associated with this command
    Returns array with element associated with this command
    this.embedImage = function(val,
    callback)
    Converts a given image file to a data URL when possible, then runs a given callback
    Converts a string to base64
    - - - -
    var ffClone = function(elem)
    Hack for Firefox bugs where text element features aren’t updated.
    var findDefs = function()
    Return the document’s defs element, create it first if necessary
    var findDuplicateGradient = function(grad)
    Check if exact gradient already exists
    c.finishUndoableChange = function()
    This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
    Converts XML entities in a string to single characters.
    - -
    - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/javascript/main.js b/docs/javascript/main.js deleted file mode 100644 index efcdca9..0000000 --- a/docs/javascript/main.js +++ /dev/null @@ -1,836 +0,0 @@ -// This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -// Natural Docs is licensed under the GPL - - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1) - { browserVer = "Opera8"; } - else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1) - { browserVer = "Opera9"; } - } - -else if (agt.indexOf("applewebkit") != -1) - { - browserType = "Safari"; - - if (agt.indexOf("version/3") != -1) - { browserVer = "Safari3"; } - else if (agt.indexOf("safari/4") != -1) - { browserVer = "Safari2"; } - } - -else if (agt.indexOf("khtml") != -1) - { - browserType = "Konqueror"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - else if (agt.indexOf("msie 7") != -1) - { browserVer = "IE7"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Firefox"; - - if (agt.indexOf("rv:1.7") != -1) - { browserVer = "Firefox1"; } - else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1) - { browserVer = "Firefox15"; } - else if (agt.indexOf("rv:1.8.1") != -1) - { browserVer = "Firefox2"; } - } - - -// -// Support Functions -// ____________________________________________________________________________ - - -function GetXPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetLeft; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function GetYPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetTop; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function MoveToPosition(item, x, y) - { - // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. - - if (item.style.left != null) - { - item.style.left = x + "px"; - item.style.top = y + "px"; - } - else if (item.style.pixelLeft != null) - { - item.style.pixelLeft = x; - item.style.pixelTop = y; - }; - }; - - -// -// Menu -// ____________________________________________________________________________ - - -function ToggleMenu(id) - { - if (!window.document.getElementById) - { return; }; - - var display = window.document.getElementById(id).style.display; - - if (display == "none") - { display = "block"; } - else - { display = "none"; } - - window.document.getElementById(id).style.display = display; - } - -function HideAllBut(ids, max) - { - if (document.getElementById) - { - ids.sort( function(a,b) { return a - b; } ); - var number = 1; - - while (number < max) - { - if (ids.length > 0 && number == ids[0]) - { ids.shift(); } - else - { - document.getElementById("MGroupContent" + number).style.display = "none"; - }; - - number++; - }; - }; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - tooltipTimer = setTimeout(showCommand, 1000); - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } -/* else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } -*/ - if (tooltip) - { - var left = GetXPosition(link); - var top = GetYPosition(link); - top += link.offsetHeight; - - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - - // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width. - if (left < 0) - { left = 0; }; - } - - MoveToPosition(tooltip, left, top); - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - - -// -// Blockquote fix for IE -// ____________________________________________________________________________ - - -function NDOnLoad() - { - if (browserVer == "IE6") - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - if (scrollboxes.item(0)) - { - NDDoResize(); - window.onresize=NDOnResize; - }; - }; - }; - - -var resizeTimer = 0; - -function NDOnResize() - { - if (resizeTimer != 0) - { clearTimeout(resizeTimer); }; - - resizeTimer = setTimeout(NDDoResize, 250); - }; - - -function NDDoResize() - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - var i; - var item; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = 100; - i++; - }; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = item.parentNode.offsetWidth; - i++; - }; - - clearTimeout(resizeTimer); - resizeTimer = 0; - } - - - -/* ________________________________________________________________________________________________________ - - Class: SearchPanel - ________________________________________________________________________________________________________ - - A class handling everything associated with the search panel. - - Parameters: - - name - The name of the global variable that will be storing this instance. Is needed to be able to set timeouts. - mode - The mode the search is going to work in. Pass CommandLineOption()>, so the - value will be something like "HTML" or "FramedHTML". - - ________________________________________________________________________________________________________ -*/ - - -function SearchPanel(name, mode, resultsPath) - { - if (!name || !mode || !resultsPath) - { alert("Incorrect parameters to SearchPanel."); }; - - - // Group: Variables - // ________________________________________________________________________ - - /* - var: name - The name of the global variable that will be storing this instance of the class. - */ - this.name = name; - - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: resultsPath - The relative path from the current HTML page to the results page directory. - */ - this.resultsPath = resultsPath; - - /* - var: keyTimeout - The timeout used between a keystroke and when a search is performed. - */ - this.keyTimeout = 0; - - /* - var: keyTimeoutLength - The length of in thousandths of a second. - */ - this.keyTimeoutLength = 500; - - /* - var: lastSearchValue - The last search string executed, or an empty string if none. - */ - this.lastSearchValue = ""; - - /* - var: lastResultsPage - The last results page. The value is only relevant if is set. - */ - this.lastResultsPage = ""; - - /* - var: deactivateTimeout - - The timeout used between when a control is deactivated and when the entire panel is deactivated. Is necessary - because a control may be deactivated in favor of another control in the same panel, in which case it should stay - active. - */ - this.deactivateTimout = 0; - - /* - var: deactivateTimeoutLength - The length of in thousandths of a second. - */ - this.deactivateTimeoutLength = 200; - - - - - // Group: DOM Elements - // ________________________________________________________________________ - - - // Function: DOMSearchField - this.DOMSearchField = function() - { return document.getElementById("MSearchField"); }; - - // Function: DOMSearchType - this.DOMSearchType = function() - { return document.getElementById("MSearchType"); }; - - // Function: DOMPopupSearchResults - this.DOMPopupSearchResults = function() - { return document.getElementById("MSearchResults"); }; - - // Function: DOMPopupSearchResultsWindow - this.DOMPopupSearchResultsWindow = function() - { return document.getElementById("MSearchResultsWindow"); }; - - // Function: DOMSearchPanel - this.DOMSearchPanel = function() - { return document.getElementById("MSearchPanel"); }; - - - - - // Group: Event Handlers - // ________________________________________________________________________ - - - /* - Function: OnSearchFieldFocus - Called when focus is added or removed from the search field. - */ - this.OnSearchFieldFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchFieldChange - Called when the content of the search field is changed. - */ - this.OnSearchFieldChange = function() - { - if (this.keyTimeout) - { - clearTimeout(this.keyTimeout); - this.keyTimeout = 0; - }; - - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != this.lastSearchValue) - { - if (searchValue != "") - { - this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength); - } - else - { - if (this.mode == "HTML") - { this.DOMPopupSearchResultsWindow().style.display = "none"; }; - this.lastSearchValue = ""; - }; - }; - }; - - - /* - Function: OnSearchTypeFocus - Called when focus is added or removed from the search type. - */ - this.OnSearchTypeFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchTypeChange - Called when the search type is changed. - */ - this.OnSearchTypeChange = function() - { - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != "") - { - this.Search(); - }; - }; - - - - // Group: Action Functions - // ________________________________________________________________________ - - - /* - Function: CloseResultsWindow - Closes the results window. - */ - this.CloseResultsWindow = function() - { - this.DOMPopupSearchResultsWindow().style.display = "none"; - this.Activate(false, true); - }; - - - /* - Function: Search - Performs a search. - */ - this.Search = function() - { - this.keyTimeout = 0; - - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var searchTopic = this.DOMSearchType().value; - - var pageExtension = searchValue.substr(0,1); - - if (pageExtension.match(/^[a-z]/i)) - { pageExtension = pageExtension.toUpperCase(); } - else if (pageExtension.match(/^[0-9]/)) - { pageExtension = 'Numbers'; } - else - { pageExtension = "Symbols"; }; - - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - // indexSectionsWithContent is defined in searchdata.js - if (indexSectionsWithContent[searchTopic][pageExtension] == true) - { - resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html'; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; - } - else - { - resultsPage = this.resultsPath + '/NoResults.html'; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; - }; - - var resultsFrame; - if (this.mode == "HTML") - { resultsFrame = window.frames.MSearchResults; } - else if (this.mode == "FramedHTML") - { resultsFrame = window.top.frames['Content']; }; - - - if (resultsPage != this.lastResultsPage || - - // Bug in IE. If everything becomes hidden in a run, none of them will be able to be reshown in the next for some - // reason. It counts the right number of results, and you can even read the display as "block" after setting it, but it - // just doesn't work in IE 6 or IE 7. So if we're on the right page but the previous search had no results, reload the - // page anyway to get around the bug. - (browserType == "IE" && hasResultsPage && - (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) ) - - { - resultsFrame.location.href = resultsPageWithSearch; - } - - // So if the results page is right and there's no IE bug, reperform the search on the existing page. We have to check if there - // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even - // if it did. - else if (hasResultsPage) - { - // We need to check if this exists in case the frame is present but didn't finish loading. - if (resultsFrame.searchResults) - { resultsFrame.searchResults.Search(searchValue); } - - // Otherwise just reload instead of waiting. - else - { resultsFrame.location.href = resultsPageWithSearch; }; - }; - - - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); - - if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block") - { - var domSearchType = this.DOMSearchType(); - - var left = GetXPosition(domSearchType); - var top = GetYPosition(domSearchType) + domSearchType.offsetHeight; - - MoveToPosition(domPopupSearchResultsWindow, left, top); - domPopupSearchResultsWindow.style.display = 'block'; - }; - - - this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; - }; - - - - // Group: Activation Functions - // Functions that handle whether the entire panel is active or not. - // ________________________________________________________________________ - - - /* - Function: Activate - - Activates or deactivates the search panel, resetting things to their default values if necessary. You can call this on every - control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently. - - Parameters: - - isActive - Whether you're activating or deactivating the panel. - ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay. - */ - this.Activate = function(isActive, ignoreDeactivateDelay) - { - // We want to ignore isActive being false while the results window is open. - if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block")) - { - if (this.inactivateTimeout) - { - clearTimeout(this.inactivateTimeout); - this.inactivateTimeout = 0; - }; - - this.DOMSearchPanel().className = 'MSearchPanelActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == 'Search') - { searchField.value = ""; } - } - else if (!ignoreDeactivateDelay) - { - this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength); - } - else - { - this.InactivateAfterTimeout(); - }; - }; - - - /* - Function: InactivateAfterTimeout - - Called by , which is set by . Inactivation occurs on a timeout because a control may - receive OnBlur() when focus is really transferring to another control in the search panel. In this case we don't want to - actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value. - So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation. - */ - this.InactivateAfterTimeout = function() - { - this.inactivateTimeout = 0; - - this.DOMSearchPanel().className = 'MSearchPanelInactive'; - this.DOMSearchField().value = "Search"; - - this.lastSearchValue = ""; - this.lastResultsPage = ""; - }; - }; - - - - -/* ________________________________________________________________________________________________________ - - Class: SearchResults - _________________________________________________________________________________________________________ - - The class that handles everything on the search results page. - _________________________________________________________________________________________________________ -*/ - - -function SearchResults(name, mode) - { - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: lastMatchCount - The number of matches from the last run of . - */ - this.lastMatchCount = 0; - - - /* - Function: Toggle - Toggles the visibility of the passed element ID. - */ - this.Toggle = function(id) - { - if (this.mode == "FramedHTML") - { return; }; - - var parentElement = document.getElementById(id); - - var element = parentElement.firstChild; - - while (element && element != parentElement) - { - if (element.nodeName == 'DIV' && element.className == 'ISubIndex') - { - if (element.style.display == 'block') - { element.style.display = "none"; } - else - { element.style.display = 'block'; } - }; - - if (element.nodeName == 'DIV' && element.hasChildNodes()) - { element = element.firstChild; } - else if (element.nextSibling) - { element = element.nextSibling; } - else - { - do - { - element = element.parentNode; - } - while (element && element != parentElement && !element.nextSibling); - - if (element && element != parentElement) - { element = element.nextSibling; }; - }; - }; - }; - - - /* - Function: Search - - Searches for the passed string. If there is no parameter, it takes it from the URL query. - - Always returns true, since other documents may try to call it and that may or may not be possible. - */ - this.Search = function(search) - { - if (!search) - { - search = window.location.search; - search = search.substring(1); // Remove the leading ? - search = unescape(search); - }; - - search = search.replace(/^ +/, ""); - search = search.replace(/ +$/, ""); - search = search.toLowerCase(); - - if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily. - { - search = search.replace(/\_/g, "_und"); - search = search.replace(/\ +/gi, "_spc"); - search = search.replace(/\~/g, "_til"); - search = search.replace(/\!/g, "_exc"); - search = search.replace(/\@/g, "_att"); - search = search.replace(/\#/g, "_num"); - search = search.replace(/\$/g, "_dol"); - search = search.replace(/\%/g, "_pct"); - search = search.replace(/\^/g, "_car"); - search = search.replace(/\&/g, "_amp"); - search = search.replace(/\*/g, "_ast"); - search = search.replace(/\(/g, "_lpa"); - search = search.replace(/\)/g, "_rpa"); - search = search.replace(/\-/g, "_min"); - search = search.replace(/\+/g, "_plu"); - search = search.replace(/\=/g, "_equ"); - search = search.replace(/\{/g, "_lbc"); - search = search.replace(/\}/g, "_rbc"); - search = search.replace(/\[/g, "_lbk"); - search = search.replace(/\]/g, "_rbk"); - search = search.replace(/\:/g, "_col"); - search = search.replace(/\;/g, "_sco"); - search = search.replace(/\"/g, "_quo"); - search = search.replace(/\'/g, "_apo"); - search = search.replace(/\/g, "_ran"); - search = search.replace(/\,/g, "_com"); - search = search.replace(/\./g, "_per"); - search = search.replace(/\?/g, "_que"); - search = search.replace(/\//g, "_sla"); - search = search.replace(/[^a-z0-9\_]i/gi, "_zzz"); - }; - - var resultRows = document.getElementsByTagName("div"); - var matches = 0; - - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); - - if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search) - { - row.style.display = "block"; - matches++; - } - else - { row.style.display = "none"; }; - }; - - i++; - }; - - document.getElementById("Searching").style.display="none"; - - if (matches == 0) - { document.getElementById("NoMatches").style.display="block"; } - else - { document.getElementById("NoMatches").style.display="none"; } - - this.lastMatchCount = matches; - - return true; - }; - }; - diff --git a/docs/javascript/searchdata.js b/docs/javascript/searchdata.js deleted file mode 100644 index eac176a..0000000 --- a/docs/javascript/searchdata.js +++ /dev/null @@ -1,122 +0,0 @@ -var indexSectionsWithContent = { - "General": { - "Symbols": false, - "Numbers": false, - "A": true, - "B": false, - "C": true, - "D": true, - "E": false, - "F": true, - "G": true, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": true, - "P": false, - "Q": false, - "R": true, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - }, - "Functions": { - "Symbols": false, - "Numbers": false, - "A": true, - "B": true, - "C": true, - "D": true, - "E": true, - "F": true, - "G": true, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": false, - "P": true, - "Q": false, - "R": true, - "S": true, - "T": true, - "U": true, - "V": false, - "W": true, - "X": false, - "Y": false, - "Z": false - }, - "Interfaces": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - }, - "Classes": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - } - } \ No newline at end of file diff --git a/docs/search/FilesS.html b/docs/search/FilesS.html deleted file mode 100644 index 690d961..0000000 --- a/docs/search/FilesS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/search/FunctionsA.html b/docs/search/FunctionsA.html deleted file mode 100644 index de24e1f..0000000 --- a/docs/search/FunctionsA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    addExtension, SelectorManager
    addSubCommand, SvgCanvas.BatchCommand
    addSvgElementFromJson, SelectorManager
    addToSelection, SelectorManager
    alignSelectedElements, SelectorManager
    assignAttributes, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsC.html b/docs/search/FunctionsC.html deleted file mode 100644 index eb4b747..0000000 --- a/docs/search/FunctionsC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    changeSelectedAttribute, SelectorManager
    cleanupElement, SelectorManager
    clear, SelectorManager
    clearSelection, SelectorManager
    cloneSelectedElements, SelectorManager
    convertToNum, SvgCanvas
    convertToPath, SelectorManager
    convertToXMLReferences, SvgCanvas.Utils
    copyElem, SelectorManager
    createLayer, SelectorManager
    cycleElement, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsD.html b/docs/search/FunctionsD.html deleted file mode 100644 index 1c28ffc..0000000 --- a/docs/search/FunctionsD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    decode64, SvgCanvas.Utils
    deleteCurrentLayer, SelectorManager
    deleteSelectedElements, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsG.html b/docs/search/FunctionsG.html deleted file mode 100644 index c7e504e..0000000 --- a/docs/search/FunctionsG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    getBBox, SelectorManager
    getBlur, SelectorManager
    getBold, SelectorManager
    getColor, SelectorManager
    getContentElem, SelectorManager
    getCurrentLayer, SelectorManager
    getDocumentTitle, SelectorManager
    getEditorNS, SelectorManager
    getElem, SelectorManager
    getFontFamily, SelectorManager
    getFontSize, SelectorManager
    getId, SelectorManager
    getItalic, SelectorManager
    getLayer, SelectorManager
    getLayerOpacity, SelectorManager
    getLayerVisibility, SelectorManager
    getMatrix, SelectorManager
    getMode, SelectorManager
    getMouseTarget, SelectorManager
    getNextId, SelectorManager
    getNextRedoCommandText, SvgCanvas.undoMgr
    getNextUndoCommandText, SvgCanvas.undoMgr
    getNumLayers, SelectorManager
    getOffset, SelectorManager
    getOpacity, SelectorManager
    getPathBBox, SelectorManager
    getRedoStackSize, SvgCanvas.undoMgr
    getResolution, SelectorManager
    getRootElem, SelectorManager
    getRotationAngle, SelectorManager
    getRubberBandBox, SelectorManager.SelectorManager
    getSelectedElems, SelectorManager
    getStrokedBBox, SelectorManager
    getStrokeOpacity, SelectorManager
    getStrokeWidth, SelectorManager
    getSvgString, SelectorManager
    getText, SelectorManager
    getTransformList, SelectorManager
    getUndoStackSize, SvgCanvas.undoMgr
    getUrlFromAttr, SelectorManager
    getVersion, SelectorManager
    getVisibleElements, SelectorManager
    getZoom, SelectorManager
    groupSelectedElements, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsM.html b/docs/search/FunctionsM.html deleted file mode 100644 index fbb3112..0000000 --- a/docs/search/FunctionsM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    matrixMultiply, SelectorManager
    moveSelectedElements, SelectorManager
    moveSelectedToLayer, SelectorManager
    moveToTopSelectedElement, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsO.html b/docs/search/FunctionsO.html deleted file mode 100644 index 76f92f6..0000000 --- a/docs/search/FunctionsO.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsR.html b/docs/search/FunctionsR.html deleted file mode 100644 index 3153d9d..0000000 --- a/docs/search/FunctionsR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    rasterExport, SelectorManager
    recalculateDimensions, SelectorManager
    rectsIntersect, SvgCanvas
    redo, SvgCanvas.undoMgr
    releaseSelector, SelectorManager.SelectorManager
    remapElement, SelectorManager
    removeFromSelection, SelectorManager
    removeUnusedDefElems, SelectorManager
    renameCurrentLayer, SelectorManager
    requestSelector, SelectorManager.SelectorManager
    reset, Selector.Selector
    resetUndoStack, SvgCanvas
    resize, Selector.Selector
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/FunctionsS.html b/docs/search/FunctionsS.html deleted file mode 100644 index 13e3338..0000000 --- a/docs/search/FunctionsS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    sanitizeSvg, SelectorManager
    save, SelectorManager
    selectAllInCurrentLayer, SelectorManager
    setBackground, SelectorManager
    setBBoxZoom, SelectorManager
    setBlur, SelectorManager
    setBlurNoUndo, SelectorManager
    setBlurOffsets, SelectorManager
    setBold, SelectorManager
    setColor, SelectorManager
    setConfig, SelectorManager
    setCurrentLayer, SelectorManager
    setCurrentLayerPosition, SelectorManager
    setDocumentTitle, SelectorManager
    setFontFamily, SelectorManager
    setFontSize, SelectorManager
    setGradient, SelectorManager
    setIdPrefix, SelectorManager
    setImageURL, SelectorManager
    setItalic, SelectorManager
    setLayerOpacity, SelectorManager
    setLayerVisibility, SelectorManager
    setMode, SelectorManager
    setOpacity, SelectorManager
    setPaint, SelectorManager
    setPaintOpacity, SelectorManager
    setRectRadius, SelectorManager
    setResolution, SelectorManager
    setRotationAngle, SelectorManager
    setSegType, SelectorManager
    setStrokeAttr, SelectorManager
    setStrokeWidth, SelectorManager
    setSvgString, SelectorManager
    setTextContent, SelectorManager
    setUiStrings, SelectorManager
    setUnitAttr, SvgCanvas
    setZoom, SelectorManager
    shortFloat, SelectorManager
    showGrips, Selector.Selector
    smoothControlPoints, SelectorManager
    snapToAngle, SvgCanvas
    svgCanvasToString, SelectorManager
    svgToString, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralA.html b/docs/search/GeneralA.html deleted file mode 100644 index f3ee0f6..0000000 --- a/docs/search/GeneralA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    addExtension, SelectorManager
    Additional editor tools, SelectorManager
    addSubCommand, SvgCanvas.BatchCommand
    addSvgElementFromJson, SelectorManager
    addToSelection, SelectorManager
    alignSelectedElements, SelectorManager
    assignAttributes, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralC.html b/docs/search/GeneralC.html deleted file mode 100644 index eb4b747..0000000 --- a/docs/search/GeneralC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    changeSelectedAttribute, SelectorManager
    cleanupElement, SelectorManager
    clear, SelectorManager
    clearSelection, SelectorManager
    cloneSelectedElements, SelectorManager
    convertToNum, SvgCanvas
    convertToPath, SelectorManager
    convertToXMLReferences, SvgCanvas.Utils
    copyElem, SelectorManager
    createLayer, SelectorManager
    cycleElement, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralD.html b/docs/search/GeneralD.html deleted file mode 100644 index 6735300..0000000 --- a/docs/search/GeneralD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    decode64, SvgCanvas.Utils
    deleteCurrentLayer, SelectorManager
    deleteSelectedElements, SelectorManager
    Document functions, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralF.html b/docs/search/GeneralF.html deleted file mode 100644 index 55c21a8..0000000 --- a/docs/search/GeneralF.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    ffClone, SelectorManager
    findDefs, SelectorManager
    findDuplicateGradient, SelectorManager
    fromXml, SvgCanvas.Utils
    Functions, Selector
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralG.html b/docs/search/GeneralG.html deleted file mode 100644 index c7e504e..0000000 --- a/docs/search/GeneralG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    getBBox, SelectorManager
    getBlur, SelectorManager
    getBold, SelectorManager
    getColor, SelectorManager
    getContentElem, SelectorManager
    getCurrentLayer, SelectorManager
    getDocumentTitle, SelectorManager
    getEditorNS, SelectorManager
    getElem, SelectorManager
    getFontFamily, SelectorManager
    getFontSize, SelectorManager
    getId, SelectorManager
    getItalic, SelectorManager
    getLayer, SelectorManager
    getLayerOpacity, SelectorManager
    getLayerVisibility, SelectorManager
    getMatrix, SelectorManager
    getMode, SelectorManager
    getMouseTarget, SelectorManager
    getNextId, SelectorManager
    getNextRedoCommandText, SvgCanvas.undoMgr
    getNextUndoCommandText, SvgCanvas.undoMgr
    getNumLayers, SelectorManager
    getOffset, SelectorManager
    getOpacity, SelectorManager
    getPathBBox, SelectorManager
    getRedoStackSize, SvgCanvas.undoMgr
    getResolution, SelectorManager
    getRootElem, SelectorManager
    getRotationAngle, SelectorManager
    getRubberBandBox, SelectorManager.SelectorManager
    getSelectedElems, SelectorManager
    getStrokedBBox, SelectorManager
    getStrokeOpacity, SelectorManager
    getStrokeWidth, SelectorManager
    getSvgString, SelectorManager
    getText, SelectorManager
    getTransformList, SelectorManager
    getUndoStackSize, SvgCanvas.undoMgr
    getUrlFromAttr, SelectorManager
    getVersion, SelectorManager
    getVisibleElements, SelectorManager
    getZoom, SelectorManager
    groupSelectedElements, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralL.html b/docs/search/GeneralL.html deleted file mode 100644 index 09038de..0000000 --- a/docs/search/GeneralL.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    Layers, SelectorManager
    linkControlPoints, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralM.html b/docs/search/GeneralM.html deleted file mode 100644 index fbb3112..0000000 --- a/docs/search/GeneralM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    matrixMultiply, SelectorManager
    moveSelectedElements, SelectorManager
    moveSelectedToLayer, SelectorManager
    moveToTopSelectedElement, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralO.html b/docs/search/GeneralO.html deleted file mode 100644 index 76f92f6..0000000 --- a/docs/search/GeneralO.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralR.html b/docs/search/GeneralR.html deleted file mode 100644 index 3153d9d..0000000 --- a/docs/search/GeneralR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    rasterExport, SelectorManager
    recalculateDimensions, SelectorManager
    rectsIntersect, SvgCanvas
    redo, SvgCanvas.undoMgr
    releaseSelector, SelectorManager.SelectorManager
    remapElement, SelectorManager
    removeFromSelection, SelectorManager
    removeUnusedDefElems, SelectorManager
    renameCurrentLayer, SelectorManager
    requestSelector, SelectorManager.SelectorManager
    reset, Selector.Selector
    resetUndoStack, SvgCanvas
    resize, Selector.Selector
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/GeneralS.html b/docs/search/GeneralS.html deleted file mode 100644 index 1176986..0000000 --- a/docs/search/GeneralS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
    Loading...
    sanitizeSvg, SelectorManager
    save, SelectorManager
    selectAllInCurrentLayer, SelectorManager
    Selection, SelectorManager
    Serialization, SelectorManager
    setBackground, SelectorManager
    setBBoxZoom, SelectorManager
    setBlur, SelectorManager
    setBlurNoUndo, SelectorManager
    setBlurOffsets, SelectorManager
    setBold, SelectorManager
    setColor, SelectorManager
    setConfig, SelectorManager
    setCurrentLayer, SelectorManager
    setCurrentLayerPosition, SelectorManager
    setDocumentTitle, SelectorManager
    setFontFamily, SelectorManager
    setFontSize, SelectorManager
    setGradient, SelectorManager
    setIdPrefix, SelectorManager
    setImageURL, SelectorManager
    setItalic, SelectorManager
    setLayerOpacity, SelectorManager
    setLayerVisibility, SelectorManager
    setMode, SelectorManager
    setOpacity, SelectorManager
    setPaint, SelectorManager
    setPaintOpacity, SelectorManager
    setRectRadius, SelectorManager
    setResolution, SelectorManager
    setRotationAngle, SelectorManager
    setSegType, SelectorManager
    setStrokeAttr, SelectorManager
    setStrokeWidth, SelectorManager
    setSvgString, SelectorManager
    setTextContent, SelectorManager
    setUiStrings, SelectorManager
    setUnitAttr, SvgCanvas
    setZoom, SelectorManager
    shortFloat, SelectorManager
    showGrips, Selector.Selector
    smoothControlPoints, SelectorManager
    snapToAngle, SvgCanvas
    svgCanvasToString, SelectorManager
    svgToString, SelectorManager
    Searching...
    No Matches
    \ No newline at end of file diff --git a/docs/search/NoResults.html b/docs/search/NoResults.html deleted file mode 100644 index 02ce888..0000000 --- a/docs/search/NoResults.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - -
    No Matches
    \ No newline at end of file diff --git a/docs/styles/main.css b/docs/styles/main.css deleted file mode 100644 index 17e9cbc..0000000 --- a/docs/styles/main.css +++ /dev/null @@ -1,767 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font: 10pt Verdana, Arial, sans-serif; - color: #000000; - margin: 0; padding: 0; - } - -.ContentPage, -.IndexPage, -.FramedMenuPage { - background-color: #E8E8E8; - } -.FramedContentPage, -.FramedIndexPage, -.FramedSearchResultsPage, -.PopupSearchResultsPage { - background-color: #FFFFFF; - } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -img { border: 0; } - - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Opera doesn't break with just wbr, but will if you add this. */ -.Opera wbr:after { - content: "\00200B"; - } - - -/* Blockquotes are used as containers for things that may need to scroll. */ -blockquote { - padding: 0; - margin: 0; - overflow: auto; - } - - -.Firefox1 blockquote { - padding-bottom: .5em; - } - -/* Turn off scrolling when printing. */ -@media print { - blockquote { - overflow: visible; - } - .IE blockquote { - width: auto; - } - } - - - -#Menu { - font-size: 9pt; - padding: 10px 0 0 0; - } -.ContentPage #Menu, -.IndexPage #Menu { - position: absolute; - top: 0; - left: 0; - width: 31ex; - overflow: hidden; - } -.ContentPage .Firefox #Menu, -.IndexPage .Firefox #Menu { - width: 27ex; - } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px; - } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0; - } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px; - } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Firefox .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - #MSearchPanel { - padding: 0px 6px; - margin: .25em 0; - } - - - #MSearchField { - font: italic 9pt Verdana, sans-serif; - color: #606060; - background-color: #E8E8E8; - border: none; - padding: 2px 4px; - width: 100%; - } - /* Only Opera gets it right. */ - .Firefox #MSearchField, - .IE #MSearchField, - .Safari #MSearchField { - width: 94%; - } - .Opera9 #MSearchField, - .Konqueror #MSearchField { - width: 97%; - } - .FramedMenuPage .Firefox #MSearchField, - .FramedMenuPage .Safari #MSearchField, - .FramedMenuPage .Konqueror #MSearchField { - width: 98%; - } - - /* Firefox doesn't do this right in frames without #MSearchPanel added on. - It's presence doesn't hurt anything other browsers. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - padding: 1px 3px; - } - .MSearchPanelActive #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - font-style: normal; - padding: 1px 3px; - } - - #MSearchType { - visibility: hidden; - font: 8pt Verdana, sans-serif; - width: 98%; - padding: 0; - border: 1px solid #C0C0C0; - } - .MSearchPanelActive #MSearchType, - /* As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchType, - #MSearchType:focus { - visibility: visible; - color: #606060; - } - #MSearchType option#MSearchEverything { - font-weight: bold; - } - - .Opera8 .MSearchPanelInactive:hover, - .Opera8 .MSearchPanelActive { - margin-left: -1px; - } - - - iframe#MSearchResults { - width: 60ex; - height: 15em; - } - #MSearchResultsWindow { - display: none; - position: absolute; - left: 0; top: 0; - border: 1px solid #000000; - background-color: #E8E8E8; - } - #MSearchResultsWindowClose { - font-weight: bold; - font-size: 8pt; - display: block; - padding: 2px 5px; - } - #MSearchResultsWindowClose:link, - #MSearchResultsWindowClose:visited { - color: #000000; - text-decoration: none; - } - #MSearchResultsWindowClose:active, - #MSearchResultsWindowClose:hover { - color: #800000; - text-decoration: none; - background-color: #F4F4F4; - } - - - - -#Content { - padding-bottom: 15px; - } - -.ContentPage #Content { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - background-color: #FFFFFF; - font-size: 9pt; /* To make 31ex match the menu's 31ex. */ - margin-left: 31ex; - } -.ContentPage .Firefox #Content { - margin-left: 27ex; - } - - - - .CTopic { - font-size: 10pt; - margin-bottom: 3em; - } - - - .CTitle { - font-size: 12pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt; - } - - .Opera .CToolTip { - max-width: 98%; - } - - /* Scrollbars would be useless. */ - .CToolTip blockquote { - overflow: hidden; - } - .IE6 .CToolTip blockquote { - overflow: visible; - } - - .CHeading { - font-weight: bold; font-size: 10pt; - margin: 1.5em 0 .5em 0; - } - - .CBody pre { - font: 10pt "Courier New", Courier, monospace; - margin: 1em 0; - } - - .CBody ul { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 10pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - - .CTopic img { - text-align: center; - display: block; - margin: 1em auto; - } - .CImageCaption { - font-variant: small-caps; - font-size: 8pt; - color: #808080; - text-align: center; - position: relative; - top: 1em; - } - - .CImageLink { - color: #808080; - font-style: italic; - } - a.CImageLink:link, - a.CImageLink:visited, - a.CImageLink:hover { color: #808080 } - - - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PDefaultValuePrefix, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - .PAfterParameters { - vertical-align: bottom; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CClass .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - background-color: #F4F4F4; - } - .CInterface .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0; - background-color: #F4F4FF; - } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype, - .CEnumeration .Prototype { - background-color: #FAF0F0; border-color: #E0B0B0; - } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 12pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* In a frame IE 6 will make them too long unless you set the width to 100%. Without frames it will be correct without a width - or slightly too long (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. IE 7 has the same - problem with frames, haven't tested it without. */ - .FramedContentPage .IE .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 9pt; width: 100% } - - .SEntry { - width: 30% } - .SDescription { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - .SDescription { padding-left: 2ex } - .SIndent1 .SEntry { padding-left: 1.5ex } .SIndent1 .SDescription { padding-left: 3.5ex } - .SIndent2 .SEntry { padding-left: 3.0ex } .SIndent2 .SDescription { padding-left: 5.0ex } - .SIndent3 .SEntry { padding-left: 4.5ex } .SIndent3 .SDescription { padding-left: 6.5ex } - .SIndent4 .SEntry { padding-left: 6.0ex } .SIndent4 .SDescription { padding-left: 8.0ex } - .SIndent5 .SEntry { padding-left: 7.5ex } .SIndent5 .SDescription { padding-left: 9.5ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - .SGroup td { - padding-top: .5em; padding-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain td, - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - font-size: 10pt; - padding-bottom: .25em } - - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - padding-top: 1em } - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; - } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 10pt; - background-color: #F4F4F4; color: #606060; - } - - .Firefox .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -#Index { - background-color: #FFFFFF; - } - -/* As opposed to .PopupSearchResultsPage #Index */ -.IndexPage #Index, -.FramedIndexPage #Index, -.FramedSearchResultsPage #Index { - padding: 15px; - } - -.IndexPage #Index { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - font-size: 9pt; /* To make 27ex match the menu's 27ex. */ - margin-left: 27ex; - } - - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .FramedSearchResultsPage .IPageTitle { - margin-bottom: 15px; - } - - .INavigationBar { - font-size: 10pt; - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px; - } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 16pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - font-size: 10pt; - padding-left: 1ex; - } - .PopupSearchResultsPage .IEntry { - font-size: 8pt; - padding: 1px 5px; - } - .PopupSearchResultsPage .Opera9 .IEntry, - .FramedSearchResultsPage .Opera9 .IEntry { - text-align: left; - } - .FramedSearchResultsPage .IEntry { - padding: 0; - } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - .PopupSearchResultsPage .ISubIndex { - display: none; - } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .IndexPage .ISymbolPrefix, - .FramedIndexPage .ISymbolPrefix { - font-size: 10pt; - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - .PopupSearchResultsPage .ISymbolPrefix, - .FramedSearchResultsPage .ISymbolPrefix { - color: #900000; - } - .PopupSearchResultsPage .ISymbolPrefix { - font-size: 8pt; - } - - .IndexPage #IFirstSymbolPrefix, - .FramedIndexPage #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - .IndexPage #ILastSymbolPrefix, - .FramedIndexPage #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - .IndexPage #IOnlySymbolPrefix, - .FramedIndexPage #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - .PopupSearchResultsPage .SRStatus { - padding: 2px 5px; - font-size: 8pt; - font-style: italic; - } - .FramedSearchResultsPage .SRStatus { - font-size: 10pt; - font-style: italic; - } - - .SRResult { - display: none; - } - - - -#Footer { - font-size: 8pt; - color: #989898; - text-align: right; - } - -#Footer p { - text-indent: 0; - margin-bottom: .5em; - } - -.ContentPage #Footer, -.IndexPage #Footer { - text-align: right; - margin: 2px; - } - -.FramedMenuPage #Footer { - text-align: center; - margin: 5em 10px 10px 10px; - padding-top: 1em; - border-top: 1px solid #C8C8C8; - } - - #Footer a:link, - #Footer a:hover, - #Footer a:visited { color: #989898 } - #Footer a:active { color: #A00000 } - diff --git a/editor/browser-not-supported.html b/editor/browser-not-supported.html deleted file mode 100644 index 1451706..0000000 --- a/editor/browser-not-supported.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - -Browser does not support SVG | Method Draw - - - -
    -Method Draw Logo
    -

    Sorry, but your browser does not support SVG. Below is a list of alternate browsers and versions that support SVG and Method Draw.

    -

    Try the latest version of Firefox, Google Chrome, Safari, Opera or Microsoft Edge.

    - - -
    - - - diff --git a/editor/css/method-draw.compiled.css b/editor/css/method-draw.compiled.css deleted file mode 100644 index 3f0345d..0000000 --- a/editor/css/method-draw.compiled.css +++ /dev/null @@ -1,417 +0,0 @@ -#svg_editor .jPicker .Icon{display:inline-block;height:24px;position:relative;text-align:left;width:25px} -#svg_editor .jPicker .Icon span.Color,#svg_editor .jPicker .Icon span.Alpha{background-position:2px 2px;display:block;height:100%;left:0;position:absolute;top:0;width:100%} -#svg_editor .jPicker .Icon span.Image{background-repeat:no-repeat;cursor:pointer;display:block;height:100%;left:0;position:absolute;top:0;width:100%} -#svg_editor .jPicker.Container{z-index:10} -table#svg_editor .jPicker{width:545px;z-index:20} -#svg_editor .jPicker .Move{background-color:#ddd;border-color:#fff #666 #666 #fff;border-style:solid;border-width:1px;cursor:move;height:12px;padding:0} -#svg_editor .jPicker .Title{display:none} -#svg_editor .jPicker div.Map{border:solid #000 1px;cursor:crosshair;height:260px;margin:0;overflow:hidden;padding:0;position:relative;width:260px} -#svg_editor .jPicker div[class="Map"]{height:256px;width:256px} -#svg_editor .jPicker div.Bar{border:solid #000 1px;cursor:n-resize;height:260px;margin:0 15px;overflow:hidden;padding:0;position:relative;width:24px} -#svg_editor .jPicker div[class="Bar"]{height:256px;width:20px} -#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Map .Map3,#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4,#svg_editor .jPicker .Bar .Map5,#svg_editor .jPicker .Bar .Map6{background-color:transparent;background-image:none;display:block;left:0;position:absolute;top:0} -#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Map .Map3{height:2596px;width:256px} -#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4{height:3896px;width:20px} -#svg_editor .jPicker .Bar .Map5,#svg_editor .jPicker .Bar .Map6{height:256px;width:20px} -#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Bar .Map6{background-repeat:no-repeat} -#svg_editor .jPicker .Map .Map3,#svg_editor .jPicker .Bar .Map5{background-repeat:repeat} -#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4{background-repeat:repeat-x} -#svg_editor .jPicker .Map .Arrow{display:block;position:absolute} -#svg_editor .jPicker .Bar .Arrow{display:block;left:0;position:absolute} -#svg_editor .jPicker .Preview{font-size:9px;text-align:center} -#svg_editor .jPicker .Preview div.bgt{height:62px;margin:0 auto;padding:0;width:62px} -#svg_editor .jPicker .Preview div span{border:1px solid #000;display:block;height:30px;margin:0 auto;padding:0;width:60px} -#svg_editor .jPicker .Preview .Active{border-bottom-width:0} -#svg_editor .jPicker .Preview .Current{border-top-width:0;cursor:pointer} -#svg_editor .jPicker .Button{text-align:center;width:115px} -#svg_editor .jPicker .Button input{width:100px} -#svg_editor .jPicker td.Radio{margin:0;padding:0;width:31px} -#svg_editor .jPicker td.Radio input{margin:0 5px 0 0;padding:0} -#svg_editor .jPicker td.Text{font-size:12px!important;height:22px;margin:0;padding:0;text-align:left;width:70px} -#svg_editor .jPicker tr.Hex td.Text{width:100px;color:#666} -#svg_editor .jPicker tr.Hex td.Text span{width:100px;color:#333} -#svg_editor .jPicker td.Text input{background-color:#fff;border:1px inset #aaa;height:15px;margin:0 0 0 5px;text-align:left;width:30px;color:#333} -#svg_editor #color_picker .jPicker tr.Hex td.Text input.Hex{width:50px;display:inline-block;float:none} -#svg_editor .jPicker tr.Hex td.Text input.AHex{width:20px;display:none} -#svg_editor .jPicker .Grid{text-align:center;float:right;width:108px} -#svg_editor .jPicker .Grid span.QuickColor{cursor:pointer;display:inline-block;height:15px;line-height:15px;margin:0;padding:0;width:18px} -#svg_editor .jPicker td{vertical-align:top} -#svg_editor .jPicker td.colorsquare{width:275px} -#svg_editor .jPicker .prev_div{margin-top:-15px} -#svg_editor .jPicker .actions{position:absolute;bottom:20px;left:20px;right:20px} -#svg_editor .jPicker .actions .Ok{position:absolute;top:0;right:0} -#svg_editor .jPicker .actions .Cancel{position:absolute;top:0;left:0} -#svg_editor .jPicker .color_preview{width:62px;margin:0 auto} -h2.jGraduate_Title{display:none} -.jGraduate_Picker{position:absolute;padding:20px} -.jGraduate_tabs li{display:inline-block;padding:5px 10px;margin-right:5px;cursor:pointer} -li.jGraduate_tab_current{background:#fff;border-radius:3px 3px 0 0} -.jGraduate_colPick{display:none} -.jGraduate_gradPick{display:none;overflow:visible} -.jGraduate_tabs{position:relative;background-color:#ddd;padding:10px 10px 0 10px;margin:-20px -20px 20px -20px;border-radius:3px 3px 0 0} -div.jGraduate_Swatch{float:left;margin:0 15px 0 0} -div.jGraduate_GradContainer{border:solid #000 1px;background-image:url(../images/map-opacity.png);background-position:0 0;height:256px;width:256px;position:relative} -div.jGraduate_GradContainer div.grad_coord{background:rgba(0,0,0,0.8);border:2px solid white;border-radius:15px;-moz-border-radius:5px;width:14px;height:14px;position:absolute;margin:-7px -7px;top:0;left:0;text-align:center;font-size:8px;line-height:14px;color:white;text-decoration:none;cursor:pointer;-moz-user-select:none;-webkit-user-select:none} -.jGraduate_AlphaArrows{position:absolute;margin-top:-10px;margin-left:250.5px} -div.jGraduate_Opacity{border:2px inset #eee;margin-top:14px;background-color:black;background-image:url(../images/Maps.png);background-position:0 -2816px;height:20px;cursor:ew-resize} -div.jGraduate_StopSlider{margin:-10px 0 0 -10px;width:276px;overflow:visible;background:white;height:45px;cursor:pointer} -div.jGraduate_StopSection{width:120px;float:left} -div.jGraduate_StopSection.jGraduate_SpreadMethod{display:none} -input.jGraduate_Ok,input.jGraduate_Cancel{display:block;width:100px} -input.jGraduate_Ok{margin:0 0 5px 0} -.colorBox{float:left;height:16px;width:16px;border:1px solid #808080;cursor:pointer;margin:4px 4px 4px 30px} -.colorBox+label{float:left;margin-top:7px} -label.jGraduate_Form_Heading{color:#333;padding:2px;font-weight:bold;font-size:13px} -div.jGraduate_Form_Section{-moz-border-radius:5px;-webkit-border-radius:5px;padding:15px 5px 5px 5px;margin:5px 2px;width:100px;text-align:center;overflow:auto;background:#eee} -div.jGraduate_Form label{padding:0 2px;color:#333} -div.jGraduate_StopSection input[type=text],div.jGraduate_Slider input[type=text]{width:33px;color:#333} -div.jGraduate_LightBox{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#000;opacity:.5;display:none} -div.jGraduate_stopPicker{position:absolute;display:none;background:white;padding:20px;border-radius:3px;width:530px;height:300px;box-shadow:0 5px 25px black} -.jGraduate_gradPick{width:526px} -.jGraduate_gradPick div.jGraduate_Slider{line-height:160%} -.jGraduate_gradPick div.jGraduate_Slider label:last-child{position:absolute;right:10px;top:0;color:#999;font-weight:bold} -.jGraduate_gradPick div.jGraduate_Slider label:last-child input{margin:0 3px 0 0;color:#333} -.jGraduate_gradPick .jGraduate_Form{float:left;width:270px;position:absolute;left:284px;width:266px;height:200px;top:195px;margin:-3px 3px 0 10px;line-height:200%} -.jGraduate_gradPick .jGraduate_Form label,.jGraduate_gradPick .jGraduate_Form input{width:auto;float:left} -.jGraduate_gradPick .jGraduate_Form.jGraduate_rg_field label,.jGraduate_gradPick .jGraduate_Form.jGraduate_rg_field input{width:auto;float:left;font-size:11px} -.jGraduate_gradPick .jGraduate_Form.jGraduate_rg_field #color_picker_jGraduate_match_ctr{float:none} -.jGraduate_gradPick .jGraduate_Form label{clear:left} -.jGraduate_gradPick .jGraduate_Points{position:static;float:left;margin:0;width:auto} -.jGraduate_Colorblocks{display:table;border-spacing:0 5px} -.jGraduate_colorblock{display:table-row} -.jGraduate_Colorblocks .jGraduate_colorblock>*{display:table-cell;vertical-align:middle;margin:0;float:none} -.jGraduate_gradPick .jGraduate_Form_Section{padding-top:9px} -.jGraduate_Slider{text-align:center;float:left;width:100%;position:relative;margin:5px 0} -.jGraduate_Slider .jGraduate_Form_Section{border:0;width:250px;padding:0 2px;overflow:visible} -.jGraduate_Slider label.prelabel{width:40px;text-align:left} -.jGraduate_SliderBar{width:140px;float:left;margin:0 5px;border:1px solid #BBB;height:20px;position:relative} -div.jGraduate_Slider input{margin-top:5px} -div.jGraduate_Slider img{top:0;left:0;position:absolute;cursor:ew-resize} -.jPicker .Button .Ok,.jGraduate_Picker .jGraduate_OkCancel .jGraduate_Ok{-webkit-appearance:none;margin:0;position:absolute;bottom:5px;right:5px} -.jPicker .Button .Cancel,.jGraduate_Picker .jGraduate_OkCancel .jGraduate_Cancel{margin:0;position:absolute;bottom:5px;left:5px} -body{background:#3f3f3c;font:13px/120% 'Lucida Sans','Lucida Grande','Lucida Sans Unicode',sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:0;padding:0} -::selection{background:#000;color:#fff} -::-moz-selection{background:#000;color:#fff} -html,body{overflow:hidden;width:100%;height:100%} -::-webkit-scrollbar{width:5px;height:5px;background:#444} -::-webkit-scrollbar-track{border-radius:10px;background:#444} -::-webkit-scrollbar-thumb{border-radius:10px;background:#666} -::-webkit-scrollbar-corner{background:#444} -#browser-not-supported{font-size:.8em;font-family:Verdana,Helvetica,Arial;color:#000} -#svgroot{-moz-user-select:none;-webkit-user-select:none;position:absolute;top:0;left:0} -#svg_editor{background:#2f2f2c} -#menu_bar{padding:0 0 0 50px;background:#2f2f2c;position:relative;z-index:2} -#menu_bar.active .menu.open .menu_list{display:block} -.menu{position:relative;z-index:5;color:#333;display:inline-block} -.menu_title{cursor:pointer;display:inline-block;padding:7px 10px;z-index:10;color:#fff;position:relative;height:16px;vertical-align:top} -.touch .menu_title{padding:7px 17px;height:26px;line-height:26px} -.menu .menu_title:hover{background:rgba(255,255,255,0.1)} -.menu_list .separator{margin:5px 0;border-top:solid #ddd 1px} -.menu_list{display:none;position:absolute;top:28px;left:0;white-space:nowrap;background:white;padding:7px 0;border-radius:0 3px 3px 3px;box-shadow:0 0 20px rgba(0,0,0,0.8)} -.touch .menu_list{top:38px} -#menu_bar.active .menu.open .menu_title{background:white;color:#333} -.menu_list .menu_item{position:relative;overflow:hidden;line-height:22px;padding:5px 69px 5px 25px;cursor:default;color:#333} -.menu_list .menu_item.tool_button{background:transparent;border:0;margin:0;padding:5px 55px 5px 25px;height:auto;width:auto} -.menu_list .menu_item.push_button_pressed:before{content:'✔';position:absolute;display:block;left:7px;top:3px;width:20px;height:20px} -.menu_list .menu_item:hover,.menu_list .menu_item.push_button_pressed:hover{background:rgba(0,0,0,0.1);color:#000} -.menu_list .menu_item.disabled:hover,.menu_list .menu_item.push_button_pressed.disabled:hover{background:transparent;color:#333} -.menu_list .menu_item.push_button_pressed{background:transparent;border:0;width:auto;height:auto;margin:0} -.menu_list .menu_item span{display:block;position:absolute;right:10px;padding:5px;background:rgba(0,0,0,0.1);top:6px;height:10px;text-align:center;font-size:10px;line-height:120%} -#svgcanvas{line-height:normal;display:inline-block;background-color:#a0a0a0;text-align:center;vertical-align:middle;width:640px;height:480px;position:relative;background:#3f3f3c} -#rulers>div{position:absolute;background:#2f2f2c;z-index:1;overflow:hidden;-webkit-font-smoothing:none} -#rulers #ruler_corner{top:30px;left:50px;width:15px;height:15px;border:solid #444 1px;z-index:2} -#ruler_x{height:15px;top:30px;left:66px;right:175px;border-top:solid #444 1px;border-right:solid #444 1px} -#ruler_x_cursor{height:15px;border-right:dotted #999 1px;position:absolute;background:#2f2f2c} -#ruler_y_cursor{width:15px;border-top:dotted #999 1px;position:absolute;background:#2f2f2c} -#rulers.moved #ruler_corner,#rulers.moved #ruler_x{top:101px} -#ruler_y{width:15px;top:46px;left:50px;bottom:40px;border-left:solid #444 1px;border-bottom:solid #444 1px} -#rulers.moved #ruler_y{top:116px} -#ruler_x canvas:first-child{margin-left:-16px} -#ruler_x canvas{float:left} -#ruler_y canvas{margin-top:-16px} -#ruler_x>div,#ruler_y>div{overflow:hidden} -#palette{display:block;position:absolute;z-index:2;left:10px;bottom:5px;width:410px;right:145px;height:30px} -.palette_item{height:20%;width:5.2%;float:left;cursor:url(../images/eyedropper.png) 0 16,crosshair} -.palette_item.transparent,.palette_item.white,.palette_item.black{background:#fff;position:absolute;width:10px;height:10px;left:-10px;top:0} -.palette_item.transparent{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAVdEVYdENyZWF0aW9uIFRpbWUAOC8yMi8xMg1cp6sAAABESURBVBiVjdBBCgAgCETRr/e/87SJKFPLnfIcQRMIwMBIShIAvgZzoSrfkzrs8WyF1+kX9r3p8AE7nL7kSpSshN+JEQ8GixkF0mSevgAAAABJRU5ErkJggg==)} -.palette_item.black{background:#000;top:10px} -.palette_item.white{background:#fff;top:20px} -#color_tools{position:relative;width:48px;height:48px;margin:6px 6px 0 6px} -.touch #color_tools{width:auto;height:auto} -#tool_fill{position:absolute;top:0;left:0;z-index:1} -.touch #tool_fill{position:static;width:36px;height:36px;margin-bottom:10px} -#tool_fill.active,#tool_stroke.active{z-index:2} -#tool_stroke{top:14px;left:14px} -.touch #tool_fill.active,.touch #tool_stroke.active{outline:4px solid #09f} -#tool_fill,#tool_stroke,#tool_canvas{box-shadow:0 0 0 1px #2f2f2c;position:absolute} -.touch #tool_fill,.touch #tool_stroke,.touch #tool_canvas{position:relative;top:0;left:0} -#color_canvas_tools{float:left;cursor:pointer} -#tool_fill .color_block{width:24px;height:24px;overflow:hidden;border:solid #ccc 1px} -.touch #tool_eyedropper{margin-top:6px} -.touch #tool_fill .color_block{width:36px;height:36px} -.touch #tool_fill .color_block svg{width:36px!important;height:36px!important} -.touch #tool_switch{display:none} -#use_panel .tool_button,#path_node_panel .tool_button{color:#999;border:solid #3f3f3c 1px;border-radius:3px;padding:3px 10px 3px 40px;background:transparent;position:relative;margin-top:10px;width:90px;height:23px;line-height:24px} -#use_panel .tool_button{padding-left:10px;margin-bottom:10px;width:124px} -#path_node_panel .tool_button img,#path_node_panel .tool_button svg{position:absolute;left:5px;top:3px} -#color_tools #tool_fill .color_block:hover,#color_tools #tool_stroke .color_block:hover{border-color:#fff} -#color_tools #tool_fill .color_block>div{position:absolute;top:0;left:0} -.touch #color_tools #tool_fill .color_block>div{position:relative} -#color_tools #tool_fill .color_block #fill_bg,#color_tools #tool_stroke .color_block #stroke_bg{position:absolute;top:1px;left:1px;bottom:1px;right:1px} -.touch #color_tools #tool_fill .color_block #fill_bg,.touch #color_tools #tool_stroke .color_block #stroke_bg{width:36px;height:36px;right:auto;bottom:auto} -.touch #tool_stroke{position:relative;top:0;left:0;z-index:0} -#stroke_color:after{content:'';position:absolute;display:block;width:8px;height:8px;left:8px;top:8px;background:#ccc;box-shadow:0 0 0 1px #000} -.touch #stroke_color:after{height:14px;left:10px;position:absolute;top:10px;width:14px} -#color_tools #tool_switch{cursor:pointer;opacity:.7;width:11px;height:11px;background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQA2LzE0LzEyP6j5+gAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAB4SURBVBiVjZHRCYUwDEVvxIF0kZKN7EjiIrrReR/PSNSKXiikcE5JUtMeADMzXQIcdRfgFWqlyyB7ap1wL+0HAnIv1DqRJUBxTkLUWXIvh9AHkIeb58UkIUnDMH4ZR0otCfhv4ynbtp7ut722ZniFG8L9xx4Ek6QfN9huARmYwR0AAAAASUVORK5CYII=) top left no-repeat;position:absolute;top:-2px;left:28px} -#color_tools #cross:hover{opacity:1} -#color_tools #tool_stroke:hover #stroke_color:after{background:#fff} -#color_tools #tool_stroke .color_block{width:24px;height:24px;overflow:hidden;border:solid #ccc 1px} -.touch #color_tools #tool_stroke .color_block{width:36px;height:36px} -#color_tools #tool_stroke .color_block>div{position:absolute;bottom:0;right:0} -.touch #color_tools #tool_stroke .color_block>div{position:relative} -#color_tools .icon_label{padding:0;width:24px;height:100%;cursor:pointer;position:absolute} -#linkLabel>svg{height:20px;padding-top:4px} -div#workarea{display:inline-table-cell;position:absolute;top:30px;left:50px;bottom:40px;right:175px;background-color:#444;overflow:auto;text-align:center;-webkit-transition:-webkit-transform 500ms cubic-bezier(0.13,0.66,0.24,0.92);-moz-transition:-moz-transform 500ms cubic-bezier(0.13,0.66,0.24,0.92);-o-transition:-o-transform 500ms cubic-bezier(0.13,0.66,0.24,0.92);-ms-transition:-ms-transform 500ms cubic-bezier(0.13,0.66,0.24,0.92);transition:transform 500ms cubic-bezier(0.13,0.66,0.24,0.92)} -.touch div#workarea{top:40px} -.menu .menu_list{display:none;position:absolute} -.tool_button,.tool_button_current,.tool_button_pressed{cursor:pointer} -.tool_button:hover,.push_button:hover,.buttonup:hover,.buttondown,.tool_button_current,.push_button_pressed{background-color:#fff} -.tool_button.disabled,.tool_button.disabled:hover{opacity:.3;background-color:#aaa} -#tools_left .tool_button{background:#2f2f2c;position:relative} -#tools_left .tool_button.loaded{background:#ccc} -#tools_left .tool_button.loaded:hover{background:#fff} -#tools_left .tool_button:after,#tools_left .tool_button_current:after{position:absolute;content:'';border:solid #2f2f2c 2px;top:-1px;left:-1px;width:26px;height:26px;z-index:0} -#tools_left .tool_button_current{background-color:#0cf} -#main_icon span{position:absolute;width:100%;height:100%;display:block;z-index:2} -#tools_top{position:absolute;width:160px;height:100%;background:#2f2f2c;right:0;top:20px;border-bottom:0;overflow:visible;padding:0 0 0 15px} -.touch #tools_top{top:30px} -label{display:block;color:#999} -div#font-selector{width:140px;height:300px;overflow:auto;margin:0 auto;position:absolute;top:27px;right:0;border:1px solid black;padding:10px;display:none;background-color:white;z-index:10;border-radius:3px;box-shadow:0 5px 10px rgba(0,0,0,0.7)} -div#font-selector img{width:100%} -div#font-selector .font-item{border-bottom:solid #ddd 1px;padding:5px 10px;margin:0 -10px} -div#font-selector .font-item:hover{background-color:#eee} -#tools_top #marker_panel *{float:left} -#tools_top #marker_panel h4{float:none} -#tools_top #marker_panel .dropdown .icon_label{width:36px;height:20px;margin-top:2px;border:solid #3f3f3c 1px;text-align:center} -#tools_top #marker_panel .dropdown button{margin-top:2px} -#tools_top #marker_panel #marker_panel_title{float:none;color:#fff;margin-bottom:3px} -#tools_top #marker_panel .dropdown .icon_label img{float:none} -#color_picker input[type=text],#color_picker input[type=number]{width:30px;background:#fff} -.dropdown_set input[type=text],.dropdown_set input[type=number]{width:50px} -input[type=text].wide,input[type=number].wide{width:110px} -input[type=text].tuco,input[type=number].tuco{width:150px} -input[type=submit],input[type=button],button{background:#4f80ff;color:#fff;border-radius:3px;padding:7px 17px;border:0;line-height:140%;font-size:14px;font-weight:bold;font-family:sans-serif} -input[type=submit]:hover,button:hover{box-shadow:inset 0 3px 10px rgba(255,255,255,0.1),inset 0 -3px 10px rgba(0,0,0,0.2)} -input[type=submit]:hover,button:hover{background:#2f84c1} -input[type=submit]:active,button:active{box-shadow:inset 0 2px 2px rgba(0,0,0,0.2);border-bottom:solid rgba(255,255,255,0.1) 1px} -#tools_left{position:absolute;border-right:0;width:50px;top:30px;bottom:0;left:0;background:#2f2f2c;z-index:4} -#workarea.wireframe #svgcontent *{fill:none;stroke:#000;stroke-width:1px;stroke-opacity:1.0;stroke-dasharray:0;opacity:1;pointer-events:stroke;vector-effect:non-scaling-stroke;filter:none} -#workarea.wireframe #svgcontent text{fill:#000;stroke:none} -#workarea.wireframe #canvasBackground>rect{fill:#FFF!important} -#workarea #canvasBackground>rect{stroke:transparent!important} -.context_panel{display:none} -#canvas_panel{display:block} -#multiselected_panel .selected_tool{vertical-align:12px} -#cur_context_panel{position:absolute;top:47px;left:68px;line-height:22px;overflow:auto;border-bottom:0;border-right:0;padding-left:5px;font-size:12px;background:black;color:#999;opacity:.5;padding:0 10px;border-radius:0 10px 10px 0} -#cur_context_panel a{float:none;text-decoration:none;color:#fff} -#cur_context_panel a:hover{text-decoration:underline} -#tools_left .tool_button,#tools_left .tool_button_current{position:relative;z-index:11} -.flyout_arrow_horiz{position:absolute;bottom:-1px;right:0;z-index:10} -.dropdown{position:relative;float:left} -.dropdown button{width:21px;height:22px;padding:0 3px 0 3px;border:0;background-color:#555;border-radius:0 2px 2px 0;margin-left:-1px;position:relative} -.dropdown button:hover{background-color:#666} -.dropdown button:after{content:'';position:absolute;border:solid transparent 4px;border-top-color:#999;top:9px;left:6px} -.dropdown button.down{border-left:1px solid #808080;border-top:1px solid #808080;border-right:1px solid #fff;border-bottom:1px solid #fff;background-color:#b0b0b0} -.dropdown ul{list-style:none;position:absolute;margin:0;padding:0;left:-80px;top:26px;z-index:4;display:none} -.dropup ul{top:auto;bottom:26px;border-radius:3px;box-shadow:0 5px 10px #000} -.dropup ul:after{content:'';display:block;position:absolute;bottom:-10px;right:50%;top:auto;width:0;height:0;border:solid transparent 5px;border-top-color:#fff} -.dropdown li{display:block;width:120px;padding:5px 10px;color:#333;background:#fff;margin:0;line-height:16px} -.dropdown li:first-child{border-radius:3px 3px 0 0} -.dropdown li:last-child{border-radius:0 0 3px 3px} -.dropdown li:hover{background-color:#ddd;color:#000} -.dropdown li.special{padding:10px;background:white;border:0;box-shadow:0 3px 10px black;border-radius:3px!important} -.dropdown li.special:after{content:'';display:block;position:absolute;top:-10px;right:50%;border:solid transparent 5px;border-bottom-color:#fff} -.dropdown li.special.down:after{bottom:-10px;right:50%;top:auto;border:solid transparent 5px;border-top-color:#fff} -.tool_button,.push_button,.tool_button_current,.push_button_pressed{height:27px;width:27px;border:solid #2f2f2c 8px;border-left-width:13px;margin:0;background-color:#ddd;cursor:pointer} -#main_menu li#tool_open,#main_menu li#tool_import{position:relative;overflow:hidden} -#tool_image{overflow:hidden} -#tool_open input,#tool_import input,#tool_import_bitmap input{position:absolute;opacity:0;font-size:10em;top:-5px;right:-5px;margin:0;cursor:pointer} -.disabled{opacity:.5;cursor:default} -.width_label{padding-right:5px} -#text{position:absolute;left:-9999px} -#tool_bold span,#tool_italic span{position:absolute;width:100%;height:100%;top:0;left:0;background:#ccc;opacity:0} -#url_notice{padding-top:4px;display:none} -#color_picker{position:absolute;display:none;background:#fff;height:350px;border-radius:3px;z-index:5;box-shadow:0 5px 10px #000;width:530px} -.tools_flyout{position:absolute;display:none;cursor:pointer;width:385px;z-index:10;left:47px!important;height:324px;background:#fff;border-radius:5px;box-shadow:0 5px 10px rgba(0,0,0,0.5)} -.tools_flyout_v{position:absolute;display:none;cursor:pointer;width:30px} -.tools_flyout .tool_button{float:left;background-color:#fff;height:24px;width:24px} -#tools_bottom{position:absolute;left:50px;right:0;bottom:0;height:40px;overflow:visible;background:#2f2f2c} -#tools_bottom_1{width:115px;float:left} -#tools_bottom_2{position:relative;float:left;margin-top:5px} -#tools_bottom input[type=text]{width:3.2em} -#tools_top h4{color:#fff;font-weight:normal;margin:0;padding:10px 0 5px 0} -#tools_top .dropdown .icon_label{border:1px solid transparent;height:auto} -#tools_top.multiselected #align_tools{display:none} -#tools_top.multiselected #multiselected_panel{display:block!important} -#tools_top.multiselected #multiselected_panel .hidable{display:none} -.draginput_cell{float:left;height:26px;height:26px;border:solid #3f3f3c 10px;outline:solid #2f2f2c 1px;background:#ddd;cursor:pointer;position:relative} -.draginput_cell:hover{background:#fff} -.draginput_cell:after{content:'';position:absolute;top:0;left:0;border:solid #3f3f3c 1px;height:26px;width:26px;z-index:0} -.align_buttons .draginput_cell:nth-child(1){border-radius:3px 0 0 0} -.align_buttons .draginput_cell:nth-child(3){border-radius:0 3px 0 0} -.align_buttons .draginput_cell:nth-child(4){border-radius:0 0 0 3px} -.align_buttons .draginput_cell:nth-child(6){border-radius:0 0 3px 0} -.align_buttons .push_button{display:block;float:left} -#option_lists ul{display:none;position:absolute;height:auto;z-index:3;margin:0;list-style:none;padding-left:0} -#option_lists .optcols2{width:70px;margin-left:-15px} -#option_lists .optcols3{width:192px;margin-left:-105px;margin-top:-25px;background:#fff;padding:5px;box-shadow:0 5px 10px #000;border-radius:3px} -#option_lists .optcols3:after{content:'';display:block;position:absolute;top:-10px;right:70px;border:solid transparent 5px;border-bottom-color:#fff} -#option_lists .tool_button,#option_lists .push_button,#option_lists .tool_button_current,#option_lists .push_button_pressed{border:0;background:transparent} -#option_lists .tool_button:hover{background:#ddd} -#option_lists ul li.current{background-color:#f4e284} -#option_lists .optcols4{width:130px;margin-left:-44px} -#option_lists ul[class^=optcols] li{float:left} -ul li.current{background-color:#f4e284} -#option_lists ul li{margin:0;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0} -#copyright{text-align:right;padding-right:.3em} -#svg_source_editor{display:none} -#svg_source_editor #svg_source_overlay{position:absolute;top:0;right:0;left:0;bottom:0;background-color:black;opacity:.6;z-index:5} -#svg_source_editor #svg_source_container{position:absolute;top:30px;left:100px;right:100px;bottom:30px;background-color:#fff;border-radius:3px;opacity:1.0;text-align:center;z-index:6;padding:15px 0} -#svg_source_editor form{position:absolute;display:block;top:15px;bottom:55px;left:15px;right:12px;padding:5px;font-size:12px} -#svg_source_textarea{width:100%;height:100%;line-height:140%;font-family:'Lucida Sans','Lucida Grande','Lucida Sans Unicode',sans-serif;font-size:12px} -#svg_source_editor #tool_source_back{position:absolute;bottom:45px;left:15px;right:15px} -#svg_source_editor #tool_source_back #tool_source_save{display:block;position:absolute;right:0} -#svg_source_editor #tool_source_back #tool_source_cancel{display:block;position:absolute;left:0} -button.cancel,input.Cancel,input.cancel,input.jGraduate_Cancel,button.cancel{-webkit-appearance:none;background-color:#999;box-shadow:0 0 1px rgba(0,0,0,0.5);margin:0} -#shape_buttons{overflow:auto;top:0;bottom:0;left:110px;right:0;position:absolute;vertical-align:top} -#shape_cats{min-width:110px;display:block;position:absolute;left:0;top:0;height:300px;background:#eee;border-radius:3px 0 0 3px;z-index:2} -#shape_cats>div{line-height:1em;padding:0 .5em;border-bottom:1px solid #ddd;background:#e8e8e8;color:#444;height:26px;line-height:26px} -#shape_cats>div:first-child{border-radius:3px 0 0 0} -#shape_cats>div:last-child{border-radius:0 0 0 3px} -#shape_cats div:hover{background:#efefef;color:#000} -#shape_cats div.current{font-weight:bold;background:#3f3f3c;color:#fff;position:relative} -#shape_cats div.current:after{content:'';position:absolute;right:-26px;top:0;border:solid transparent 13px;border-left-color:#3f3f3c} -.toolbar_button button .svg_icon{display:none} -#dialog_box{display:none} -#dialog_box_overlay{background:black;opacity:.5;height:100%;left:0;position:absolute;top:0;width:100%;z-index:6} -#dialog_content{height:95px;margin:10px 10px 5px 10px;overflow:auto;text-align:left;font-size:13px} -#dialog_buttons input:last-child{background:#999!important;position:absolute;left:10px;bottom:10px} -#dialog_buttons input:first-child{position:absolute;right:10px;bottom:10px} -#dialog_content.prompt{height:75px} -#dialog_content p{margin:10px;line-height:1.3em} -#dialog_container{position:absolute;left:50%;top:50%;width:300px;margin-left:-150px;height:150px;margin-top:-80px;position:fixed;z-index:50001;background:#fff} -#dialog_container,#dialog_content{border-radius:3px} -#dialog_buttons input[type=text]{width:90%;display:block;margin:0 0 5px 11px} -#dialog_buttons input[type=button]{margin:0 1em} -.invisible{visibility:none} -.ui-slider{position:relative;text-align:left} -.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default} -.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0} -.ui-slider-horizontal{height:.8em} -.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em} -.ui-slider-horizontal .ui-slider-range{top:0;height:100%} -.ui-slider-horizontal .ui-slider-range-min{left:0} -.ui-slider-horizontal .ui-slider-range-max{right:0} -.ui-slider-vertical{width:.8em;height:100px} -.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em} -.ui-slider-vertical .ui-slider-range{left:0;width:100%} -.ui-slider-vertical .ui-slider-range-min{bottom:0} -.ui-slider-vertical .ui-slider-range-max{top:0} -.ui-slider{background:#3f3f3c;border-radius:10px} -.ui-slider-handle{box-shadow:0 3px 3px rgba(0,0,0,0.3);border-radius:30px;background:#fff;background-image:-ms-linear-gradient(top,#ccc 0,#fff 100%);background-image:-moz-linear-gradient(top,#ccc 0,#fff 100%);background-image:-o-linear-gradient(top,#ccc 0,#fff 100%);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ccc),color-stop(1,#fff));background-image:-webkit-linear-gradient(top,#ccc 0,#fff 100%);background-image:linear-gradient(top,#ccc 0,#fff 100%)} -.ui-slider-handle:focus{outline:0} -#shape_buttons{background:#fff;border-radius:0 3px 3px 0;padding:10px} -.tools_flyout .tool_button,.tools_flyout .tool_flyout{background:#fff;width:40px;height:40px;margin:5px;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;border-width:0} -.contextMenu{position:absolute;z-index:99999;border:solid 1px rgba(0,0,0,.33);background:rgba(255,255,255,.95);padding:5px 0;margin:0;display:none;font:12px/15px 'Lucida Sans','Lucida Grande',Helvetica,Verdana,sans-serif;border-radius:5px;-moz-border-radius:5px;-moz-box-shadow:2px 5px 10px rgba(0,0,0,.3);-webkit-box-shadow:2px 5px 10px rgba(0,0,0,.3);box-shadow:2px 5px 10px rgba(0,0,0,.3)} -.touch .contextMenu{border:solid 5px rgba(0,0,0,.7);padding:0;margin:0 0 0 20px;font:18px/24px sans-serif;border-radius:5px;-webkit-box-shadow:2px 5px 20px 3px #000;box-shadow:2px 5px 20px rgba(0,0,0,0.5)} -.touch .contextMenu:after{content:'';width:0;height:0;border:solid transparent 10px;border-right-color:rgba(0,0,0,.7);position:absolute;top:50%;left:-25px;margin-top:-10px;z-index:1000} -.contextMenu LI{list-style:none;padding:0;margin:0} -.contextMenu .shortcut{width:115px;text-align:right;float:right} -.touch .contextMenu .shortcut{display:none} -.touch .shortcut{display:none} -.contextMenu A{-moz-user-select:none;-webkit-user-select:none;color:#222;text-decoration:none;display:block;line-height:20px;height:20px;background-position:6px center;background-repeat:no-repeat;outline:0;padding:0 15px 1px 20px} -.touch .contextMenu A{padding:0 15px;border-bottom:#;font-weight:bold;border-top:solid 1px #e3e3e3;height:40px;line-height:40px;min-width:200px} -.contextMenu LI.hover A{background-color:#2e5dea;color:white;cursor:default} -.contextMenu LI.disabled A{color:#999} -.touch .contextMenu LI.disabled A{display:none} -.contextMenu LI.hover.disabled A{background-color:transparent} -.contextMenu LI.separator{border-top:solid 1px #e3e3e3;padding-top:5px;margin-top:5px} -.touch .contextMenu LI.separator{border-top:0;margin:0;padding:0} -#menu{display:none;position:absolute;top:0;left:0;right:0;height:30px;background:#000;z-index:10;color:#fff} -#workarea.rect,#workarea.line,#workarea.ellipse,#workarea.path,#workarea.shapelib{cursor:crosshair} -#workarea.text{cursor:text} -#workarea.eyedropper{cursor:url(../images/eyedropper.png) 0 16,crosshair} -#workarea.fhpath{cursor:url(../images/pencil_cursor.png) 0 16,crosshair} -#workarea.rotate *{cursor:url(../images/rotate.png) 12 12,auto} -#workarea.select text,#workarea.multiselect text{cursor:default} -#workarea.n-resize *{cursor:n-resize!important} -#workarea.e-resize *{cursor:e-resize!important} -#workarea.w-resize *{cursor:w-resize!important} -#workarea.s-resize *{cursor:s-resize!important} -#workarea.ne-resize *{cursor:ne-resize!important} -#workarea.se-resize *{cursor:se-resize!important} -#workarea.nw-resize *{cursor:nw-resize!important} -#workarea.sw-resize *{cursor:sw-resize!important} -#workarea.copy{cursor:copy} -#workarea.zoom{cursor:crosshair;cursor:-moz-zoom-in;cursor:-webkit-zoom-in} -#workarea.zoom.out{cursor:crosshair;cursor:-moz-zoom-out;cursor:-webkit-zoom-out} -#selectorRubberBand{shape-rendering:crispEdges} -.clearfix:before,.clearfix:after{content:"";display:table} -.clearfix:after{clear:both} -.clearfix{*zoom:1} -#group_title{display:none} -#base_unit_container{display:none;position:absolute;z-index:20} -.draginput{background:#3f3f3c;border-radius:3px;-webkit-font-smoothing:antialiased;width:70px;height:70px;display:block;position:relative;float:left;margin:0 5px 5px 0} -.draginput .caret{border:solid transparent 5px;border-top-color:#999;position:absolute;width:0;height:0;right:5px;margin-top:-2px;top:50%} -.draginput label{margin:28px 10px 0 5px;font-size:14px;color:white;font-weight:bold;font-family:sans-serif} -.draginput label#resolution_label,.draginput label#seg_type_label{font:bold 12px/110% sans-serif;position:absolute;left:auto;right:10px;z-index:0;text-align:right} -.draginput label#seg_type_label{margin-top:40px} -.draginput label#seg_type_label .caret{top:66%} -.draginput label#resolution_label .pull{position:relative;left:-15px} -.draginput label#resolution_label span{right:-13px;left:auto;font-size:16px;top:2px;font-weight:bold;color:white} -.touch .draginput.active:after{content:attr(data-value);display:block;position:absolute;background:#fff;font-size:16px;top:0;width:30px;left:-50px;padding:0 5px;color:#333;z-index:10;font-family:sans-serif;font-weight:bold;text-align:right;padding-right:10px;height:20px;line-height:20px;letter-spacing:-1px} -.touch .draginput.active:before{content:'';height:0;width:0;position:absolute;top:5px;left:-5px;border:solid transparent 5px;border-left-color:#fff} -.draginput input{border:0;background:transparent;font:24px/normal sans-serif;text-align:center;color:#4f80ff;padding:30px 0 16px;width:100%;height:24px;position:relative;z-index:2} -.draginput.twocol{width:145px} -#tool_font_family .caret{right:40px;top:55%} -#tool_font_family select{width:110px} -#tool_bold,#tool_italic{font:bold 20px/35px serif;text-align:center;position:absolute;padding:0;color:#ccc;background:transparent;border:0;width:35px;height:35px;margin:0;top:0;right:0} -#tool_italic{border-top:solid #2f2f2c 2px;top:35px;font-weight:bold;font-style:italic;font-size:24px} -#tool_bold:hover,#tool_italic:hover{color:#fff} -#tool_bold.active,#tool_italic.active{color:#50a0ff} -#preview_font{font-size:20px;color:#fff;height:70px;line-height:75px;padding:0 0 0 10px;white-space:nowrap;width:100px;overflow:hidden;border-right:solid #2f2f2c 2px;position:relative} -#preview_font:after{content:'';position:absolute;right:0;top:3px;bottom:3px;width:15px;border-right:solid #3f3f3c 10px;background:transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZzU4MCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjAlIj48c3RvcCBzdG9wLWNvbG9yPSIjM2YzZjNjIiBzdG9wLW9wYWNpdHk9IjAiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiMzZjNmM2MiIG9mZnNldD0iMC43Ii8+PC9saW5lYXJHcmFkaWVudD48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2c1ODApIiAvPjwvc3ZnPg==)} -.draginput input,.draginput input:hover,.draginput input:active{cursor:url(../images/drag.png),move;cursor:-webkit-grab;cursor:-moz-grab} -.draginput input[type="checkbox"],.draginput input[type="checkbox"]:hover,.draginput input[type="checkbox"]:active{cursor:pointer} -.draginput.checkbox{cursor:pointer} -.draginput.active input,.draginput.active input:hover,.draginput.active input:active{cursor:url(../images/dragging.png),move;cursor:-webkit-grabbing;cursor:-moz-grabbing} -.draginput span{font:11px/130% sans-serif;color:#ccc;display:block;position:absolute;top:5px;left:5px;text-align:left} -.draginput.error{background:#900} -.draginput.error input{color:#fff} -.draginput.stroke_tool{text-align:center} -.draginput select{-webkit-appearance:none;opacity:0;display:block;position:absolute;height:100%;width:100%;margin:0;z-index:1;top:0;left:0} -.draginput_cursor{position:absolute;top:50%;width:100%;border-top:solid rgba(50,100,200,0.25) 3px;margin-top:-2px;z-index:0} -.draginput input[readonly=readonly]{-webkit-appearance:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} -.draginput input:focus{background:#50a0ff;color:#fff;outline:0;box-shadow:0 0 5px 2px #50a0ff} -.draginput input:focus+span{z-index:10;color:#fff} -.draginput .push_bottom{bottom:0;position:absolute} -#zoom_label{height:20px;background:transparent;cursor:default!important;width:auto;padding:0 10px;margin:0} -#zoom_panel{padding:9px 0;right:175px;position:absolute} -#zoom_label img,#zoom_label svg{width:16px;height:16px} -#logo svg{pointer-events:none} -#zoomLabel{width:16px;height:16px;cursor:pointer;background:#ccc} -#zoomLabel:after{content:'';position:absolute;border-left:solid #2f2f2c 1px;left:0;height:16px} -#zoom_label input{color:#ccc;font-size:13px;height:auto;width:auto;padding:0;cursor:default;position:static} -#zoom_label span{top:0;left:0} -body.dragging *{cursor:url(../images/dragging.png),move;cursor:-webkit-grabbing;cursor:-moz-grabbing} -body.drag *{cursor:url(../images/dragging.png),move;cursor:-webkit-grabbing;cursor:-moz-grabbing} -input[readonly=readonly]:focus{box-shadow:none} -#color_canvas_tools,#fill_bg,#stroke_bg{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMAQMAAABsu86kAAAAA3NCSVQICAjb4U/gAAAABlBMVEXu7u7///8o06qaAAAACXBIWXMAAAsSAAALEgHS3X78AAAAFXRFWHRDcmVhdGlvbiBUaW1lADcvMjIvMTL7FNdCAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M1cbXjNgAAABFJREFUCJljYP7AgIb+MKAhAM8/C5vWL6zSAAAAAElFTkSuQmCC) top left repeat} -#color_canvas_tools{width:60px;height:40px;margin:23px 5px 5px 5px;position:relative;overflow:hidden} -#color_canvas_tools{display:block} -#tool_angle_indicator{width:50px;height:50px;border-radius:50px;background:rgba(255,255,255,0.05);position:absolute;bottom:2px;left:10px} -#tool_angle_indicator_cursor{width:4px;height:25px;border-top:solid #50a0ff 3px;position:absolute;margin:0 0 0 23px;-webkit-transform-origin:50% 0;-moz-transform-origin:50% 0;-o-transform-origin:50% 0;-ms-transform-origin:50% 0;transform-origin:50% 0} -#stroke_style_label{font-size:30px;margin-top:33px;letter-spacing:-1px} -.stroke_tool .caret{top:60%} -#tool_align_relative{position:absolute;top:-5px;left:0;right:20px;display:block} -#tool_align_relative select{width:100%;display:block} \ No newline at end of file diff --git a/editor/embedapi.html b/editor/embedapi.html deleted file mode 100644 index 889af20..0000000 --- a/editor/embedapi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - -
    - - - - diff --git a/editor/extensions/closepath_icons.svg b/editor/extensions/closepath_icons.svg deleted file mode 100644 index 7294f5e..0000000 --- a/editor/extensions/closepath_icons.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/editor/extensions/ext-arrows.js b/editor/extensions/ext-arrows.js deleted file mode 100644 index 4f45192..0000000 --- a/editor/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -methodDraw.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/editor/extensions/ext-closepath.js b/editor/extensions/ext-closepath.js deleted file mode 100644 index dc73f1a..0000000 --- a/editor/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -methodDraw.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/editor/extensions/ext-connector.js b/editor/extensions/ext-connector.js deleted file mode 100644 index ffd54df..0000000 --- a/editor/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -methodDraw.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = methodDraw.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $('').appendTo("head");Db()}},Fb=function(){Da(a("#view_menu"));var f=!a("#tool_snap").hasClass("push_button_pressed");f?a("#tool_snap").addClass("push_button_pressed"):a("#tool_snap").removeClass("push_button_pressed");u.gridSnapping=f},Eb=function(){window.self!=window.top&&top.exit_fullscreen()},Gb=function(){Da(a("#view_menu")); -if(a("#tool_rulers").hasClass("push_button_pressed")){a("#tool_rulers").removeClass("push_button_pressed");a("#show_rulers").attr("checked",false);u.showRulers=false}else{a("#tool_rulers").addClass("push_button_pressed");a("#show_rulers").attr("checked",true);u.showRulers=true}a("#rulers").toggle(!!u.showRulers)},Db=function(){if(!g){var f="#workarea.wireframe #svgcontent * { stroke-width: "+1/e.getZoom()+"px; }";a("#wireframe_rules").text(L.hasClass("wireframe")?f:"")}},yb=function(f,s){if(!ga){Da(a("#view_menu")); -ga=true;a("#save_output_btns").toggle(!!s);a("#tool_source_back").toggle(!s);var o=S=e.getSvgString();a("#svg_source_textarea").val(o);a("#svg_source_editor").fadeIn();a("#svg_source_textarea").focus().select()}},Ab=function(){if(ga){if(e.setSvgString(a("#svg_source_textarea").val())){e.clearSelection();sb();Ca();ua()}else a.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?",function(f){if(!f)return false;e.clearSelection();sb();Ca();ua()});M()}},Jb=c.setIcon= -function(f,s){var o=typeof s==="string"?a.getSvgIcon(s,true):s.clone();o?a(f).find("img").replaceWith(o):console.log("NOTE: Icon image missing: "+s)},wb;wb=function(){var f=/^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,s=document.getElementsByTagName("script")[0],o;for(o in s.style)if(f.test(o))return o.match(f)[0];if("WebkitOpacity"in s.style)return"Webkit";if("KhtmlOpacity"in s.style)return"Khtml";return""}();var hb=function(f,s){wb.toLowerCase();var o=["top","left","bottom","right"];f.each(function(){for(var p= -a(this),B=p.outerWidth()*(s-1),F=p.outerHeight()*(s-1),I=0;I<4;I++){var J=o[I],O=p.data("orig_margin-"+J);if(O==null){O=parseInt(p.css("margin-"+J));p.data("orig_margin-"+J,O)}O=O*s;if(J==="right")O+=B;else if(J==="bottom")O+=F;p.css("margin-"+J,O)}})},Lb=c.setIconSize=function(f,s){if(!(f==b.size&&!s)){var o=a("#tools_top .toolset, #editor_panel > *, #history_panel > *, #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *, #g_panel > *, #tool_font_size > *, .tools_flyout"), -p=1;p=typeof f=="number"?f:{s:0.75,m:1,l:1.25,xl:1.5}[f];c.tool_scale=H=p;ca();var B=o.parents(":hidden");B.css("visibility","hidden").show();hb(o,p);B.css("visibility","visible").hide();o=a("#tool_size_rules");if(o.length)o.empty();else o=a('').appendTo("head");if(f!="m"){var F="";a.each(cssResizeRules,function(I,J){I="#svg_editor "+I.replace(/,/g,", #svg_editor");F+=I+"{";a.each(J,function(O,W){if(typeof W==="number")var aa=W*p+"px";else if(W[f]||W.all)aa=W[f]|| -W.all;F+=O+":"+aa+";"});F+="}"});B="-"+wb.toLowerCase()+"-";F+="#tools_top .toolset, #editor_panel > *, #history_panel > *, #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *, #g_panel > *, #tool_font_size > *, .tools_flyout{"+B+"transform: scale("+p+");} #svg_editor div.toolset .toolset {"+B+"transform: scale(1); margin: 1px !important;} #svg_editor .ui-slider {"+B+"transform: scale("+1/p+");}";o.text(F)}ca()}},Hb=function(){a("#dialog_box").hide();if(ga){if(ga)S!== -a("#svg_source_textarea").val()?a.confirm("Ignore changes made to SVG source?",function(f){f&&sb()}):sb();$a()}else Z&&e.leaveContext()},sb=function(){a("#svg_source_editor").hide();ga=false;a("#svg_source_textarea").blur()};a(window).width();a(window).height();var $a=a.noop;a(window).resize(function(){A()});(function(){L.scroll(function(){if(a("#ruler_x").length!=0)a("#ruler_x")[0].scrollLeft=L[0].scrollLeft;if(a("#ruler_y").length!=0)a("#ruler_y")[0].scrollTop=L[0].scrollTop})})();a("#url_notice").click(function(){a.alert(this.title)}); -a("#change_image_url").click(function(){var f=e.getHref(T);f=f.indexOf("data:")===0?"":f;a.prompt("Enter the new image URL",f,function(s){s&&Ia(s)})});var xb=function(f){var s=f[0].id=="stroke_color"?"stroke":"fill",o=f[0].id=="canvas_color";if(o)s="canvas";var p=c.paintBox[s].paint;f=s=="stroke"?"Pick a Stroke Paint and Opacity":"Pick a Fill Paint and Opacity";o=o?{right:175,top:50}:{left:50,bottom:50};a("#color_picker").draggable({cancel:".jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker", -containment:"window"}).removeAttr("style").css(o).jGraduate({paint:p,window:{pickerTitle:f},images:{clientPath:u.jGraduatePath},newstop:"inverse"},function(B){p=new a.jGraduate.Paint(B);c.paintBox[s].setPaint(p);e.setPaint(s,p);a("#color_picker").hide()},function(){a("#color_picker").hide()})};d=function(f,s){var o=document.getElementById("canvas_background"),p={color:"fff",opacity:1};if(s=="stroke")p=u.initStroke;if(s=="fill")p=u.initFill;if(s=="canvas"&&o)if(o=o.getAttribute("fill").match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/))p= -{color:("0"+parseInt(o[1],10).toString(16)).slice(-2)+("0"+parseInt(o[2],10).toString(16)).slice(-2)+("0"+parseInt(o[3],10).toString(16)).slice(-2),opacity:1};o=(new DOMParser).parseFromString(' ',"text/xml").documentElement;o=a(f)[0].appendChild(document.importNode(o,true));s==="canvas"?o.setAttribute("width",60.5): -o.setAttribute("width","100%");this.rect=o.firstChild;this.defs=o.getElementsByTagName("defs")[0];this.grad=this.defs.firstChild;this.paint=new a.jGraduate.Paint({solidColor:p.color});this.type=s;this.setPaint=function(B,F){this.paint=B;var I="none",J=B.type,O=B.alpha/100;switch(J){case "solidColor":I=B[J]=="none"||B[J]=="one"?"none":"#"+B[J];break;case "linearGradient":case "radialGradient":this.defs.removeChild(this.grad);this.grad=this.defs.appendChild(B[J]);I="url(#"+(this.grad.id="gradbox_"+ -this.type)+")"}this.rect.setAttribute("fill",I);this.rect.setAttribute("opacity",O);if(this.type=="canvas")if(J=document.getElementById("canvas_background")){ma=e.getResolution();J.setAttribute("x",-1);J.setAttribute("y",-1);J.setAttribute("width",ma.w+2);J.setAttribute("height",ma.h+2);I.indexOf("url")==-1&&J.setAttribute("fill",I)}else Ha(I);if(F){e.setColor(this.type,I,true);e.setPaintOpacity(this.type,O,true)}};this.update=function(B){if(T){var F=this.type;switch(T.tagName){case "use":case "image":case "foreignObject":return; -case "g":case "a":for(var I=null,J=T.getElementsByTagName("*"),O=0,W=J.length;O=1){O=e.getResolution();a("#canvas_width").val(O.w.toFixed());a("#canvas_height").val(O.h.toFixed());a("#resolution_label").html("
    "+O.w+"\u00d7
    "+O.h+"
    ")}else requestAnimationFrame(J)};J()}else{a("#resolution_label").html("Custom");f.removeAttribute("readonly");f.focus();f.select();if(f.value=="fit"){f.value=100;s.value=100}}});a("#zoom").change(function(){La(this)});a("input,select").attr("autocomplete","off");var m=function(){var f= -[{sel:"#tool_select",fn:ub,evt:"click",key:["V",true]},{sel:"#tool_fhpath",fn:nb,evt:"click",key:["Q",true]},{sel:"#tool_line",fn:gb,evt:"click",key:["L",true]},{sel:"#tool_rect",fn:Sa,evt:"click",key:["R",true],icon:"rect"},{sel:"#tool_ellipse",fn:Xa,evt:"mouseup",key:["C",true],icon:"ellipse"},{sel:"#tool_path",fn:xa,evt:"click",key:["P",true]},{sel:"#tool_text",fn:Qa,evt:"click",key:["T",true]},{sel:"#tool_image",fn:ya,evt:"mouseup"},{sel:"#tool_zoom",fn:sa,evt:"mouseup",key:["Z",true]},{sel:"#tool_clear", -fn:ba,evt:"mouseup",key:[z+"N",true]},{sel:"#tool_save",fn:function(){if(ga)Ab();else{Da(a("#file_menu"));e.save({images:b.img_save,round_digits:6})}},evt:"mouseup",key:[z+"S",true]},{sel:"#tool_export",fn:Ra,evt:"mouseup"},{sel:"#tool_open",fn:eb,evt:"mouseup"},{sel:"#tool_import",fn:Wa,evt:"mouseup"},{sel:"#tool_source",fn:yb,evt:"click",key:[z+"U",true]},{sel:"#tool_wireframe",fn:Kb,evt:"click"},{sel:"#tool_snap",fn:Fb,evt:"click"},{sel:"#tool_rulers",fn:Gb,evt:"click"},{sel:"#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel", -fn:Hb,evt:"click",key:["esc",false,false],hidekey:true},{sel:"#tool_source_save",fn:Ab,evt:"click"},{sel:"#tool_delete,#tool_delete_multi",fn:bb,evt:"click",key:["del/backspace",true]},{sel:"#tool_reorient",fn:kb,evt:"click"},{sel:"#tool_node_link",fn:vb,evt:"change"},{sel:"#tool_node_clone",fn:qb,evt:"click"},{sel:"#tool_node_delete",fn:lb,evt:"click"},{sel:"#tool_openclose_path",fn:V,evt:"click"},{sel:"#tool_add_subpath",fn:ha,evt:"click"},{sel:"#tool_move_top",fn:rb,evt:"click",key:z+"shift+up"}, -{sel:"#tool_move_bottom",fn:Ja,evt:"click",key:z+"shift+down"},{sel:"#tool_move_up",fn:Ka,evt:"click",key:[z+"up",true]},{sel:"#tool_move_down",fn:pb,evt:"click",key:[z+"down",true]},{sel:"#tool_topath",fn:ob,evt:"click"},{sel:"#tool_make_link,#tool_make_link_multi",fn:db,evt:"click"},{sel:"#tool_clone,#tool_clone_multi",fn:Cb,evt:"click",key:[z+"D",true]},{sel:"#tool_group",fn:mb,evt:"click",key:[z+"G",true]},{sel:"#tool_ungroup",fn:mb,evt:"click",key:z+"shift+G"},{sel:"#tool_unlink_use",fn:mb,evt:"click"}, -{sel:"[id^=tool_align]",fn:Bb,evt:"click"},{sel:"#tool_undo",fn:Na,evt:"click",key:z+"z"},{sel:"#tool_redo",fn:ib,evt:"click",key:["y",true]},{sel:"#tool_cut",fn:jb,evt:"click",key:[z+"x",true]},{sel:"#tool_copy",fn:Ya,evt:"click",key:z+"c"},{sel:"#tool_paste",fn:Ta,evt:"click",key:z+"v"},{sel:"#tool_switch",fn:ab,evt:"click",key:["x",true]},{sel:"#tool_bold",fn:Ba,evt:"mousedown",key:[z+"B",true]},{sel:"#tool_italic",fn:Pa,evt:"mousedown",key:[z+"I",true]},{sel:"#copy_save_done",fn:Hb,evt:"click"}, -{key:"ctrl+left",fn:function(){P(0,1)}},{key:"ctrl+right",fn:function(){P(1,1)}},{key:"ctrl+shift+left",fn:function(){P(0,5)}},{key:"ctrl+shift+right",fn:function(){P(1,5)}},{key:"shift+O",fn:R},{key:"shift+P",fn:da},{key:[z+"+",true],fn:function(){Ca(2)}},{key:[z+"-",true],fn:function(){Ca(0.5)}},{key:["up",true],fn:function(){Za(0,-1)}},{key:["down",true],fn:function(){Za(0,1)}},{key:["left",true],fn:function(){Za(-1,0)}},{key:["right",true],fn:function(){Za(1,0)}},{key:"shift+up",fn:function(){Za(0, --10)}},{key:"shift+down",fn:function(){Za(0,10)}},{key:"shift+left",fn:function(){Za(-10,0)}},{key:"shift+right",fn:function(){Za(10,0)}},{key:["alt+up",true],fn:function(){e.cloneSelectedElements(0,-1)}},{key:["alt+down",true],fn:function(){e.cloneSelectedElements(0,1)}},{key:["alt+left",true],fn:function(){e.cloneSelectedElements(-1,0)}},{key:["alt+right",true],fn:function(){e.cloneSelectedElements(1,0)}},{key:["alt+shift+up",true],fn:function(){e.cloneSelectedElements(0,-10)}},{key:["alt+shift+down", -true],fn:function(){e.cloneSelectedElements(0,10)}},{key:["alt+shift+left",true],fn:function(){e.cloneSelectedElements(-10,0)}},{key:["alt+shift+right",true],fn:function(){e.cloneSelectedElements(10,0)}},{key:z+"A",fn:function(){e.selectAllInCurrentLayer()}},{key:"I",fn:function(){var o=a(".tool_button_current");if(o.length&&o[0].id!=="tool_eyedropper"){o.removeClass("tool_button_current").addClass("tool_button");a("#tool_eyedropper").addClass("tool_button_current").removeClass("tool_button")}e.setMode("eyedropper")}}, -{key:z+"shift+z",fn:ib},{key:"esc",fn:Eb}],s={"4/Shift+4":"#tools_rect_show","5/Shift+5":"#tools_ellipse_show"};return{setAll:function(){var o={};a.each(f,function(p,B){if(B.sel){var F=a(B.sel);if(F.length==0)return true;if(B.evt){if(svgedit.browser.isTouch()&&B.evt==="click")B.evt="mousedown";F[B.evt](B.fn)}if(B.parent&&a(B.parent+"_show").length!=0){var I=a(B.parent);I.length||(I=Y(B.parent.substr(1)));I.append(F);a.isArray(o[B.parent])||(o[B.parent]=[]);o[B.parent].push(B)}}if(B.key){var J=B.fn, -O=false;if(a.isArray(B.key)){I=B.key[0];if(B.key.length>1)O=B.key[1]}else I=B.key;I+="";svgedit.browser.isMac&&I.indexOf("+")!=-1&&I.split("+")[0]=="ctrl"&&I.replace("ctrl","cmd");a.each(I.split("/"),function(aa,X){a(document).bind("keydown",X,function(ea){J();O&&ea.preventDefault();return false})});if(B.sel&&!B.hidekey&&F.attr("title")){var W=F.attr("title").split("[")[0]+" ("+I+")";s[I]=B.sel;F.parents("#main_menu").length||F.attr("title",W)}}});la(o);a(window).bind("keydown","tab",function(p){if(U=== -"canvas"){p.preventDefault();da()}}).bind("keydown","shift+tab",function(p){if(U==="canvas"){p.preventDefault();R()}});a("#tool_zoom").dblclick(Fa)},setTitles:function(){a.each(s,function(o,p){var B=a(p).parents("#main_menu").length;a(p).each(function(){var F=B?a(this).text().split(" [")[0]:this.title.split(" [")[0],I="";a.each(o.split("/"),function(J,O){var W=O.split("+"),aa="";if(W.length>1){aa=W[0]+"+";O=W[1]}I+=(J?"/":"")+aa+O});if(B)this.lastChild.textContent=F+" ["+I+"]";else this.title=F+" ["+ -I+"]"})})},getButtonData:function(o){var p;a.each(f,function(B,F){if(F.sel===o)p=F});return p}}}();m.setAll();c.ready(function(){var f=u.initTool,s=a("#tools_left, #svg_editor .tools_flyout"),o=s.find("#tool_"+f);f=s.find("#"+f);(o.length?o:f.length?f:a("#tool_select")).click().mouseup();u.wireframe&&a("#tool_wireframe").click();u.showlayers&&toggleSidePanel();a("#rulers").toggle(!!u.showRulers)});a("#canvas_height").dragInput({min:10,max:null,step:10,callback:h,cursor:false,dragAdjust:0.1});a("#canvas_width").dragInput({min:10, -max:null,step:10,callback:h,cursor:false,dragAdjust:0.1});a("#rect_width").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_height").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_cx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_cy").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_rx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false}); -a("#ellipse_ry").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_height").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_cx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_cy").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_r").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_height").dragInput({min:0,max:null,step:1,callback:changeAttribute, -cursor:false});a("#selected_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#selected_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_node_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_node_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_width").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_x1").dragInput({min:null, -max:null,step:1,callback:changeAttribute,cursor:false});a("#line_x2").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_y1").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_y2").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false}); -a("#rect_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#g_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#g_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#text_y").dragInput({min:null,max:null,step:1,callback:changeAttribute, -cursor:false});a("#text_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_rx").dragInput({min:0,max:100,step:1,callback:changeAttribute,cursor:true});a("#stroke_width").dragInput({min:0,max:99,step:1,callback:function(f){var s=f.value;if(s==0&&T&&["line","polyline"].indexOf(T.nodeName)>=0)s=f.value=1;e.setStrokeWidth(s)},cursor:true,smallStep:0.1,start:1.5});a("#angle").dragInput({min:-180, -max:180,step:1,callback:function(f){e.setRotationAngle(f.value,true);rotateCursor(f.value);a("#tool_reorient").toggleClass("disabled",f.value==0)},cursor:false,dragAdjust:0.5});a("#font_size").dragInput({min:1,max:250,step:1,callback:function(f){e.setFontSize(f.value)},cursor:true,stepfunc:function(f,s){var o=f.value-0,p=o+s,B=p>=o;if(s===0)return o;return o>=24?B?Math.round(o*1.1):Math.round(o/1.1):o<=1?B?o*2:o/2:p},dragAdjust:0.15});a("#group_opacity").dragInput({min:0,max:100,step:5,callback:changeAttribute, -cursor:true,start:100});a("#blur").dragInput({min:0,max:10,step:0.1,callback:function(f,s){val=f.value;a("#blur").val(val);s?e.setBlur(val,true):e.setBlurNoUndo(val)},cursor:true,start:0});a("#zoom").val(e.getZoom()*100);a("#workarea").contextMenu({menu:"cmenu_canvas",inSpeed:0},function(f){switch(f){case "delete":bb();break;case "cut":jb();break;case "copy":Ya();break;case "paste":e.pasteElements();break;case "paste_in_place":e.pasteElements("in_place");break;case "group":e.groupSelectedElements(); -break;case "ungroup":e.ungroupSelectedElement();break;case "move_front":rb();break;case "move_up":cb("Up");break;case "move_down":cb("Down");break;case "move_back":Ja();break;default:svgedit.contextmenu&&svgedit.contextmenu.hasCustomHandler(f)&&svgedit.contextmenu.getCustomHandler(f).call()}});a(".contextMenu li").mousedown(function(f){f.preventDefault()});a("#cmenu_canvas li").disableContextMenu();N.enableContextMenuItems("#delete,#cut,#copy");window.onbeforeunload=function(){if(w.getUndoStackSize()=== -0)c.show_save_warning=false;if(!u.no_save_warning&&c.show_save_warning)return"There are unsaved changes."};c.openPrep=function(f){a("#main_menu").hide();w.getUndoStackSize()===0?f(true):a.confirm("Do you want to open a new file?\nThis will also erase your undo history",f)};if(window.FileReader){d=function(f){f.stopPropagation();f.preventDefault();a("#workarea").removeAttr("style");a("#main_menu").hide();var s=null;if(s=f.type=="drop"?f.dataTransfer.files[0]:this.files[0])if(s.type.indexOf("image")!= --1)if(s.type.indexOf("svg")!=-1){f=new FileReader;f.onloadend=function(o){e.importSvgString(o.target.result,true);e.ungroupSelectedElement();e.ungroupSelectedElement();e.groupSelectedElements();e.alignSelectedElements("m","page");e.alignSelectedElements("c","page")};f.readAsText(s)}else{f=new FileReader;f.onloadend=function(o){insertNewImage=function(I,J){var O=e.addSvgElementFromJson({element:"image",attr:{x:0,y:0,width:I,height:J,id:e.getNextId(),style:"pointer-events:inherit"}});e.setHref(O,o.target.result); -e.selectOnly([O]);e.alignSelectedElements("m","page");e.alignSelectedElements("c","page");Ea()};var p=100,B=100,F=new Image;F.src=o.target.result;document.body.appendChild(F);F.onload=function(){p=F.offsetWidth;B=F.offsetHeight;insertNewImage(p,B);document.body.removeChild(F)}};f.readAsDataURL(s)}};L=a("#workarea");L[0].addEventListener("dragenter",function(f){f.stopPropagation();f.preventDefault();L.css({"-webkit-transform":"scale3d(1.1,1.1,1)","-moz-transform":"scale3d(1.1,1.1,1)","-o-transform":"scale(1.1)", -"-ms-transform":"scale3d(1.1,1.1,1)",transform:"scale3d(1.1,1.1,1)"})},false);L[0].addEventListener("dragover",function(f){f.stopPropagation();f.preventDefault()},false);L[0].addEventListener("dragleave",function(f){L.removeAttr("style");f.stopPropagation();f.preventDefault()},false);L[0].addEventListener("drop",d,false);var C=a('').change(function(){var f=this;c.openPrep(function(s){if(s){e.clear();if(f.files.length==1){s=new FileReader;s.onloadend=function(o){n(o.target.result); -A()};s.readAsText(f.files[0])}}})});a("#tool_open").show().prepend(C);d=a('').change(d);a("#tool_import").show().prepend(d)}var A=c.updateCanvas=function(f,s){var o=L.width(),p=L.height(),B=o,F=p,I=e.getZoom(),J=L,O=a("#svgcanvas"),W={x:J[0].scrollLeft+B/2,y:J[0].scrollTop+F/2},aa=u.canvas_expansion;o=Math.max(B,e.contentW*I*aa);p=Math.max(F,e.contentH*I*aa);o==B&&p==F?L.css("overflow","hidden"):L.css("overflow","scroll");aa=O.height()/2;var X=O.width()/2;O.width(o).height(p);var ea= -p/2,Q=o/2,ka=e.updateCanvas(o,p),ra=Q/X;o=o/2-B/2;p=p/2-F/2;if(s){s.x+=ka.x;s.y+=ka.y}else s={x:Q+(W.x-X)*ra,y:ea+(W.y-aa)*ra};if(f)if(e.contentW>J.width()){L[0].scrollLeft=ka.x-10;L[0].scrollTop=ka.y-10}else{J[0].scrollLeft=o;J[0].scrollTop=p}else{J[0].scrollLeft=s.x-B/2;J[0].scrollTop=s.y-F/2}if(u.showRulers){B=O;I=I;document.getElementById("workarea");document.getElementById("title_show");I||(I=e.getZoom());B||(B=a("#svgcanvas"));F=e.getContentElem();J=svgedit.units.getTypeMap()[u.baseUnit];for(O= -0;O<2;O++){X=(W=O===0)?"x":"y";ra=W?"width":"height";aa=F.getAttribute(X)-0;X=a("#ruler_"+X+" canvas:first");$hcanv=X.clone();X.replaceWith($hcanv);o=$hcanv[0];ea=X=B[ra]()*2;o.parentNode.style[ra]=ea+"px";Q=0;var ta;ka=o.getContext("2d");ka.fillStyle="rgb(200,0,0)";ka.fillRect(0,0,o.width,o.height);$hcanv.siblings().remove();if(X>=3E4){var Aa=parseInt(X/3E4)+1;ta=Array(Aa);ta[0]=ka;for(p=1;p=1)p=Math.round(Aa);else{p=(o+"").split(".")[1].length;p=Aa.toFixed(p)-0}if(p!==0&&p!==1E3&&p%1E3===0)p=p/1E3+"K";if(W){ka.fillText(p,Ma+2,8);ka.fillStyle="#777"}else{Aa= -(p+"").split("");for(p=0;pX){Q++;ka.stroke();if(Q>=ta.length){p=10;Ma=ea;continue}ka=ta[Q];Ma-=3E4;tb=Math.round(Ma+Aa*p)+0.5}var zb=p%2?12:10;if(W){ka.moveTo(tb,15);ka.lineTo(tb,zb)}else{ka.moveTo(15,tb);ka.lineTo(zb,tb)}}}ka.strokeStyle="#666";ka.stroke()}L.scroll()}},G=[];for(d=0.1;d<1E5;d*=10){G.push(1*d);G.push(2*d);G.push(5*d)}A(true);try{var E=function(f){if(window.JSON&& -JSON.stringify)return JSON.stringify(f);var s=arguments.callee;if(typeof f=="boolean"||typeof f=="number")return f+"";else if(typeof f=="string")return'"'+f.replace(/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,function(B){return"\\u"+("0000"+B.charCodeAt(0).toString(16)).slice(-4)})+'"';else if(f.length){for(var o=0;o0?(b-u)/k:200,q=d/l*k,z=0,D=this.getAttribute("data-attr"),w=methodDraw.canvas,K=svgedit.browser.isTouch(),L=true,N=d&&this.dragCfg.cursor?$("
    ").appendTo(e):false;c.attr("readonly","readonly");N&&!isNaN(this.dragCfg.start)&&N.css("top",this.dragCfg.start*-1/q+l);this.adjustValue= -function(H,U){var S;H=parseFloat(H);S=isNaN(this.value)?this.dragCfg.reset:$.isFunction(this.dragCfg.stepfunc)?this.dragCfg.stepfunc(this,H):Number((Number(this.value)+Number(H)).toFixed(5));if(b!==null)S=Math.min(S,b);if(u!==null)S=Math.max(S,u);N&&this.updateCursor(S);this.value=S;e.attr("data-value",S);$.isFunction(this.dragCfg.callback)&&this.dragCfg.callback(this,U)};e.toggleClass("draginput",e.is("label"));this.move=function(H,U,S){if(K)H=H.originalEvent.touches[0];if(z===0)z=U;U=(H.pageY-z)* --1;z=H.pageY;S=U*q*n;this.adjustValue(S.toFixed(k<1?1:0))};this.stop=function(){var H=w.getSelectedElems();$("body").removeClass("dragging");e.removeClass("active");L=true;$(window).unbind("mousemove.draginput touchmove.draginput mouseup.draginput touchend.draginput");z=0;if(H[0]){H=w.undoMgr.finishUndoableChange();H.isEmpty()||w.undoMgr.addCommandToHistory(H)}this.adjustValue(0,L)};this.updateCursor=function(){var H=parseFloat(this.value)*-1/q+l;N.css("top",H)};this.launch=function(H){var U=w.getSelectedElems(); -if(K)H=H.originalEvent.touches[0];var S=H.pageY,M=this.value,T=this;w.undoMgr.beginUndoableChange(D,U);$("body").addClass("dragging");e.addClass("active");$(window).bind("mousemove.draginput touchmove.draginput",function(ia){T.move(ia,S,parseFloat(M))});$(window).bind("mouseup.draginput touchend.draginput",function(){T.stop()})};$(this).attr("readonly","readonly").attr("data-scale",q).attr("data-domain",l).attr("data-cursor",N!=false).bind("mousedown touchstart",function(H){this.blur();this.launch(H)}).bind("dblclick taphold", -function(){this.removeAttribute("readonly","readonly");this.focus();this.select()}).keydown(function(H){switch(H.keyCode){case 13:this.adjustValue(0);this.blur()}}).focus(function(){this.getAttribute("readonly")==="readonly"&&this.blur()}).blur(function(){this.setAttribute("readonly","readonly")}).bind("mousewheel",function(H,U,S,M){U=w.getSelectedElems();L&&w.undoMgr.beginUndoableChange(D,U);L=false;clearTimeout(window.undoTimeout);window.undoTimeout=setTimeout(function(){T.stop()},200);var T=this; -if(M>0)this.adjustValue(this.dragCfg.step);else M<0&&this.adjustValue(-this.dragCfg.step);H.preventDefault()})})};$.fn.dragInput.updateCursor=function(a){var n=parseFloat(a.value),e=parseFloat(a.getAttribute("data-scale")),c=parseFloat(a.getAttribute("data-domain"));n=n*-1/e+c+"px";a=a.parentNode.lastChild;if(a.className=="draginput_cursor")a.style.top=n};svgedit=svgedit||{}; -(function(){var a=this;if(!svgedit.contextmenu)svgedit.contextmenu={};a.contextMenuExtensions={};methodDraw.ready(function(){for(menuItem in contextMenuExtensions){var n=contextMenuExtensions[menuItem];Object.keys(a.contextMenuExtensions).length==0&&$("#cmenu_canvas").append("
  • ");var e=n.shortcut||"";$("#cmenu_canvas").append("
  • "+n.label+""+e+"
  • ")}});svgedit.contextmenu.resetCustomMenus=function(){a.contextMenuExtensions= -{}};svgedit.contextmenu.add=function(n){if(n&&n.id&&n.label&&n.action&&typeof n.action=="function")if(n.id in a.contextMenuExtensions)console.error('Cannot add extension "'+n.id+'", an extension by that name already exists"');else{console.log("Registed contextmenu item: {id:"+n.id+", label:"+n.label+"}");a.contextMenuExtensions[n.id]=n}else console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function")};svgedit.contextmenu.hasCustomHandler= -function(n){return a.contextMenuExtensions[n]&&true};svgedit.contextmenu.getCustomHandler=function(n){return a.contextMenuExtensions[n].action}})();(function(a,n){function e(l){return!a(l).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(l,u){var b=l.nodeName.toLowerCase();if("area"===b){b=l.parentNode;var k=b.name;if(!l.href||!k||b.nodeName.toLowerCase()!=="map")return false;b=a("img[usemap=#"+k+"]")[0];return!!b&&e(b)}return(/input|select|textarea|button|object/.test(b)?!l.disabled:"a"==b?l.href||u:u)&&e(l)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.17", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(l,u){return typeof l=="number"?this.each(function(){var b= -this;setTimeout(function(){a(b).focus();u&&u.call(b)},l)}):this._focus.apply(this,arguments)},scrollParent:function(){var l;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?l=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):l=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this, -"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!l.length?a(document):l},zIndex:function(l){if(l!==n)return this.css("zIndex",l);if(this.length){l=a(this[0]);for(var u;l.length&&l[0]!==document;){u=l.css("position");if(u==="absolute"||u==="relative"||u==="fixed"){u=parseInt(l.css("zIndex"),10);if(!isNaN(u)&&u!==0)return u}l=l.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(l){l.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(l,u){function b(z,D,w,K){a.each(k,function(){D-=parseFloat(a.curCSS(z,"padding"+this,true))||0;w&&(D-=parseFloat(a.curCSS(z,"border"+this+"Width",true))||0);K&&(D-=parseFloat(a.curCSS(z,"margin"+this,true))||0)});return D}var k=u==="Width"?["Left","Right"]:["Top","Bottom"],d=u.toLowerCase(),q={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight, -outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+u]=function(z){if(z===n)return q["inner"+u].call(this);return this.each(function(){a(this).css(d,b(this,z)+"px")})};a.fn["outer"+u]=function(z,D){if(typeof z!="number")return q["outer"+u].call(this,z);return this.each(function(){a(this).css(d,b(this,z,true,D)+"px")})}}),a.extend(a.expr[":"],{data:function(l,u,b){return!!a.data(l,b[3])},focusable:function(l){return c(l,!isNaN(a.attr(l,"tabindex")))},tabbable:function(l){var u=a.attr(l, -"tabindex"),b=isNaN(u);return(b||u>=0)&&c(l,!b)}}),a(function(){var l=document.body,u=l.appendChild(u=document.createElement("div"));a.extend(u.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=u.offsetHeight===100;a.support.selectstart="onselectstart"in u;l.removeChild(u).style.display="none"}),a.extend(a.ui,{plugin:{add:function(l,u,b){l=a.ui[l].prototype;for(var k in b){l.plugins[k]=l.plugins[k]||[];l.plugins[k].push([u,b[k]])}},call:function(l,u,b){if((u=l.plugins[u])&& -l.element[0].parentNode)for(var k=0;k0)return true;l[b]=1;k=l[b]>0;l[b]=0;return k},isOverAxis:function(l,u,b){return l>u&&l=9)&&!e.button)return this._mouseUp(e);if(this._mouseStarted){this._mouseDrag(e);return e.preventDefault()}this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==false,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e));return!this._mouseStarted},_mouseUp:function(e){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);this._mouseStarted&& -(this._mouseStarted=false,e.target==this._mouseDownEvent.target&&a.data(e.target,this.widgetName+".preventClickEvent",true),this._mouseStop(e));return false},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){this.options.helper=="original"&& -!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative");this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(n){var e=this.options; -if(this.helper||e.disabled||a(n.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(n);if(!this.handle)return false;e.iframeFix&&a(e.iframeFix===true?"iframe":e.iframeFix).each(function(){a('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(n){var e=this.options;this.helper= -this._createHelper(n);this._cacheHelperProportions();a.ui.ddmanager&&(a.ui.ddmanager.current=this);this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:n.pageX-this.offset.left,top:n.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(n);this.originalPageX=n.pageX;this.originalPageY=n.pageY;e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt);e.containment&&this._setContainment();if(this._trigger("start",n)===false){this._clear();return false}this._cacheHelperProportions();a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,n);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(n,true);a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,n);return true}, -_mouseDrag:function(n,e){this.position=this._generatePosition(n);this.positionAbs=this._convertPositionTo("absolute");if(!e){var c=this._uiHash();if(this._trigger("drag",n,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,n);return false},_mouseStop:function(n){var e= -false;a.ui.ddmanager&&!this.options.dropBehaviour&&(e=a.ui.ddmanager.drop(this,n));this.dropped&&(e=this.dropped,this.dropped=false);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!e||this.options.revert=="valid"&&e||this.options.revert===true||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,e)){var c=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10), -function(){c._trigger("stop",n)!==false&&c._clear()})}else this._trigger("stop",n)!==false&&this._clear();return false},_mouseUp:function(n){this.options.iframeFix===true&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,n);return a.ui.mouse.prototype._mouseUp.call(this,n)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(n){var e=!this.options.handle|| -!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==n.target&&(e=true)});return e},_createHelper:function(n){var e=this.options;n=a.isFunction(e.helper)?a(e.helper.apply(this.element[0],[n])):e.helper=="clone"?this.element.clone().removeAttr("id"):this.element;n.parents("body").length||n.appendTo(e.appendTo=="parent"?this.element[0].parentNode:e.appendTo);n[0]!=this.element[0]&&!/(fixed|absolute)/.test(n.css("position"))&& -n.css("position","absolute");return n},_adjustOffsetFromHelper:function(n){typeof n=="string"&&(n=n.split(" "));a.isArray(n)&&(n={left:+n[0],top:+n[1]||0});"left"in n&&(this.offset.click.left=n.left+this.margins.left);"right"in n&&(this.offset.click.left=this.helperProportions.width-n.right+this.margins.left);"top"in n&&(this.offset.click.top=n.top+this.margins.top);"bottom"in n&&(this.offset.click.top=this.helperProportions.height-n.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var n=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(n.left+=this.scrollParent.scrollLeft(),n.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)n={top:0,left:0};return{top:n.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:n.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var n=this.element.position();return{top:n.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:n.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var n=this.options;n.containment=="parent"&&(n.containment=this.helper[0].parentNode);if(n.containment=="document"||n.containment=="window")this.containment=[n.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,n.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(n.containment=="document"?0:a(window).scrollLeft())+a(n.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(n.containment=="document"?0:a(window).scrollTop())+(a(n.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(n.containment)&&n.containment.constructor!=Array){n=a(n.containment);var e=n[0];if(e){n.offset();var c=a(e).css("overflow")!= -"hidden";this.containment=[(parseInt(a(e).css("borderLeftWidth"),10)||0)+(parseInt(a(e).css("paddingLeft"),10)||0),(parseInt(a(e).css("borderTopWidth"),10)||0)+(parseInt(a(e).css("paddingTop"),10)||0),(c?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(a(e).css("borderLeftWidth"),10)||0)-(parseInt(a(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(a(e).css("borderTopWidth"), -10)||0)-(parseInt(a(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=n}}else n.containment.constructor==Array&&(this.containment=n.containment)},_convertPositionTo:function(n,e){e||(e=this.position);var c=n=="absolute"?1:-1,l=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,u=/(html|body)/i.test(l[0].tagName);return{top:e.top+ -this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():u?0:l.scrollTop())*c),left:e.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():u?0:l.scrollLeft())*c)}},_generatePosition:function(n){var e=this.options,c=this.cssPosition=="absolute"&& -(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,l=/(html|body)/i.test(c[0].tagName),u=n.pageX,b=n.pageY;if(this.originalPosition){var k;if(this.containment){if(this.relative_container){k=this.relative_container.offset();k=[this.containment[0]+k.left,this.containment[1]+k.top,this.containment[2]+k.left,this.containment[3]+k.top]}else k=this.containment;n.pageX-this.offset.click.leftk[2]&&(u=k[2]+this.offset.click.left);n.pageY-this.offset.click.top>k[3]&&(b=k[3]+this.offset.click.top)}if(e.grid){b=e.grid[1]?this.originalPageY+Math.round((b-this.originalPageY)/e.grid[1])*e.grid[1]:this.originalPageY;b=k?b-this.offset.click.topk[3]?b-this.offset.click.topk[2]?u-this.offset.click.left=0;z--){var D=c.snapElements[z].left,w=D+c.snapElements[z].width,K=c.snapElements[z].top,L=K+c.snapElements[z].height;if(D-u
    ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(e.range==="min"||e.range==="max"?" ui-slider-range-"+e.range:"")));for(var b=c.length;b"); -this.handles=c.add(a(u.join("")).appendTo(n.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(k){k.preventDefault()}).hover(function(){e.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){e.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(k){a(this).data("index.ui-slider-handle", -k)});this.handles.keydown(function(k){var d=true,q=a(this).data("index.ui-slider-handle"),z,D,w;if(!n.options.disabled){switch(k.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d=false;if(!n._keySliding){n._keySliding=true;a(this).addClass("ui-state-active");z=n._start(k,q);if(z===false)return}}z=n.options.step;n.options.values&&n.options.values.length? -D=w=n.values(q):D=w=n.value();switch(k.keyCode){case a.ui.keyCode.HOME:w=n._valueMin();break;case a.ui.keyCode.END:w=n._valueMax();break;case a.ui.keyCode.PAGE_UP:w=n._trimAlignValue(D+(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.PAGE_DOWN:w=n._trimAlignValue(D-(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(D===n._valueMax())return;w=n._trimAlignValue(D+z);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(D===n._valueMin())return;w=n._trimAlignValue(D- -z)}n._slide(k,q,w);return d}}).keyup(function(k){var d=a(this).data("index.ui-slider-handle");n._keySliding&&(n._keySliding=false,n._stop(k,d),n._change(k,d),a(this).removeClass("ui-state-active"))});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(n){var e=this.options,c,l,u,b,k;if(e.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:n.pageX,y:n.pageY});l=this._valueMax()-this._valueMin()+1;b=this;this.handles.each(function(d){var q=Math.abs(c-b.values(d));l>q&&(l=q,u=a(this),k=d)});e.range===true&&this.values(1)===e.min&&(k+=1,u=a(this.handles[k]));if(this._start(n,k)===false)return false; -this._mouseSliding=true;b._handleIndex=k;u.addClass("ui-state-active").focus();e=u.offset();this._clickOffset=!a(n.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:n.pageX-e.left-u.width()/2,top:n.pageY-e.top-u.height()/2-(parseInt(u.css("borderTopWidth"),10)||0)-(parseInt(u.css("borderBottomWidth"),10)||0)+(parseInt(u.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(n,k,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(n){var e= -this._normValueFromMouse({x:n.pageX,y:n.pageY});this._slide(n,this._handleIndex,e);return false},_mouseStop:function(n){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(n,this._handleIndex);this._change(n,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(n){var e,c;this.orientation==="horizontal"? -(e=this.elementSize.width,c=n.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,c=n.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0));n=c/e;n>1&&(n=1);n<0&&(n=0);this.orientation==="vertical"&&(n=1-n);e=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+n*e)},_start:function(n,e){var c={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(e), -c.values=this.values());return this._trigger("start",n,c)},_slide:function(n,e,c){var l,u,b;this.options.values&&this.options.values.length?(l=this.values(e?0:1),this.options.values.length===2&&this.options.range===true&&(e===0&&c>l||e===1&&c1){this.options.values[n]=this._trimAlignValue(e);this._refreshValue();this._change(null,n)}else{if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(n):this.value();c=this.options.values;l=arguments[0];for(u=0;u=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,c=(n-this._valueMin())%e;n=n-c;Math.abs(c)*2>=e&&(n+=c>0?e:-e);return parseFloat(n.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var n= -this.options.range,e=this.options,c=this,l=this._animateOff?false:e.animate,u,b={},k,d,q,z;this.options.values&&this.options.values.length?this.handles.each(function(D){u=(c.values(D)-c._valueMin())/(c._valueMax()-c._valueMin())*100;b[c.orientation==="horizontal"?"left":"bottom"]=u+"%";a(this).stop(1,1)[l?"animate":"css"](b,e.animate);c.options.range===true&&(c.orientation==="horizontal"?(D===0&&c.range.stop(1,1)[l?"animate":"css"]({left:u+"%"},e.animate),D===1&&c.range[l?"animate":"css"]({width:u- -k+"%"},{queue:false,duration:e.animate})):(D===0&&c.range.stop(1,1)[l?"animate":"css"]({bottom:u+"%"},e.animate),D===1&&c.range[l?"animate":"css"]({height:u-k+"%"},{queue:false,duration:e.animate})));k=u}):(d=this.value(),q=this._valueMin(),z=this._valueMax(),u=z!==q?(d-q)/(z-q)*100:0,b[c.orientation==="horizontal"?"left":"bottom"]=u+"%",this.handle.stop(1,1)[l?"animate":"css"](b,e.animate),n==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[l?"animate":"css"]({width:u+"%"},e.animate), -n==="max"&&this.orientation==="horizontal"&&this.range[l?"animate":"css"]({width:100-u+"%"},{queue:false,duration:e.animate}),n==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[l?"animate":"css"]({height:u+"%"},e.animate),n==="max"&&this.orientation==="vertical"&&this.range[l?"animate":"css"]({height:100-u+"%"},{queue:false,duration:e.animate}))}});a.extend(a.ui.slider,{version:"1.8.17"})})(jQuery);(function(a){Math.precision=function(b,k){if(k===undefined)k=0;return Math.round(b*Math.pow(10,k))/Math.pow(10,k)};var n=function(b,k){var d=this,q=b.find("img:first"),z=0,D=100,w=100,K=0,L=100,N=100,H=0,U=0,S,M,T=[],ia=function(Y){for(var ca=0;capa)ca=pa;if(Y<0)Y=0;else if(Y>oa)Y=oa;ja.call(d,"xy",{x:ca/pa*w+z,y:Y/oa*N+K})},ja=function(Y,ca,pa){if(ca===undefined){if(Y===undefined||Y==null)Y="xy";switch(Y.toLowerCase()){case "x":return H;case "y":return U; -default:return{x:H,y:U}}}if(!(pa!=null&&pa==d)){var oa=false,na,ma;if(Y==null)Y="xy";switch(Y.toLowerCase()){case "x":na=ca&&(ca.x&&ca.x|0||ca|0)||0;break;case "y":ma=ca&&(ca.y&&ca.y|0||ca|0)||0;break;default:na=ca&&ca.x&&ca.x|0||0;ma=ca&&ca.y&&ca.y|0||0}if(na!=null){if(naD)na=D;if(H!=na){H=na;oa=true}}if(ma!=null){if(maL)ma=L;if(U!=ma){U=ma;oa=true}}oa&&ia.call(d,pa||d)}},la=function(Y){a.isFunction(Y)&&T.push(Y)};a.extend(true,d,{val:ja,range:function(Y,ca){if(ca=== -undefined){if(Y===undefined||Y==null)Y="all";switch(Y.toLowerCase()){case "minx":return z;case "maxx":return D;case "rangex":return{minX:z,maxX:D,rangeX:w};case "miny":return K;case "maxy":return L;case "rangey":return{minY:K,maxY:L,rangeY:N};default:return{minX:z,maxX:D,rangeX:w,minY:K,maxY:L,rangeY:N}}}var pa,oa,na,ma;if(Y==null)Y="all";switch(Y.toLowerCase()){case "minx":pa=ca&&(ca.minX&&ca.minX|0||ca|0)||0;break;case "maxx":oa=ca&&(ca.maxX&&ca.maxX|0||ca|0)||0;break;case "rangex":pa=ca&&ca.minX&& -ca.minX|0||0;oa=ca&&ca.maxX&&ca.maxX|0||0;break;case "miny":na=ca&&(ca.minY&&ca.minY|0||ca|0)||0;break;case "maxy":ma=ca&&(ca.maxY&&ca.maxY|0||ca|0)||0;break;case "rangey":na=ca&&ca.minY&&ca.minY|0||0;ma=ca&&ca.maxY&&ca.maxY|0||0;break;default:pa=ca&&ca.minX&&ca.minX|0||0;oa=ca&&ca.maxX&&ca.maxX|0||0;na=ca&&ca.minY&&ca.minY|0||0;ma=ca&&ca.maxY&&ca.maxY|0||0}if(pa!=null&&z!=pa){z=pa;w=D-z}if(oa!=null&&D!=oa){D=oa;w=D-z}if(na!=null&&K!=na){K=na;N=L-K}if(ma!=null&&L!=ma){L=ma;N=L-K}},bind:la,unbind:function(Y){if(a.isFunction(Y))for(var ca;(ca= -a.inArray(Y,T))!=-1;)T.splice(ca,1)},destroy:function(){a(document).unbind("mouseup",fa).unbind("mousemove",Z);b.unbind("mousedown",ga);T=q=b=null}});q.src=k.arrow&&k.arrow.image;q.w=k.arrow&&k.arrow.width||q.width();q.h=k.arrow&&k.arrow.height||q.height();b.w=k.map&&k.map.width||b.width();b.h=k.map&&k.map.height||b.height();b.bind("mousedown",ga);la.call(d,function(){var Y=0,ca=0,pa=b.w,oa=b.h,na=q.w,ma=q.h;setTimeout(function(){if(w>0)Y=H==D?pa:H/w*pa|0;if(N>0)ca=U==L?oa:U/N*oa|0;if(na>=pa)Y=(pa>> -1)-(na>>1);else Y-=na>>1;if(ma>=oa)ca=(oa>>1)-(ma>>1);else ca-=ma>>1;q.css({left:Y+"px",top:ca+"px"})},0)})},e=function(b,k,d,q){var z=this;b=b.find("td.Text input");var D=b.eq(3),w=b.eq(4),K=b.eq(5),L=b.length>7?b.eq(6):null,N=b.eq(0),H=b.eq(1),U=b.eq(2),S=b.eq(b.length>7?7:6),M=b.length>7?b.eq(8):null,T=function(ja){if(!(ja.target.value==""&&ja.target!=S.get(0)&&(d!=null&&ja.target!=d.get(0)||d==null))){if(!Z(ja))return ja;switch(ja.target){case D.get(0):switch(ja.keyCode){case 38:D.val(fa.call(z, -(D.val()<<0)+1,0,255));k.val("r",D.val(),ja.target);return false;case 40:D.val(fa.call(z,(D.val()<<0)-1,0,255));k.val("r",D.val(),ja.target);return false}break;case w.get(0):switch(ja.keyCode){case 38:w.val(fa.call(z,(w.val()<<0)+1,0,255));k.val("g",w.val(),ja.target);return false;case 40:w.val(fa.call(z,(w.val()<<0)-1,0,255));k.val("g",w.val(),ja.target);return false}break;case K.get(0):switch(ja.keyCode){case 38:K.val(fa.call(z,(K.val()<<0)+1,0,255));k.val("b",K.val(),ja.target);return false;case 40:K.val(fa.call(z, -(K.val()<<0)-1,0,255));k.val("b",K.val(),ja.target);return false}break;case L&&L.get(0):switch(ja.keyCode){case 38:L.val(fa.call(z,parseFloat(L.val())+1,0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);return false;case 40:L.val(fa.call(z,parseFloat(L.val())-1,0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);return false}break;case N.get(0):switch(ja.keyCode){case 38:N.val(fa.call(z,(N.val()<<0)+1,0,360));k.val("h",N.val(),ja.target);return false;case 40:N.val(fa.call(z, -(N.val()<<0)-1,0,360));k.val("h",N.val(),ja.target);return false}break;case H.get(0):switch(ja.keyCode){case 38:H.val(fa.call(z,(H.val()<<0)+1,0,100));k.val("s",H.val(),ja.target);return false;case 40:H.val(fa.call(z,(H.val()<<0)-1,0,100));k.val("s",H.val(),ja.target);return false}break;case U.get(0):switch(ja.keyCode){case 38:U.val(fa.call(z,(U.val()<<0)+1,0,100));k.val("v",U.val(),ja.target);return false;case 40:U.val(fa.call(z,(U.val()<<0)-1,0,100));k.val("v",U.val(),ja.target);return false}}}}, -ia=function(ja){if(!(ja.target.value==""&&ja.target!=S.get(0)&&(d!=null&&ja.target!=d.get(0)||d==null))){if(!Z(ja))return ja;switch(ja.target){case D.get(0):D.val(fa.call(z,D.val(),0,255));k.val("r",D.val(),ja.target);break;case w.get(0):w.val(fa.call(z,w.val(),0,255));k.val("g",w.val(),ja.target);break;case K.get(0):K.val(fa.call(z,K.val(),0,255));k.val("b",K.val(),ja.target);break;case L&&L.get(0):L.val(fa.call(z,L.val(),0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);break;case N.get(0):N.val(fa.call(z, -N.val(),0,360));k.val("h",N.val(),ja.target);break;case H.get(0):H.val(fa.call(z,H.val(),0,100));k.val("s",H.val(),ja.target);break;case U.get(0):U.val(fa.call(z,U.val(),0,100));k.val("v",U.val(),ja.target);break;case S.get(0):S.val(S.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));d&&d.val(S.val());k.val("hex",S.val()!=""?S.val():null,ja.target);break;case d&&d.get(0):d.val(d.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));S.val(d.val());k.val("hex",d.val()!=""?d.val(): -null,ja.target);break;case M&&M.get(0):M.val(M.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,2));k.val("a",M.val()!=null?parseInt(M.val(),16):null,ja.target)}}},ga=function(ja){if(k.val()!=null)switch(ja.target){case D.get(0):D.val(k.val("r"));break;case w.get(0):w.val(k.val("g"));break;case K.get(0):K.val(k.val("b"));break;case L&&L.get(0):L.val(Math.precision(k.val("a")*100/255,q));break;case N.get(0):N.val(k.val("h"));break;case H.get(0):H.val(k.val("s"));break;case U.get(0):U.val(k.val("v")); -break;case S.get(0):case d&&d.get(0):S.val(k.val("hex"));d&&d.val(k.val("hex"));break;case M&&M.get(0):M.val(k.val("ahex").substring(6))}},Z=function(ja){switch(ja.keyCode){case 9:case 16:case 29:case 37:case 39:return false;case "c".charCodeAt():case "v".charCodeAt():if(ja.ctrlKey)return false}return true},fa=function(ja,la,Y){if(ja==""||isNaN(ja))return la;if(ja>Y)return Y;if(ja255)Z.r=255;if(d!=Z.r){d=Z.r;ga=true}break;case "g":if(ua)continue;fa=true;Z.g=M&&M.g&&M.g|0||M&&M|0||0;if(Z.g<0)Z.g=0;else if(Z.g>255)Z.g=255;if(q!=Z.g){q=Z.g;ga=true}break;case "b":if(ua)continue;fa=true;Z.b=M&&M.b&&M.b|0||M&&M|0||0;if(Z.b<0)Z.b=0;else if(Z.b>255)Z.b=255;if(z!=Z.b){z=Z.b;ga=true}break;case "a":Z.a=M&&M.a!=null?M.a|0:M!=null?M|0:255;if(Z.a< -0)Z.a=0;else if(Z.a>255)Z.a=255;if(D!=Z.a){D=Z.a;ga=true}break;case "h":if(fa)continue;ua=true;Z.h=M&&M.h&&M.h|0||M&&M|0||0;if(Z.h<0)Z.h=0;else if(Z.h>360)Z.h=360;if(w!=Z.h){w=Z.h;ga=true}break;case "s":if(fa)continue;ua=true;Z.s=M&&M.s!=null?M.s|0:M!=null?M|0:100;if(Z.s<0)Z.s=0;else if(Z.s>100)Z.s=100;if(K!=Z.s){K=Z.s;ga=true}break;case "v":if(fa)continue;ua=true;Z.v=M&&M.v!=null?M.v|0:M!=null?M|0:100;if(Z.v<0)Z.v=0;else if(Z.v>100)Z.v=100;if(L!=Z.v){L=Z.v;ga=true}}if(ga){if(fa){d=d||0;q=q||0;z= -z||0;M=u.rgbToHsv({r:d,g:q,b:z});w=M.h;K=M.s;L=M.v}else if(ua){w=w||0;K=K!=null?K:100;L=L!=null?L:100;M=u.hsvToRgb({h:w,s:K,v:L});d=M.r;q=M.g;z=M.b}D=D!=null?D:255;H.call(k,T||k)}}}};a.extend(true,k,{val:U,bind:function(S){a.isFunction(S)&&N.push(S)},unbind:function(S){if(a.isFunction(S))for(var M;(M=a.inArray(S,N))!=-1;)N.splice(M,1)},destroy:function(){N=null}});if(b)if(b.ahex!=null)U("ahex",b);else if(b.hex!=null)U((b.a!=null?"a":"")+"hex",b.a!=null?{ahex:b.hex+u.intToHex(b.a)}:b);else if(b.r!= -null&&b.g!=null&&b.b!=null)U("rgb"+(b.a!=null?"a":""),b);else if(b.h!=null&&b.s!=null&&b.v!=null)U("hsv"+(b.a!=null?"a":""),b)},ColorMethods:{hexToRgba:function(b){b=this.validateHex(b);if(b=="")return{r:null,g:null,b:null,a:null};var k="00",d="00",q="00",z="255";if(b.length==6)b+="ff";if(b.length>6){k=b.substring(0,2);d=b.substring(2,4);q=b.substring(4,6);z=b.substring(6,b.length)}else{if(b.length>4){k=b.substring(4,b.length);b=b.substring(0,4)}if(b.length>2){d=b.substring(2,b.length);b=b.substring(0, -2)}if(b.length>0)q=b.substring(0,b.length)}return{r:this.hexToInt(k),g:this.hexToInt(d),b:this.hexToInt(q),a:this.hexToInt(z)}},validateHex:function(b){if(typeof b=="object")return"";b=b.toLowerCase().replace(/[^a-f0-9]/g,"");if(b.length>8)b=b.substring(0,8);return b},rgbaToHex:function(b){return this.intToHex(b.r)+this.intToHex(b.g)+this.intToHex(b.b)+this.intToHex(b.a)},intToHex:function(b){b=(b|0).toString(16);if(b.length==1)b="0"+b;return b.toLowerCase()},hexToInt:function(b){return parseInt(b, -16)},rgbToHsv:function(b){var k=b.r/255,d=b.g/255;b=b.b/255;var q={h:0,s:0,v:0},z=0,D=0;if(k>=d&&k>=b){D=k;z=d>b?b:d}else if(d>=b&&d>=k){D=d;z=k>b?b:k}else{D=b;z=d>k?k:d}q.v=D;q.s=D?(D-z)/D:0;if(q.s){z=D-z;q.h=k==D?(d-b)/z:d==D?2+(b-k)/z:4+(k-d)/z;q.h=parseInt(q.h*60);if(q.h<0)q.h+=360}else q.h=0;q.s=q.s*100|0;q.v=q.v*100|0;return q},hsvToRgb:function(b){var k={r:0,g:0,b:0,a:100},d=b.h,q=b.s;b=b.v;if(q==0)k.r=b==0?k.g=k.b=0:k.g=k.b=b*255/100|0;else{if(d==360)d=0;d/=60;q/=100;b/=100;var z=d|0,D=d- -z;d=b*(1-q);var w=b*(1-q*D);q=b*(1-q*(1-D));switch(z){case 0:k.r=b;k.g=q;k.b=d;break;case 1:k.r=w;k.g=b;k.b=d;break;case 2:k.r=d;k.g=b;k.b=q;break;case 3:k.r=d;k.g=w;k.b=b;break;case 4:k.r=q;k.g=d;k.b=b;break;case 5:k.r=b;k.g=d;k.b=w}k.r=k.r*255|0;k.g=k.g*255|0;k.b=k.b*255|0}return k}}};var c=a.jPicker.Color,l=a.jPicker.List,u=a.jPicker.ColorMethods;a.fn.jPicker=function(b){var k=arguments;return this.each(function(){var d=this,q=a.extend(true,{},a.fn.jPicker.defaults,b);if(a(d).get(0).nodeName.toLowerCase()== -"input"){a.extend(true,q,{window:{bindToInput:true,expandable:true,input:a(d)}});if(a(d).val()==""){q.color.active=new c({hex:null});q.color.current=new c({hex:null})}else if(u.validateHex(a(d).val())){q.color.active=new c({hex:a(d).val(),a:q.color.active.val("a")});q.color.current=new c({hex:a(d).val(),a:q.color.active.val("a")})}}if(q.window.expandable)a(d).after('    '); -else q.window.liveUpdate=false;var z=parseFloat(navigator.appVersion.split("MSIE")[1])<7&&document.body.filters,D=null,w=null,K=null,L=null,N=null,H=null,U=null,S=null,M=null,T=null,ia=null,ga=null,Z=null,fa=null,ua=null,ja=null,la=null,Y=null,ca=null,pa=null,oa=null,na=null,ma=null,Ha=null,Ia=null,Ea=null,Va=null,Ua=null,La=function(R){var P=da.active,ba=P.val("hex"),Ba,Pa;q.color.mode=R;switch(R){case "h":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,0);sa.call(d,L,100);ya.call(d, -N,260);sa.call(d,N,100);Sa.call(d,K,"transparent");ya.call(d,U,0);sa.call(d,U,100);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,M,260);sa.call(d,M,100);ya.call(d,T,260);sa.call(d,T,100);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:100,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:360});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("s"),y:100-P.val("v")},Z);fa.val("y",360-P.val("h"),fa);break;case "s":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,-260);ya.call(d, -N,-520);ya.call(d,U,-260);ya.call(d,S,-520);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:360,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:100});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("v")},Z);fa.val("y",100-P.val("s"),fa);break;case "v":setTimeout(function(){Sa.call(d,w,"000000");ya.call(d,L,-780);ya.call(d,N,260);Sa.call(d,K,ba);ya.call(d,U,-520);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:360, -minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:100});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("s")},Z);fa.val("y",100-P.val("v"),fa);break;case "r":Ba=-1040;Pa=-780;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("b"),y:255-P.val("g")},Z);fa.val("y",255-P.val("r"),fa);break;case "g":Ba=-1560;Pa=-1820;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255}); -if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("b"),y:255-P.val("r")},Z);fa.val("y",255-P.val("g"),fa);break;case "b":Ba=-2080;Pa=-2860;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("r"),y:255-P.val("g")},Z);fa.val("y",255-P.val("b"),fa);break;case "a":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,-260);ya.call(d,N,-520);ya.call(d,U,260);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,ga,0);sa.call(d, -ga,100)},0);Z.range("all",{minX:0,maxX:360,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("v")},Z);fa.val("y",255-P.val("a"),fa);break;default:throw"Invalid Mode";}switch(R){case "s":case "v":case "a":setTimeout(function(){sa.call(d,L,100);sa.call(d,U,100);ya.call(d,M,260);sa.call(d,M,100);ya.call(d,T,260);sa.call(d,T,100)},0);break;case "r":case "g":case "b":setTimeout(function(){Sa.call(d,w,"transparent");Sa.call(d,K,"transparent"); -sa.call(d,U,100);sa.call(d,L,100);ya.call(d,L,Ba);ya.call(d,N,Ba-260);ya.call(d,U,Pa-780);ya.call(d,S,Pa-520);ya.call(d,M,Pa);ya.call(d,T,Pa-260);ya.call(d,ga,260);sa.call(d,ga,100)},0)}P.val("ahex")!=null&&qa.call(d,P)},qa=function(R,P){if(P==null||P!=fa&&P!=Z)va.call(d,R,P);setTimeout(function(){ub.call(d,R);nb.call(d,R);gb.call(d,R)},0)},wa=function(R,P){var ba=da.active;if(!(P!=Z&&ba.val()==null)){var Ba=R.val("all");switch(q.color.mode){case "h":ba.val("sv",{s:Ba.x,v:100-Ba.y},P);break;case "s":case "a":ba.val("hv", -{h:Ba.x,v:100-Ba.y},P);break;case "v":ba.val("hs",{h:Ba.x,s:100-Ba.y},P);break;case "r":ba.val("gb",{g:255-Ba.y,b:Ba.x},P);break;case "g":ba.val("rb",{r:255-Ba.y,b:Ba.x},P);break;case "b":ba.val("rg",{r:Ba.x,g:255-Ba.y},P)}}},za=function(R,P){var ba=da.active;if(!(P!=fa&&ba.val()==null))switch(q.color.mode){case "h":ba.val("h",{h:360-R.val("y")},P);break;case "s":ba.val("s",{s:100-R.val("y")},P);break;case "v":ba.val("v",{v:100-R.val("y")},P);break;case "r":ba.val("r",{r:255-R.val("y")},P);break; -case "g":ba.val("g",{g:255-R.val("y")},P);break;case "b":ba.val("b",{b:255-R.val("y")},P);break;case "a":ba.val("a",255-R.val("y"),P)}},va=function(R,P){if(P!=Z)switch(q.color.mode){case "h":var ba=R.val("sv");Z.val("xy",{x:ba!=null?ba.s:100,y:100-(ba!=null?ba.v:100)},P);break;case "s":case "a":ba=R.val("hv");Z.val("xy",{x:ba&&ba.h||0,y:100-(ba!=null?ba.v:100)},P);break;case "v":ba=R.val("hs");Z.val("xy",{x:ba&&ba.h||0,y:100-(ba!=null?ba.s:100)},P);break;case "r":ba=R.val("bg");Z.val("xy",{x:ba&& -ba.b||0,y:255-(ba&&ba.g||0)},P);break;case "g":ba=R.val("br");Z.val("xy",{x:ba&&ba.b||0,y:255-(ba&&ba.r||0)},P);break;case "b":ba=R.val("rg");Z.val("xy",{x:ba&&ba.r||0,y:255-(ba&&ba.g||0)},P)}if(P!=fa)switch(q.color.mode){case "h":fa.val("y",360-(R.val("h")||0),P);break;case "s":ba=R.val("s");fa.val("y",100-(ba!=null?ba:100),P);break;case "v":ba=R.val("v");fa.val("y",100-(ba!=null?ba:100),P);break;case "r":fa.val("y",255-(R.val("r")||0),P);break;case "g":fa.val("y",255-(R.val("g")||0),P);break;case "b":fa.val("y", -255-(R.val("b")||0),P);break;case "a":ba=R.val("a");fa.val("y",255-(ba!=null?ba:255),P)}},ub=function(R){try{var P=R.val("all");pa.css({backgroundColor:P&&"#"+P.hex||"transparent"});sa.call(d,pa,P&&Math.precision(P.a*100/255,4)||0)}catch(ba){}},nb=function(R){switch(q.color.mode){case "h":Sa.call(d,w,(new c({h:R.val("h")||0,s:100,v:100})).val("hex"));break;case "s":case "a":var P=R.val("s");sa.call(d,N,100-(P!=null?P:100));break;case "v":P=R.val("v");sa.call(d,L,P!=null?P:100);break;case "r":sa.call(d, -N,Math.precision((R.val("r")||0)/255*100,4));break;case "g":sa.call(d,N,Math.precision((R.val("g")||0)/255*100,4));break;case "b":sa.call(d,N,Math.precision((R.val("b")||0)/255*100))}R=R.val("a");sa.call(d,H,Math.precision((255-(R||0))*100/255,4))},gb=function(R){switch(q.color.mode){case "h":var P=R.val("a");sa.call(d,ia,Math.precision((255-(P||0))*100/255,4));break;case "s":P=R.val("hva");var ba=new c({h:P&&P.h||0,s:100,v:P!=null?P.v:100});Sa.call(d,K,ba.val("hex"));sa.call(d,S,100-(P!=null?P.v: -100));sa.call(d,ia,Math.precision((255-(P&&P.a||0))*100/255,4));break;case "v":P=R.val("hsa");ba=new c({h:P&&P.h||0,s:P!=null?P.s:100,v:100});Sa.call(d,K,ba.val("hex"));sa.call(d,ia,Math.precision((255-(P&&P.a||0))*100/255,4));break;case "r":case "g":case "b":ba=P=0;R=R.val("rgba");if(q.color.mode=="r"){P=R&&R.b||0;ba=R&&R.g||0}else if(q.color.mode=="g"){P=R&&R.b||0;ba=R&&R.r||0}else if(q.color.mode=="b"){P=R&&R.r||0;ba=R&&R.g||0}var Ba=ba>P?P:ba;sa.call(d,S,P>ba?Math.precision((P-ba)/(255-ba)*100, -4):0);sa.call(d,M,ba>P?Math.precision((ba-P)/(255-P)*100,4):0);sa.call(d,T,Math.precision(Ba/255*100,4));sa.call(d,ia,Math.precision((255-(R&&R.a||0))*100/255,4));break;case "a":P=R.val("a");Sa.call(d,K,R.val("hex")||"000000");sa.call(d,ia,P!=null?0:100);sa.call(d,ga,P!=null?100:0)}},Sa=function(R,P){R.css({backgroundColor:P&&P.length==6&&"#"+P||"transparent"})},Xa=function(R,P){if(z&&(P.indexOf("AlphaBar.png")!=-1||P.indexOf("Bars.png")!=-1||P.indexOf("Maps.png")!=-1)){R.attr("pngSrc",P);R.css({backgroundImage:"none", -filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+P+"', sizingMethod='scale')"})}else R.css({backgroundImage:"url('"+P+"')"})},ya=function(R,P){R.css({top:P+"px"})},sa=function(R,P){R.css({visibility:P>0?"visible":"hidden"});if(P>0&&P<100)if(z){var ba=R.attr("pngSrc");ba!=null&&(ba.indexOf("AlphaBar.png")!=-1||ba.indexOf("Bars.png")!=-1||ba.indexOf("Maps.png")!=-1)?R.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ba+"', sizingMethod='scale') progid:DXImageTransform.Microsoft.Alpha(opacity="+ -P+")"}):R.css({opacity:Math.precision(P/100,4)})}else R.css({opacity:Math.precision(P/100,4)});else if(P==0||P==100)if(z){ba=R.attr("pngSrc");ba!=null&&(ba.indexOf("AlphaBar.png")!=-1||ba.indexOf("Bars.png")!=-1||ba.indexOf("Maps.png")!=-1)?R.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ba+"', sizingMethod='scale')"}):R.css({opacity:""})}else R.css({opacity:""})},Fa=function(){da.active.val("ahex",da.current.val("ahex"))},Qa=function(){da.current.val("ahex",da.active.val("ahex"))}, -xa=function(R){a(this).parents("tbody:first").find('input:radio[value!="'+R.target.value+'"]').removeAttr("checked");La.call(d,R.target.value)},bb=function(){Fa.call(d)},jb=function(){Fa.call(d);q.window.expandable&&qb.call(d);a.isFunction(Za)&&Za.call(d,da.active,ma)},Ya=function(){Qa.call(d);q.window.expandable&&qb.call(d);a.isFunction(kb)&&kb.call(d,da.active,na)},Ta=function(){vb.call(d)},rb=function(R){var P=R.val("hex");oa.css({backgroundColor:P&&"#"+P||"transparent"});sa.call(d,oa,Math.precision((R.val("a")|| -0)*100/255,4))},Ja=function(R){var P=R.val("hex");R=R.val("va");Ia.css({backgroundColor:P&&"#"+P||"transparent"});sa.call(d,Ea,Math.precision((255-(R&&R.a||0))*100/255,4));if(q.window.bindToInput&&q.window.updateInputColor)q.window.input.css({backgroundColor:P&&"#"+P||"transparent",color:R==null||R.v>75?"#000000":"#ffffff"})},Ka=function(R){ja=parseInt(D.css("left"));la=parseInt(D.css("top"));Y=R.pageX;ca=R.pageY;a(document).bind("mousemove",pb).bind("mouseup",cb);R.preventDefault()},pb=function(R){D.css({left:ja- -(Y-R.pageX)+"px",top:la-(ca-R.pageY)+"px"});q.window.expandable&&!a.support.boxModel&&D.prev().css({left:D.css("left"),top:D.css("top")});R.stopPropagation();R.preventDefault();return false},cb=function(R){a(document).unbind("mousemove",pb).unbind("mouseup",cb);R.stopPropagation();R.preventDefault();return false},ob=function(R){R.preventDefault();R.stopPropagation();da.active.val("ahex",a(this).attr("title")||null,R.target);return false},kb=a.isFunction(k[1])&&k[1]||null,db=a.isFunction(k[2])&&k[2]|| -null,Za=a.isFunction(k[3])&&k[3]||null,vb=function(){da.current.val("ahex",da.active.val("ahex"));var R=function(){if(!(!q.window.expandable||a.support.boxModel)){var P=D.find("table:first");D.before(" - - diff --git a/method-draw/extensions/closepath_icons.svg b/method-draw/extensions/closepath_icons.svg deleted file mode 100644 index 7294f5e..0000000 --- a/method-draw/extensions/closepath_icons.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/method-draw/extensions/ext-arrows.js b/method-draw/extensions/ext-arrows.js deleted file mode 100644 index 4f45192..0000000 --- a/method-draw/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -methodDraw.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/method-draw/extensions/ext-closepath.js b/method-draw/extensions/ext-closepath.js deleted file mode 100644 index dc73f1a..0000000 --- a/method-draw/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -methodDraw.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/method-draw/extensions/ext-connector.js b/method-draw/extensions/ext-connector.js deleted file mode 100644 index ffd54df..0000000 --- a/method-draw/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -methodDraw.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = methodDraw.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $('').appendTo("head");Db()}},Fb=function(){Da(a("#view_menu"));var f=!a("#tool_snap").hasClass("push_button_pressed");f?a("#tool_snap").addClass("push_button_pressed"):a("#tool_snap").removeClass("push_button_pressed");u.gridSnapping=f},Eb=function(){window.self!=window.top&&top.exit_fullscreen()},Gb=function(){Da(a("#view_menu")); -if(a("#tool_rulers").hasClass("push_button_pressed")){a("#tool_rulers").removeClass("push_button_pressed");a("#show_rulers").attr("checked",false);u.showRulers=false}else{a("#tool_rulers").addClass("push_button_pressed");a("#show_rulers").attr("checked",true);u.showRulers=true}a("#rulers").toggle(!!u.showRulers)},Db=function(){if(!g){var f="#workarea.wireframe #svgcontent * { stroke-width: "+1/e.getZoom()+"px; }";a("#wireframe_rules").text(L.hasClass("wireframe")?f:"")}},yb=function(f,s){if(!ga){Da(a("#view_menu")); -ga=true;a("#save_output_btns").toggle(!!s);a("#tool_source_back").toggle(!s);var o=S=e.getSvgString();a("#svg_source_textarea").val(o);a("#svg_source_editor").fadeIn();a("#svg_source_textarea").focus().select()}},Ab=function(){if(ga){if(e.setSvgString(a("#svg_source_textarea").val())){e.clearSelection();sb();Ca();ua()}else a.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?",function(f){if(!f)return false;e.clearSelection();sb();Ca();ua()});M()}},Jb=c.setIcon= -function(f,s){var o=typeof s==="string"?a.getSvgIcon(s,true):s.clone();o?a(f).find("img").replaceWith(o):console.log("NOTE: Icon image missing: "+s)},wb;wb=function(){var f=/^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,s=document.getElementsByTagName("script")[0],o;for(o in s.style)if(f.test(o))return o.match(f)[0];if("WebkitOpacity"in s.style)return"Webkit";if("KhtmlOpacity"in s.style)return"Khtml";return""}();var hb=function(f,s){wb.toLowerCase();var o=["top","left","bottom","right"];f.each(function(){for(var p= -a(this),B=p.outerWidth()*(s-1),F=p.outerHeight()*(s-1),I=0;I<4;I++){var J=o[I],O=p.data("orig_margin-"+J);if(O==null){O=parseInt(p.css("margin-"+J));p.data("orig_margin-"+J,O)}O=O*s;if(J==="right")O+=B;else if(J==="bottom")O+=F;p.css("margin-"+J,O)}})},Lb=c.setIconSize=function(f,s){if(!(f==b.size&&!s)){var o=a("#tools_top .toolset, #editor_panel > *, #history_panel > *, #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *, #g_panel > *, #tool_font_size > *, .tools_flyout"), -p=1;p=typeof f=="number"?f:{s:0.75,m:1,l:1.25,xl:1.5}[f];c.tool_scale=H=p;ca();var B=o.parents(":hidden");B.css("visibility","hidden").show();hb(o,p);B.css("visibility","visible").hide();o=a("#tool_size_rules");if(o.length)o.empty();else o=a('').appendTo("head");if(f!="m"){var F="";a.each(cssResizeRules,function(I,J){I="#svg_editor "+I.replace(/,/g,", #svg_editor");F+=I+"{";a.each(J,function(O,W){if(typeof W==="number")var aa=W*p+"px";else if(W[f]||W.all)aa=W[f]|| -W.all;F+=O+":"+aa+";"});F+="}"});B="-"+wb.toLowerCase()+"-";F+="#tools_top .toolset, #editor_panel > *, #history_panel > *, #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *, #g_panel > *, #tool_font_size > *, .tools_flyout{"+B+"transform: scale("+p+");} #svg_editor div.toolset .toolset {"+B+"transform: scale(1); margin: 1px !important;} #svg_editor .ui-slider {"+B+"transform: scale("+1/p+");}";o.text(F)}ca()}},Hb=function(){a("#dialog_box").hide();if(ga){if(ga)S!== -a("#svg_source_textarea").val()?a.confirm("Ignore changes made to SVG source?",function(f){f&&sb()}):sb();$a()}else Z&&e.leaveContext()},sb=function(){a("#svg_source_editor").hide();ga=false;a("#svg_source_textarea").blur()};a(window).width();a(window).height();var $a=a.noop;a(window).resize(function(){A()});(function(){L.scroll(function(){if(a("#ruler_x").length!=0)a("#ruler_x")[0].scrollLeft=L[0].scrollLeft;if(a("#ruler_y").length!=0)a("#ruler_y")[0].scrollTop=L[0].scrollTop})})();a("#url_notice").click(function(){a.alert(this.title)}); -a("#change_image_url").click(function(){var f=e.getHref(T);f=f.indexOf("data:")===0?"":f;a.prompt("Enter the new image URL",f,function(s){s&&Ia(s)})});var xb=function(f){var s=f[0].id=="stroke_color"?"stroke":"fill",o=f[0].id=="canvas_color";if(o)s="canvas";var p=c.paintBox[s].paint;f=s=="stroke"?"Pick a Stroke Paint and Opacity":"Pick a Fill Paint and Opacity";o=o?{right:175,top:50}:{left:50,bottom:50};a("#color_picker").draggable({cancel:".jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker", -containment:"window"}).removeAttr("style").css(o).jGraduate({paint:p,window:{pickerTitle:f},images:{clientPath:u.jGraduatePath},newstop:"inverse"},function(B){p=new a.jGraduate.Paint(B);c.paintBox[s].setPaint(p);e.setPaint(s,p);a("#color_picker").hide()},function(){a("#color_picker").hide()})};d=function(f,s){var o=document.getElementById("canvas_background"),p={color:"fff",opacity:1};if(s=="stroke")p=u.initStroke;if(s=="fill")p=u.initFill;if(s=="canvas"&&o)if(o=o.getAttribute("fill").match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/))p= -{color:("0"+parseInt(o[1],10).toString(16)).slice(-2)+("0"+parseInt(o[2],10).toString(16)).slice(-2)+("0"+parseInt(o[3],10).toString(16)).slice(-2),opacity:1};o=(new DOMParser).parseFromString(' ',"text/xml").documentElement;o=a(f)[0].appendChild(document.importNode(o,true));s==="canvas"?o.setAttribute("width",60.5): -o.setAttribute("width","100%");this.rect=o.firstChild;this.defs=o.getElementsByTagName("defs")[0];this.grad=this.defs.firstChild;this.paint=new a.jGraduate.Paint({solidColor:p.color});this.type=s;this.setPaint=function(B,F){this.paint=B;var I="none",J=B.type,O=B.alpha/100;switch(J){case "solidColor":I=B[J]=="none"||B[J]=="one"?"none":"#"+B[J];break;case "linearGradient":case "radialGradient":this.defs.removeChild(this.grad);this.grad=this.defs.appendChild(B[J]);I="url(#"+(this.grad.id="gradbox_"+ -this.type)+")"}this.rect.setAttribute("fill",I);this.rect.setAttribute("opacity",O);if(this.type=="canvas")if(J=document.getElementById("canvas_background")){ma=e.getResolution();J.setAttribute("x",-1);J.setAttribute("y",-1);J.setAttribute("width",ma.w+2);J.setAttribute("height",ma.h+2);I.indexOf("url")==-1&&J.setAttribute("fill",I)}else Ha(I);if(F){e.setColor(this.type,I,true);e.setPaintOpacity(this.type,O,true)}};this.update=function(B){if(T){var F=this.type;switch(T.tagName){case "use":case "image":case "foreignObject":return; -case "g":case "a":for(var I=null,J=T.getElementsByTagName("*"),O=0,W=J.length;O=1){O=e.getResolution();a("#canvas_width").val(O.w.toFixed());a("#canvas_height").val(O.h.toFixed());a("#resolution_label").html("
    "+O.w+"\u00d7
    "+O.h+"
    ")}else requestAnimationFrame(J)};J()}else{a("#resolution_label").html("Custom");f.removeAttribute("readonly");f.focus();f.select();if(f.value=="fit"){f.value=100;s.value=100}}});a("#zoom").change(function(){La(this)});a("input,select").attr("autocomplete","off");var m=function(){var f= -[{sel:"#tool_select",fn:ub,evt:"click",key:["V",true]},{sel:"#tool_fhpath",fn:nb,evt:"click",key:["Q",true]},{sel:"#tool_line",fn:gb,evt:"click",key:["L",true]},{sel:"#tool_rect",fn:Sa,evt:"click",key:["R",true],icon:"rect"},{sel:"#tool_ellipse",fn:Xa,evt:"mouseup",key:["C",true],icon:"ellipse"},{sel:"#tool_path",fn:xa,evt:"click",key:["P",true]},{sel:"#tool_text",fn:Qa,evt:"click",key:["T",true]},{sel:"#tool_image",fn:ya,evt:"mouseup"},{sel:"#tool_zoom",fn:sa,evt:"mouseup",key:["Z",true]},{sel:"#tool_clear", -fn:ba,evt:"mouseup",key:[z+"N",true]},{sel:"#tool_save",fn:function(){if(ga)Ab();else{Da(a("#file_menu"));e.save({images:b.img_save,round_digits:6})}},evt:"mouseup",key:[z+"S",true]},{sel:"#tool_export",fn:Ra,evt:"mouseup"},{sel:"#tool_open",fn:eb,evt:"mouseup"},{sel:"#tool_import",fn:Wa,evt:"mouseup"},{sel:"#tool_source",fn:yb,evt:"click",key:[z+"U",true]},{sel:"#tool_wireframe",fn:Kb,evt:"click"},{sel:"#tool_snap",fn:Fb,evt:"click"},{sel:"#tool_rulers",fn:Gb,evt:"click"},{sel:"#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel", -fn:Hb,evt:"click",key:["esc",false,false],hidekey:true},{sel:"#tool_source_save",fn:Ab,evt:"click"},{sel:"#tool_delete,#tool_delete_multi",fn:bb,evt:"click",key:["del/backspace",true]},{sel:"#tool_reorient",fn:kb,evt:"click"},{sel:"#tool_node_link",fn:vb,evt:"change"},{sel:"#tool_node_clone",fn:qb,evt:"click"},{sel:"#tool_node_delete",fn:lb,evt:"click"},{sel:"#tool_openclose_path",fn:V,evt:"click"},{sel:"#tool_add_subpath",fn:ha,evt:"click"},{sel:"#tool_move_top",fn:rb,evt:"click",key:z+"shift+up"}, -{sel:"#tool_move_bottom",fn:Ja,evt:"click",key:z+"shift+down"},{sel:"#tool_move_up",fn:Ka,evt:"click",key:[z+"up",true]},{sel:"#tool_move_down",fn:pb,evt:"click",key:[z+"down",true]},{sel:"#tool_topath",fn:ob,evt:"click"},{sel:"#tool_make_link,#tool_make_link_multi",fn:db,evt:"click"},{sel:"#tool_clone,#tool_clone_multi",fn:Cb,evt:"click",key:[z+"D",true]},{sel:"#tool_group",fn:mb,evt:"click",key:[z+"G",true]},{sel:"#tool_ungroup",fn:mb,evt:"click",key:z+"shift+G"},{sel:"#tool_unlink_use",fn:mb,evt:"click"}, -{sel:"[id^=tool_align]",fn:Bb,evt:"click"},{sel:"#tool_undo",fn:Na,evt:"click",key:z+"z"},{sel:"#tool_redo",fn:ib,evt:"click",key:["y",true]},{sel:"#tool_cut",fn:jb,evt:"click",key:[z+"x",true]},{sel:"#tool_copy",fn:Ya,evt:"click",key:z+"c"},{sel:"#tool_paste",fn:Ta,evt:"click",key:z+"v"},{sel:"#tool_switch",fn:ab,evt:"click",key:["x",true]},{sel:"#tool_bold",fn:Ba,evt:"mousedown",key:[z+"B",true]},{sel:"#tool_italic",fn:Pa,evt:"mousedown",key:[z+"I",true]},{sel:"#copy_save_done",fn:Hb,evt:"click"}, -{key:"ctrl+left",fn:function(){P(0,1)}},{key:"ctrl+right",fn:function(){P(1,1)}},{key:"ctrl+shift+left",fn:function(){P(0,5)}},{key:"ctrl+shift+right",fn:function(){P(1,5)}},{key:"shift+O",fn:R},{key:"shift+P",fn:da},{key:[z+"+",true],fn:function(){Ca(2)}},{key:[z+"-",true],fn:function(){Ca(0.5)}},{key:["up",true],fn:function(){Za(0,-1)}},{key:["down",true],fn:function(){Za(0,1)}},{key:["left",true],fn:function(){Za(-1,0)}},{key:["right",true],fn:function(){Za(1,0)}},{key:"shift+up",fn:function(){Za(0, --10)}},{key:"shift+down",fn:function(){Za(0,10)}},{key:"shift+left",fn:function(){Za(-10,0)}},{key:"shift+right",fn:function(){Za(10,0)}},{key:["alt+up",true],fn:function(){e.cloneSelectedElements(0,-1)}},{key:["alt+down",true],fn:function(){e.cloneSelectedElements(0,1)}},{key:["alt+left",true],fn:function(){e.cloneSelectedElements(-1,0)}},{key:["alt+right",true],fn:function(){e.cloneSelectedElements(1,0)}},{key:["alt+shift+up",true],fn:function(){e.cloneSelectedElements(0,-10)}},{key:["alt+shift+down", -true],fn:function(){e.cloneSelectedElements(0,10)}},{key:["alt+shift+left",true],fn:function(){e.cloneSelectedElements(-10,0)}},{key:["alt+shift+right",true],fn:function(){e.cloneSelectedElements(10,0)}},{key:z+"A",fn:function(){e.selectAllInCurrentLayer()}},{key:"I",fn:function(){var o=a(".tool_button_current");if(o.length&&o[0].id!=="tool_eyedropper"){o.removeClass("tool_button_current").addClass("tool_button");a("#tool_eyedropper").addClass("tool_button_current").removeClass("tool_button")}e.setMode("eyedropper")}}, -{key:z+"shift+z",fn:ib},{key:"esc",fn:Eb}],s={"4/Shift+4":"#tools_rect_show","5/Shift+5":"#tools_ellipse_show"};return{setAll:function(){var o={};a.each(f,function(p,B){if(B.sel){var F=a(B.sel);if(F.length==0)return true;if(B.evt){if(svgedit.browser.isTouch()&&B.evt==="click")B.evt="mousedown";F[B.evt](B.fn)}if(B.parent&&a(B.parent+"_show").length!=0){var I=a(B.parent);I.length||(I=Y(B.parent.substr(1)));I.append(F);a.isArray(o[B.parent])||(o[B.parent]=[]);o[B.parent].push(B)}}if(B.key){var J=B.fn, -O=false;if(a.isArray(B.key)){I=B.key[0];if(B.key.length>1)O=B.key[1]}else I=B.key;I+="";svgedit.browser.isMac&&I.indexOf("+")!=-1&&I.split("+")[0]=="ctrl"&&I.replace("ctrl","cmd");a.each(I.split("/"),function(aa,X){a(document).bind("keydown",X,function(ea){J();O&&ea.preventDefault();return false})});if(B.sel&&!B.hidekey&&F.attr("title")){var W=F.attr("title").split("[")[0]+" ("+I+")";s[I]=B.sel;F.parents("#main_menu").length||F.attr("title",W)}}});la(o);a(window).bind("keydown","tab",function(p){if(U=== -"canvas"){p.preventDefault();da()}}).bind("keydown","shift+tab",function(p){if(U==="canvas"){p.preventDefault();R()}});a("#tool_zoom").dblclick(Fa)},setTitles:function(){a.each(s,function(o,p){var B=a(p).parents("#main_menu").length;a(p).each(function(){var F=B?a(this).text().split(" [")[0]:this.title.split(" [")[0],I="";a.each(o.split("/"),function(J,O){var W=O.split("+"),aa="";if(W.length>1){aa=W[0]+"+";O=W[1]}I+=(J?"/":"")+aa+O});if(B)this.lastChild.textContent=F+" ["+I+"]";else this.title=F+" ["+ -I+"]"})})},getButtonData:function(o){var p;a.each(f,function(B,F){if(F.sel===o)p=F});return p}}}();m.setAll();c.ready(function(){var f=u.initTool,s=a("#tools_left, #svg_editor .tools_flyout"),o=s.find("#tool_"+f);f=s.find("#"+f);(o.length?o:f.length?f:a("#tool_select")).click().mouseup();u.wireframe&&a("#tool_wireframe").click();u.showlayers&&toggleSidePanel();a("#rulers").toggle(!!u.showRulers)});a("#canvas_height").dragInput({min:10,max:null,step:10,callback:h,cursor:false,dragAdjust:0.1});a("#canvas_width").dragInput({min:10, -max:null,step:10,callback:h,cursor:false,dragAdjust:0.1});a("#rect_width").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_height").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_cx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_cy").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#ellipse_rx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false}); -a("#ellipse_ry").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_height").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_cx").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_cy").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#circle_r").dragInput({min:1,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_height").dragInput({min:0,max:null,step:1,callback:changeAttribute, -cursor:false});a("#selected_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#selected_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_node_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_node_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_width").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_x1").dragInput({min:null, -max:null,step:1,callback:changeAttribute,cursor:false});a("#line_x2").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_y1").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#line_y2").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#path_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false}); -a("#rect_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#g_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#g_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#text_y").dragInput({min:null,max:null,step:1,callback:changeAttribute, -cursor:false});a("#text_x").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#image_y").dragInput({min:null,max:null,step:1,callback:changeAttribute,cursor:false});a("#rect_rx").dragInput({min:0,max:100,step:1,callback:changeAttribute,cursor:true});a("#stroke_width").dragInput({min:0,max:99,step:1,callback:function(f){var s=f.value;if(s==0&&T&&["line","polyline"].indexOf(T.nodeName)>=0)s=f.value=1;e.setStrokeWidth(s)},cursor:true,smallStep:0.1,start:1.5});a("#angle").dragInput({min:-180, -max:180,step:1,callback:function(f){e.setRotationAngle(f.value,true);rotateCursor(f.value);a("#tool_reorient").toggleClass("disabled",f.value==0)},cursor:false,dragAdjust:0.5});a("#font_size").dragInput({min:1,max:250,step:1,callback:function(f){e.setFontSize(f.value)},cursor:true,stepfunc:function(f,s){var o=f.value-0,p=o+s,B=p>=o;if(s===0)return o;return o>=24?B?Math.round(o*1.1):Math.round(o/1.1):o<=1?B?o*2:o/2:p},dragAdjust:0.15});a("#group_opacity").dragInput({min:0,max:100,step:5,callback:changeAttribute, -cursor:true,start:100});a("#blur").dragInput({min:0,max:10,step:0.1,callback:function(f,s){val=f.value;a("#blur").val(val);s?e.setBlur(val,true):e.setBlurNoUndo(val)},cursor:true,start:0});a("#zoom").val(e.getZoom()*100);a("#workarea").contextMenu({menu:"cmenu_canvas",inSpeed:0},function(f){switch(f){case "delete":bb();break;case "cut":jb();break;case "copy":Ya();break;case "paste":e.pasteElements();break;case "paste_in_place":e.pasteElements("in_place");break;case "group":e.groupSelectedElements(); -break;case "ungroup":e.ungroupSelectedElement();break;case "move_front":rb();break;case "move_up":cb("Up");break;case "move_down":cb("Down");break;case "move_back":Ja();break;default:svgedit.contextmenu&&svgedit.contextmenu.hasCustomHandler(f)&&svgedit.contextmenu.getCustomHandler(f).call()}});a(".contextMenu li").mousedown(function(f){f.preventDefault()});a("#cmenu_canvas li").disableContextMenu();N.enableContextMenuItems("#delete,#cut,#copy");window.onbeforeunload=function(){if(w.getUndoStackSize()=== -0)c.show_save_warning=false;if(!u.no_save_warning&&c.show_save_warning)return"There are unsaved changes."};c.openPrep=function(f){a("#main_menu").hide();w.getUndoStackSize()===0?f(true):a.confirm("Do you want to open a new file?\nThis will also erase your undo history",f)};if(window.FileReader){d=function(f){f.stopPropagation();f.preventDefault();a("#workarea").removeAttr("style");a("#main_menu").hide();var s=null;if(s=f.type=="drop"?f.dataTransfer.files[0]:this.files[0])if(s.type.indexOf("image")!= --1)if(s.type.indexOf("svg")!=-1){f=new FileReader;f.onloadend=function(o){e.importSvgString(o.target.result,true);e.ungroupSelectedElement();e.ungroupSelectedElement();e.groupSelectedElements();e.alignSelectedElements("m","page");e.alignSelectedElements("c","page")};f.readAsText(s)}else{f=new FileReader;f.onloadend=function(o){insertNewImage=function(I,J){var O=e.addSvgElementFromJson({element:"image",attr:{x:0,y:0,width:I,height:J,id:e.getNextId(),style:"pointer-events:inherit"}});e.setHref(O,o.target.result); -e.selectOnly([O]);e.alignSelectedElements("m","page");e.alignSelectedElements("c","page");Ea()};var p=100,B=100,F=new Image;F.src=o.target.result;document.body.appendChild(F);F.onload=function(){p=F.offsetWidth;B=F.offsetHeight;insertNewImage(p,B);document.body.removeChild(F)}};f.readAsDataURL(s)}};L=a("#workarea");L[0].addEventListener("dragenter",function(f){f.stopPropagation();f.preventDefault();L.css({"-webkit-transform":"scale3d(1.1,1.1,1)","-moz-transform":"scale3d(1.1,1.1,1)","-o-transform":"scale(1.1)", -"-ms-transform":"scale3d(1.1,1.1,1)",transform:"scale3d(1.1,1.1,1)"})},false);L[0].addEventListener("dragover",function(f){f.stopPropagation();f.preventDefault()},false);L[0].addEventListener("dragleave",function(f){L.removeAttr("style");f.stopPropagation();f.preventDefault()},false);L[0].addEventListener("drop",d,false);var C=a('').change(function(){var f=this;c.openPrep(function(s){if(s){e.clear();if(f.files.length==1){s=new FileReader;s.onloadend=function(o){n(o.target.result); -A()};s.readAsText(f.files[0])}}})});a("#tool_open").show().prepend(C);d=a('').change(d);a("#tool_import").show().prepend(d)}var A=c.updateCanvas=function(f,s){var o=L.width(),p=L.height(),B=o,F=p,I=e.getZoom(),J=L,O=a("#svgcanvas"),W={x:J[0].scrollLeft+B/2,y:J[0].scrollTop+F/2},aa=u.canvas_expansion;o=Math.max(B,e.contentW*I*aa);p=Math.max(F,e.contentH*I*aa);o==B&&p==F?L.css("overflow","hidden"):L.css("overflow","scroll");aa=O.height()/2;var X=O.width()/2;O.width(o).height(p);var ea= -p/2,Q=o/2,ka=e.updateCanvas(o,p),ra=Q/X;o=o/2-B/2;p=p/2-F/2;if(s){s.x+=ka.x;s.y+=ka.y}else s={x:Q+(W.x-X)*ra,y:ea+(W.y-aa)*ra};if(f)if(e.contentW>J.width()){L[0].scrollLeft=ka.x-10;L[0].scrollTop=ka.y-10}else{J[0].scrollLeft=o;J[0].scrollTop=p}else{J[0].scrollLeft=s.x-B/2;J[0].scrollTop=s.y-F/2}if(u.showRulers){B=O;I=I;document.getElementById("workarea");document.getElementById("title_show");I||(I=e.getZoom());B||(B=a("#svgcanvas"));F=e.getContentElem();J=svgedit.units.getTypeMap()[u.baseUnit];for(O= -0;O<2;O++){X=(W=O===0)?"x":"y";ra=W?"width":"height";aa=F.getAttribute(X)-0;X=a("#ruler_"+X+" canvas:first");$hcanv=X.clone();X.replaceWith($hcanv);o=$hcanv[0];ea=X=B[ra]()*2;o.parentNode.style[ra]=ea+"px";Q=0;var ta;ka=o.getContext("2d");ka.fillStyle="rgb(200,0,0)";ka.fillRect(0,0,o.width,o.height);$hcanv.siblings().remove();if(X>=3E4){var Aa=parseInt(X/3E4)+1;ta=Array(Aa);ta[0]=ka;for(p=1;p=1)p=Math.round(Aa);else{p=(o+"").split(".")[1].length;p=Aa.toFixed(p)-0}if(p!==0&&p!==1E3&&p%1E3===0)p=p/1E3+"K";if(W){ka.fillText(p,Ma+2,8);ka.fillStyle="#777"}else{Aa= -(p+"").split("");for(p=0;pX){Q++;ka.stroke();if(Q>=ta.length){p=10;Ma=ea;continue}ka=ta[Q];Ma-=3E4;tb=Math.round(Ma+Aa*p)+0.5}var zb=p%2?12:10;if(W){ka.moveTo(tb,15);ka.lineTo(tb,zb)}else{ka.moveTo(15,tb);ka.lineTo(zb,tb)}}}ka.strokeStyle="#666";ka.stroke()}L.scroll()}},G=[];for(d=0.1;d<1E5;d*=10){G.push(1*d);G.push(2*d);G.push(5*d)}A(true);try{var E=function(f){if(window.JSON&& -JSON.stringify)return JSON.stringify(f);var s=arguments.callee;if(typeof f=="boolean"||typeof f=="number")return f+"";else if(typeof f=="string")return'"'+f.replace(/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,function(B){return"\\u"+("0000"+B.charCodeAt(0).toString(16)).slice(-4)})+'"';else if(f.length){for(var o=0;o0?(b-u)/k:200,q=d/l*k,z=0,D=this.getAttribute("data-attr"),w=methodDraw.canvas,K=svgedit.browser.isTouch(),L=true,N=d&&this.dragCfg.cursor?$("
    ").appendTo(e):false;c.attr("readonly","readonly");N&&!isNaN(this.dragCfg.start)&&N.css("top",this.dragCfg.start*-1/q+l);this.adjustValue= -function(H,U){var S;H=parseFloat(H);S=isNaN(this.value)?this.dragCfg.reset:$.isFunction(this.dragCfg.stepfunc)?this.dragCfg.stepfunc(this,H):Number((Number(this.value)+Number(H)).toFixed(5));if(b!==null)S=Math.min(S,b);if(u!==null)S=Math.max(S,u);N&&this.updateCursor(S);this.value=S;e.attr("data-value",S);$.isFunction(this.dragCfg.callback)&&this.dragCfg.callback(this,U)};e.toggleClass("draginput",e.is("label"));this.move=function(H,U,S){if(K)H=H.originalEvent.touches[0];if(z===0)z=U;U=(H.pageY-z)* --1;z=H.pageY;S=U*q*n;this.adjustValue(S.toFixed(k<1?1:0))};this.stop=function(){var H=w.getSelectedElems();$("body").removeClass("dragging");e.removeClass("active");L=true;$(window).unbind("mousemove.draginput touchmove.draginput mouseup.draginput touchend.draginput");z=0;if(H[0]){H=w.undoMgr.finishUndoableChange();H.isEmpty()||w.undoMgr.addCommandToHistory(H)}this.adjustValue(0,L)};this.updateCursor=function(){var H=parseFloat(this.value)*-1/q+l;N.css("top",H)};this.launch=function(H){var U=w.getSelectedElems(); -if(K)H=H.originalEvent.touches[0];var S=H.pageY,M=this.value,T=this;w.undoMgr.beginUndoableChange(D,U);$("body").addClass("dragging");e.addClass("active");$(window).bind("mousemove.draginput touchmove.draginput",function(ia){T.move(ia,S,parseFloat(M))});$(window).bind("mouseup.draginput touchend.draginput",function(){T.stop()})};$(this).attr("readonly","readonly").attr("data-scale",q).attr("data-domain",l).attr("data-cursor",N!=false).bind("mousedown touchstart",function(H){this.blur();this.launch(H)}).bind("dblclick taphold", -function(){this.removeAttribute("readonly","readonly");this.focus();this.select()}).keydown(function(H){switch(H.keyCode){case 13:this.adjustValue(0);this.blur()}}).focus(function(){this.getAttribute("readonly")==="readonly"&&this.blur()}).blur(function(){this.setAttribute("readonly","readonly")}).bind("mousewheel",function(H,U,S,M){U=w.getSelectedElems();L&&w.undoMgr.beginUndoableChange(D,U);L=false;clearTimeout(window.undoTimeout);window.undoTimeout=setTimeout(function(){T.stop()},200);var T=this; -if(M>0)this.adjustValue(this.dragCfg.step);else M<0&&this.adjustValue(-this.dragCfg.step);H.preventDefault()})})};$.fn.dragInput.updateCursor=function(a){var n=parseFloat(a.value),e=parseFloat(a.getAttribute("data-scale")),c=parseFloat(a.getAttribute("data-domain"));n=n*-1/e+c+"px";a=a.parentNode.lastChild;if(a.className=="draginput_cursor")a.style.top=n};svgedit=svgedit||{}; -(function(){var a=this;if(!svgedit.contextmenu)svgedit.contextmenu={};a.contextMenuExtensions={};methodDraw.ready(function(){for(menuItem in contextMenuExtensions){var n=contextMenuExtensions[menuItem];Object.keys(a.contextMenuExtensions).length==0&&$("#cmenu_canvas").append("
  • ");var e=n.shortcut||"";$("#cmenu_canvas").append("
  • "+n.label+""+e+"
  • ")}});svgedit.contextmenu.resetCustomMenus=function(){a.contextMenuExtensions= -{}};svgedit.contextmenu.add=function(n){if(n&&n.id&&n.label&&n.action&&typeof n.action=="function")if(n.id in a.contextMenuExtensions)console.error('Cannot add extension "'+n.id+'", an extension by that name already exists"');else{console.log("Registed contextmenu item: {id:"+n.id+", label:"+n.label+"}");a.contextMenuExtensions[n.id]=n}else console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function")};svgedit.contextmenu.hasCustomHandler= -function(n){return a.contextMenuExtensions[n]&&true};svgedit.contextmenu.getCustomHandler=function(n){return a.contextMenuExtensions[n].action}})();(function(a,n){function e(l){return!a(l).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(l,u){var b=l.nodeName.toLowerCase();if("area"===b){b=l.parentNode;var k=b.name;if(!l.href||!k||b.nodeName.toLowerCase()!=="map")return false;b=a("img[usemap=#"+k+"]")[0];return!!b&&e(b)}return(/input|select|textarea|button|object/.test(b)?!l.disabled:"a"==b?l.href||u:u)&&e(l)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.17", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(l,u){return typeof l=="number"?this.each(function(){var b= -this;setTimeout(function(){a(b).focus();u&&u.call(b)},l)}):this._focus.apply(this,arguments)},scrollParent:function(){var l;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?l=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):l=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this, -"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!l.length?a(document):l},zIndex:function(l){if(l!==n)return this.css("zIndex",l);if(this.length){l=a(this[0]);for(var u;l.length&&l[0]!==document;){u=l.css("position");if(u==="absolute"||u==="relative"||u==="fixed"){u=parseInt(l.css("zIndex"),10);if(!isNaN(u)&&u!==0)return u}l=l.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(l){l.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(l,u){function b(z,D,w,K){a.each(k,function(){D-=parseFloat(a.curCSS(z,"padding"+this,true))||0;w&&(D-=parseFloat(a.curCSS(z,"border"+this+"Width",true))||0);K&&(D-=parseFloat(a.curCSS(z,"margin"+this,true))||0)});return D}var k=u==="Width"?["Left","Right"]:["Top","Bottom"],d=u.toLowerCase(),q={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight, -outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+u]=function(z){if(z===n)return q["inner"+u].call(this);return this.each(function(){a(this).css(d,b(this,z)+"px")})};a.fn["outer"+u]=function(z,D){if(typeof z!="number")return q["outer"+u].call(this,z);return this.each(function(){a(this).css(d,b(this,z,true,D)+"px")})}}),a.extend(a.expr[":"],{data:function(l,u,b){return!!a.data(l,b[3])},focusable:function(l){return c(l,!isNaN(a.attr(l,"tabindex")))},tabbable:function(l){var u=a.attr(l, -"tabindex"),b=isNaN(u);return(b||u>=0)&&c(l,!b)}}),a(function(){var l=document.body,u=l.appendChild(u=document.createElement("div"));a.extend(u.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=u.offsetHeight===100;a.support.selectstart="onselectstart"in u;l.removeChild(u).style.display="none"}),a.extend(a.ui,{plugin:{add:function(l,u,b){l=a.ui[l].prototype;for(var k in b){l.plugins[k]=l.plugins[k]||[];l.plugins[k].push([u,b[k]])}},call:function(l,u,b){if((u=l.plugins[u])&& -l.element[0].parentNode)for(var k=0;k0)return true;l[b]=1;k=l[b]>0;l[b]=0;return k},isOverAxis:function(l,u,b){return l>u&&l=9)&&!e.button)return this._mouseUp(e);if(this._mouseStarted){this._mouseDrag(e);return e.preventDefault()}this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==false,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e));return!this._mouseStarted},_mouseUp:function(e){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);this._mouseStarted&& -(this._mouseStarted=false,e.target==this._mouseDownEvent.target&&a.data(e.target,this.widgetName+".preventClickEvent",true),this._mouseStop(e));return false},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){this.options.helper=="original"&& -!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative");this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(n){var e=this.options; -if(this.helper||e.disabled||a(n.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(n);if(!this.handle)return false;e.iframeFix&&a(e.iframeFix===true?"iframe":e.iframeFix).each(function(){a('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(n){var e=this.options;this.helper= -this._createHelper(n);this._cacheHelperProportions();a.ui.ddmanager&&(a.ui.ddmanager.current=this);this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:n.pageX-this.offset.left,top:n.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(n);this.originalPageX=n.pageX;this.originalPageY=n.pageY;e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt);e.containment&&this._setContainment();if(this._trigger("start",n)===false){this._clear();return false}this._cacheHelperProportions();a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,n);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(n,true);a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,n);return true}, -_mouseDrag:function(n,e){this.position=this._generatePosition(n);this.positionAbs=this._convertPositionTo("absolute");if(!e){var c=this._uiHash();if(this._trigger("drag",n,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,n);return false},_mouseStop:function(n){var e= -false;a.ui.ddmanager&&!this.options.dropBehaviour&&(e=a.ui.ddmanager.drop(this,n));this.dropped&&(e=this.dropped,this.dropped=false);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!e||this.options.revert=="valid"&&e||this.options.revert===true||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,e)){var c=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10), -function(){c._trigger("stop",n)!==false&&c._clear()})}else this._trigger("stop",n)!==false&&this._clear();return false},_mouseUp:function(n){this.options.iframeFix===true&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,n);return a.ui.mouse.prototype._mouseUp.call(this,n)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(n){var e=!this.options.handle|| -!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==n.target&&(e=true)});return e},_createHelper:function(n){var e=this.options;n=a.isFunction(e.helper)?a(e.helper.apply(this.element[0],[n])):e.helper=="clone"?this.element.clone().removeAttr("id"):this.element;n.parents("body").length||n.appendTo(e.appendTo=="parent"?this.element[0].parentNode:e.appendTo);n[0]!=this.element[0]&&!/(fixed|absolute)/.test(n.css("position"))&& -n.css("position","absolute");return n},_adjustOffsetFromHelper:function(n){typeof n=="string"&&(n=n.split(" "));a.isArray(n)&&(n={left:+n[0],top:+n[1]||0});"left"in n&&(this.offset.click.left=n.left+this.margins.left);"right"in n&&(this.offset.click.left=this.helperProportions.width-n.right+this.margins.left);"top"in n&&(this.offset.click.top=n.top+this.margins.top);"bottom"in n&&(this.offset.click.top=this.helperProportions.height-n.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var n=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(n.left+=this.scrollParent.scrollLeft(),n.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)n={top:0,left:0};return{top:n.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:n.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var n=this.element.position();return{top:n.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:n.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var n=this.options;n.containment=="parent"&&(n.containment=this.helper[0].parentNode);if(n.containment=="document"||n.containment=="window")this.containment=[n.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,n.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(n.containment=="document"?0:a(window).scrollLeft())+a(n.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(n.containment=="document"?0:a(window).scrollTop())+(a(n.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(n.containment)&&n.containment.constructor!=Array){n=a(n.containment);var e=n[0];if(e){n.offset();var c=a(e).css("overflow")!= -"hidden";this.containment=[(parseInt(a(e).css("borderLeftWidth"),10)||0)+(parseInt(a(e).css("paddingLeft"),10)||0),(parseInt(a(e).css("borderTopWidth"),10)||0)+(parseInt(a(e).css("paddingTop"),10)||0),(c?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(a(e).css("borderLeftWidth"),10)||0)-(parseInt(a(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(a(e).css("borderTopWidth"), -10)||0)-(parseInt(a(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=n}}else n.containment.constructor==Array&&(this.containment=n.containment)},_convertPositionTo:function(n,e){e||(e=this.position);var c=n=="absolute"?1:-1,l=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,u=/(html|body)/i.test(l[0].tagName);return{top:e.top+ -this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():u?0:l.scrollTop())*c),left:e.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():u?0:l.scrollLeft())*c)}},_generatePosition:function(n){var e=this.options,c=this.cssPosition=="absolute"&& -(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,l=/(html|body)/i.test(c[0].tagName),u=n.pageX,b=n.pageY;if(this.originalPosition){var k;if(this.containment){if(this.relative_container){k=this.relative_container.offset();k=[this.containment[0]+k.left,this.containment[1]+k.top,this.containment[2]+k.left,this.containment[3]+k.top]}else k=this.containment;n.pageX-this.offset.click.leftk[2]&&(u=k[2]+this.offset.click.left);n.pageY-this.offset.click.top>k[3]&&(b=k[3]+this.offset.click.top)}if(e.grid){b=e.grid[1]?this.originalPageY+Math.round((b-this.originalPageY)/e.grid[1])*e.grid[1]:this.originalPageY;b=k?b-this.offset.click.topk[3]?b-this.offset.click.topk[2]?u-this.offset.click.left=0;z--){var D=c.snapElements[z].left,w=D+c.snapElements[z].width,K=c.snapElements[z].top,L=K+c.snapElements[z].height;if(D-u
    ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(e.range==="min"||e.range==="max"?" ui-slider-range-"+e.range:"")));for(var b=c.length;b"); -this.handles=c.add(a(u.join("")).appendTo(n.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(k){k.preventDefault()}).hover(function(){e.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){e.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(k){a(this).data("index.ui-slider-handle", -k)});this.handles.keydown(function(k){var d=true,q=a(this).data("index.ui-slider-handle"),z,D,w;if(!n.options.disabled){switch(k.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d=false;if(!n._keySliding){n._keySliding=true;a(this).addClass("ui-state-active");z=n._start(k,q);if(z===false)return}}z=n.options.step;n.options.values&&n.options.values.length? -D=w=n.values(q):D=w=n.value();switch(k.keyCode){case a.ui.keyCode.HOME:w=n._valueMin();break;case a.ui.keyCode.END:w=n._valueMax();break;case a.ui.keyCode.PAGE_UP:w=n._trimAlignValue(D+(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.PAGE_DOWN:w=n._trimAlignValue(D-(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(D===n._valueMax())return;w=n._trimAlignValue(D+z);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(D===n._valueMin())return;w=n._trimAlignValue(D- -z)}n._slide(k,q,w);return d}}).keyup(function(k){var d=a(this).data("index.ui-slider-handle");n._keySliding&&(n._keySliding=false,n._stop(k,d),n._change(k,d),a(this).removeClass("ui-state-active"))});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(n){var e=this.options,c,l,u,b,k;if(e.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:n.pageX,y:n.pageY});l=this._valueMax()-this._valueMin()+1;b=this;this.handles.each(function(d){var q=Math.abs(c-b.values(d));l>q&&(l=q,u=a(this),k=d)});e.range===true&&this.values(1)===e.min&&(k+=1,u=a(this.handles[k]));if(this._start(n,k)===false)return false; -this._mouseSliding=true;b._handleIndex=k;u.addClass("ui-state-active").focus();e=u.offset();this._clickOffset=!a(n.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:n.pageX-e.left-u.width()/2,top:n.pageY-e.top-u.height()/2-(parseInt(u.css("borderTopWidth"),10)||0)-(parseInt(u.css("borderBottomWidth"),10)||0)+(parseInt(u.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(n,k,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(n){var e= -this._normValueFromMouse({x:n.pageX,y:n.pageY});this._slide(n,this._handleIndex,e);return false},_mouseStop:function(n){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(n,this._handleIndex);this._change(n,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(n){var e,c;this.orientation==="horizontal"? -(e=this.elementSize.width,c=n.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,c=n.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0));n=c/e;n>1&&(n=1);n<0&&(n=0);this.orientation==="vertical"&&(n=1-n);e=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+n*e)},_start:function(n,e){var c={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(e), -c.values=this.values());return this._trigger("start",n,c)},_slide:function(n,e,c){var l,u,b;this.options.values&&this.options.values.length?(l=this.values(e?0:1),this.options.values.length===2&&this.options.range===true&&(e===0&&c>l||e===1&&c1){this.options.values[n]=this._trimAlignValue(e);this._refreshValue();this._change(null,n)}else{if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(n):this.value();c=this.options.values;l=arguments[0];for(u=0;u=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,c=(n-this._valueMin())%e;n=n-c;Math.abs(c)*2>=e&&(n+=c>0?e:-e);return parseFloat(n.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var n= -this.options.range,e=this.options,c=this,l=this._animateOff?false:e.animate,u,b={},k,d,q,z;this.options.values&&this.options.values.length?this.handles.each(function(D){u=(c.values(D)-c._valueMin())/(c._valueMax()-c._valueMin())*100;b[c.orientation==="horizontal"?"left":"bottom"]=u+"%";a(this).stop(1,1)[l?"animate":"css"](b,e.animate);c.options.range===true&&(c.orientation==="horizontal"?(D===0&&c.range.stop(1,1)[l?"animate":"css"]({left:u+"%"},e.animate),D===1&&c.range[l?"animate":"css"]({width:u- -k+"%"},{queue:false,duration:e.animate})):(D===0&&c.range.stop(1,1)[l?"animate":"css"]({bottom:u+"%"},e.animate),D===1&&c.range[l?"animate":"css"]({height:u-k+"%"},{queue:false,duration:e.animate})));k=u}):(d=this.value(),q=this._valueMin(),z=this._valueMax(),u=z!==q?(d-q)/(z-q)*100:0,b[c.orientation==="horizontal"?"left":"bottom"]=u+"%",this.handle.stop(1,1)[l?"animate":"css"](b,e.animate),n==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[l?"animate":"css"]({width:u+"%"},e.animate), -n==="max"&&this.orientation==="horizontal"&&this.range[l?"animate":"css"]({width:100-u+"%"},{queue:false,duration:e.animate}),n==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[l?"animate":"css"]({height:u+"%"},e.animate),n==="max"&&this.orientation==="vertical"&&this.range[l?"animate":"css"]({height:100-u+"%"},{queue:false,duration:e.animate}))}});a.extend(a.ui.slider,{version:"1.8.17"})})(jQuery);(function(a){Math.precision=function(b,k){if(k===undefined)k=0;return Math.round(b*Math.pow(10,k))/Math.pow(10,k)};var n=function(b,k){var d=this,q=b.find("img:first"),z=0,D=100,w=100,K=0,L=100,N=100,H=0,U=0,S,M,T=[],ia=function(Y){for(var ca=0;capa)ca=pa;if(Y<0)Y=0;else if(Y>oa)Y=oa;ja.call(d,"xy",{x:ca/pa*w+z,y:Y/oa*N+K})},ja=function(Y,ca,pa){if(ca===undefined){if(Y===undefined||Y==null)Y="xy";switch(Y.toLowerCase()){case "x":return H;case "y":return U; -default:return{x:H,y:U}}}if(!(pa!=null&&pa==d)){var oa=false,na,ma;if(Y==null)Y="xy";switch(Y.toLowerCase()){case "x":na=ca&&(ca.x&&ca.x|0||ca|0)||0;break;case "y":ma=ca&&(ca.y&&ca.y|0||ca|0)||0;break;default:na=ca&&ca.x&&ca.x|0||0;ma=ca&&ca.y&&ca.y|0||0}if(na!=null){if(naD)na=D;if(H!=na){H=na;oa=true}}if(ma!=null){if(maL)ma=L;if(U!=ma){U=ma;oa=true}}oa&&ia.call(d,pa||d)}},la=function(Y){a.isFunction(Y)&&T.push(Y)};a.extend(true,d,{val:ja,range:function(Y,ca){if(ca=== -undefined){if(Y===undefined||Y==null)Y="all";switch(Y.toLowerCase()){case "minx":return z;case "maxx":return D;case "rangex":return{minX:z,maxX:D,rangeX:w};case "miny":return K;case "maxy":return L;case "rangey":return{minY:K,maxY:L,rangeY:N};default:return{minX:z,maxX:D,rangeX:w,minY:K,maxY:L,rangeY:N}}}var pa,oa,na,ma;if(Y==null)Y="all";switch(Y.toLowerCase()){case "minx":pa=ca&&(ca.minX&&ca.minX|0||ca|0)||0;break;case "maxx":oa=ca&&(ca.maxX&&ca.maxX|0||ca|0)||0;break;case "rangex":pa=ca&&ca.minX&& -ca.minX|0||0;oa=ca&&ca.maxX&&ca.maxX|0||0;break;case "miny":na=ca&&(ca.minY&&ca.minY|0||ca|0)||0;break;case "maxy":ma=ca&&(ca.maxY&&ca.maxY|0||ca|0)||0;break;case "rangey":na=ca&&ca.minY&&ca.minY|0||0;ma=ca&&ca.maxY&&ca.maxY|0||0;break;default:pa=ca&&ca.minX&&ca.minX|0||0;oa=ca&&ca.maxX&&ca.maxX|0||0;na=ca&&ca.minY&&ca.minY|0||0;ma=ca&&ca.maxY&&ca.maxY|0||0}if(pa!=null&&z!=pa){z=pa;w=D-z}if(oa!=null&&D!=oa){D=oa;w=D-z}if(na!=null&&K!=na){K=na;N=L-K}if(ma!=null&&L!=ma){L=ma;N=L-K}},bind:la,unbind:function(Y){if(a.isFunction(Y))for(var ca;(ca= -a.inArray(Y,T))!=-1;)T.splice(ca,1)},destroy:function(){a(document).unbind("mouseup",fa).unbind("mousemove",Z);b.unbind("mousedown",ga);T=q=b=null}});q.src=k.arrow&&k.arrow.image;q.w=k.arrow&&k.arrow.width||q.width();q.h=k.arrow&&k.arrow.height||q.height();b.w=k.map&&k.map.width||b.width();b.h=k.map&&k.map.height||b.height();b.bind("mousedown",ga);la.call(d,function(){var Y=0,ca=0,pa=b.w,oa=b.h,na=q.w,ma=q.h;setTimeout(function(){if(w>0)Y=H==D?pa:H/w*pa|0;if(N>0)ca=U==L?oa:U/N*oa|0;if(na>=pa)Y=(pa>> -1)-(na>>1);else Y-=na>>1;if(ma>=oa)ca=(oa>>1)-(ma>>1);else ca-=ma>>1;q.css({left:Y+"px",top:ca+"px"})},0)})},e=function(b,k,d,q){var z=this;b=b.find("td.Text input");var D=b.eq(3),w=b.eq(4),K=b.eq(5),L=b.length>7?b.eq(6):null,N=b.eq(0),H=b.eq(1),U=b.eq(2),S=b.eq(b.length>7?7:6),M=b.length>7?b.eq(8):null,T=function(ja){if(!(ja.target.value==""&&ja.target!=S.get(0)&&(d!=null&&ja.target!=d.get(0)||d==null))){if(!Z(ja))return ja;switch(ja.target){case D.get(0):switch(ja.keyCode){case 38:D.val(fa.call(z, -(D.val()<<0)+1,0,255));k.val("r",D.val(),ja.target);return false;case 40:D.val(fa.call(z,(D.val()<<0)-1,0,255));k.val("r",D.val(),ja.target);return false}break;case w.get(0):switch(ja.keyCode){case 38:w.val(fa.call(z,(w.val()<<0)+1,0,255));k.val("g",w.val(),ja.target);return false;case 40:w.val(fa.call(z,(w.val()<<0)-1,0,255));k.val("g",w.val(),ja.target);return false}break;case K.get(0):switch(ja.keyCode){case 38:K.val(fa.call(z,(K.val()<<0)+1,0,255));k.val("b",K.val(),ja.target);return false;case 40:K.val(fa.call(z, -(K.val()<<0)-1,0,255));k.val("b",K.val(),ja.target);return false}break;case L&&L.get(0):switch(ja.keyCode){case 38:L.val(fa.call(z,parseFloat(L.val())+1,0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);return false;case 40:L.val(fa.call(z,parseFloat(L.val())-1,0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);return false}break;case N.get(0):switch(ja.keyCode){case 38:N.val(fa.call(z,(N.val()<<0)+1,0,360));k.val("h",N.val(),ja.target);return false;case 40:N.val(fa.call(z, -(N.val()<<0)-1,0,360));k.val("h",N.val(),ja.target);return false}break;case H.get(0):switch(ja.keyCode){case 38:H.val(fa.call(z,(H.val()<<0)+1,0,100));k.val("s",H.val(),ja.target);return false;case 40:H.val(fa.call(z,(H.val()<<0)-1,0,100));k.val("s",H.val(),ja.target);return false}break;case U.get(0):switch(ja.keyCode){case 38:U.val(fa.call(z,(U.val()<<0)+1,0,100));k.val("v",U.val(),ja.target);return false;case 40:U.val(fa.call(z,(U.val()<<0)-1,0,100));k.val("v",U.val(),ja.target);return false}}}}, -ia=function(ja){if(!(ja.target.value==""&&ja.target!=S.get(0)&&(d!=null&&ja.target!=d.get(0)||d==null))){if(!Z(ja))return ja;switch(ja.target){case D.get(0):D.val(fa.call(z,D.val(),0,255));k.val("r",D.val(),ja.target);break;case w.get(0):w.val(fa.call(z,w.val(),0,255));k.val("g",w.val(),ja.target);break;case K.get(0):K.val(fa.call(z,K.val(),0,255));k.val("b",K.val(),ja.target);break;case L&&L.get(0):L.val(fa.call(z,L.val(),0,100));k.val("a",Math.precision(L.val()*255/100,q),ja.target);break;case N.get(0):N.val(fa.call(z, -N.val(),0,360));k.val("h",N.val(),ja.target);break;case H.get(0):H.val(fa.call(z,H.val(),0,100));k.val("s",H.val(),ja.target);break;case U.get(0):U.val(fa.call(z,U.val(),0,100));k.val("v",U.val(),ja.target);break;case S.get(0):S.val(S.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));d&&d.val(S.val());k.val("hex",S.val()!=""?S.val():null,ja.target);break;case d&&d.get(0):d.val(d.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));S.val(d.val());k.val("hex",d.val()!=""?d.val(): -null,ja.target);break;case M&&M.get(0):M.val(M.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,2));k.val("a",M.val()!=null?parseInt(M.val(),16):null,ja.target)}}},ga=function(ja){if(k.val()!=null)switch(ja.target){case D.get(0):D.val(k.val("r"));break;case w.get(0):w.val(k.val("g"));break;case K.get(0):K.val(k.val("b"));break;case L&&L.get(0):L.val(Math.precision(k.val("a")*100/255,q));break;case N.get(0):N.val(k.val("h"));break;case H.get(0):H.val(k.val("s"));break;case U.get(0):U.val(k.val("v")); -break;case S.get(0):case d&&d.get(0):S.val(k.val("hex"));d&&d.val(k.val("hex"));break;case M&&M.get(0):M.val(k.val("ahex").substring(6))}},Z=function(ja){switch(ja.keyCode){case 9:case 16:case 29:case 37:case 39:return false;case "c".charCodeAt():case "v".charCodeAt():if(ja.ctrlKey)return false}return true},fa=function(ja,la,Y){if(ja==""||isNaN(ja))return la;if(ja>Y)return Y;if(ja255)Z.r=255;if(d!=Z.r){d=Z.r;ga=true}break;case "g":if(ua)continue;fa=true;Z.g=M&&M.g&&M.g|0||M&&M|0||0;if(Z.g<0)Z.g=0;else if(Z.g>255)Z.g=255;if(q!=Z.g){q=Z.g;ga=true}break;case "b":if(ua)continue;fa=true;Z.b=M&&M.b&&M.b|0||M&&M|0||0;if(Z.b<0)Z.b=0;else if(Z.b>255)Z.b=255;if(z!=Z.b){z=Z.b;ga=true}break;case "a":Z.a=M&&M.a!=null?M.a|0:M!=null?M|0:255;if(Z.a< -0)Z.a=0;else if(Z.a>255)Z.a=255;if(D!=Z.a){D=Z.a;ga=true}break;case "h":if(fa)continue;ua=true;Z.h=M&&M.h&&M.h|0||M&&M|0||0;if(Z.h<0)Z.h=0;else if(Z.h>360)Z.h=360;if(w!=Z.h){w=Z.h;ga=true}break;case "s":if(fa)continue;ua=true;Z.s=M&&M.s!=null?M.s|0:M!=null?M|0:100;if(Z.s<0)Z.s=0;else if(Z.s>100)Z.s=100;if(K!=Z.s){K=Z.s;ga=true}break;case "v":if(fa)continue;ua=true;Z.v=M&&M.v!=null?M.v|0:M!=null?M|0:100;if(Z.v<0)Z.v=0;else if(Z.v>100)Z.v=100;if(L!=Z.v){L=Z.v;ga=true}}if(ga){if(fa){d=d||0;q=q||0;z= -z||0;M=u.rgbToHsv({r:d,g:q,b:z});w=M.h;K=M.s;L=M.v}else if(ua){w=w||0;K=K!=null?K:100;L=L!=null?L:100;M=u.hsvToRgb({h:w,s:K,v:L});d=M.r;q=M.g;z=M.b}D=D!=null?D:255;H.call(k,T||k)}}}};a.extend(true,k,{val:U,bind:function(S){a.isFunction(S)&&N.push(S)},unbind:function(S){if(a.isFunction(S))for(var M;(M=a.inArray(S,N))!=-1;)N.splice(M,1)},destroy:function(){N=null}});if(b)if(b.ahex!=null)U("ahex",b);else if(b.hex!=null)U((b.a!=null?"a":"")+"hex",b.a!=null?{ahex:b.hex+u.intToHex(b.a)}:b);else if(b.r!= -null&&b.g!=null&&b.b!=null)U("rgb"+(b.a!=null?"a":""),b);else if(b.h!=null&&b.s!=null&&b.v!=null)U("hsv"+(b.a!=null?"a":""),b)},ColorMethods:{hexToRgba:function(b){b=this.validateHex(b);if(b=="")return{r:null,g:null,b:null,a:null};var k="00",d="00",q="00",z="255";if(b.length==6)b+="ff";if(b.length>6){k=b.substring(0,2);d=b.substring(2,4);q=b.substring(4,6);z=b.substring(6,b.length)}else{if(b.length>4){k=b.substring(4,b.length);b=b.substring(0,4)}if(b.length>2){d=b.substring(2,b.length);b=b.substring(0, -2)}if(b.length>0)q=b.substring(0,b.length)}return{r:this.hexToInt(k),g:this.hexToInt(d),b:this.hexToInt(q),a:this.hexToInt(z)}},validateHex:function(b){if(typeof b=="object")return"";b=b.toLowerCase().replace(/[^a-f0-9]/g,"");if(b.length>8)b=b.substring(0,8);return b},rgbaToHex:function(b){return this.intToHex(b.r)+this.intToHex(b.g)+this.intToHex(b.b)+this.intToHex(b.a)},intToHex:function(b){b=(b|0).toString(16);if(b.length==1)b="0"+b;return b.toLowerCase()},hexToInt:function(b){return parseInt(b, -16)},rgbToHsv:function(b){var k=b.r/255,d=b.g/255;b=b.b/255;var q={h:0,s:0,v:0},z=0,D=0;if(k>=d&&k>=b){D=k;z=d>b?b:d}else if(d>=b&&d>=k){D=d;z=k>b?b:k}else{D=b;z=d>k?k:d}q.v=D;q.s=D?(D-z)/D:0;if(q.s){z=D-z;q.h=k==D?(d-b)/z:d==D?2+(b-k)/z:4+(k-d)/z;q.h=parseInt(q.h*60);if(q.h<0)q.h+=360}else q.h=0;q.s=q.s*100|0;q.v=q.v*100|0;return q},hsvToRgb:function(b){var k={r:0,g:0,b:0,a:100},d=b.h,q=b.s;b=b.v;if(q==0)k.r=b==0?k.g=k.b=0:k.g=k.b=b*255/100|0;else{if(d==360)d=0;d/=60;q/=100;b/=100;var z=d|0,D=d- -z;d=b*(1-q);var w=b*(1-q*D);q=b*(1-q*(1-D));switch(z){case 0:k.r=b;k.g=q;k.b=d;break;case 1:k.r=w;k.g=b;k.b=d;break;case 2:k.r=d;k.g=b;k.b=q;break;case 3:k.r=d;k.g=w;k.b=b;break;case 4:k.r=q;k.g=d;k.b=b;break;case 5:k.r=b;k.g=d;k.b=w}k.r=k.r*255|0;k.g=k.g*255|0;k.b=k.b*255|0}return k}}};var c=a.jPicker.Color,l=a.jPicker.List,u=a.jPicker.ColorMethods;a.fn.jPicker=function(b){var k=arguments;return this.each(function(){var d=this,q=a.extend(true,{},a.fn.jPicker.defaults,b);if(a(d).get(0).nodeName.toLowerCase()== -"input"){a.extend(true,q,{window:{bindToInput:true,expandable:true,input:a(d)}});if(a(d).val()==""){q.color.active=new c({hex:null});q.color.current=new c({hex:null})}else if(u.validateHex(a(d).val())){q.color.active=new c({hex:a(d).val(),a:q.color.active.val("a")});q.color.current=new c({hex:a(d).val(),a:q.color.active.val("a")})}}if(q.window.expandable)a(d).after('    '); -else q.window.liveUpdate=false;var z=parseFloat(navigator.appVersion.split("MSIE")[1])<7&&document.body.filters,D=null,w=null,K=null,L=null,N=null,H=null,U=null,S=null,M=null,T=null,ia=null,ga=null,Z=null,fa=null,ua=null,ja=null,la=null,Y=null,ca=null,pa=null,oa=null,na=null,ma=null,Ha=null,Ia=null,Ea=null,Va=null,Ua=null,La=function(R){var P=da.active,ba=P.val("hex"),Ba,Pa;q.color.mode=R;switch(R){case "h":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,0);sa.call(d,L,100);ya.call(d, -N,260);sa.call(d,N,100);Sa.call(d,K,"transparent");ya.call(d,U,0);sa.call(d,U,100);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,M,260);sa.call(d,M,100);ya.call(d,T,260);sa.call(d,T,100);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:100,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:360});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("s"),y:100-P.val("v")},Z);fa.val("y",360-P.val("h"),fa);break;case "s":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,-260);ya.call(d, -N,-520);ya.call(d,U,-260);ya.call(d,S,-520);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:360,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:100});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("v")},Z);fa.val("y",100-P.val("s"),fa);break;case "v":setTimeout(function(){Sa.call(d,w,"000000");ya.call(d,L,-780);ya.call(d,N,260);Sa.call(d,K,ba);ya.call(d,U,-520);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,ga,260);sa.call(d,ga,100)},0);Z.range("all",{minX:0,maxX:360, -minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:100});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("s")},Z);fa.val("y",100-P.val("v"),fa);break;case "r":Ba=-1040;Pa=-780;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("b"),y:255-P.val("g")},Z);fa.val("y",255-P.val("r"),fa);break;case "g":Ba=-1560;Pa=-1820;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255}); -if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("b"),y:255-P.val("r")},Z);fa.val("y",255-P.val("g"),fa);break;case "b":Ba=-2080;Pa=-2860;Z.range("all",{minX:0,maxX:255,minY:0,maxY:255});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("r"),y:255-P.val("g")},Z);fa.val("y",255-P.val("b"),fa);break;case "a":setTimeout(function(){Sa.call(d,w,"transparent");ya.call(d,L,-260);ya.call(d,N,-520);ya.call(d,U,260);ya.call(d,S,260);sa.call(d,S,100);ya.call(d,ga,0);sa.call(d, -ga,100)},0);Z.range("all",{minX:0,maxX:360,minY:0,maxY:100});fa.range("rangeY",{minY:0,maxY:255});if(P.val("ahex")==null)break;Z.val("xy",{x:P.val("h"),y:100-P.val("v")},Z);fa.val("y",255-P.val("a"),fa);break;default:throw"Invalid Mode";}switch(R){case "s":case "v":case "a":setTimeout(function(){sa.call(d,L,100);sa.call(d,U,100);ya.call(d,M,260);sa.call(d,M,100);ya.call(d,T,260);sa.call(d,T,100)},0);break;case "r":case "g":case "b":setTimeout(function(){Sa.call(d,w,"transparent");Sa.call(d,K,"transparent"); -sa.call(d,U,100);sa.call(d,L,100);ya.call(d,L,Ba);ya.call(d,N,Ba-260);ya.call(d,U,Pa-780);ya.call(d,S,Pa-520);ya.call(d,M,Pa);ya.call(d,T,Pa-260);ya.call(d,ga,260);sa.call(d,ga,100)},0)}P.val("ahex")!=null&&qa.call(d,P)},qa=function(R,P){if(P==null||P!=fa&&P!=Z)va.call(d,R,P);setTimeout(function(){ub.call(d,R);nb.call(d,R);gb.call(d,R)},0)},wa=function(R,P){var ba=da.active;if(!(P!=Z&&ba.val()==null)){var Ba=R.val("all");switch(q.color.mode){case "h":ba.val("sv",{s:Ba.x,v:100-Ba.y},P);break;case "s":case "a":ba.val("hv", -{h:Ba.x,v:100-Ba.y},P);break;case "v":ba.val("hs",{h:Ba.x,s:100-Ba.y},P);break;case "r":ba.val("gb",{g:255-Ba.y,b:Ba.x},P);break;case "g":ba.val("rb",{r:255-Ba.y,b:Ba.x},P);break;case "b":ba.val("rg",{r:Ba.x,g:255-Ba.y},P)}}},za=function(R,P){var ba=da.active;if(!(P!=fa&&ba.val()==null))switch(q.color.mode){case "h":ba.val("h",{h:360-R.val("y")},P);break;case "s":ba.val("s",{s:100-R.val("y")},P);break;case "v":ba.val("v",{v:100-R.val("y")},P);break;case "r":ba.val("r",{r:255-R.val("y")},P);break; -case "g":ba.val("g",{g:255-R.val("y")},P);break;case "b":ba.val("b",{b:255-R.val("y")},P);break;case "a":ba.val("a",255-R.val("y"),P)}},va=function(R,P){if(P!=Z)switch(q.color.mode){case "h":var ba=R.val("sv");Z.val("xy",{x:ba!=null?ba.s:100,y:100-(ba!=null?ba.v:100)},P);break;case "s":case "a":ba=R.val("hv");Z.val("xy",{x:ba&&ba.h||0,y:100-(ba!=null?ba.v:100)},P);break;case "v":ba=R.val("hs");Z.val("xy",{x:ba&&ba.h||0,y:100-(ba!=null?ba.s:100)},P);break;case "r":ba=R.val("bg");Z.val("xy",{x:ba&& -ba.b||0,y:255-(ba&&ba.g||0)},P);break;case "g":ba=R.val("br");Z.val("xy",{x:ba&&ba.b||0,y:255-(ba&&ba.r||0)},P);break;case "b":ba=R.val("rg");Z.val("xy",{x:ba&&ba.r||0,y:255-(ba&&ba.g||0)},P)}if(P!=fa)switch(q.color.mode){case "h":fa.val("y",360-(R.val("h")||0),P);break;case "s":ba=R.val("s");fa.val("y",100-(ba!=null?ba:100),P);break;case "v":ba=R.val("v");fa.val("y",100-(ba!=null?ba:100),P);break;case "r":fa.val("y",255-(R.val("r")||0),P);break;case "g":fa.val("y",255-(R.val("g")||0),P);break;case "b":fa.val("y", -255-(R.val("b")||0),P);break;case "a":ba=R.val("a");fa.val("y",255-(ba!=null?ba:255),P)}},ub=function(R){try{var P=R.val("all");pa.css({backgroundColor:P&&"#"+P.hex||"transparent"});sa.call(d,pa,P&&Math.precision(P.a*100/255,4)||0)}catch(ba){}},nb=function(R){switch(q.color.mode){case "h":Sa.call(d,w,(new c({h:R.val("h")||0,s:100,v:100})).val("hex"));break;case "s":case "a":var P=R.val("s");sa.call(d,N,100-(P!=null?P:100));break;case "v":P=R.val("v");sa.call(d,L,P!=null?P:100);break;case "r":sa.call(d, -N,Math.precision((R.val("r")||0)/255*100,4));break;case "g":sa.call(d,N,Math.precision((R.val("g")||0)/255*100,4));break;case "b":sa.call(d,N,Math.precision((R.val("b")||0)/255*100))}R=R.val("a");sa.call(d,H,Math.precision((255-(R||0))*100/255,4))},gb=function(R){switch(q.color.mode){case "h":var P=R.val("a");sa.call(d,ia,Math.precision((255-(P||0))*100/255,4));break;case "s":P=R.val("hva");var ba=new c({h:P&&P.h||0,s:100,v:P!=null?P.v:100});Sa.call(d,K,ba.val("hex"));sa.call(d,S,100-(P!=null?P.v: -100));sa.call(d,ia,Math.precision((255-(P&&P.a||0))*100/255,4));break;case "v":P=R.val("hsa");ba=new c({h:P&&P.h||0,s:P!=null?P.s:100,v:100});Sa.call(d,K,ba.val("hex"));sa.call(d,ia,Math.precision((255-(P&&P.a||0))*100/255,4));break;case "r":case "g":case "b":ba=P=0;R=R.val("rgba");if(q.color.mode=="r"){P=R&&R.b||0;ba=R&&R.g||0}else if(q.color.mode=="g"){P=R&&R.b||0;ba=R&&R.r||0}else if(q.color.mode=="b"){P=R&&R.r||0;ba=R&&R.g||0}var Ba=ba>P?P:ba;sa.call(d,S,P>ba?Math.precision((P-ba)/(255-ba)*100, -4):0);sa.call(d,M,ba>P?Math.precision((ba-P)/(255-P)*100,4):0);sa.call(d,T,Math.precision(Ba/255*100,4));sa.call(d,ia,Math.precision((255-(R&&R.a||0))*100/255,4));break;case "a":P=R.val("a");Sa.call(d,K,R.val("hex")||"000000");sa.call(d,ia,P!=null?0:100);sa.call(d,ga,P!=null?100:0)}},Sa=function(R,P){R.css({backgroundColor:P&&P.length==6&&"#"+P||"transparent"})},Xa=function(R,P){if(z&&(P.indexOf("AlphaBar.png")!=-1||P.indexOf("Bars.png")!=-1||P.indexOf("Maps.png")!=-1)){R.attr("pngSrc",P);R.css({backgroundImage:"none", -filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+P+"', sizingMethod='scale')"})}else R.css({backgroundImage:"url('"+P+"')"})},ya=function(R,P){R.css({top:P+"px"})},sa=function(R,P){R.css({visibility:P>0?"visible":"hidden"});if(P>0&&P<100)if(z){var ba=R.attr("pngSrc");ba!=null&&(ba.indexOf("AlphaBar.png")!=-1||ba.indexOf("Bars.png")!=-1||ba.indexOf("Maps.png")!=-1)?R.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ba+"', sizingMethod='scale') progid:DXImageTransform.Microsoft.Alpha(opacity="+ -P+")"}):R.css({opacity:Math.precision(P/100,4)})}else R.css({opacity:Math.precision(P/100,4)});else if(P==0||P==100)if(z){ba=R.attr("pngSrc");ba!=null&&(ba.indexOf("AlphaBar.png")!=-1||ba.indexOf("Bars.png")!=-1||ba.indexOf("Maps.png")!=-1)?R.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ba+"', sizingMethod='scale')"}):R.css({opacity:""})}else R.css({opacity:""})},Fa=function(){da.active.val("ahex",da.current.val("ahex"))},Qa=function(){da.current.val("ahex",da.active.val("ahex"))}, -xa=function(R){a(this).parents("tbody:first").find('input:radio[value!="'+R.target.value+'"]').removeAttr("checked");La.call(d,R.target.value)},bb=function(){Fa.call(d)},jb=function(){Fa.call(d);q.window.expandable&&qb.call(d);a.isFunction(Za)&&Za.call(d,da.active,ma)},Ya=function(){Qa.call(d);q.window.expandable&&qb.call(d);a.isFunction(kb)&&kb.call(d,da.active,na)},Ta=function(){vb.call(d)},rb=function(R){var P=R.val("hex");oa.css({backgroundColor:P&&"#"+P||"transparent"});sa.call(d,oa,Math.precision((R.val("a")|| -0)*100/255,4))},Ja=function(R){var P=R.val("hex");R=R.val("va");Ia.css({backgroundColor:P&&"#"+P||"transparent"});sa.call(d,Ea,Math.precision((255-(R&&R.a||0))*100/255,4));if(q.window.bindToInput&&q.window.updateInputColor)q.window.input.css({backgroundColor:P&&"#"+P||"transparent",color:R==null||R.v>75?"#000000":"#ffffff"})},Ka=function(R){ja=parseInt(D.css("left"));la=parseInt(D.css("top"));Y=R.pageX;ca=R.pageY;a(document).bind("mousemove",pb).bind("mouseup",cb);R.preventDefault()},pb=function(R){D.css({left:ja- -(Y-R.pageX)+"px",top:la-(ca-R.pageY)+"px"});q.window.expandable&&!a.support.boxModel&&D.prev().css({left:D.css("left"),top:D.css("top")});R.stopPropagation();R.preventDefault();return false},cb=function(R){a(document).unbind("mousemove",pb).unbind("mouseup",cb);R.stopPropagation();R.preventDefault();return false},ob=function(R){R.preventDefault();R.stopPropagation();da.active.val("ahex",a(this).attr("title")||null,R.target);return false},kb=a.isFunction(k[1])&&k[1]||null,db=a.isFunction(k[2])&&k[2]|| -null,Za=a.isFunction(k[3])&&k[3]||null,vb=function(){da.current.val("ahex",da.active.val("ahex"));var R=function(){if(!(!q.window.expandable||a.support.boxModel)){var P=D.find("table:first");D.before("