diff --git a/CHANGES b/CHANGES index d043438a..4837483d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,12 @@ 2.0.1 - ???? ??, ???? --------------------- -* added tooltips (patch by codedread) -* fix flyout menus (patch by codedread) +* added tooltips +* fix flyout menus * ask before clearing the drawing (suggested by martin.vidner) -* control group, fill and stroke opacity (suggested by coderead) +* control group, fill and stroke opacity +* fix flyouts when using color picker +* change license from GPLv2 to Apache License v2.0 +* replaced Farbtastic with jPicker, because of the license issues 2.0 - June 03, 2009 ------------------ diff --git a/COPYING b/COPYING deleted file mode 100644 index d511905c..00000000 --- a/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + 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/README b/README index e9b26c19..581857b9 100644 --- a/README +++ b/README @@ -16,6 +16,6 @@ jQuery Right-Click Plugin http://abeautifulsite.net/notebook/68 Copyright (c) 2008 Cory S.N. LaViska -Farbtastic -http://acko.net/dev/farbtastic -Copyright (c) 2007 Steven Wittens +jPicker +http://www.digitalmagicpro.com/jPicker/ +Copyright (c) 2009 Christopher T. Tillman diff --git a/editor/farbtastic.css b/editor/farbtastic.css deleted file mode 100644 index ece6184c..00000000 --- a/editor/farbtastic.css +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Farbtastic Color Picker 1.2 - * © 2008 Steven Wittens - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -.farbtastic { - position: relative; -} -.farbtastic * { - position: absolute; - cursor: crosshair; -} -.farbtastic, .farbtastic .wheel { - width: 195px; - height: 195px; -} -.farbtastic .color, .farbtastic .overlay { - top: 47px; - left: 47px; - width: 101px; - height: 101px; -} -.farbtastic .wheel { - background: url('images/wheel.png') no-repeat; - width: 195px; - height: 195px; -} -.farbtastic .overlay { - background: url('images/mask.png') no-repeat; -} -.farbtastic .marker { - width: 17px; - height: 17px; - margin: -8px 0 0 -8px; - overflow: hidden; - background: url('images/marker.png') no-repeat; -} diff --git a/editor/farbtastic.js b/editor/farbtastic.js deleted file mode 100644 index c346bda4..00000000 --- a/editor/farbtastic.js +++ /dev/null @@ -1,348 +0,0 @@ -/** - * Farbtastic Color Picker 1.2 - * © 2008 Steven Wittens - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -jQuery.fn.farbtastic = function (callback) { - $.farbtastic(this, callback); - return this; -}; - -jQuery.farbtastic = function (container, callback) { - var container = $(container).get(0); - return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback)); -} - -jQuery._farbtastic = function (container, callback) { - // Store farbtastic object - var fb = this; - - // Insert markup - $(container).html('
'); - var e = $('.farbtastic', container); - fb.wheel = $('.wheel', container).get(0); - // Dimensions - fb.radius = 84; - fb.square = 100; - fb.width = 194; - - // Fix background PNGs in IE6 - if (navigator.appVersion.match(/MSIE [0-6]\./)) { - $('*', e).each(function () { - if (this.currentStyle.backgroundImage != 'none') { - var image = this.currentStyle.backgroundImage; - image = this.currentStyle.backgroundImage.substring(5, image.length - 2); - $(this).css({ - 'backgroundImage': 'none', - 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" - }); - } - }); - } - - /** - * Link to the given element(s) or callback. - */ - fb.linkTo = function (callback) { - // Unbind previous nodes - if (typeof fb.callback == 'object') { - $(fb.callback).unbind('keyup', fb.updateValue); - } - - // Reset color - fb.color = null; - - // Bind callback or elements - if (typeof callback == 'function') { - fb.callback = callback; - } - else if (typeof callback == 'object' || typeof callback == 'string') { - fb.callback = $(callback); - fb.callback.bind('keyup', fb.updateValue); - if (fb.callback.get(0).value) { - fb.setColor(fb.callback.get(0).value); - } - } - return this; - } - fb.updateValue = function (event) { - if (this.value && this.value != fb.color) { - fb.setColor(this.value); - } - } - - /** - * Change color with HTML syntax #123456 - */ - fb.setColor = function (color) { - var unpack = fb.unpack(color); - if (fb.color != color && unpack) { - fb.rgb = unpack; - fb.color = fb.pack(unpack); - fb.hsl = fb.RGBToHSL(fb.rgb); - fb.updateDisplay(); - } - return this; - } - - /** - * Change color with HSL triplet [0..1, 0..1, 0..1] - */ - fb.setHSL = function (hsl) { - fb.hsl = hsl; - fb.rgb = fb.HSLToRGB(hsl); - fb.color = fb.pack(fb.rgb); - fb.updateDisplay(); - return this; - } - - ///////////////////////////////////////////////////// - - /** - * Retrieve the coordinates of the given event relative to the center - * of the widget. - */ - fb.widgetCoords = function (event) { - var x, y; - var el = event.target || event.srcElement; - var reference = fb.wheel; - - if (typeof event.offsetX != 'undefined') { - // Use offset coordinates and find common offsetParent - var pos = { x: event.offsetX, y: event.offsetY }; - - // Send the coordinates upwards through the offsetParent chain. - var e = el; - while (e) { - e.mouseX = pos.x; - e.mouseY = pos.y; - pos.x += e.offsetLeft; - pos.y += e.offsetTop; - e = e.offsetParent; - } - - // Look for the coordinates starting from the wheel widget. - var e = reference; - var offset = { x: 0, y: 0 } - while (e) { - if (typeof e.mouseX != 'undefined') { - x = e.mouseX - offset.x; - y = e.mouseY - offset.y; - break; - } - offset.x += e.offsetLeft; - offset.y += e.offsetTop; - e = e.offsetParent; - } - - // Reset stored coordinates - e = el; - while (e) { - e.mouseX = undefined; - e.mouseY = undefined; - e = e.offsetParent; - } - } - else { - // Use absolute coordinates - var pos = fb.absolutePosition(reference); - x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x; - y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y; - } - // Subtract distance to middle - return { x: x - fb.width / 2, y: y - fb.width / 2 }; - } - - /** - * Mousedown handler - */ - fb.mousedown = function (event) { - // Capture mouse - if (!document.dragging) { - $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup); - document.dragging = true; - } - - // Check which area is being dragged - var pos = fb.widgetCoords(event); - fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square; - - // Process - fb.mousemove(event); - return false; - } - - /** - * Mousemove handler - */ - fb.mousemove = function (event) { - // Get coordinates relative to color picker center - var pos = fb.widgetCoords(event); - - // Set new HSL parameters - if (fb.circleDrag) { - var hue = Math.atan2(pos.x, -pos.y) / 6.28; - if (hue < 0) hue += 1; - fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]); - } - else { - var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5)); - var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5)); - fb.setHSL([fb.hsl[0], sat, lum]); - } - return false; - } - - /** - * Mouseup handler - */ - fb.mouseup = function () { - // Uncapture mouse - $(document).unbind('mousemove', fb.mousemove); - $(document).unbind('mouseup', fb.mouseup); - document.dragging = false; - } - - /** - * Update the markers and styles - */ - fb.updateDisplay = function () { - // Markers - var angle = fb.hsl[0] * 6.28; - $('.h-marker', e).css({ - left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px', - top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px' - }); - - $('.sl-marker', e).css({ - left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px', - top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px' - }); - - // Saturation/Luminance gradient - $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5]))); - - // Linked elements or callback - if (typeof fb.callback == 'object') { - // Set background/foreground color - $(fb.callback).css({ - backgroundColor: fb.color, - color: fb.hsl[2] > 0.5 ? '#000' : '#fff' - }); - - // Change linked value - $(fb.callback).each(function() { - if (this.value && this.value != fb.color) { - this.value = fb.color; - } - }); - } - else if (typeof fb.callback == 'function') { - fb.callback.call(fb, fb.color); - } - } - - /** - * Get absolute position of element - */ - fb.absolutePosition = function (el) { - var r = { x: el.offsetLeft, y: el.offsetTop }; - // Resolve relative to offsetParent - if (el.offsetParent) { - var tmp = fb.absolutePosition(el.offsetParent); - r.x += tmp.x; - r.y += tmp.y; - } - return r; - }; - - /* Various color utility functions */ - fb.pack = function (rgb) { - var r = Math.round(rgb[0] * 255); - var g = Math.round(rgb[1] * 255); - var b = Math.round(rgb[2] * 255); - return '#' + (r < 16 ? '0' : '') + r.toString(16) + - (g < 16 ? '0' : '') + g.toString(16) + - (b < 16 ? '0' : '') + b.toString(16); - } - - fb.unpack = function (color) { - if (color.length == 7) { - return [parseInt('0x' + color.substring(1, 3)) / 255, - parseInt('0x' + color.substring(3, 5)) / 255, - parseInt('0x' + color.substring(5, 7)) / 255]; - } - else if (color.length == 4) { - return [parseInt('0x' + color.substring(1, 2)) / 15, - parseInt('0x' + color.substring(2, 3)) / 15, - parseInt('0x' + color.substring(3, 4)) / 15]; - } else if (color.substring(0,4) == 'rgb(') { - color = color.substring(4, color.length-1).split(','); - return [ parseInt(color[0])/255, parseInt(color[1])/255, parseInt(color[2])/255 ]; - } - } - - fb.HSLToRGB = function (hsl) { - var m1, m2, r, g, b; - var h = hsl[0], s = hsl[1], l = hsl[2]; - m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s; - m1 = l * 2 - m2; - return [this.hueToRGB(m1, m2, h+0.33333), - this.hueToRGB(m1, m2, h), - this.hueToRGB(m1, m2, h-0.33333)]; - } - - fb.hueToRGB = function (m1, m2, h) { - h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); - if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; - if (h * 2 < 1) return m2; - if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; - return m1; - } - - fb.RGBToHSL = function (rgb) { - var min, max, delta, h, s, l; - var r = rgb[0], g = rgb[1], b = rgb[2]; - min = Math.min(r, Math.min(g, b)); - max = Math.max(r, Math.max(g, b)); - delta = max - min; - l = (min + max) / 2; - s = 0; - if (l > 0 && l < 1) { - s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l)); - } - h = 0; - if (delta > 0) { - if (max == r && max != g) h += (g - b) / delta; - if (max == g && max != b) h += (2 + (b - r) / delta); - if (max == b && max != r) h += (4 + (r - g) / delta); - h /= 6; - } - return [h, s, l]; - } - - // Install mousedown handler (the others are set on the document on-demand) - $('*', e).mousedown(fb.mousedown); - - // Init color - fb.setColor('#000000'); - - // Set linked elements/callback - if (callback) { - fb.linkTo(callback); - } -} diff --git a/editor/images/marker.png b/editor/images/marker.png deleted file mode 100644 index 3929bbb5..00000000 Binary files a/editor/images/marker.png and /dev/null differ diff --git a/editor/images/mask.png b/editor/images/mask.png deleted file mode 100644 index b0a4d406..00000000 Binary files a/editor/images/mask.png and /dev/null differ diff --git a/editor/images/wheel.png b/editor/images/wheel.png deleted file mode 100644 index 97b343d9..00000000 Binary files a/editor/images/wheel.png and /dev/null differ diff --git a/editor/jpicker/images/bar-blue-bl.png b/editor/jpicker/images/bar-blue-bl.png new file mode 100644 index 00000000..1ffcb504 Binary files /dev/null and b/editor/jpicker/images/bar-blue-bl.png differ diff --git a/editor/jpicker/images/bar-blue-br.png b/editor/jpicker/images/bar-blue-br.png new file mode 100644 index 00000000..c4264013 Binary files /dev/null and b/editor/jpicker/images/bar-blue-br.png differ diff --git a/editor/jpicker/images/bar-blue-tl.png b/editor/jpicker/images/bar-blue-tl.png new file mode 100644 index 00000000..4a8b872a Binary files /dev/null and b/editor/jpicker/images/bar-blue-tl.png differ diff --git a/editor/jpicker/images/bar-blue-tr.png b/editor/jpicker/images/bar-blue-tr.png new file mode 100644 index 00000000..a25d44a1 Binary files /dev/null and b/editor/jpicker/images/bar-blue-tr.png differ diff --git a/editor/jpicker/images/bar-brightness.png b/editor/jpicker/images/bar-brightness.png new file mode 100644 index 00000000..d17b0f01 Binary files /dev/null and b/editor/jpicker/images/bar-brightness.png differ diff --git a/editor/jpicker/images/bar-green-bl.png b/editor/jpicker/images/bar-green-bl.png new file mode 100644 index 00000000..a7debb35 Binary files /dev/null and b/editor/jpicker/images/bar-green-bl.png differ diff --git a/editor/jpicker/images/bar-green-br.png b/editor/jpicker/images/bar-green-br.png new file mode 100644 index 00000000..e077fb1f Binary files /dev/null and b/editor/jpicker/images/bar-green-br.png differ diff --git a/editor/jpicker/images/bar-green-tl.png b/editor/jpicker/images/bar-green-tl.png new file mode 100644 index 00000000..6b4cb400 Binary files /dev/null and b/editor/jpicker/images/bar-green-tl.png differ diff --git a/editor/jpicker/images/bar-green-tr.png b/editor/jpicker/images/bar-green-tr.png new file mode 100644 index 00000000..245c106e Binary files /dev/null and b/editor/jpicker/images/bar-green-tr.png differ diff --git a/editor/jpicker/images/bar-hue.png b/editor/jpicker/images/bar-hue.png new file mode 100644 index 00000000..549b719d Binary files /dev/null and b/editor/jpicker/images/bar-hue.png differ diff --git a/editor/jpicker/images/bar-red-bl.png b/editor/jpicker/images/bar-red-bl.png new file mode 100644 index 00000000..698ec23b Binary files /dev/null and b/editor/jpicker/images/bar-red-bl.png differ diff --git a/editor/jpicker/images/bar-red-br.png b/editor/jpicker/images/bar-red-br.png new file mode 100644 index 00000000..0fd913a9 Binary files /dev/null and b/editor/jpicker/images/bar-red-br.png differ diff --git a/editor/jpicker/images/bar-red-tl.png b/editor/jpicker/images/bar-red-tl.png new file mode 100644 index 00000000..a50a0f56 Binary files /dev/null and b/editor/jpicker/images/bar-red-tl.png differ diff --git a/editor/jpicker/images/bar-red-tr.png b/editor/jpicker/images/bar-red-tr.png new file mode 100644 index 00000000..2b91cc7d Binary files /dev/null and b/editor/jpicker/images/bar-red-tr.png differ diff --git a/editor/jpicker/images/bar-saturation.png b/editor/jpicker/images/bar-saturation.png new file mode 100644 index 00000000..047fb166 Binary files /dev/null and b/editor/jpicker/images/bar-saturation.png differ diff --git a/editor/jpicker/images/map-blue-max.png b/editor/jpicker/images/map-blue-max.png new file mode 100644 index 00000000..93b4ccc5 Binary files /dev/null and b/editor/jpicker/images/map-blue-max.png differ diff --git a/editor/jpicker/images/map-blue-min.png b/editor/jpicker/images/map-blue-min.png new file mode 100644 index 00000000..5329ad29 Binary files /dev/null and b/editor/jpicker/images/map-blue-min.png differ diff --git a/editor/jpicker/images/map-brightness.png b/editor/jpicker/images/map-brightness.png new file mode 100644 index 00000000..53c80efa Binary files /dev/null and b/editor/jpicker/images/map-brightness.png differ diff --git a/editor/jpicker/images/map-green-max.png b/editor/jpicker/images/map-green-max.png new file mode 100644 index 00000000..702eab8d Binary files /dev/null and b/editor/jpicker/images/map-green-max.png differ diff --git a/editor/jpicker/images/map-green-min.png b/editor/jpicker/images/map-green-min.png new file mode 100644 index 00000000..01b3f99d Binary files /dev/null and b/editor/jpicker/images/map-green-min.png differ diff --git a/editor/jpicker/images/map-hue.png b/editor/jpicker/images/map-hue.png new file mode 100644 index 00000000..eae13e92 Binary files /dev/null and b/editor/jpicker/images/map-hue.png differ diff --git a/editor/jpicker/images/map-red-max.png b/editor/jpicker/images/map-red-max.png new file mode 100644 index 00000000..ebabdb92 Binary files /dev/null and b/editor/jpicker/images/map-red-max.png differ diff --git a/editor/jpicker/images/map-red-min.png b/editor/jpicker/images/map-red-min.png new file mode 100644 index 00000000..5ef601a4 Binary files /dev/null and b/editor/jpicker/images/map-red-min.png differ diff --git a/editor/jpicker/images/map-saturation-overlay.png b/editor/jpicker/images/map-saturation-overlay.png new file mode 100644 index 00000000..6b30e2ad Binary files /dev/null and b/editor/jpicker/images/map-saturation-overlay.png differ diff --git a/editor/jpicker/images/map-saturation.png b/editor/jpicker/images/map-saturation.png new file mode 100644 index 00000000..8bd743d3 Binary files /dev/null and b/editor/jpicker/images/map-saturation.png differ diff --git a/editor/jpicker/images/mappoint.gif b/editor/jpicker/images/mappoint.gif new file mode 100644 index 00000000..f5f85574 Binary files /dev/null and b/editor/jpicker/images/mappoint.gif differ diff --git a/editor/jpicker/images/picker.gif b/editor/jpicker/images/picker.gif new file mode 100644 index 00000000..374d8910 Binary files /dev/null and b/editor/jpicker/images/picker.gif differ diff --git a/editor/jpicker/images/rangearrows.gif b/editor/jpicker/images/rangearrows.gif new file mode 100644 index 00000000..218872cc Binary files /dev/null and b/editor/jpicker/images/rangearrows.gif differ diff --git a/editor/jpicker/jpicker.css b/editor/jpicker/jpicker.css new file mode 100644 index 00000000..ca61bc47 --- /dev/null +++ b/editor/jpicker/jpicker.css @@ -0,0 +1,188 @@ +/*[compact]*/ +.jPicker_Picker { + display: inline-block; + height: 24px; /* change this value if using a different sized color picker icon */ + position: relative; /* make this element an absolute positioning container */ + text-align: left; /* make the zero width children position to the left of container */ + width: 25px; /* change this value if using a different sized color picker icon */ +} +.jPicker_Color { + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; +} +.jPicker_Icon { + background-repeat: no-repeat; + cursor: pointer; + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; +} +.jPicker_Container { + display: none; + z-index: 10; /* make sure container draws above color picker icon in Firefox/Safari/Chrome/Opera/etc. - + IE calculates z-index so this won't work - we will hide all color picker icons placed after the selected one in code when shown in IE */ +} +.jPicker_table { + background-color: #efefef; + border: 1px outset #666; + font-family: Arial, Helvetica, Sans-Serif; + font-size: 12px; + height: 320px; + margin: 0px; + padding: 5px; + width: 560px; +} +.jPicker_table td { + margin: 0px; + padding: 0px; + vertical-align: top; +} +.jPicker_MoveBar { + background-color: #dddddd; + border: 1px outset #aaa; + cursor: move; + height: 12px; +} +.jPicker_ColorMap { + border: 2px inset #eee; + cursor: crosshair; + height: 260px; /* IE 6 incorrectly draws border inside the width and height instead of outside - We will fix this to 256px later */ + margin: 12px 5px; + overflow: hidden; /* hide the overdraw of the Color Map icon when at edge of viewing box */ + padding: 0px; + position: relative; /* make this element an absolute positioning container */ + width: 260px; /* IE 6 incorrectly draws border inside the width and height instead of outside - We will fix this to 256px later */ +} +div[class="jPicker_ColorMap"] { + height: 256px; /* correct to 256px for browsers that support the "[class="xxx"]" selector (IE7+,Firefox,Safari,Chrome,Opera,etc.) */ + width: 256px; /* correct to 256px for browsers that support the "[class="xxx"]" selector (IE7+,Firefox,Safari,Chrome,Opera,etc.) */ +} +.jPicker_ColorMap_l1, .jPicker_ColorMap_l2 { + background-repeat: no-repeat; + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; +} +.jPicker_ColorMap_l1 { + background-color: #000000; + background-image: none; +} +.jPicker_ColorMap_l2 { + background-color: transparent; +} +.jPicker_ColorMap_Arrow { + display: block; + position: absolute; +} +.jPicker_ColorBar { + border: 2px inset #eee; + cursor: n-resize; + height: 260px; /* IE 6 incorrectly draws border inside the width and height instead of outside - We will fix this to 256px later */ + margin: 12px 10px; + padding: 0px; + position: relative; + width: 24px; /* IE 6 incorrectly draws border inside the width and height instead of outside - We will fix this to 20px later */ +} +div[class="jPicker_ColorBar"] { + height: 256px; /* correct to 256px for browsers that support the "[class="xxx"]" selector (IE7+,Firefox,Safari,Chrome,Opera,etc.) */ + width: 20px; /* correct to 20px for browsers that support the "[class="xxx"]" selector (IE7+,Firefox,Safari,Chrome,Opera,etc.) */ +} +.jPicker_ColorBar_l1, .jPicker_ColorBar_l2, .jPicker_ColorBar_l3, .jPicker_ColorBar_l4 { + background-repeat: no-repeat; + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; +} +.jPicker_ColorBar_l1, .jPicker_ColorBar_l2, .jPicker_ColorBar_l3 { + background-color: transparent; + background-image: none; +} +.jPicker_ColorBar_l4 { + background-color: transparent; +} +.jPicker_ColorBar_Arrow { + display: block; + left: -10px; /* (arrow width / 2) - (element width / 2) - position arrows' center in elements' center */ + position: absolute; +} +.jPicker_Preview { + font-size: x-small; + text-align: center; +} +.jPicker_Preview div { + border: 2px inset #eee; + height: 62px; + margin: 0px auto; + padding: 0px; + width: 62px; +} +.jPicker_Preview div span { + border: 1px solid #000; + display: block; + height: 30px; + margin: 0px auto; + padding: 0px; + width: 60px; +} +.jPicker_Preview div span.jPicker_Active { + border-bottom-width: 0px; +} +.jPicker_Preview div span.jPicker_Current { + border-top-width: 0px; + cursor: pointer; +} +.jPicker_OkCancel { + text-align: center; + width: 120px; +} +.jPicker_OkCancel input { + width: 100px; +} +.jPicker_OkCancel input.jPicker_Ok { + margin: 12px 0px 5px 0px; +} +.jPicker_Spacer { + height: 10px; +} +.jPicker_RadioText { + background-color: #fff; + border: 1px inset #aaa; + margin: 0px 0px 0px 5px; + width: 30px; +} +.jPicker_EnterHex { + text-align: right; +} +.jPicker_Hex { + background-color: #fff; + border: 1px inset #aaa; + margin: 0px 19px 0px 5px; + width: 50px; +} +.jPicker_Grid { + text-align: center; +} +.jPicker_QuickColor { + border: 1px inset #aaa; + cursor: pointer; + display: block; + float: left; + height: 12px; + line-height: 12px; + margin: 2px 3px 1px 3px; + padding: 0px; + width: 12px; +} diff --git a/editor/jpicker/jpicker.js b/editor/jpicker/jpicker.js new file mode 100644 index 00000000..7392cb16 --- /dev/null +++ b/editor/jpicker/jpicker.js @@ -0,0 +1,1510 @@ +/* + * jPicker 1.0.2 + * + * jQuery Plugin for Photoshop style color picker + * + * Copyright (c) 2009 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($) +{ + 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(id, options) + { + var $this = this, // private properties, methods, and events - keep these variables and classes invisible to outside code + bar = $('#' + id), // 1D or 2D area used for dragging + arrow = $('#' + id + '_Arrow'), // the arrow image image to drag + barMouseDown = // bind the mousedown to the bar not the arrow for quick snapping to the clicked location + function(e) + { + setValuesFromMousePosition(e); + // 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', docMouseMove).bind('mouseup', docMouseUp); + e.stopPropagation(); + e.preventDefault(); // don't try to select anything or drag the image to the desktop + return false; + }, + docMouseMove = // set the values as the mouse moves + function(e) + { + setValuesFromMousePosition(e); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + docMouseUp = // unbind the document events - they aren't needed when not dragging + function(e) + { + $(document).unbind('mouseup', docMouseUp).unbind('mousemove', docMouseMove); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + setValuesFromMousePosition = // calculate mouse position and set value within the current range + function(e) + { + var offset = bar.offset(), // lets not calculate this more than once + x = e.pageX - offset.left - parseInt(bar.css('border-left-width')), + y = e.pageY - offset.top - parseInt(bar.css('border-top-width')), + barW = bar.w, // local copies for YUI compressor + barH = bar.h, + newX, + newY; + // keep the arrow within the bounds of the bar + if (x < 0) x = 0; + else if (x > barW) x = barW; + if (y < 0) y = 0; + else if (y > barH) y = barH; + // we will use Math.floor for ALL conversion to pixel lengths - parseInt takes a string as input so it boxes the number into a string THEN converts it + // number.toFixed(0) spends time processing rounding which when dealing with imprecise pixels is unnecessary + newX = Math.floor(x / barW * $this.mxX); + newY = Math.floor(y / barH * $this.mxY); + $this.x = newX; + $this.y = newY; + // if x or y have no range, set it to 1D dragging + if ($this.mxX == $this.mnX) x = 0; + if ($this.mxY == $this.mnY) y = 0; + // set the arrow position + $this.setArrowPosition(x, y); + // check if this.valuesChanged is a function and execute it if it is + $.isFunction($this.valuesChanged) && $this.valuesChanged($this); + }; + $.extend(true, $this, // public properties, methods, and event - these we need to access from other controls + { + settings: options, // we'll set map and arrow dimensions and image sources + x: 0, // this is the calculated x value based on the x range and mouse position + y: 0, // this is the calculated y value based on the y range and mouse position + mnX: 0, // set the min x value + mxX: 0, // set the max x value + mnY: 100, // set the min y value + mxY: 100, // set the max y value + valuesChanged: $.isFunction(arguments[2]) && arguments[2] || null, // pass this argument or assign the variable to register for callbacks + setPositioningVariables: + function(e) + { + var map = $this.settings.map; // local copy for YUI compressor + bar.w = map && map.width || bar.width(); + bar.h = map && map.height || bar.height(); + $this.MinX = 0; + $this.MinY = 0; + $this.MaxX = bar.w; + $this.MaxY = bar.h; + }, + setArrowPositionFromValues: + function(e) + { + $this.setPositioningVariables(); + var arrowOffsetX = 0, + arrowOffsetY = 0, + // local copies for YUI compressor + mnX = $this.mnX, + mxX = $this.mxX, + mnY = $this.mnY, + mxY = $this.mxY, + x = $this.x, + y = $this.y; + if (mnX != mxX) // range is greater than zero + { + // constrain to bounds + if (x == mnX) arrowOffsetX = 0; + else if (x == mxX) arrowOffsetX = bar.w; + else // set arrow x position + { + if (mnX < 1) mxX += Math.abs(mnX) + 1; + if (x < 1) x += 1; + arrowOffsetX = x / mxX * bar.w; + if (parseInt(arrowOffsetX) == (mxX - 1)) arrowOffsetX = mxX; + else arrowOffsetX = parseInt(arrowOffsetX); + if (mnX < 1) arrowOffsetX -= Math.abs(mnX) - 1; + } + } + if (mnY != mxY) // range is greater than zero + { + // constrain to bounds + if (y == mnY) arrowOffsetY = 0; + else if (y == mxY) arrowOffsetY = bar.h; + else // set arrow y position + { + if (mnY < 1) mxY += Math.abs(mnY) + 1; + if (y < 1) y += 1; + arrowOffsetY = y / mxY * bar.h; + if (parseInt(arrowOffsetY) == (mxY - 1)) arrowOffsetY = mxY; + else arrowOffsetY = parseInt(arrowOffsetY); + if (mnY < 1) arrowOffsetY -= Math.abs(mnY) - 1; + } + } + // set the arrow position based on these offsets + $this.setArrowPosition(arrowOffsetX, arrowOffsetY); + }, + setArrowPosition: + function(offsetX, offsetY) + { + var barW = bar.w, // local copies for YUI compressor + barH = bar.h, + arrowW = arrow.w, + arrowH = arrow.h; + // constrain arrow to bar x + if (offsetX < 0) offsetX = 0; + else if (offsetX > barW) offsetX = barW; + // constrain arrow to bar y + if (offsetY < 0) offsetY = 0; + else if (offsetY > barH) offsetY = barH; + // if arrow width is greater than bar width, center arrow and prevent horizontal dragging + if (arrowW > barW) offsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) + else offsetX -= arrowW >> 1; + // if arrow height is greater than bar height, center arrow and prevent vertical dragging + if (arrowH > barH) offsetY = (barH >> 1) - (arrowH >> 1); + else offsetY -= arrowH >> 1; + // set the elements offsets + arrow.css({ left: offsetX + 'px', top: offsetY + 'px' }); + }, + destroy: + function() + { + // unbind all possible events and null objects + $(document).unbind('mouseup', docMouseUp).unbind('mousemove', docMouseMove); + bar.unbind('mousedown', barMouseDown); + bar = null; + arrow = null; + $this.valuesChanged = null; + } + }); + // initialize this control + arrow.src = $this.settings.arrow && $this.settings.arrow.image; + arrow.w = $this.settings.arrow && $this.settings.arrow.width || arrow.width(); + arrow.h = $this.settings.arrow && $this.settings.arrow.height || arrow.height(); + $this.setPositioningVariables(); + // bind mousedown event + bar.bind('mousedown', barMouseDown); + $this.setArrowPositionFromValues(); + // first callback to set initial values + $.isFunction($this.valuesChanged) && $this.valuesChanged($this); + }, + ColorValuePicker = // controls for all the input elements for the typing in color values + function(id) + { + var $this = this, // private properties and methods + hsvKeyUp = // hue, saturation, or brightness input box key up - validate value and set color + function(e) + { + if (e.target.value == '') return; + validateHsv(e); + $this.setValuesFromHsv(); + $.isFunction($this.valuesChanged) && $this.valuesChanged($this); + }, + rgbKeyUp = // red, green, or blue input box key up - validate and set color + function(e) + { + if (e.target.value == '') return; + validateRgb(e); + $this.setValuesFromRgb(); + $.isFunction($this.valuesChanged) && $this.valuesChanged($this); + }, + hsvBlur = // hue, saturation, or brightness input box blur - reset to original if value empty + function(e) + { + if (e.target.value == '') $this.setValuesFromRgb(); + }, + rgbBlur = // red, green, or blue input box blur - reset to original value if empty + function(e) + { + if (e.target.value == '') $this.setValuesFromHsv(); + }, + hexKeyUp = // hex input box key up - validate and set color + function(e) + { + if (e.target.value == '') return; + validateHex(e); + $this.setValuesFromHex(); + $.isFunction($this.valuesChanged) && $this.valuesChanged($this); + }, + hexBlur = // hex input box blur - reset to original value if empty + function(e) + { + if (e.target.value == '') $this.setValuesFromHsv(); + }, + validateRgb = // validate rgb values + function(e) + { + if (!validateKey(e)) return e; + fields.red.val(setValueInRange(fields.red.val(), 0, 255)); + fields.green.val(setValueInRange(fields.green.val(), 0, 255)); + fields.blue.val(setValueInRange(fields.blue.val(), 0, 255)); + }, + validateHsv = // validate hsv values + function(e) + { + if (!validateKey(e)) return e; + fields.hue.val(setValueInRange(fields.hue.val(), 0, 360)); + fields.saturation.val(setValueInRange(fields.saturation.val(), 0, 100)); + fields.value.val(setValueInRange(fields.value.val(), 0, 100)); + }, + validateHex = // validate hex value + function(e) + { + if (!validateKey(e)) return e; + fields.hex.val(fields.hex.val().replace(/[^a-fA-F0-9]/g, '0').toLowerCase().substring(0, 6)); + }, + validateKey = // validate key + function(e) + { + switch(e.keyCode) + { + case 9: + case 16: + case 29: + case 37: + case 38: + case 40: + 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; + value = parseInt(value); + if (value > max) return max; + if (value < min) return min; + return value; + }; + $.extend(true, $this, // public properties and methods + { + color: new Color(), + fields: + { + hue: $('#' + id + '_jPicker_Hue'), + saturation: $('#' + id + '_jPicker_Saturation'), + value: $('#' + id + '_jPicker_Brightness'), + red: $('#' + id + '_jPicker_Red'), + green: $('#' + id + '_jPicker_Green'), + blue: $('#' + id + '_jPicker_Blue'), + hex: $('#' + id + '_jPicker_Hex') + }, + valuesChanged: $.isFunction(arguments[1]) && arguments[1] || null, + bindedHexKeyUp: // binded input element key up + function(e) + { + hexKeyUp(e); + }, + setValuesFromRgb: // set values when rgb changes + function() + { + color.fromRgb(fields.red.val(), fields.green.val(), fields.blue.val()); + fields.hex.val(color.hex); + fields.hue.val(color.h); + fields.saturation.val(color.s); + fields.value.val(color.v); + }, + setValuesFromHsv: // set values when hsv changes + function() + { + color.fromHsv(fields.hue.val(), fields.saturation.val(), fields.value.val()); + fields.hex.val(color.hex); + fields.red.val(color.r); + fields.green.val(color.g); + fields.blue.val(color.b); + }, + setValuesFromHex: // set values when hex changes + function() + { + color.fromHex(fields.hex.val()); + fields.red.val(color.r); + fields.green.val(color.g); + fields.blue.val(color.b); + fields.hue.val(color.h); + fields.saturation.val(color.s); + fields.value.val(color.v); + }, + destroy: + function() + { + // unbind all events and null objects + fields.hue.add(fields.saturation).add(fields.value).unbind('keyup', events.hsvKeyUp).unbind('blur', hsvBlur); + fields.red.add(fields.green).add(fields.blue).unbind('keyup', events.rgbKeyUp).unbind('blur', rgbBlur); + fields.hex.unbind('keyup', $this.hexKeyUp); + fields = null; + color = null; + $this.valuesChanged = null; + } + }); + var fields = $this.fields, color = $this.color; // local copies for YUI compressor + fields.hue.add(fields.saturation).add(fields.value).bind('keyup', hsvKeyUp).bind('blur', hsvBlur); + fields.red.add(fields.green).add(fields.blue).bind('keyup', rgbKeyUp).bind('blur', rgbBlur); + fields.hex.bind('keyup', hexKeyUp); + if (fields.hex.val() != '') + { + color.fromHex(fields.hex.val()); + $this.setValuesFromHex(); + } + }; + $.jPicker = + { + List: [], // array holding references to each active instance of the control + getListElementById: // retrieve the jPicker object by the initiating objects id + function(id) + { + var List = $.jPicker.List; + for (i = 0; i < List.length; i++) if (List[i].id == id) return List[i]; + return null; + }, + 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; + $.extend(true, $this, // public properties and methods + { + r: 0, // Red + g: 0, // Green + b: 0, // Blue + h: 0, // Hue + s: 0, // Saturation + v: 0, // Brightness + hex: '', // Hex + fromRgb: + function(r, g, b) + { + var $this = this; + $this.r = r; + $this.g = g; + $this.b = b; + var newHsv = ColorMethods.rgbToHsv($this); + $this.h = newHsv.h; + $this.s = newHsv.s; + $this.v = newHsv.v; + $this.hex = ColorMethods.rgbToHex($this); + }, + fromHsv: + function(h, s, v) + { + var $this = this; + $this.h = h; + $this.s = s; + $this.v = v; + var newRgb = ColorMethods.hsvToRgb($this); + $this.r = newRgb.r; + $this.g = newRgb.g; + $this.b = newRgb.b; + $this.hex = ColorMethods.rgbToHex(newRgb); + }, + fromHex: + function(hex) + { + var $this = this; + $this.hex = hex; + var newRgb = ColorMethods.hexToRgb(hex); + $this.r = newRgb.r; + $this.g = newRgb.g; + $this.b = newRgb.b; + var newHsv = ColorMethods.rgbToHsv(newRgb); + $this.h = newHsv.h; + $this.s = newHsv.s; + $this.v = newHsv.v; + $this.hex = ColorMethods.rgbToHex(newRgb); + } + }); + if (init) + { + if (init.hex) $this.fromHex(init.hex); + else if (init.r) $this.fromRgb(init.r, init.g, init.b); + else if (init.h) $this.fromHsv(init.h, init.s, init.v); + } + }, + ColorMethods: // color conversion methods - make public to give use to external scripts + { + hexToRgb: + function(hex) + { + hex = this.validateHex(hex); + var r = '00', g = '00', b = '00'; + if (hex.length == 6) + { + r = hex.substring(0, 2); + g = hex.substring(2, 4); + b = hex.substring(4, 6); + } + 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) }; + }, + validateHex: + function(hex) + { + hex = hex.toLowerCase().replace(/[^a-f0-9]/g, '0'); + if (hex.length > 6) hex = hex.substring(0, 6); + return hex; + }, + rgbToHex: + function(rgb) + { + return this.intToHex(rgb.r) + this.intToHex(rgb.g) + this.intToHex(rgb.b); + }, + intToHex: + function(dec) + { + var result = parseInt(dec).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 = parseInt(hsv.s * 100); + hsv.v = parseInt(hsv.v * 100); + return hsv; + }, + hsvToRgb: + function(hsv) + { + var rgb = { r: 0, g: 0, b: 0 }, 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 = parseInt(v * 255 / 100); + } + else + { + if (h == 360) h = 0; + h /= 60; + s = s / 100; + v = v / 100; + var i = parseInt(h), + 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 = parseInt(rgb.r * 255); + rgb.g = parseInt(rgb.g * 255); + rgb.b = parseInt(rgb.b * 255); + } + 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), id = $this.attr('id'), $settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor + if (!id) + { + alert('Container element must have an id attribute to maintain unique id strings for sub-elements.'); + return; + } + 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, + input: $this + } + }); + if (ColorMethods.validateHex($this.val())) + { + $settings.color.active = new Color({ hex: $this.val() }); + $settings.color.current = new Color({ hex: $this.val() }); + } + $this.after('   '); + } + else // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results + { + $settings.window.draggable = false; + $settings.window.liveUpdate = false; + } + var isLessThanIE7 = parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters, // needed to run the AlphaImageLoader function for IE6 + colorMapL1 = null, // different layers of colorMap and colorBar + colorMapL2 = null, + colorBarL1 = null, + colorBarL2 = null, + colorBarL3 = null, + colorBarL4 = null, + container = null, + hue = null, // radio buttons + saturation = null, + value = null, + red = null, + green = null, + blue = 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, + activeColor = null, // color boxes above the radio buttons + currentColor = null, + okButton = null, + cancelButton = null, + grid = null, // preset colors grid + colorBox = null, // colorBox for popup button + colorIcon = null, // colorIcon popup icon + moveBar = null, // drag bar + setColorMode = // set color mode and update visuals for the new color mode + function(colorMode) + { + color.active = colorPicker.color; + var active = color.active, // local copies for YUI compressor + clientPath = images.clientPath, + resetImage = + function(img) + { + setAlpha(img, 100); + img.css({ backgroundColor: '', backgroundImage: 'none', filter: '' }); + }; + resetImage(colorMapL1); // reset images + resetImage(colorMapL2); + resetImage(colorBarL1); + resetImage(colorBarL2); + resetImage(colorBarL3); + resetImage(colorBarL4); + hue.add(saturation).add(value).add(red).add(green).add(blue).removeAttr('checked'); + switch (colorMode) + { + case 'h': + hue.attr('checked', true); + colorMapL1.css({ backgroundColor: '#' + active.hex }); + colorMapL2.css({ backgroundColor: 'transparent' }); + setImg(colorMapL2, clientPath + 'map-hue.png'); + setAlpha(colorMapL2, 100); + setImg(colorBarL4, clientPath + 'bar-hue.png'); + colorMap.mxX = 100; + colorMap.mxY = 100; + colorBar.mxY = 360; + break; + case 's': + saturation.attr('checked', true); + setImg(colorMapL1, clientPath + 'map-saturation.png'); + setImg(colorMapL2, clientPath + 'map-saturation-overlay.png'); + setAlpha(colorMapL2, 0); + setBG(colorBarL3, active.hex); + setImg(colorBarL4, clientPath + 'bar-saturation.png'); + colorMap.mxX = 360; + colorMap.mxY = 100; + colorBar.mxY = 100; + break; + case 'v': + value.attr('checked', true); + setBG(colorMapL1, '000'); + setImg(colorMapL2, clientPath + 'map-brightness.png'); + colorBarL3.css({ backgroundColor: '#' + active.hex }); + setImg(colorBarL4, clientPath + 'bar-brightness.png'); + colorMap.mxX = 360; + colorMap.mxY = 100; + colorBar.mxY = 100; + break; + case 'r': + red.attr('checked', true); + setImg(colorMapL2, clientPath + 'map-red-max.png'); + setImg(colorMapL1, clientPath + 'map-red-min.png'); + setImg(colorBarL4, clientPath + 'bar-red-tl.png'); + setImg(colorBarL3, clientPath + 'bar-red-tr.png'); + setImg(colorBarL2, clientPath + 'bar-red-br.png'); + setImg(colorBarL1, clientPath + 'bar-red-bl.png'); + break; + case 'g': + green.attr('checked', true); + setImg(colorMapL2, clientPath + 'map-green-max.png'); + setImg(colorMapL1, clientPath + 'map-green-min.png'); + setImg(colorBarL4, clientPath + 'bar-green-tl.png'); + setImg(colorBarL3, clientPath + 'bar-green-tr.png'); + setImg(colorBarL2, clientPath + 'bar-green-br.png'); + setImg(colorBarL1, clientPath + 'bar-green-bl.png'); + break; + case 'b': + blue.attr('checked', true); + setImg(colorMapL2, clientPath + 'map-blue-max.png'); + setImg(colorMapL1, clientPath + 'map-blue-min.png'); + setImg(colorBarL4, clientPath + 'bar-blue-tl.png'); + setImg(colorBarL3, clientPath + 'bar-blue-tr.png'); + setImg(colorBarL2, clientPath + 'bar-blue-br.png'); + setImg(colorBarL1, clientPath + 'bar-blue-bl.png'); + break; + default: + throw ('Invalid Mode'); + break; + } + switch (colorMode) + { + case 'h': + case 's': + case 'v': + colorMap.mnX = 1; + colorMap.mnY = 1; + colorBar.mnY = 1; + break; + case 'r': + case 'g': + case 'b': + colorMap.mnX = 0; + colorMap.mnY = 0; + colorBar.mnY = 0; + colorMap.mxX = 255; + colorMap.mxY = 255; + colorBar.mxY = 255; + break; + } + color.mode = colorMode; + positionMapAndBarArrows(); + updateMapVisuals(); + updateBarVisuals(); + if (window.bindToInput && window.liveUpdate) + { + window.input.val(active.hex).css( + { + backgroundColor: '#' + active.hex, + color: active.v > 75 ? '#000000' : '#ffffff' + }); + colorBox.css({ backgroundColor: '#' + active.hex }); + } + $.isFunction($this.liveCallback) && $this.liveCallback(active); + }, + textValuesChanged = // Update color when user changes text values + function() + { + positionMapAndBarArrows(); + updateVisuals(); + color.active = colorPicker.color; + var active = color.active; // local copy for YUI compressor + if (window.bindToInput && window.liveUpdate) + { + window.input.val(colorPicker.fields.hex.val()).css( + { + backgroundColor: '#' + active.hex, + color: active.v > 75 ? '#000000' : '#ffffff' + }); + colorBox.css({ backgroundColor: '#' + active.hex }); + } + $.isFunction($this.liveCallback) && $this.liveCallback(active); + }, + mapValueChanged = // user has dragged the ColorMap pointer + function() + { + if (!colorPicker || !colorMap || !colorBar) return; + color.active = colorPicker.color; + var fields = colorPicker.fields, // local copies for YUI compressor + active = color.active; + switch (color.mode) + { + case 'h': + fields.saturation.val(colorMap.x); + fields.value.val(100 - colorMap.y); + break; + case 's': + fields.hue.val(colorMap.x); + fields.value.val(100 - colorMap.y); + break; + case 'v': + fields.hue.val(colorMap.x); + fields.saturation.val(100 - colorMap.y); + break; + case 'r': + fields.blue.val(colorMap.x); + fields.green.val(255 - colorMap.y); + break; + case 'g': + fields.blue.val(colorMap.x); + fields.red.val(255 - colorMap.y); + break; + case 'b': + fields.red.val(colorMap.x); + fields.green.val(255 - colorMap.y); + break; + } + switch (color.mode) + { + case 'h': + case 's': + case 'v': + colorPicker.setValuesFromHsv(); + break; + case 'r': + case 'g': + case 'b': + colorPicker.setValuesFromRgb(); + break; + } + updateVisuals(); + if (window.bindToInput && window.liveUpdate) + { + window.input.val(active.hex).css( + { + backgroundColor: '#' + active.hex, + color: active.v > 75 ? '#000000' : '#ffffff' + }); + colorBox.css({ backgroundColor: '#' + active.hex }); + } + $.isFunction($this.liveCallback) && $this.liveCallback(active); + }, + barValueChanged = // user has dragged the ColorBar slider + function() + { + if (!colorPicker || !colorMap || !colorBar) return; + color.active = colorPicker.color; + var fields = colorPicker.fields, // local copies for YUI compressor + active = color.active; + switch (color.mode) + { + case 'h': + fields.hue.val(360 - colorBar.y); + break; + case 's': + fields.saturation.val(100 - colorBar.y); + break; + case 'v': + fields.value.val(100 - colorBar.y); + break; + case 'r': + fields.red.val(255 - colorBar.y); + break; + case 'g': + fields.green.val(255 - colorBar.y); + break; + case 'b': + fields.blue.val(255 - colorBar.y); + break; + } + switch (color.mode) + { + case 'h': + case 's': + case 'v': + colorPicker.setValuesFromHsv(); + break; + case 'r': + case 'g': + case 'b': + colorPicker.setValuesFromRgb(); + break; + } + updateVisuals(); + if (window.bindToInput && window.liveUpdate) + { + window.input.val(active.hex).css( + { + backgroundColor: '#' + active.hex, + color: active.v > 75 ? '#000000' : '#ffffff' + }); + colorBox.css({ backgroundColor: '#' + active.hex }); + } + $.isFunction($this.liveCallback) && $this.liveCallback(active); + }, + positionMapAndBarArrows = // position map and bar arrows to match current color + function() + { + color.active = colorPicker.color; + var sliderValue = 0, + active = color.active; // local copy for YUI compressor + switch ($this.settings.color.mode) + { + case 'h': + sliderValue = 360 - active.h; + break; + case 's': + sliderValue = 100 - active.s; + break; + case 'v': + sliderValue = 100 - active.v; + break; + case 'r': + sliderValue = 255 - active.r; + break; + case 'g': + sliderValue = 255 - active.g; + break; + case 'b': + sliderValue = 255 - active.b; + break; + } + colorBar.y = sliderValue; + colorBar.setArrowPositionFromValues(); + var mapX = 0, mapY = 0; + switch ($this.settings.color.mode) + { + case 'h': + mapX = active.s; + mapY = 100 - active.v; + break; + case 's': + mapX = active.h; + mapY = 100 - active.v; + break; + case 'v': + mapX = active.h; + mapY = 100 - active.s; + break; + case 'r': + mapX = active.b; + mapY = 256 - active.g; + break; + case 'g': + mapX = active.b; + mapY = 256 - active.r; + break; + case 'b': + mapX = active.r; + mapY = 256 - active.g; + break; + } + colorMap.x = mapX; + colorMap.y = mapY; + colorMap.setArrowPositionFromValues(); + }, + updateVisuals = + function() + { + updatePreview(); + updateMapVisuals(); + updateBarVisuals(); + }, + updatePreview = + function() + { + try + { + activeColor.css({ backgroundColor: '#' + colorPicker.color.hex }); + } + catch (e) { } + }, + updateMapVisuals = + function() + { + if (!color || !colorPicker) return; + color.active = colorPicker.color; + var active = color.active; // local copy for YUI compressor + switch (color.mode) + { + case 'h': + var newColor = new Color({ h: active.h, s: 100, v: 100 }); + setBG(colorMapL1, newColor.hex); + break; + case 's': + setAlpha(colorMapL2, 100 - active.s); + break; + case 'v': + setAlpha(colorMapL2, active.v); + break; + case 'r': + setAlpha(colorMapL2, active.r / 256 * 100); + break; + case 'g': + setAlpha(colorMapL2, active.g / 256 * 100); + break; + case 'b': + setAlpha(colorMapL2, active.b / 256 * 100); + break; + } + }, + updateBarVisuals = + function() + { + if (!color || !colorPicker) return; + color.active = colorPicker.color; + var active = color.active, // local copy for YUI compressor + mode = color.mode, + fields = colorPicker.fields; + switch (mode) + { + case 'h': + break; + case 's': + var saturatedColor = new Color({ h: active.h, s: 100, v: active.v }); + setBG(colorBarL3, saturatedColor.hex); + break; + case 'v': + var valueColor = new Color({ h: active.h, s: active.s, v: 100 }); + setBG(colorBarL3, valueColor.hex); + break; + case 'r': + case 'g': + case 'b': + var hValue = 0, vValue = 0; + if (mode == 'r') + { + hValue = fields.blue.val(); + vValue = fields.green.val(); + } + else if (mode == 'g') + { + hValue = fields.blue.val(); + vValue = fields.red.val(); + } + else if (mode == 'b') + { + hValue = fields.red.val(); + vValue = fields.green.val(); + } + var horzPer = hValue / 256 * 100, vertPer = vValue / 256 * 100, horzPerRev = (256 - hValue) / 256 * 100, vertPerRev = (256 - vValue) / 256 * 100; + setAlpha(colorBarL4, vertPer > horzPerRev ? horzPerRev : vertPer); + setAlpha(colorBarL3, vertPer > horzPer ? horzPer : vertPer); + setAlpha(colorBarL2, vertPerRev > horzPer ? horzPer : vertPerRev); + setAlpha(colorBarL1, vertPerRev > horzPerRev ? horzPerRev : vertPerRev); + break; + } + }, + setBG = + function(el, c) + { + try + { + el.css({ backgroundColor: '#' + c }); + } + catch (e) { } + }, + setImg = + function(img, src) + { + if (src.indexOf('png') && this.isLessThanIE7) + { + img.attr('pngSrc', src); + img.css({ backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\')' }); + } + else img.css({ backgroundImage: 'url(' + src + ')' }); + }, + setAlpha = + function(obj, alpha) + { + if (alpha == 0) + { + obj.css({ display: 'none' }); + return; + } + else if (alpha < 100) + { + obj.css({ display: '' }); + if (this.isLessThanIE7) + { + var src = obj.attr('pngSrc'); + if (src != null && src.indexOf('map-hue') == -1) + obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' }); + } + else obj.css({ opacity: alpha / 100 }); + } + else if (alpha == 100) // IE7 still will not combine 8-bit PNG translucency AND element opacity without drawing errors + // Even opacity:1.0 (or filter:Alpha(opacity=100)) causes issues, so remove it if opaque + { + obj.css({ display: '' }); + if (this.isLessThanIE7) + { + var src = obj.attr('pngSrc'); + if (src != null && src.indexOf('map-hue') == -1) obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\')' }); + } + else obj.css({ opacity: '' }); + } + }, + revertColor = // revert color to original color when opened + function() + { + colorPicker.fields.hex.val(color.current.hex); + colorPicker.setValuesFromHex(); + $.isFunction(colorPicker.valuesChanged) && colorPicker.valuesChanged(colorPicker); + }, + radioClicked = + function(e) + { + setColorMode(e.target.value); + }, + currentClicked = + function() + { + revertColor(); + }, + cancelClicked = + function() + { + revertColor(); + window.bindToInput && $this.hide(); + $.isFunction($this.cancelCallback) && $this.cancelCallback(); + }, + commitColor = // commit the color changes + function() + { + var active = color.active; // local copies for YUI compressor + color.current = new Color({ hex: active.hex }); + currentColor.css({ backgroundColor: '#' + active.hex }); + if (window.bindToInput) + { + window.input.val(active.hex).css( + { + backgroundColor: '#' + active.hex, + color: active.v > 75 ? '#000000' : '#ffffff' + }); + colorBox.css({ backgroundColor: '#' + active.hex }); + } + $.isFunction($this.commitCallback) && $this.commitCallback(active); + }, + okClicked = + function() + { + commitColor(); + window.bindToInput && $this.hide(); + }, + colorIconClicked = + function() + { + $this.show(); + }, + moveBarMouseDown = + function(e) + { + var element = window.element, // local copies for YUI compressor + page = 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.stopPropagation(); + e.preventDefault(); // prevent attempted dragging of the column + return false; + }, + documentMouseMove = + function(e) + { + container.css({ left: elementStartX - (pageStartX - e.pageX) + 'px', top: elementStartY - (pageStartY - e.pageY) + 'px' }); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + documentMouseUp = + function(e) + { + $(document).unbind('mousemove', documentMouseMove).unbind('mouseup', documentMouseUp); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + bindedHexKeyUp = + function(e) + { + colorPicker.fields.hex.val($this.settings.window.input.val()); + colorPicker.bindedHexKeyUp(e); + }, + quickPickClicked = + function(e) + { + colorPicker.fields.hex.val(color.quickList[e.data.i].hex); + colorPicker.setValuesFromHex(); + $.isFunction(colorPicker.valuesChanged) && colorPicker.valuesChanged(colorPicker); + }; + $.extend(true, $this, // pulic properties, methods, and callbacks + { + id: $this.attr('id'), + settings: $settings, + color: null, + icon: null, + commitCallback: $.isFunction($arguments[1]) && $arguments[1] || null, // commitCallback function can be overridden to return the selected color to a method you specify when the user clicks "OK" + liveCallback: $.isFunction($arguments[2]) && $arguments[2] || null, // liveCallback function can be overridden to return the selected color to a method you specify in live mode (continuous update) + cancelCallback: $.isFunction($arguments[3]) && $arguments[3] || null, // cancelCallback function can be overridden to a method you specify when the user clicks "Cancel" + show: + function() + { + if (document.all) // In IE, due to calculated z-index values, we need to hide all color picker icons that appear later in the source code than this one + { + var foundthis = false; + for (i = 0; i < List.length; i++) + { + if (foundthis) List[i].color.add(List[i].icon).css({ display: 'none' }); + if (List[i].id == $this.id) foundthis = true; + } + } + color.current = new Color({ hex: color.active.hex }); + currentColor.css({ backgroundColor: '#' + color.active.hex }); + container.css({ display: 'block' }); + colorMap.setPositioningVariables(); + colorBar.setPositioningVariables(); + positionMapAndBarArrows(); + }, + hide: + function() + { + if (document.all) // In IE, show the previously hidden color picker icons again + { + var foundthis = false; + for (i = 0; i < List.length; i++) + { + if (foundthis) List[i].color.add(List[i].icon).css({ display: 'block' }); + if (List[i].id == $this.id) foundthis = true; + } + } + container.css({ display: 'none' }); + }, + destroy: // destroys this control entirely, removing all events and objects, and removing itself from the List + function() + { + if (window.bindToInput) + { + colorIcon = $('#' + $this.id + '_jPicker_Icon').unbind('click', colorIconClicked); + window.input.unbind('keyup', bindedHexKeyUp).unbind('change', bindedHexKeyUp); + } + hue.add(saturation).add(value).add(red).add(green).add(blue).unbind('click', radioClicked); + currentColor.unbind('click', currentClicked); + cancelButton.unbind('click', cancelClicked); + okButton.unbind('click', okClicked); + if (window.draggable) moveBar.unbind('mousedown', moveBarMouseDown); + if (color.quickList && color.quickList.length > 0) + for (i = 0; i < color.quickList.length; i++) + $('#' + $this.id + '_jPicker_Grid_' + i, container).unbind('click', quickPickClicked); + hue = null; + saturation = null; + value = null; + red = null; + green = null; + blue = null; + colorMapL1 = null; + colorMapL2 = null; + colorBarL1 = null; + colorBarL2 = null; + colorBarL3 = null; + colorBarL4 = null; + activeColor = null; + currentColor = null; + okButton = null; + cancelButton = null; + grid = null; + $this.color = null; + $this.icon = null; + colorMap.destroy(); + colorMap = null; + colorBar.destroy(); + colorBar = null; + colorPicker.destroy(); + colorPicker = null; + $this.commitCallback = null; + $this.cancelCallback = null; + $this.liveCallback = null; + container.html(''); + for (i = 0; i < List.length; i++) if (List[i].id == $this.id) List.splice(i, 1); + } + }); + var images = $this.settings.images, // local copies for YUI compressor + window = $this.settings.window, + color = $this.settings.color; + container = window.bindToInput ? $('#' + id + '_jPicker_Container') : $this; + if (window.bindToInput) + 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: window.position.x == 'left' ? '-535px' : window.position.x == 'center' ? '-268px' : window.position.x == 'right' ? '0px' : window.position.x == 'screenCenter' ? + (($(document).width() >> 1) - 268) - $('#' + id + '_jPicker_Picker').offset().left + 'px' : window.position.x, + position: 'absolute', + top: window.position.y == 'top' ? '-320px' : window.position.y == 'center' ? '-148px' : window.position.y == 'bottom' ? '25px' : window.position.y + }); + // if default colors are hex strings, change them to color objects + if ((typeof (color.active)).toString().toLowerCase() == 'string') color.active = new Color({ hex: color.active.substring(1) }); + if ((typeof (color.current)).toString().toLowerCase() == 'string') color.current = new Color({ hex: color.current.substring(1) }); + // 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 + container.html('' + (window.draggable ? '' : '') + '
  
    
new
  
current

 
°
%
%
 
#:
'); + // initialize the objects to the source code just injected + hue = $('#' + $this.id + '_jPicker_HueRadio', container); + saturation = $('#' + $this.id + '_jPicker_SaturationRadio', container); + value = $('#' + $this.id + '_jPicker_BrightnessRadio', container); + red = $('#' + $this.id + '_jPicker_RedRadio', container); + green = $('#' + $this.id + '_jPicker_GreenRadio', container); + blue = $('#' + $this.id + '_jPicker_BlueRadio', container); + colorMapL1 = $('#' + $this.id + '_jPicker_ColorMap_l1', container); + colorMapL2 = $('#' + $this.id + '_jPicker_ColorMap_l2', container); + colorBarL1 = $('#' + $this.id + '_jPicker_ColorBar_l1', container); + colorBarL2 = $('#' + $this.id + '_jPicker_ColorBar_l2', container); + colorBarL3 = $('#' + $this.id + '_jPicker_ColorBar_l3', container); + colorBarL4 = $('#' + $this.id + '_jPicker_ColorBar_l4', container); + activeColor = $('#' + $this.id + '_jPicker_Active', container).css({ backgroundColor: '#' + color.active.hex }); + currentColor = $('#' + $this.id + '_jPicker_Current', container).css({ backgroundColor: '#' + color.current.hex }); + okButton = $('#' + $this.id + '_jPicker_Ok', container); + cancelButton = $('#' + $this.id + '_jPicker_Cancel', container); + grid = $('#' + $this.id + '_jPicker_Grid', container); + $this.color = $('#' + $this.id + '_jPicker_Color'); + $this.icon = $('#' + $this.id + '_jPicker_Icon'); + // create color pickers and maps + colorPicker = new ColorValuePicker($this.id, textValuesChanged); + colorMap = new Slider($this.id + '_jPicker_ColorMap', + { + 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 + } + }, + mapValueChanged); + colorBar = new Slider($this.id + '_jPicker_ColorBar', + { + 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 + } + }, + barValueChanged); + // bind to input + if (window.bindToInput) + { + colorBox = $('#' + $this.id + '_jPicker_Color').css({ backgroundColor: '#' + color.current.hex }); + colorIcon = $('#' + $this.id + '_jPicker_Icon').css( + { + backgroundImage: 'url(' + images.clientPath + images.picker.file + ')' + }).bind('click', colorIconClicked); + window.input.bind('keyup', bindedHexKeyUp).bind('change', bindedHexKeyUp); + } + hue.add(saturation).add(value).add(red).add(green).add(blue).bind('click', radioClicked); + currentColor.bind('click', currentClicked); + cancelButton.bind('click', cancelClicked); + okButton.bind('click', okClicked); + if (window.draggable) moveBar = $('#' + $this.id + '_jPicker_MoveBar', container).bind('mousedown', moveBarMouseDown); + // initialize quick list + if (color.quickList && color.quickList.length > 0) + { + grid.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].substring(1) }); + grid.append(' '); + $('#' + $this.id + '_jPicker_Grid_' + i, container).css({ backgroundColor: '#' + color.quickList[i].hex }).bind('click', { i: i }, quickPickClicked); + } + } + setColorMode(color.mode); + colorPicker.fields.hex.val(colorBar.hex); + colorPicker.setValuesFromHex(); + positionMapAndBarArrows(); + updateVisuals(); + commitColor(); + $.isFunction($this.commitCallback) && $this.commitCallback(color.current); + if (!window.bindToInput) $this.show(); + List.push($this); + }); + }; + $.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: + { + position: + { + x: 'screenCenter', /* acceptable values "left", "center", "right", "screenCenter", or relative px value */ + y: 'top' /* acceptable values "top", "bottom", "center", or relative px value */ + }, + draggable: true, /* set to false automatically if not binded to an input element */ + liveUpdate: true /* set false if you want the user to have to click "OK" before the binded input box updates values */ + }, + color: + { + mode: 'h', /* acceptabled values "h" (hue), "s" (saturation), "v" (brightness), "r" (red), "g" (green), "b" (blue) */ + current: new Color({ hex: 'ffffff' }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) INCLUDING the "#" prefix */ + active: new Color({ hex: 'ffc000' }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) INCLUDING 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) INCLUDING 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 }) + ] + }, + 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.gif', /* ColorBar arrow icon */ + width: 40, + height: 9 + } + }, + picker: + { + file: 'picker.gif', /* Color Picker icon */ + width: 25, + height: 24 + } + } + }; +})(jQuery); \ No newline at end of file diff --git a/editor/jquery.js b/editor/jquery.js index b1ae21d8..92635743 100644 --- a/editor/jquery.js +++ b/editor/jquery.js @@ -1,4 +1,4 @@ -/* +/*! * jQuery JavaScript Library v1.3.2 * http://jquery.com/ * @@ -9,11 +9,4368 @@ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) * Revision: 6246 */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* +(function(){ + +var + // Will speed up references to window, and allows munging its name. + window = this, + // Will speed up references to undefined, and allows munging its name. + undefined, + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + // Map over the $ in case of overwrite + _$ = window.$, + + jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/, + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + this.context = selector; + return this; + } + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem && elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + var ret = jQuery( elem || [] ); + ret.context = document; + ret.selector = selector; + return ret; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return jQuery( document ).ready( selector ); + + // Make sure that old selector state is passed along + if ( selector.selector && selector.context ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return this.setArray(jQuery.isArray( selector ) ? + selector : + jQuery.makeArray(selector)); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.3.2", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num === undefined ? + + // Return a 'clean' array + Array.prototype.slice.call( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) + ret.selector = this.selector + (this.selector ? " " : "") + selector; + else if ( name ) + ret.selector = this.selector + "." + name + "(" + selector + ")"; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( typeof name === "string" ) + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text !== "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).clone(); + + if ( this[0].parentNode ) + wrap.insertBefore( this[0] ); + + wrap.map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }).append(this); + } + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: [].push, + sort: [].sort, + splice: [].splice, + + find: function( selector ) { + if ( this.length === 1 ) { + var ret = this.pushStack( [], "find", selector ); + ret.length = 0; + jQuery.find( selector, this[0], ret ); + return ret; + } else { + return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + })), "find", selector ); + } + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement("div"); + div.appendChild( this.cloneNode(true) ); + html = div.innerHTML; + } + + return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; + } else + return this.cloneNode(true); + }); + + // Copy the events from the original to the clone + if ( events === true ) { + var orig = this.find("*").andSelf(), i = 0; + + ret.find("*").andSelf().each(function(){ + if ( this.nodeName !== orig[i].nodeName ) + return; + + var events = jQuery.data( orig[i], "events" ); + + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + + i++; + }); + } + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, jQuery.grep(this, function(elem){ + return elem.nodeType === 1; + }) ), "filter", selector ); + }, + + closest: function( selector ) { + var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null, + closer = 0; + + return this.map(function(){ + var cur = this; + while ( cur && cur.ownerDocument ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) { + jQuery.data(cur, "closest", closer); + return cur; + } + cur = cur.parentNode; + closer++; + } + }); + }, + + not: function( selector ) { + if ( typeof selector === "string" ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return this.pushStack( jQuery.unique( jQuery.merge( + this.get(), + typeof selector === "string" ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ))); + }, + + is: function( selector ) { + return !!selector && jQuery.multiFilter( selector, this ).length > 0; + }, + + hasClass: function( selector ) { + return !!selector && this.is( "." + selector ); + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if( jQuery.nodeName( elem, 'option' ) ) + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + if ( typeof value === "number" ) + value += ''; + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(value); + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value === undefined ? + (this[0] ? + this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, +i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ), + "slice", Array.prototype.slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function( args, table, callback ) { + if ( this[0] ) { + var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), + scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), + first = fragment.firstChild; + + if ( first ) + for ( var i = 0, l = this.length; i < l; i++ ) + callback.call( root(this[i], first), this.length > 1 || i > 0 ? + fragment.cloneNode(true) : fragment ); + + if ( scripts ) + jQuery.each( scripts, evalScript ); + } + + return this; + + function root( elem, cur ) { + return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ? + (elem.getElementsByTagName("tbody")[0] || + elem.appendChild(elem.ownerDocument.createElement("tbody"))) : + elem; + } + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +function now(){ + return +new Date; +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) + continue; + + // Recurse if we're merging object values + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) + target[ name ] = jQuery.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); + + // Don't bring in undefined values + else if ( copy !== undefined ) + target[ name ] = copy; + + } + + // Return the modified object + return target; +}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, + // cache defaultView + defaultView = document.defaultView || {}, + toString = Object.prototype.toString; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument ); + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && /\S/.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.support.scriptEval ) + script.appendChild( document.createTextNode( data ) ); + else + script.text = data; + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, length = object.length; + + if ( args ) { + if ( length === undefined ) { + for ( name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( ; i < length; ) + if ( callback.apply( object[ i++ ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( length === undefined ) { + for ( name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames !== undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use hasClass("class") + has: function( elem, className ) { + return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force, extra ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + + if ( extra === "border" ) + return; + + jQuery.each( which, function() { + if ( !extra ) + val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + if ( extra === "margin" ) + val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0; + else + val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + } + + if ( elem.offsetWidth !== 0 ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, Math.round(val)); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret, style = elem.style; + + // We need to handle opacity special in IE + if ( name == "opacity" && !jQuery.support.opacity ) { + ret = jQuery.attr( style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && style && style[ name ] ) + ret = style[ name ]; + + else if ( defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var computedStyle = defaultView.getComputedStyle( elem, null ); + + if ( computedStyle ) + ret = computedStyle.getPropertyValue( name ); + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + } + } + + return ret; + }, + + clean: function( elems, context, fragment ) { + context = context || document; + + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { + var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); + if ( match ) + return [ context.createElement( match[1] ) ]; + } + + var ret = [], scripts = [], div = context.createElement("div"); + + jQuery.each(elems, function(i, elem){ + if ( typeof elem === "number" ) + elem += ''; + + if ( !elem ) + return; + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase(); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and - + SVG-edit demo @@ -15,11 +15,7 @@
-
-
- - -
+
diff --git a/editor/svg-editor.js b/editor/svg-editor.js index 6a925849..c697c31a 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -1,5 +1,4 @@ var palette = ["#000000","#202020","#404040","#606060","#808080","#a0a0a0","#c0c0c0","#e0e0e0","#ffffff","#800000","#ff0000","#808000","#ffff00","#008000","#00ff00","#008080","#00ffff","#000080","#0000ff","#800080","#ff00ff","#2b0000","#550000","#800000","#aa0000","#d40000","#ff0000","#ff2a2a","#ff5555","#ff8080","#ffaaaa","#ffd5d5","#280b0b","#501616","#782121","#a02c2c","#c83737","#d35f5f","#de8787","#e9afaf","#f4d7d7","#241c1c","#483737","#6c5353","#916f6f","#ac9393","#c8b7b7","#e3dbdb","#2b1100","#552200","#803300","#aa4400","#d45500","#ff6600","#ff7f2a","#ff9955","#ffb380","#ffccaa","#ffe6d5","#28170b","#502d16","#784421","#a05a2c","#c87137","#d38d5f","#deaa87","#e9c6af","#f4e3d7","#241f1c","#483e37","#6c5d53","#917c6f","#ac9d93","#c8beb7","#e3dedb","#2b2200","#554400","#806600","#aa8800","#d4aa00","#ffcc00","#ffd42a","#ffdd55","#ffe680","#ffeeaa","#fff6d5","#28220b","#504416","#786721","#a0892c","#c8ab37","#d3bc5f","#decd87","#e9ddaf","#f4eed7","#24221c","#484537","#6c6753","#918a6f","#aca793","#c8c4b7","#e3e2db","#222b00","#445500","#668000","#88aa00","#aad400","#ccff00","#d4ff2a","#ddff55","#e5ff80","#eeffaa","#f6ffd5","#22280b","#445016","#677821","#89a02c","#abc837","#bcd35f","#cdde87","#dde9af","#eef4d7","#22241c","#454837","#676c53","#8a916f","#a7ac93","#c4c8b7","#e2e3db","#112b00","#225500","#338000","#44aa00","#55d400","#66ff00","#7fff2a","#99ff55","#b3ff80","#ccffaa","#e5ffd5","#17280b","#2d5016","#447821","#5aa02c","#71c837","#8dd35f","#aade87","#c6e9af","#e3f4d7","#1f241c","#3e4837","#5d6c53","#7c916f","#9dac93","#bec8b7","#dee3db","#002b00","#005500","#008000","#00aa00","#00d400","#00ff00","#2aff2a","#55ff55","#80ff80","#aaffaa","#d5ffd5","#0b280b","#165016","#217821","#2ca02c","#37c837","#5fd35f","#87de87","#afe9af","#d7f4d7","#1c241c","#374837","#536c53","#6f916f","#93ac93","#b7c8b7","#dbe3db","#002b11","#005522","#008033","#00aa44","#00d455","#00ff66","#2aff80","#55ff99","#80ffb3","#aaffcc","#d5ffe6","#0b2817","#16502d","#217844","#2ca05a","#37c871","#5fd38d","#87deaa","#afe9c6","#d7f4e3","#1c241f","#37483e","#536c5d","#6f917c","#93ac9d","#b7c8be","#dbe3de","#002b22","#005544","#008066","#00aa88","#00d4aa","#00ffcc","#2affd5","#55ffdd","#80ffe6","#aaffee","#d5fff6","#0b2822","#165044","#217867","#2ca089","#37c8ab","#5fd3bc","#87decd","#afe9dd","#d7f4ee","#1c2422","#374845","#536c67","#6f918a","#93aca7","#b7c8c4","#dbe3e2","#00222b","#004455","#006680","#0088aa","#00aad4","#00ccff","#2ad4ff","#55ddff","#80e5ff","#aaeeff","#d5f6ff","#0b2228","#164450","#216778","#2c89a0","#37abc8","#5fbcd3","#87cdde","#afdde9","#d7eef4","#1c2224","#374548","#53676c","#6f8a91","#93a7ac","#b7c4c8","#dbe2e3","#00112b","#002255","#003380","#0044aa","#0055d4","#0066ff","#2a7fff","#5599ff","#80b3ff","#aaccff","#d5e5ff","#0b1728","#162d50","#214478","#2c5aa0","#3771c8","#5f8dd3","#87aade","#afc6e9","#d7e3f4","#1c1f24","#373e48","#535d6c","#6f7c91","#939dac","#b7bec8","#dbdee3","#00002b","#000055","#000080","#0000aa","#0000d4","#0000ff","#2a2aff","#5555ff","#8080ff","#aaaaff","#d5d5ff","#0b0b28","#161650","#212178","#2c2ca0","#3737c8","#5f5fd3","#8787de","#afafe9","#d7d7f4","#1c1c24","#373748","#53536c","#6f6f91","#9393ac","#b7b7c8","#dbdbe3","#11002b","#220055","#330080","#4400aa","#5500d4","#6600ff","#7f2aff","#9955ff","#b380ff","#ccaaff","#e5d5ff","#170b28","#2d1650","#442178","#5a2ca0","#7137c8","#8d5fd3","#aa87de","#c6afe9","#e3d7f4","#1f1c24","#3e3748","#5d536c","#7c6f91","#9d93ac","#beb7c8","#dedbe3","#22002b","#440055","#660080","#8800aa","#aa00d4","#cc00ff","#d42aff","#dd55ff","#e580ff","#eeaaff","#f6d5ff","#220b28","#441650","#672178","#892ca0","#ab37c8","#bc5fd3","#cd87de","#ddafe9","#eed7f4","#221c24","#453748","#67536c","#8a6f91","#a793ac","#c4b7c8","#e2dbe3","#2b0022","#550044","#800066","#aa0088","#d400aa","#ff00cc","#ff2ad4","#ff55dd","#ff80e5","#ffaaee","#ffd5f6","#280b22","#501644","#782167","#a02c89","#c837ab","#d35fbc","#de87cd","#e9afdd","#f4d7ee","#241c22","#483745","#6c5367","#916f8a","#ac93a7","#c8b7c4","#e3dbe2","#2b0011","#550022","#800033","#aa0044","#d40055","#ff0066","#ff2a7f","#ff5599","#ff80b2","#ffaacc","#ffd5e5","#280b17","#50162d","#782144","#a02c5a","#c83771","#d35f8d","#de87aa","#e9afc6","#f4d7e3","#241c1f","#48373e","#6c535d","#916f7c","#ac939d","#c8b7be","#e3dbde"] -var picker = null; $(document).ready(function(){ var str = '
' @@ -8,6 +7,7 @@ $(document).ready(function(){ }); $('#palette').append(str); + var pos = $('#tools_rect_show').position(); $('#tools_rect').css({'left': pos.left+2, 'top': pos.top+2}); pos = $('#tools_ellipse_show').position(); @@ -126,59 +126,63 @@ $(document).ready(function(){ SvgCanvas.serialize(serializeHandler); }); - $('#fill_color').click(function(){ + var colorPicker = function(elem) { $('.tools_flyout').hide(); - var color = $(this).css('background-color'); - if (color == 'transparent') color = '#ffffff'; - picker.setColor(color); - picker.mode = 'fill'; - pos = $(this).position(); - $('#color_pick').css({'left': pos.left, 'top': pos.top}).show(); + var oldbg = elem.css('background'); + var color = elem.css('background-color'); + if (color == 'transparent') { + } else { + if (color.length == 7 && color[0] == '#') { // #hheexx notation + color = new $.jPicker.Color( { hex: color.substring(1,7) } ); + } else if (color.substring(0,4) == 'rgb(' && color[color.length-1] == ')') { // rgb(r,g,b) notation + var rgb = color.substring(4,color.length-1).split(','); + color = new $.jPicker.Color({ r: rgb[0], g: rgb[1], b: rgb[2] }); + } else { + color = new $.jPicker.Color({ hex: 'ffffff' }); + } + } + var pos = elem.position(); + picker = 'stroke'; + $('#color_picker').css({'left': pos.left, 'top': pos.top}).jPicker({ + images: { clientPath: "jpicker/images/" }, + color: { active: color } + }, function(color){ + elem.css('background', '#' + this.settings.color.active.hex); + if (elem.attr('id') == 'stroke_color') { + SvgCanvas.setStrokeColor('#' + this.settings.color.active.hex); + } else if (elem.attr('id') == 'fill_color') { + SvgCanvas.setFillColor('#' + this.settings.color.active.hex); + } + $('#color_picker').hide(); + } + , null, function(){ + elem.css('background', oldbg); + $('#color_picker').hide(); + }); + } + + $('#fill_color').click(function(){ + colorPicker($(this)); }); $('#stroke_color').click(function(){ - $('.tools_flyout').hide(); - var color = $(this).css('background-color'); - if (color == 'transparent') color = '#ffffff'; - picker.setColor(color); - picker.mode = 'stroke'; - pos = $(this).position(); - $('#color_pick').css({'left': pos.left, 'top': pos.top}).show(); + colorPicker($(this)); }); - $('#color_pick_ok').click(function(){ - $('#color_pick').hide(); - if (picker.mode == 'stroke') { - $('#stroke_color').css('background', picker.color); - SvgCanvas.setStrokeColor(picker.color); - } - if (picker.mode == 'fill') { - $('#fill_color').css('background', picker.color); - SvgCanvas.setFillColor(picker.color); - } - }); - - picker = $.farbtastic('#color_pick_wheel', function(){ - $('#color_pick_text').attr('value', this.color); - }); - - $('#color_pick_text').keyup(function(){ - picker.setColor($(this).attr('value')); - }); - - // This hides any flyouts and then shows the rect flyout + // this hides any flyouts and then shows the rect flyout $('#tools_rect_show').click(function(){ $('.tools_flyout').hide(); $('#tools_rect').show(); }); - // This hides any flyouts and then shows the circle flyout + // this hides any flyouts and then shows the circle flyout $('#tools_ellipse_show').click(function(){ $('.tools_flyout').hide(); $('#tools_ellipse').show(); }); + }) -function serializeHandler(svg) { +var serializeHandler = function(svg) { alert(svg); }