Simple Lightbox - Version 1.1

Version Description

  • Added: Enable/disable lightbox functionality by page type (Home, Pages/Posts, Archive, etc.)
  • Added: Automatically activate lightbox functionality for image links
  • Added: Link to settings menu on plugin listing page
  • Optimized: Options menu field building
  • Optimized: Loading of default values for plugin options
  • Optimized: General code optimizations
Download this release

Release Info

Developer Archetyped
Plugin Icon wp plugin Simple Lightbox
Version 1.1
Comparing to
See all releases

Version 1.1

COPYING ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ <signature of Ty Coon>, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
css/lightbox.css ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #lightbox{
2
+ position: absolute;
3
+ top: 20px;
4
+ left: 0;
5
+ width: 100%;
6
+ z-index: 3100;
7
+ text-align: center;
8
+ line-height: 0;
9
+ color:#151410;
10
+ }
11
+
12
+ #lightbox a, #lightbox a:hover {
13
+ border-bottom:none;
14
+ color:#151410;
15
+ text-decoration:underline;
16
+ }
17
+
18
+ #lightbox a img{ border: none; }
19
+
20
+ #outerImageContainer{
21
+ position: relative;
22
+ background-color: #fff;
23
+ width: 250px;
24
+ height: 250px;
25
+ margin: 0 auto;
26
+ }
27
+
28
+ #imageContainer{
29
+ padding: 10px;
30
+ }
31
+
32
+ #loading{
33
+ position: absolute;
34
+ top: 40%;
35
+ left: 0%;
36
+ height: 25%;
37
+ width: 100%;
38
+ text-align: center;
39
+ line-height: 0;
40
+ }
41
+ #loadingLink {
42
+ display:block;
43
+ margin:0 auto;
44
+ padding:0;
45
+ width:32px;
46
+ height:32px;
47
+ background:url("../images/loading.gif") center center no-repeat;
48
+ text-indent:-9999px;
49
+ }
50
+ #hoverNav{
51
+ position: absolute;
52
+ top: 0;
53
+ left: 0;
54
+ height: 100%;
55
+ width: 100%;
56
+ z-index: 10;
57
+ }
58
+ #imageContainer>#hoverNav{ left: 0;}
59
+ #hoverNav a{ outline: none;}
60
+
61
+ #prevLinkImg, #nextLinkImg{
62
+ width: 49%;
63
+ height: 100%;
64
+ background: transparent url("../images/blank.gif") no-repeat; /* Trick IE into showing hover */
65
+ display: block;
66
+ text-indent:-9999px;
67
+ }
68
+ #prevLinkImg { left: 0; float: left;}
69
+ #nextLinkImg { right: 0; float: right;}
70
+ #prevLinkImg:hover, #prevLinkImg:visited:hover { background: url("../images/prevlabel.gif") left 15% no-repeat; }
71
+ #nextLinkImg:hover, #nextLinkImg:visited:hover { background: url("../images/nextlabel.gif") right 15% no-repeat; }
72
+
73
+
74
+ #imageDataContainer{
75
+ font: 10px Verdana, Helvetica, sans-serif;
76
+ background-color: #fff;
77
+ margin: 0 auto;
78
+ line-height: 1.4em;
79
+ }
80
+
81
+ #imageData{
82
+ padding:0 10px;
83
+ }
84
+ #imageDetails{ width: 70%; float: left; text-align: left; }
85
+ #caption{ font-weight: bold; }
86
+ #numberDisplay{ display: block; clear: left; }
87
+ #detailsNav{ display: block; clear: left; padding:0 0 10px 0; }
88
+ #prevLinkDetails { margin:0 8px 0 0; }
89
+ #nextLinkDetails { margin:0 8px 0 0; }
90
+ #closeLink {
91
+ display:block;
92
+ margin:0;
93
+ padding:0 0 10px 0;
94
+ text-decoration:none;
95
+ float:right;
96
+ width:66px;
97
+ height:28px;
98
+ background:url("../images/closelabel.gif") no-repeat;
99
+ text-indent:-9999px;
100
+ overflow:hidden;
101
+ }
102
+
103
+ #overlay{
104
+ position: absolute;
105
+ top: 0;
106
+ left: 0;
107
+ z-index: 3090;
108
+ width: 100%;
109
+ height: 500px;
110
+ background-color: #151410;
111
+ filter:alpha(opacity=60);
112
+ -moz-opacity: 0.6;
113
+ opacity: 0.6;
114
+ }
115
+
116
+
117
+ .clearfix:after {
118
+ content: ".";
119
+ display: block;
120
+ height: 0;
121
+ clear: both;
122
+ visibility: hidden;
123
+ }
124
+
125
+ * html>body .clearfix {
126
+ display: inline-block;
127
+ width: 100%;
128
+ }
129
+
130
+ * html .clearfix {
131
+ /* Hides from IE-mac \*/
132
+ height: 1%;
133
+ /* End hide from IE-mac */
134
+ }
135
+
images/blank.gif ADDED
Binary file
images/closelabel.gif ADDED
Binary file
images/loading.gif ADDED
Binary file
images/nextlabel.gif ADDED
Binary file
images/prevlabel.gif ADDED
Binary file
includes/class.base.php ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'class.utilities.php';
4
+
5
+ /**
6
+ * @package Simple Lightbox
7
+ * @subpackage Base
8
+ * @author Archetyped
9
+ *
10
+ */
11
+ class SLB_Base {
12
+
13
+ /**
14
+ * Prefix for Cornerstone-related data (attributes, DB tables, etc.)
15
+ * @var string
16
+ */
17
+ var $prefix = 'slb';
18
+
19
+ /**
20
+ * Utilities
21
+ * @var SLB_Utilities
22
+ */
23
+ var $util = null;
24
+
25
+ /**
26
+ * Legacy constructor
27
+ */
28
+ function SLB_Base() {
29
+ $this->__construct();
30
+ }
31
+
32
+ /**
33
+ * Constructor
34
+ */
35
+ function __construct() {
36
+ $this->util =& new SLB_Utilities();
37
+ }
38
+
39
+ /**
40
+ * Default initialization method
41
+ * To be overriden by child classes
42
+ */
43
+ function init() {}
44
+
45
+ /**
46
+ * Returns callback to instance method
47
+ * @param string $method Method name
48
+ * @return array Callback array
49
+ */
50
+ function &m($method) {
51
+ return $this->util->m($this, $method);
52
+ }
53
+
54
+ /**
55
+ * Retrieves post metadata for internal methods
56
+ * Metadata set internally is wrapped in an array so it is unwrapped before returned the retrieved value
57
+ * @see get_post_meta()
58
+ * @param int $post_id Post ID
59
+ * @param string $key Name of metadata to retrieve
60
+ * @param boolean $single Whether or not to retrieve single value or not
61
+ * @return mixed Retrieved post metadata
62
+ */
63
+ function post_meta_get($post_id, $key, $single = false) {
64
+ $meta_value = get_post_meta($post_id, $this->post_meta_get_key($key), $single);
65
+ if (is_array($meta_value) && count($meta_value) == 1)
66
+ $meta_value = $meta_value[0];
67
+ return $meta_value;
68
+ }
69
+
70
+ /**
71
+ * Wraps metadata in array for storage in database
72
+ * @param mixed $meta_value Value to be set as metadata
73
+ * @return array Wrapped metadata value
74
+ */
75
+ function post_meta_prepare_value($meta_value) {
76
+ return array($meta_value);
77
+ }
78
+
79
+ /**
80
+ * Adds Metadata for a post to database
81
+ * For internal methods
82
+ * @see add_post_meta
83
+ * @param $post_id
84
+ * @param $meta_key
85
+ * @param $meta_value
86
+ * @param $unique
87
+ * @return boolean Result of operation
88
+ */
89
+ function post_meta_add($post_id, $meta_key, $meta_value, $unique = false) {
90
+ $meta_value = $this->post_meta_value_prepare($meta_value);
91
+ return add_post_meta($post_id, $meta_key, $meta_value, $unique);
92
+ }
93
+
94
+ /**
95
+ * Updates post metadata for internal data/methods
96
+ * @see update_post_meta()
97
+ * @param $post_id
98
+ * @param $meta_key
99
+ * @param $meta_value
100
+ * @param $prev_value
101
+ * @return boolean Result of operation
102
+ */
103
+ function post_meta_update($post_id, $meta_key, $meta_value, $prev_value = '') {
104
+ $meta_value = $this->post_meta_prepare_value($meta_value);
105
+ return update_post_meta($post_id, $meta_key, $meta_value, $prev_value);
106
+ }
107
+
108
+ /**
109
+ * Builds postmeta key for custom data set by plugin
110
+ * @param string $key Base key name
111
+ * @return string Formatted postmeta key
112
+ */
113
+ function post_meta_get_key($key) {
114
+ $sep = '_';
115
+ if ( strpos($key, $sep . $this->prefix) !== 0 ) {
116
+ $key_base = func_get_args();
117
+ if ( !empty($key_base) ) {
118
+ $key = array_merge((array)$this->prefix, $key_base);
119
+ return $sep . implode($sep, $key);
120
+ }
121
+ }
122
+
123
+ return $key;
124
+ }
125
+
126
+ /**
127
+ * Retrieve class prefix (with separator if set)
128
+ * @param bool|string $sep Separator to append to class prefix (Default: no separator)
129
+ * @return string Class prefix
130
+ */
131
+ function get_prefix($sep = false) {
132
+ $sep = ( is_string($sep) ) ? $sep : '';
133
+ $prefix = ( !empty($this->prefix) ) ? $this->prefix . $sep : '';
134
+ return $prefix;
135
+ }
136
+
137
+ /**
138
+ * Prepend plugin prefix to some text
139
+ * @param string $text Text to add to prefix
140
+ * @param string $sep Text used to separate prefix and text
141
+ * @return string Text with prefix prepended
142
+ */
143
+ function add_prefix($text = '', $sep = '_') {
144
+ return $this->get_prefix($sep) . $text;
145
+ }
146
+
147
+ function remove_prefix($text = '', $sep = '_') {
148
+ if ( !empty($text) && strpos($text, ( $p = $this->get_prefix($sep) )) === 0 )
149
+ $text = substr($text, strlen($p));
150
+ return $text;
151
+ }
152
+
153
+ /**
154
+ * Creates a meta key for storing post meta data
155
+ * Prefixes standard prefixed text with underscore to hide meta data on post edit forms
156
+ * @param string $text Text to use as base of meta key
157
+ * @return string Formatted meta key
158
+ */
159
+ function make_meta_key($text = '') {
160
+ return '_' . $this->add_prefix($text);
161
+ }
162
+
163
+ /**
164
+ * Returns Database prefix for Cornerstone-related DB Tables
165
+ * @return string Database prefix
166
+ */
167
+ function get_db_prefix() {
168
+ global $wpdb;
169
+ return $wpdb->prefix . $this->get_prefix('_');
170
+ }
171
+ }
172
+
173
+ ?>
includes/class.utilities.php ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Utility methods
5
+ *
6
+ * @package Simple Lightbox
7
+ * @subpackage Utilities
8
+ * @author Archetyped
9
+ *
10
+ */
11
+ class SLB_Utilities {
12
+
13
+ function SLB_Utilities() {
14
+ $this->__construct();
15
+ }
16
+
17
+ function __construct() {
18
+
19
+ }
20
+
21
+ /**
22
+ * Returns callback array to instance method
23
+ * @param object $obj Instance object
24
+ * @param string $method Name of method
25
+ * @return array Callback array
26
+ */
27
+ function &m(&$obj, $method = '') {
28
+ if ( $obj == null && isset($this) )
29
+ $obj =& $this;
30
+ $arr = array(&$obj, $method);
31
+ return $arr;
32
+ }
33
+
34
+ /* Helper Functions */
35
+
36
+ /*-** WP **-*/
37
+
38
+ /**
39
+ * Checks if $post is a valid Post object
40
+ * If $post is not valid, assigns global post object to $post (if available)
41
+ * @return bool TRUE if $post is valid object by end of function processing
42
+ * @param object $post Post object to evaluate
43
+ */
44
+ function check_post(&$post) {
45
+ if (empty($post)) {
46
+ if (isset($GLOBALS['post'])) {
47
+ $post = $GLOBALS['post'];
48
+ $GLOBALS['post'] =& $post;
49
+ }
50
+ else
51
+ return false;
52
+ }
53
+ if (is_array($post))
54
+ $post = (object) $post;
55
+ elseif (is_numeric($post))
56
+ $post = get_post($post);
57
+ if (!is_object($post))
58
+ return false;
59
+ return true;
60
+ }
61
+
62
+ /*-** Request **-*/
63
+
64
+ /**
65
+ * Checks $_SERVER['SCRIPT_NAME'] to see if file base name matches specified file name
66
+ * @param string $filename Filename to check for
67
+ * @return bool TRUE if current page matches specified filename, FALSE otherwise
68
+ */
69
+ function is_file( $filename ) {
70
+ return ( $filename == basename( $_SERVER['SCRIPT_NAME'] ) );
71
+ }
72
+
73
+ /**
74
+ * Checks whether the current page is a management page
75
+ * @return bool TRUE if current page is a management page, FALSE otherwise
76
+ */
77
+ function is_admin_management_page() {
78
+ return ( is_admin()
79
+ && ( $this->is_file('edit.php')
80
+ || ( $this->is_file('admin.php')
81
+ && isset($_GET['page'])
82
+ && strpos($_GET['page'], 'cnr') === 0 )
83
+ )
84
+ );
85
+ }
86
+
87
+ /**
88
+ * Returns URL of file (assumes that it is in plugin directory)
89
+ * @param string $file name of file get URL
90
+ * @return string File path
91
+ */
92
+ function get_file_url($file) {
93
+ if (is_string($file) && '' != trim($file)) {
94
+ $file = ltrim(trim($file), '/');
95
+ $file = sprintf('%s/%s', $this->get_url_base(), $file);
96
+ }
97
+ return $file;
98
+ }
99
+
100
+ /**
101
+ * Retrieve base URL for plugin-specific files
102
+ * @return string Base URL
103
+ */
104
+ function get_url_base() {
105
+ static $url_base = '';
106
+ if ( '' == $url_base ) {
107
+ $sl_f = '/';
108
+ $sl_b = '\\';
109
+ $plugin_dir = str_replace(str_replace($sl_f, $sl_b, WP_PLUGIN_DIR), '', str_replace($sl_f, $sl_b, dirname(dirname(__FILE__))));
110
+ $url_base = str_replace($sl_b, $sl_f, WP_PLUGIN_URL . $plugin_dir);
111
+ }
112
+ return $url_base;
113
+ }
114
+
115
+ function get_path_base() {
116
+ static $path_base = '';
117
+ if ( '' == $path_base ) {
118
+ $sl_f = '/';
119
+ $sl_b = '\\';
120
+ $plugin_dir = str_replace(str_replace($sl_f, $sl_b, WP_PLUGIN_DIR), '', str_replace($sl_f, $sl_b, dirname(dirname(__FILE__))));
121
+ $path_base = str_replace($sl_b, $sl_f, WP_PLUGIN_DIR . $plugin_dir);
122
+ }
123
+
124
+ return $path_base;
125
+ }
126
+
127
+ function get_plugin_base_file() {
128
+ $file = 'main.php';
129
+ return $this->get_path_base() . '/' . $file;
130
+ }
131
+
132
+ function get_plugin_base_name() {
133
+ $file = $this->get_plugin_base_file();
134
+ $front = dirname(dirname($file));
135
+ $name = substr($file, strlen($front) + 1);
136
+ return $name;
137
+ }
138
+
139
+ /**
140
+ * Retrieve current action based on URL query variables
141
+ * @return string Current action
142
+ */
143
+ function get_action($default = null) {
144
+ $action = '';
145
+ if ( isset($_GET['action']) )
146
+ $action = $_GET['action'];
147
+ elseif ( isset($_GET['page']) && ($pos = strrpos($_GET['page'], '-')) && $pos !== false && ( $pos != count($_GET['page']) - 1 ) )
148
+ $action = trim(substr($_GET['page'], $pos + 1), '-_');
149
+ if ( empty($action) )
150
+ $action = $default;
151
+ return $action;
152
+ }
153
+
154
+ /*-** General **-*/
155
+
156
+ /**
157
+ * Checks if a property exists in a class or object
158
+ * (Compatibility method for PHP 4
159
+ * @param mixed $class Class or object to check
160
+ * @param string $property Name of property to look for in $class
161
+ */
162
+ function property_exists($class, $property) {
163
+ if ( !is_object($class) && !is_array($class) )
164
+ return false;
165
+ if ( function_exists('property_exists') && is_object($class) ) {
166
+ return property_exists($class, $property);
167
+ } else {
168
+ return array_key_exists($property, $class);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Retrieve specified property from object or array
174
+ * @param object|array $obj Object or array to get property from
175
+ * @param string $property Property name to retrieve
176
+ * @return mixed Property value
177
+ */
178
+ function &get_property(&$obj, $property) {
179
+ $property = trim($property);
180
+ //Object
181
+ if ( is_object($obj) )
182
+ return $obj->{$property};
183
+ //Array
184
+ if ( is_array($obj) )
185
+ return $obj[$property];
186
+ //Class
187
+ if ( is_string($obj) && class_exists($obj) ) {
188
+ $cvars = get_class_vars($obj);
189
+ if ( isset($cvars[$property]) )
190
+ return $cvars[$property];
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Merges 1 or more arrays together
196
+ * Methodology
197
+ * - Set first parameter as base array
198
+ * - All other parameters will be merged into base array
199
+ * - Iterate through other parameters (arrays)
200
+ * - Skip all non-array parameters
201
+ * - Iterate though key/value pairs of current array
202
+ * - Merge item in base array with current item based on key name
203
+ * - If the current item's value AND the corresponding item in the base array are BOTH arrays, recursively merge the the arrays
204
+ * - If the current item's value OR the corresponding item in the base array is NOT an array, current item overwrites base item
205
+ * @todo Append numerical elements (as opposed to overwriting element at same index in base array)
206
+ * @param array Variable number of arrays
207
+ * @return array Merged array
208
+ */
209
+ function array_merge_recursive_distinct() {
210
+ //Get all arrays passed to function
211
+ $args = func_get_args();
212
+ if (empty($args))
213
+ return false;
214
+ //Set first array as base array
215
+ $merged = $args[0];
216
+ //Iterate through arrays to merge
217
+ $arg_length = count($args);
218
+ for ($x = 1; $x < $arg_length; $x++) {
219
+ //Skip if argument is not an array (only merge arrays)
220
+ if (!is_array($args[$x]))
221
+ continue;
222
+ //Iterate through argument items
223
+ foreach ($args[$x] as $key => $val) {
224
+ if (!isset($merged[$key]) || !is_array($merged[$key]) || !is_array($val)) {
225
+ $merged[$key] = $val;
226
+ } elseif (is_array($merged[$key]) && is_array($val)) {
227
+ $merged[$key] = $this->array_merge_recursive_distinct($merged[$key], $val);
228
+ }
229
+ //$merged[$key] = (is_array($val) && isset($merged[$key])) ? $this->array_merge_recursive_distinct($merged[$key], $val) : $val;
230
+ }
231
+ }
232
+ return $merged;
233
+ }
234
+
235
+ /**
236
+ * Replaces string value in one array with the value of the matching element in a another array
237
+ *
238
+ * @param string $search Text to search for in array
239
+ * @param array $arr_replace Array to use for replacing values
240
+ * @param array $arr_subject Array to search for specified value
241
+ * @return array Searched array with replacements made
242
+ */
243
+ function array_replace_recursive($search, $arr_replace, $arr_subject) {
244
+ foreach ($arr_subject as $key => $val) {
245
+ //Skip element if key does not exist in the replacement array
246
+ if (!isset($arr_replace[$key]))
247
+ continue;
248
+ //If element values for both arrays are strings, replace text
249
+ if (is_string($val) && strpos($val, $search) !== false && is_string($arr_replace[$key]))
250
+ $arr_subject[$key] = str_replace($search, $arr_replace[$key], $val);
251
+ //If value in both arrays are arrays, recursively replace text
252
+ if (is_array($val) && is_array($arr_replace[$key]))
253
+ $arr_subject[$key] = $this->array_replace_recursive($search, $arr_replace[$key], $val);
254
+ }
255
+
256
+ return $arr_subject;
257
+ }
258
+
259
+ /**
260
+ * Checks if item at specified path in array is set
261
+ * @param array $arr Array to check for item
262
+ * @param array $path Array of segments that form path to array (each array item is a deeper dimension in the array)
263
+ * @return boolean TRUE if item is set in array, FALSE otherwise
264
+ */
265
+ function array_item_isset(&$arr, &$path) {
266
+ $f_path = $this->get_array_path($path);
267
+ return eval('return isset($arr' . $f_path . ');');
268
+ }
269
+
270
+ /**
271
+ * Returns value of item at specified path in array
272
+ * @param array $arr Array to get item from
273
+ * @param array $path Array of segments that form path to array (each array item is a deeper dimension in the array)
274
+ * @return mixed Value of item in array (Default: empty string)
275
+ */
276
+ function &get_array_item(&$arr, &$path) {
277
+ $item = '';
278
+ if ($this->array_item_isset($arr, $path)) {
279
+ eval('$item =& $arr' . $this->get_array_path($path) . ';');
280
+ }
281
+ return $item;
282
+ }
283
+
284
+ function get_array_path($attribute = '', $format = null) {
285
+ //Formatted value
286
+ $fmtd = '';
287
+ if (!empty($attribute)) {
288
+ //Make sure attribute is array
289
+ if (!is_array($attribute)) {
290
+ $attribute = array($attribute);
291
+ }
292
+ //Format attribute
293
+ $format = strtolower($format);
294
+ switch ($format) {
295
+ case 'id':
296
+ $fmtd = array_shift($attribute) . '[' . implode('][', $attribute) . ']';
297
+ break;
298
+ case 'metadata':
299
+ case 'attribute':
300
+ //Join segments
301
+ $delim = '_';
302
+ $fmtd = implode($delim, $attribute);
303
+ //Replace white space and repeating delimiters
304
+ $fmtd = str_replace(' ', $delim, $fmtd);
305
+ while (strpos($fmtd, $delim.$delim) !== false)
306
+ $fmtd = str_replace($delim.$delim, $delim, $fmtd);
307
+ //Prefix formatted value with delimeter for metadata keys
308
+ if ('metadata' == $format)
309
+ $fmtd = $delim . $fmtd;
310
+ break;
311
+ case 'path':
312
+ case 'post':
313
+ default:
314
+ $fmtd = '["' . implode('"]["', $attribute) . '"]';
315
+ }
316
+ }
317
+ return $fmtd;
318
+ }
319
+
320
+ /**
321
+ * Builds array of path elements based on arguments
322
+ * Each item in path array represents a deeper level in structure path is for (object, array, filesystem, etc.)
323
+ * @param array|string Value to add to the path
324
+ * @return array 1-dimensional array of path elements
325
+ */
326
+ function build_path() {
327
+ $path = array();
328
+ $args = func_get_args();
329
+
330
+ //Iterate through parameters and build path
331
+ foreach ( $args as $arg ) {
332
+ if ( empty($arg) )
333
+ continue;
334
+
335
+ if (is_array($arg)) {
336
+ //Recurse through array items to pull out any more arrays
337
+ foreach ($arg as $key => $val) {
338
+ $path = array_merge($path, $this->build_path($val));
339
+ }
340
+ //$path = array_merge($path, array_values($arg));
341
+ } elseif ( is_scalar($arg) ) {
342
+ $path[] = $arg;
343
+ }
344
+ }
345
+
346
+ return $path;
347
+ }
348
+
349
+ function build_attribute_string($attr = array(), $esc_values = true) {
350
+ $ret = '';
351
+ if ( empty($attr) || ! is_array($attr) )
352
+ return $ret;
353
+ $ret = array();
354
+ foreach ( $attr as $key => $val ) {
355
+ $ret[] = $key . '="' . ( ( $esc_values ) ? esc_attr($val) : $val ) . '"';
356
+ }
357
+ return implode(' ', $ret);
358
+ }
359
+
360
+ /*-** Admin **-*/
361
+
362
+ /**
363
+ * Add submenu page in the admin menu
364
+ * Adds ability to set the position of the page in the menu
365
+ * @see add_submin_menu (Wraps functionality)
366
+ *
367
+ * @param $parent
368
+ * @param $page_title
369
+ * @param $menu_title
370
+ * @param $access_level
371
+ * @param $file
372
+ * @param $function
373
+ * @param int $pos Index position of menu page
374
+ *
375
+ * @global array $submenu Admin page submenus
376
+ */
377
+ function add_submenu_page($parent, $page_title, $menu_title, $access_level, $file, $function = '', $pos = false) {
378
+ global $submenu;
379
+
380
+ //Add submenu page as usual
381
+ $args = func_get_args();
382
+ $hookname = call_user_func_array('add_submenu_page', $args);
383
+
384
+ if ( is_int($pos) ) {
385
+ //Get last submenu added
386
+ $parent = $this->get_submenu_parent_file($parent);
387
+ $subs =& $submenu[$parent];
388
+
389
+ //Make sure menu isn't already in the desired position
390
+ if ( $pos <= ( count($subs) - 1 ) ) {
391
+ //Get submenu that was just added
392
+ $sub = array_pop($subs);
393
+ //Insert into desired position
394
+ if ( 0 == $pos ) {
395
+ array_unshift($subs, $sub);
396
+ } else {
397
+ $top = array_slice($subs, 0, $pos);
398
+ $bottom = array_slice($subs, $pos);
399
+ array_push($top, $sub);
400
+ $subs = array_merge($top, $bottom);
401
+ }
402
+ }
403
+ }
404
+
405
+ return $hookname;
406
+ }
407
+
408
+ /**
409
+ * Remove admin submenu
410
+ * @param string $parent Submenu parent file
411
+ * @param string $file Submenu file name
412
+ * @return int|null Index of removed submenu (NULL if submenu not found)
413
+ *
414
+ * @global array $submenu
415
+ * @global array $_registered_pages
416
+ */
417
+ function remove_submenu_page($parent, $file) {
418
+ global $submenu, $_registered_pages;
419
+ $ret = null;
420
+
421
+ $parent = $this->get_submenu_parent_file($parent);
422
+ $file = plugin_basename($file);
423
+ $file_index = 2;
424
+
425
+ //Find submenu
426
+ if ( isset($submenu[$parent]) ) {
427
+ $subs =& $submenu[$parent];
428
+ for ($x = 0; $x < count($subs); $x++) {
429
+ if ( $subs[$x][$file_index] == $file ) {
430
+ //Remove matching submenu
431
+ $hookname = get_plugin_page_hookname($file, $parent);
432
+ remove_all_actions($hookname);
433
+ unset($_registered_pages[$hookname]);
434
+ unset($subs[$x]);
435
+ $subs = array_values($subs);
436
+ //Set index and stop processing
437
+ $ret = $x;
438
+ break;
439
+ }
440
+ }
441
+ }
442
+
443
+ return $ret;
444
+ }
445
+
446
+ /**
447
+ * Replace a submenu page
448
+ * Adds a submenu page in the place of an existing submenu page that has the same $file value
449
+ *
450
+ * @param $parent
451
+ * @param $page_title
452
+ * @param $menu_title
453
+ * @param $access_level
454
+ * @param $file
455
+ * @param $function
456
+ * @return string Hookname
457
+ *
458
+ * @global array $submenu
459
+ */
460
+ function replace_submenu_page($parent, $page_title, $menu_title, $access_level, $file, $function = '') {
461
+ global $submenu;
462
+ //Remove matching submenu (if exists)
463
+ $pos = $this->remove_submenu_page($parent, $file);
464
+ //Insert submenu page
465
+ $hookname = $this->add_submenu_page($parent, $page_title, $menu_title, $access_level, $file, $function, $pos);
466
+ return $hookname;
467
+ }
468
+
469
+ /**
470
+ * Retrieves parent file for submenu
471
+ * @param string $parent Parent file
472
+ * @return string Formatted parent file name
473
+ *
474
+ * @global array $_wp_real_parent_file;
475
+ */
476
+ function get_submenu_parent_file($parent) {
477
+ global $_wp_real_parent_file;
478
+ $parent = plugin_basename($parent);
479
+ if ( isset($_wp_real_parent_file[$parent]) )
480
+ $parent = $_wp_real_parent_file[$parent];
481
+ return $parent;
482
+ }
483
+ }
js/dev/effects.js ADDED
@@ -0,0 +1,1094 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007
2
+
3
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ // Contributors:
5
+ // Justin Palmer (http://encytemedia.com/)
6
+ // Mark Pilgrim (http://diveintomark.org/)
7
+ // Martin Bialasinki
8
+ //
9
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
10
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
11
+
12
+ // converts rgb() and #xxx to #xxxxxx format,
13
+ // returns self (or first argument) if not convertable
14
+ String.prototype.parseColor = function() {
15
+ var color = '#';
16
+ if(this.slice(0,4) == 'rgb(') {
17
+ var cols = this.slice(4,this.length-1).split(',');
18
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
19
+ } else {
20
+ if(this.slice(0,1) == '#') {
21
+ if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
22
+ if(this.length==7) color = this.toLowerCase();
23
+ }
24
+ }
25
+ return(color.length==7 ? color : (arguments[0] || this));
26
+ }
27
+
28
+ /*--------------------------------------------------------------------------*/
29
+
30
+ Element.collectTextNodes = function(element) {
31
+ return $A($(element).childNodes).collect( function(node) {
32
+ return (node.nodeType==3 ? node.nodeValue :
33
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
34
+ }).flatten().join('');
35
+ }
36
+
37
+ Element.collectTextNodesIgnoreClass = function(element, className) {
38
+ return $A($(element).childNodes).collect( function(node) {
39
+ return (node.nodeType==3 ? node.nodeValue :
40
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
41
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
42
+ }).flatten().join('');
43
+ }
44
+
45
+ Element.setContentZoom = function(element, percent) {
46
+ element = $(element);
47
+ element.setStyle({fontSize: (percent/100) + 'em'});
48
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
49
+ return element;
50
+ }
51
+
52
+ Element.getInlineOpacity = function(element){
53
+ return $(element).style.opacity || '';
54
+ }
55
+
56
+ Element.forceRerendering = function(element) {
57
+ try {
58
+ element = $(element);
59
+ var n = document.createTextNode(' ');
60
+ element.appendChild(n);
61
+ element.removeChild(n);
62
+ } catch(e) { }
63
+ };
64
+
65
+ /*--------------------------------------------------------------------------*/
66
+
67
+ Array.prototype.call = function() {
68
+ var args = arguments;
69
+ this.each(function(f){ f.apply(this, args) });
70
+ }
71
+
72
+ /*--------------------------------------------------------------------------*/
73
+
74
+ var Effect = {
75
+ _elementDoesNotExistError: {
76
+ name: 'ElementDoesNotExistError',
77
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
78
+ },
79
+ tagifyText: function(element) {
80
+ if(typeof Builder == 'undefined')
81
+ throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
82
+
83
+ var tagifyStyle = 'position:relative';
84
+ if(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
85
+
86
+ element = $(element);
87
+ $A(element.childNodes).each( function(child) {
88
+ if(child.nodeType==3) {
89
+ child.nodeValue.toArray().each( function(character) {
90
+ element.insertBefore(
91
+ Builder.node('span',{style: tagifyStyle},
92
+ character == ' ' ? String.fromCharCode(160) : character),
93
+ child);
94
+ });
95
+ Element.remove(child);
96
+ }
97
+ });
98
+ },
99
+ multiple: function(element, effect) {
100
+ var elements;
101
+ if(((typeof element == 'object') ||
102
+ (typeof element == 'function')) &&
103
+ (element.length))
104
+ elements = element;
105
+ else
106
+ elements = $(element).childNodes;
107
+
108
+ var options = Object.extend({
109
+ speed: 0.1,
110
+ delay: 0.0
111
+ }, arguments[2] || {});
112
+ var masterDelay = options.delay;
113
+
114
+ $A(elements).each( function(element, index) {
115
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
116
+ });
117
+ },
118
+ PAIRS: {
119
+ 'slide': ['SlideDown','SlideUp'],
120
+ 'blind': ['BlindDown','BlindUp'],
121
+ 'appear': ['Appear','Fade']
122
+ },
123
+ toggle: function(element, effect) {
124
+ element = $(element);
125
+ effect = (effect || 'appear').toLowerCase();
126
+ var options = Object.extend({
127
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
128
+ }, arguments[2] || {});
129
+ Effect[element.visible() ?
130
+ Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
131
+ }
132
+ };
133
+
134
+ var Effect2 = Effect; // deprecated
135
+
136
+ /* ------------- transitions ------------- */
137
+
138
+ Effect.Transitions = {
139
+ linear: Prototype.K,
140
+ sinoidal: function(pos) {
141
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
142
+ },
143
+ reverse: function(pos) {
144
+ return 1-pos;
145
+ },
146
+ flicker: function(pos) {
147
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
148
+ return (pos > 1 ? 1 : pos);
149
+ },
150
+ wobble: function(pos) {
151
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
152
+ },
153
+ pulse: function(pos, pulses) {
154
+ pulses = pulses || 5;
155
+ return (
156
+ Math.round((pos % (1/pulses)) * pulses) == 0 ?
157
+ ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
158
+ 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
159
+ );
160
+ },
161
+ none: function(pos) {
162
+ return 0;
163
+ },
164
+ full: function(pos) {
165
+ return 1;
166
+ }
167
+ };
168
+
169
+ /* ------------- core effects ------------- */
170
+
171
+ Effect.ScopedQueue = Class.create();
172
+ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
173
+ initialize: function() {
174
+ this.effects = [];
175
+ this.interval = null;
176
+ },
177
+ _each: function(iterator) {
178
+ this.effects._each(iterator);
179
+ },
180
+ add: function(effect) {
181
+ var timestamp = new Date().getTime();
182
+
183
+ var position = (typeof effect.options.queue == 'string') ?
184
+ effect.options.queue : effect.options.queue.position;
185
+
186
+ switch(position) {
187
+ case 'front':
188
+ // move unstarted effects after this effect
189
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
190
+ e.startOn += effect.finishOn;
191
+ e.finishOn += effect.finishOn;
192
+ });
193
+ break;
194
+ case 'with-last':
195
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
196
+ break;
197
+ case 'end':
198
+ // start effect after last queued effect has finished
199
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
200
+ break;
201
+ }
202
+
203
+ effect.startOn += timestamp;
204
+ effect.finishOn += timestamp;
205
+
206
+ if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
207
+ this.effects.push(effect);
208
+
209
+ if(!this.interval)
210
+ this.interval = setInterval(this.loop.bind(this), 15);
211
+ },
212
+ remove: function(effect) {
213
+ this.effects = this.effects.reject(function(e) { return e==effect });
214
+ if(this.effects.length == 0) {
215
+ clearInterval(this.interval);
216
+ this.interval = null;
217
+ }
218
+ },
219
+ loop: function() {
220
+ var timePos = new Date().getTime();
221
+ for(var i=0, len=this.effects.length;i<len;i++)
222
+ this.effects[i] && this.effects[i].loop(timePos);
223
+ }
224
+ });
225
+
226
+ Effect.Queues = {
227
+ instances: $H(),
228
+ get: function(queueName) {
229
+ if(typeof queueName != 'string') return queueName;
230
+
231
+ if(!this.instances[queueName])
232
+ this.instances[queueName] = new Effect.ScopedQueue();
233
+
234
+ return this.instances[queueName];
235
+ }
236
+ }
237
+ Effect.Queue = Effect.Queues.get('global');
238
+
239
+ Effect.DefaultOptions = {
240
+ transition: Effect.Transitions.sinoidal,
241
+ duration: 1.0, // seconds
242
+ fps: 100, // 100= assume 66fps max.
243
+ sync: false, // true for combining
244
+ from: 0.0,
245
+ to: 1.0,
246
+ delay: 0.0,
247
+ queue: 'parallel'
248
+ }
249
+
250
+ Effect.Base = function() {};
251
+ Effect.Base.prototype = {
252
+ position: null,
253
+ start: function(options) {
254
+ function codeForEvent(options,eventName){
255
+ return (
256
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
257
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
258
+ );
259
+ }
260
+ if(options.transition === false) options.transition = Effect.Transitions.linear;
261
+ this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
262
+ this.currentFrame = 0;
263
+ this.state = 'idle';
264
+ this.startOn = this.options.delay*1000;
265
+ this.finishOn = this.startOn+(this.options.duration*1000);
266
+ this.fromToDelta = this.options.to-this.options.from;
267
+ this.totalTime = this.finishOn-this.startOn;
268
+ this.totalFrames = this.options.fps*this.options.duration;
269
+
270
+ eval('this.render = function(pos){ '+
271
+ 'if(this.state=="idle"){this.state="running";'+
272
+ codeForEvent(options,'beforeSetup')+
273
+ (this.setup ? 'this.setup();':'')+
274
+ codeForEvent(options,'afterSetup')+
275
+ '};if(this.state=="running"){'+
276
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
277
+ 'this.position=pos;'+
278
+ codeForEvent(options,'beforeUpdate')+
279
+ (this.update ? 'this.update(pos);':'')+
280
+ codeForEvent(options,'afterUpdate')+
281
+ '}}');
282
+
283
+ this.event('beforeStart');
284
+ if(!this.options.sync)
285
+ Effect.Queues.get(typeof this.options.queue == 'string' ?
286
+ 'global' : this.options.queue.scope).add(this);
287
+ },
288
+ loop: function(timePos) {
289
+ if(timePos >= this.startOn) {
290
+ if(timePos >= this.finishOn) {
291
+ this.render(1.0);
292
+ this.cancel();
293
+ this.event('beforeFinish');
294
+ if(this.finish) this.finish();
295
+ this.event('afterFinish');
296
+ return;
297
+ }
298
+ var pos = (timePos - this.startOn) / this.totalTime,
299
+ frame = Math.round(pos * this.totalFrames);
300
+ if(frame > this.currentFrame) {
301
+ this.render(pos);
302
+ this.currentFrame = frame;
303
+ }
304
+ }
305
+ },
306
+ cancel: function() {
307
+ if(!this.options.sync)
308
+ Effect.Queues.get(typeof this.options.queue == 'string' ?
309
+ 'global' : this.options.queue.scope).remove(this);
310
+ this.state = 'finished';
311
+ },
312
+ event: function(eventName) {
313
+ if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
314
+ if(this.options[eventName]) this.options[eventName](this);
315
+ },
316
+ inspect: function() {
317
+ var data = $H();
318
+ for(property in this)
319
+ if(typeof this[property] != 'function') data[property] = this[property];
320
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
321
+ }
322
+ }
323
+
324
+ Effect.Parallel = Class.create();
325
+ Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
326
+ initialize: function(effects) {
327
+ this.effects = effects || [];
328
+ this.start(arguments[1]);
329
+ },
330
+ update: function(position) {
331
+ this.effects.invoke('render', position);
332
+ },
333
+ finish: function(position) {
334
+ this.effects.each( function(effect) {
335
+ effect.render(1.0);
336
+ effect.cancel();
337
+ effect.event('beforeFinish');
338
+ if(effect.finish) effect.finish(position);
339
+ effect.event('afterFinish');
340
+ });
341
+ }
342
+ });
343
+
344
+ Effect.Event = Class.create();
345
+ Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
346
+ initialize: function() {
347
+ var options = Object.extend({
348
+ duration: 0
349
+ }, arguments[0] || {});
350
+ this.start(options);
351
+ },
352
+ update: Prototype.emptyFunction
353
+ });
354
+
355
+ Effect.Opacity = Class.create();
356
+ Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
357
+ initialize: function(element) {
358
+ this.element = $(element);
359
+ if(!this.element) throw(Effect._elementDoesNotExistError);
360
+ // make this work on IE on elements without 'layout'
361
+ if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
362
+ this.element.setStyle({zoom: 1});
363
+ var options = Object.extend({
364
+ from: this.element.getOpacity() || 0.0,
365
+ to: 1.0
366
+ }, arguments[1] || {});
367
+ this.start(options);
368
+ },
369
+ update: function(position) {
370
+ this.element.setOpacity(position);
371
+ }
372
+ });
373
+
374
+ Effect.Move = Class.create();
375
+ Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
376
+ initialize: function(element) {
377
+ this.element = $(element);
378
+ if(!this.element) throw(Effect._elementDoesNotExistError);
379
+ var options = Object.extend({
380
+ x: 0,
381
+ y: 0,
382
+ mode: 'relative'
383
+ }, arguments[1] || {});
384
+ this.start(options);
385
+ },
386
+ setup: function() {
387
+ // Bug in Opera: Opera returns the "real" position of a static element or
388
+ // relative element that does not have top/left explicitly set.
389
+ // ==> Always set top and left for position relative elements in your stylesheets
390
+ // (to 0 if you do not need them)
391
+ this.element.makePositioned();
392
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
393
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
394
+ if(this.options.mode == 'absolute') {
395
+ // absolute movement, so we need to calc deltaX and deltaY
396
+ this.options.x = this.options.x - this.originalLeft;
397
+ this.options.y = this.options.y - this.originalTop;
398
+ }
399
+ },
400
+ update: function(position) {
401
+ this.element.setStyle({
402
+ left: Math.round(this.options.x * position + this.originalLeft) + 'px',
403
+ top: Math.round(this.options.y * position + this.originalTop) + 'px'
404
+ });
405
+ }
406
+ });
407
+
408
+ // for backwards compatibility
409
+ Effect.MoveBy = function(element, toTop, toLeft) {
410
+ return new Effect.Move(element,
411
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
412
+ };
413
+
414
+ Effect.Scale = Class.create();
415
+ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
416
+ initialize: function(element, percent) {
417
+ this.element = $(element);
418
+ if(!this.element) throw(Effect._elementDoesNotExistError);
419
+ var options = Object.extend({
420
+ scaleX: true,
421
+ scaleY: true,
422
+ scaleContent: true,
423
+ scaleFromCenter: false,
424
+ scaleMode: 'box', // 'box' or 'contents' or {} with provided values
425
+ scaleFrom: 100.0,
426
+ scaleTo: percent
427
+ }, arguments[2] || {});
428
+ this.start(options);
429
+ },
430
+ setup: function() {
431
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
432
+ this.elementPositioning = this.element.getStyle('position');
433
+
434
+ this.originalStyle = {};
435
+ ['top','left','width','height','fontSize'].each( function(k) {
436
+ this.originalStyle[k] = this.element.style[k];
437
+ }.bind(this));
438
+
439
+ this.originalTop = this.element.offsetTop;
440
+ this.originalLeft = this.element.offsetLeft;
441
+
442
+ var fontSize = this.element.getStyle('font-size') || '100%';
443
+ ['em','px','%','pt'].each( function(fontSizeType) {
444
+ if(fontSize.indexOf(fontSizeType)>0) {
445
+ this.fontSize = parseFloat(fontSize);
446
+ this.fontSizeType = fontSizeType;
447
+ }
448
+ }.bind(this));
449
+
450
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
451
+
452
+ this.dims = null;
453
+ if(this.options.scaleMode=='box')
454
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
455
+ if(/^content/.test(this.options.scaleMode))
456
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
457
+ if(!this.dims)
458
+ this.dims = [this.options.scaleMode.originalHeight,
459
+ this.options.scaleMode.originalWidth];
460
+ },
461
+ update: function(position) {
462
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
463
+ if(this.options.scaleContent && this.fontSize)
464
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
465
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
466
+ },
467
+ finish: function(position) {
468
+ if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
469
+ },
470
+ setDimensions: function(height, width) {
471
+ var d = {};
472
+ if(this.options.scaleX) d.width = Math.round(width) + 'px';
473
+ if(this.options.scaleY) d.height = Math.round(height) + 'px';
474
+ if(this.options.scaleFromCenter) {
475
+ var topd = (height - this.dims[0])/2;
476
+ var leftd = (width - this.dims[1])/2;
477
+ if(this.elementPositioning == 'absolute') {
478
+ if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
479
+ if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
480
+ } else {
481
+ if(this.options.scaleY) d.top = -topd + 'px';
482
+ if(this.options.scaleX) d.left = -leftd + 'px';
483
+ }
484
+ }
485
+ this.element.setStyle(d);
486
+ }
487
+ });
488
+
489
+ Effect.Highlight = Class.create();
490
+ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
491
+ initialize: function(element) {
492
+ this.element = $(element);
493
+ if(!this.element) throw(Effect._elementDoesNotExistError);
494
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
495
+ this.start(options);
496
+ },
497
+ setup: function() {
498
+ // Prevent executing on elements not in the layout flow
499
+ if(this.element.getStyle('display')=='none') { this.cancel(); return; }
500
+ // Disable background image during the effect
501
+ this.oldStyle = {};
502
+ if (!this.options.keepBackgroundImage) {
503
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
504
+ this.element.setStyle({backgroundImage: 'none'});
505
+ }
506
+ if(!this.options.endcolor)
507
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
508
+ if(!this.options.restorecolor)
509
+ this.options.restorecolor = this.element.getStyle('background-color');
510
+ // init color calculations
511
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
512
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
513
+ },
514
+ update: function(position) {
515
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
516
+ return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
517
+ },
518
+ finish: function() {
519
+ this.element.setStyle(Object.extend(this.oldStyle, {
520
+ backgroundColor: this.options.restorecolor
521
+ }));
522
+ }
523
+ });
524
+
525
+ Effect.ScrollTo = Class.create();
526
+ Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
527
+ initialize: function(element) {
528
+ this.element = $(element);
529
+ this.start(arguments[1] || {});
530
+ },
531
+ setup: function() {
532
+ Position.prepare();
533
+ var offsets = Position.cumulativeOffset(this.element);
534
+ if(this.options.offset) offsets[1] += this.options.offset;
535
+ var max = window.innerHeight ?
536
+ window.height - window.innerHeight :
537
+ document.body.scrollHeight -
538
+ (document.documentElement.clientHeight ?
539
+ document.documentElement.clientHeight : document.body.clientHeight);
540
+ this.scrollStart = Position.deltaY;
541
+ this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
542
+ },
543
+ update: function(position) {
544
+ Position.prepare();
545
+ window.scrollTo(Position.deltaX,
546
+ this.scrollStart + (position*this.delta));
547
+ }
548
+ });
549
+
550
+ /* ------------- combination effects ------------- */
551
+
552
+ Effect.Fade = function(element) {
553
+ element = $(element);
554
+ var oldOpacity = element.getInlineOpacity();
555
+ var options = Object.extend({
556
+ from: element.getOpacity() || 1.0,
557
+ to: 0.0,
558
+ afterFinishInternal: function(effect) {
559
+ if(effect.options.to!=0) return;
560
+ effect.element.hide().setStyle({opacity: oldOpacity});
561
+ }}, arguments[1] || {});
562
+ return new Effect.Opacity(element,options);
563
+ }
564
+
565
+ Effect.Appear = function(element) {
566
+ element = $(element);
567
+ var options = Object.extend({
568
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
569
+ to: 1.0,
570
+ // force Safari to render floated elements properly
571
+ afterFinishInternal: function(effect) {
572
+ effect.element.forceRerendering();
573
+ },
574
+ beforeSetup: function(effect) {
575
+ effect.element.setOpacity(effect.options.from).show();
576
+ }}, arguments[1] || {});
577
+ return new Effect.Opacity(element,options);
578
+ }
579
+
580
+ Effect.Puff = function(element) {
581
+ element = $(element);
582
+ var oldStyle = {
583
+ opacity: element.getInlineOpacity(),
584
+ position: element.getStyle('position'),
585
+ top: element.style.top,
586
+ left: element.style.left,
587
+ width: element.style.width,
588
+ height: element.style.height
589
+ };
590
+ return new Effect.Parallel(
591
+ [ new Effect.Scale(element, 200,
592
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
593
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
594
+ Object.extend({ duration: 1.0,
595
+ beforeSetupInternal: function(effect) {
596
+ Position.absolutize(effect.effects[0].element)
597
+ },
598
+ afterFinishInternal: function(effect) {
599
+ effect.effects[0].element.hide().setStyle(oldStyle); }
600
+ }, arguments[1] || {})
601
+ );
602
+ }
603
+
604
+ Effect.BlindUp = function(element) {
605
+ element = $(element);
606
+ element.makeClipping();
607
+ return new Effect.Scale(element, 0,
608
+ Object.extend({ scaleContent: false,
609
+ scaleX: false,
610
+ restoreAfterFinish: true,
611
+ afterFinishInternal: function(effect) {
612
+ effect.element.hide().undoClipping();
613
+ }
614
+ }, arguments[1] || {})
615
+ );
616
+ }
617
+
618
+ Effect.BlindDown = function(element) {
619
+ element = $(element);
620
+ var elementDimensions = element.getDimensions();
621
+ return new Effect.Scale(element, 100, Object.extend({
622
+ scaleContent: false,
623
+ scaleX: false,
624
+ scaleFrom: 0,
625
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
626
+ restoreAfterFinish: true,
627
+ afterSetup: function(effect) {
628
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
629
+ },
630
+ afterFinishInternal: function(effect) {
631
+ effect.element.undoClipping();
632
+ }
633
+ }, arguments[1] || {}));
634
+ }
635
+
636
+ Effect.SwitchOff = function(element) {
637
+ element = $(element);
638
+ var oldOpacity = element.getInlineOpacity();
639
+ return new Effect.Appear(element, Object.extend({
640
+ duration: 0.4,
641
+ from: 0,
642
+ transition: Effect.Transitions.flicker,
643
+ afterFinishInternal: function(effect) {
644
+ new Effect.Scale(effect.element, 1, {
645
+ duration: 0.3, scaleFromCenter: true,
646
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
647
+ beforeSetup: function(effect) {
648
+ effect.element.makePositioned().makeClipping();
649
+ },
650
+ afterFinishInternal: function(effect) {
651
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
652
+ }
653
+ })
654
+ }
655
+ }, arguments[1] || {}));
656
+ }
657
+
658
+ Effect.DropOut = function(element) {
659
+ element = $(element);
660
+ var oldStyle = {
661
+ top: element.getStyle('top'),
662
+ left: element.getStyle('left'),
663
+ opacity: element.getInlineOpacity() };
664
+ return new Effect.Parallel(
665
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
666
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
667
+ Object.extend(
668
+ { duration: 0.5,
669
+ beforeSetup: function(effect) {
670
+ effect.effects[0].element.makePositioned();
671
+ },
672
+ afterFinishInternal: function(effect) {
673
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
674
+ }
675
+ }, arguments[1] || {}));
676
+ }
677
+
678
+ Effect.Shake = function(element) {
679
+ element = $(element);
680
+ var oldStyle = {
681
+ top: element.getStyle('top'),
682
+ left: element.getStyle('left') };
683
+ return new Effect.Move(element,
684
+ { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
685
+ new Effect.Move(effect.element,
686
+ { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
687
+ new Effect.Move(effect.element,
688
+ { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
689
+ new Effect.Move(effect.element,
690
+ { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
691
+ new Effect.Move(effect.element,
692
+ { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
693
+ new Effect.Move(effect.element,
694
+ { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
695
+ effect.element.undoPositioned().setStyle(oldStyle);
696
+ }}) }}) }}) }}) }}) }});
697
+ }
698
+
699
+ Effect.SlideDown = function(element) {
700
+ element = $(element).cleanWhitespace();
701
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
702
+ var oldInnerBottom = element.down().getStyle('bottom');
703
+ var elementDimensions = element.getDimensions();
704
+ return new Effect.Scale(element, 100, Object.extend({
705
+ scaleContent: false,
706
+ scaleX: false,
707
+ scaleFrom: window.opera ? 0 : 1,
708
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
709
+ restoreAfterFinish: true,
710
+ afterSetup: function(effect) {
711
+ effect.element.makePositioned();
712
+ effect.element.down().makePositioned();
713
+ if(window.opera) effect.element.setStyle({top: ''});
714
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
715
+ },
716
+ afterUpdateInternal: function(effect) {
717
+ effect.element.down().setStyle({bottom:
718
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
719
+ },
720
+ afterFinishInternal: function(effect) {
721
+ effect.element.undoClipping().undoPositioned();
722
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
723
+ }, arguments[1] || {})
724
+ );
725
+ }
726
+
727
+ Effect.SlideUp = function(element) {
728
+ element = $(element).cleanWhitespace();
729
+ var oldInnerBottom = element.down().getStyle('bottom');
730
+ return new Effect.Scale(element, window.opera ? 0 : 1,
731
+ Object.extend({ scaleContent: false,
732
+ scaleX: false,
733
+ scaleMode: 'box',
734
+ scaleFrom: 100,
735
+ restoreAfterFinish: true,
736
+ beforeStartInternal: function(effect) {
737
+ effect.element.makePositioned();
738
+ effect.element.down().makePositioned();
739
+ if(window.opera) effect.element.setStyle({top: ''});
740
+ effect.element.makeClipping().show();
741
+ },
742
+ afterUpdateInternal: function(effect) {
743
+ effect.element.down().setStyle({bottom:
744
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
745
+ },
746
+ afterFinishInternal: function(effect) {
747
+ effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
748
+ effect.element.down().undoPositioned();
749
+ }
750
+ }, arguments[1] || {})
751
+ );
752
+ }
753
+
754
+ // Bug in opera makes the TD containing this element expand for a instance after finish
755
+ Effect.Squish = function(element) {
756
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
757
+ restoreAfterFinish: true,
758
+ beforeSetup: function(effect) {
759
+ effect.element.makeClipping();
760
+ },
761
+ afterFinishInternal: function(effect) {
762
+ effect.element.hide().undoClipping();
763
+ }
764
+ });
765
+ }
766
+
767
+ Effect.Grow = function(element) {
768
+ element = $(element);
769
+ var options = Object.extend({
770
+ direction: 'center',
771
+ moveTransition: Effect.Transitions.sinoidal,
772
+ scaleTransition: Effect.Transitions.sinoidal,
773
+ opacityTransition: Effect.Transitions.full
774
+ }, arguments[1] || {});
775
+ var oldStyle = {
776
+ top: element.style.top,
777
+ left: element.style.left,
778
+ height: element.style.height,
779
+ width: element.style.width,
780
+ opacity: element.getInlineOpacity() };
781
+
782
+ var dims = element.getDimensions();
783
+ var initialMoveX, initialMoveY;
784
+ var moveX, moveY;
785
+
786
+ switch (options.direction) {
787
+ case 'top-left':
788
+ initialMoveX = initialMoveY = moveX = moveY = 0;
789
+ break;
790
+ case 'top-right':
791
+ initialMoveX = dims.width;
792
+ initialMoveY = moveY = 0;
793
+ moveX = -dims.width;
794
+ break;
795
+ case 'bottom-left':
796
+ initialMoveX = moveX = 0;
797
+ initialMoveY = dims.height;
798
+ moveY = -dims.height;
799
+ break;
800
+ case 'bottom-right':
801
+ initialMoveX = dims.width;
802
+ initialMoveY = dims.height;
803
+ moveX = -dims.width;
804
+ moveY = -dims.height;
805
+ break;
806
+ case 'center':
807
+ initialMoveX = dims.width / 2;
808
+ initialMoveY = dims.height / 2;
809
+ moveX = -dims.width / 2;
810
+ moveY = -dims.height / 2;
811
+ break;
812
+ }
813
+
814
+ return new Effect.Move(element, {
815
+ x: initialMoveX,
816
+ y: initialMoveY,
817
+ duration: 0.01,
818
+ beforeSetup: function(effect) {
819
+ effect.element.hide().makeClipping().makePositioned();
820
+ },
821
+ afterFinishInternal: function(effect) {
822
+ new Effect.Parallel(
823
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
824
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
825
+ new Effect.Scale(effect.element, 100, {
826
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
827
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
828
+ ], Object.extend({
829
+ beforeSetup: function(effect) {
830
+ effect.effects[0].element.setStyle({height: '0px'}).show();
831
+ },
832
+ afterFinishInternal: function(effect) {
833
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
834
+ }
835
+ }, options)
836
+ )
837
+ }
838
+ });
839
+ }
840
+
841
+ Effect.Shrink = function(element) {
842
+ element = $(element);
843
+ var options = Object.extend({
844
+ direction: 'center',
845
+ moveTransition: Effect.Transitions.sinoidal,
846
+ scaleTransition: Effect.Transitions.sinoidal,
847
+ opacityTransition: Effect.Transitions.none
848
+ }, arguments[1] || {});
849
+ var oldStyle = {
850
+ top: element.style.top,
851
+ left: element.style.left,
852
+ height: element.style.height,
853
+ width: element.style.width,
854
+ opacity: element.getInlineOpacity() };
855
+
856
+ var dims = element.getDimensions();
857
+ var moveX, moveY;
858
+
859
+ switch (options.direction) {
860
+ case 'top-left':
861
+ moveX = moveY = 0;
862
+ break;
863
+ case 'top-right':
864
+ moveX = dims.width;
865
+ moveY = 0;
866
+ break;
867
+ case 'bottom-left':
868
+ moveX = 0;
869
+ moveY = dims.height;
870
+ break;
871
+ case 'bottom-right':
872
+ moveX = dims.width;
873
+ moveY = dims.height;
874
+ break;
875
+ case 'center':
876
+ moveX = dims.width / 2;
877
+ moveY = dims.height / 2;
878
+ break;
879
+ }
880
+
881
+ return new Effect.Parallel(
882
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
883
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
884
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
885
+ ], Object.extend({
886
+ beforeStartInternal: function(effect) {
887
+ effect.effects[0].element.makePositioned().makeClipping();
888
+ },
889
+ afterFinishInternal: function(effect) {
890
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
891
+ }, options)
892
+ );
893
+ }
894
+
895
+ Effect.Pulsate = function(element) {
896
+ element = $(element);
897
+ var options = arguments[1] || {};
898
+ var oldOpacity = element.getInlineOpacity();
899
+ var transition = options.transition || Effect.Transitions.sinoidal;
900
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
901
+ reverser.bind(transition);
902
+ return new Effect.Opacity(element,
903
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
904
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
905
+ }, options), {transition: reverser}));
906
+ }
907
+
908
+ Effect.Fold = function(element) {
909
+ element = $(element);
910
+ var oldStyle = {
911
+ top: element.style.top,
912
+ left: element.style.left,
913
+ width: element.style.width,
914
+ height: element.style.height };
915
+ element.makeClipping();
916
+ return new Effect.Scale(element, 5, Object.extend({
917
+ scaleContent: false,
918
+ scaleX: false,
919
+ afterFinishInternal: function(effect) {
920
+ new Effect.Scale(element, 1, {
921
+ scaleContent: false,
922
+ scaleY: false,
923
+ afterFinishInternal: function(effect) {
924
+ effect.element.hide().undoClipping().setStyle(oldStyle);
925
+ } });
926
+ }}, arguments[1] || {}));
927
+ };
928
+
929
+ Effect.Morph = Class.create();
930
+ Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
931
+ initialize: function(element) {
932
+ this.element = $(element);
933
+ if(!this.element) throw(Effect._elementDoesNotExistError);
934
+ var options = Object.extend({
935
+ style: {}
936
+ }, arguments[1] || {});
937
+ if (typeof options.style == 'string') {
938
+ if(options.style.indexOf(':') == -1) {
939
+ var cssText = '', selector = '.' + options.style;
940
+ $A(document.styleSheets).reverse().each(function(styleSheet) {
941
+ if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
942
+ else if (styleSheet.rules) cssRules = styleSheet.rules;
943
+ $A(cssRules).reverse().each(function(rule) {
944
+ if (selector == rule.selectorText) {
945
+ cssText = rule.style.cssText;
946
+ throw $break;
947
+ }
948
+ });
949
+ if (cssText) throw $break;
950
+ });
951
+ this.style = cssText.parseStyle();
952
+ options.afterFinishInternal = function(effect){
953
+ effect.element.addClassName(effect.options.style);
954
+ effect.transforms.each(function(transform) {
955
+ if(transform.style != 'opacity')
956
+ effect.element.style[transform.style] = '';
957
+ });
958
+ }
959
+ } else this.style = options.style.parseStyle();
960
+ } else this.style = $H(options.style)
961
+ this.start(options);
962
+ },
963
+ setup: function(){
964
+ function parseColor(color){
965
+ if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
966
+ color = color.parseColor();
967
+ return $R(0,2).map(function(i){
968
+ return parseInt( color.slice(i*2+1,i*2+3), 16 )
969
+ });
970
+ }
971
+ this.transforms = this.style.map(function(pair){
972
+ var property = pair[0], value = pair[1], unit = null;
973
+
974
+ if(value.parseColor('#zzzzzz') != '#zzzzzz') {
975
+ value = value.parseColor();
976
+ unit = 'color';
977
+ } else if(property == 'opacity') {
978
+ value = parseFloat(value);
979
+ if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
980
+ this.element.setStyle({zoom: 1});
981
+ } else if(Element.CSS_LENGTH.test(value)) {
982
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
983
+ value = parseFloat(components[1]);
984
+ unit = (components.length == 3) ? components[2] : null;
985
+ }
986
+
987
+ var originalValue = this.element.getStyle(property);
988
+ return {
989
+ style: property.camelize(),
990
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
991
+ targetValue: unit=='color' ? parseColor(value) : value,
992
+ unit: unit
993
+ };
994
+ }.bind(this)).reject(function(transform){
995
+ return (
996
+ (transform.originalValue == transform.targetValue) ||
997
+ (
998
+ transform.unit != 'color' &&
999
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
1000
+ )
1001
+ )
1002
+ });
1003
+ },
1004
+ update: function(position) {
1005
+ var style = {}, transform, i = this.transforms.length;
1006
+ while(i--)
1007
+ style[(transform = this.transforms[i]).style] =
1008
+ transform.unit=='color' ? '#'+
1009
+ (Math.round(transform.originalValue[0]+
1010
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
1011
+ (Math.round(transform.originalValue[1]+
1012
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
1013
+ (Math.round(transform.originalValue[2]+
1014
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
1015
+ transform.originalValue + Math.round(
1016
+ ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1017
+ this.element.setStyle(style, true);
1018
+ }
1019
+ });
1020
+
1021
+ Effect.Transform = Class.create();
1022
+ Object.extend(Effect.Transform.prototype, {
1023
+ initialize: function(tracks){
1024
+ this.tracks = [];
1025
+ this.options = arguments[1] || {};
1026
+ this.addTracks(tracks);
1027
+ },
1028
+ addTracks: function(tracks){
1029
+ tracks.each(function(track){
1030
+ var data = $H(track).values().first();
1031
+ this.tracks.push($H({
1032
+ ids: $H(track).keys().first(),
1033
+ effect: Effect.Morph,
1034
+ options: { style: data }
1035
+ }));
1036
+ }.bind(this));
1037
+ return this;
1038
+ },
1039
+ play: function(){
1040
+ return new Effect.Parallel(
1041
+ this.tracks.map(function(track){
1042
+ var elements = [$(track.ids) || $$(track.ids)].flatten();
1043
+ return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1044
+ }).flatten(),
1045
+ this.options
1046
+ );
1047
+ }
1048
+ });
1049
+
1050
+ Element.CSS_PROPERTIES = $w(
1051
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1052
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1053
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1054
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1055
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
1056
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1057
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1058
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1059
+ 'right textIndent top width wordSpacing zIndex');
1060
+
1061
+ Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1062
+
1063
+ String.prototype.parseStyle = function(){
1064
+ var element = document.createElement('div');
1065
+ element.innerHTML = '<div style="' + this + '"></div>';
1066
+ var style = element.childNodes[0].style, styleRules = $H();
1067
+
1068
+ Element.CSS_PROPERTIES.each(function(property){
1069
+ if(style[property]) styleRules[property] = style[property];
1070
+ });
1071
+ if(Prototype.Browser.IE && this.indexOf('opacity') > -1) {
1072
+ styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1073
+ }
1074
+ return styleRules;
1075
+ };
1076
+
1077
+ Element.morph = function(element, style) {
1078
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1079
+ return element;
1080
+ };
1081
+
1082
+ ['getInlineOpacity','forceRerendering','setContentZoom',
1083
+ 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1084
+ function(f) { Element.Methods[f] = Element[f]; }
1085
+ );
1086
+
1087
+ Element.Methods.visualEffect = function(element, effect, options) {
1088
+ s = effect.dasherize().camelize();
1089
+ effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1090
+ new Effect[effect_class](element, options);
1091
+ return $(element);
1092
+ };
1093
+
1094
+ Element.addMethods();
js/dev/lightbox.js ADDED
@@ -0,0 +1,705 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // -----------------------------------------------------------------------------------
2
+ //
3
+ // Lightbox Slideshow v1.1
4
+ // by Justin Barkhuff - http://www.justinbarkhuff.com/lab/lightbox_slideshow/
5
+ // Updated: 2007-08-15
6
+ //
7
+ // Largely based on Lightbox v2.02
8
+ // by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
9
+ // 3/31/06
10
+ //
11
+ // Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
12
+ //
13
+ // The code inserts html at the bottom of the page that looks similar to this:
14
+ //
15
+ // <div id="overlay"></div>
16
+ // <div id="lightbox">
17
+ // <div id="outerImageContainer">
18
+ // <div id="imageContainer">
19
+ // <img id="lightboxImage" />
20
+ // <div id="hoverNav">
21
+ // <a href="javascript:void(0);" id="prevLinkImg">&laquo; prev</a>
22
+ // <a href="javascript:void(0);" id="nextLinkImg">next &raquo;</a>
23
+ // </div>
24
+ // <div id="loading">
25
+ // <a href="javascript:void(0);" id="loadingLink">loading</a>
26
+ // </div>
27
+ // </div>
28
+ // </div>
29
+ // <div id="imageDataContainer">
30
+ // <div id="imageData">
31
+ // <div id="imageDetails">
32
+ // <span id="caption"></span>
33
+ // <span id="numberDisplay"></span>
34
+ // <span id="detailsNav">
35
+ // <a id="prevLinkDetails" href="javascript:void(0);">&laquo; prev</a>
36
+ // <a id="nextLinkDetails" href="javascript:void(0);">next &raquo;</a>
37
+ // <a id="slideShowControl" href="javascript:void(0);">stop slideshow</a>
38
+ // </span>
39
+ // </div>
40
+ // <div id="close">
41
+ // <a id="closeLink" href="javascript:void(0);">close</a>
42
+ // </div>
43
+ // </div>
44
+ // </div>
45
+ // </div>
46
+ //
47
+ // -----------------------------------------------------------------------------------
48
+
49
+ //
50
+ // Lightbox Object
51
+ //
52
+
53
+ var Lightbox = {
54
+ activeImage : null,
55
+ badObjects : ['select','object','embed'],
56
+ container : null,
57
+ enableSlideshow : null,
58
+ groupName : null,
59
+ imageArray : [],
60
+ options : null,
61
+ overlayDuration : null,
62
+ overlayOpacity : null,
63
+ playSlides : null,
64
+ refTags : ['a','area'],
65
+ relAttribute : null,
66
+ resizeDuration : null,
67
+ slideShowTimer : null,
68
+ startImage : null,
69
+
70
+ //
71
+ // initialize()
72
+ // Constructor sets class properties and configuration options and
73
+ // inserts html at the bottom of the page which is used to display the shadow
74
+ // overlay and the image container.
75
+ //
76
+ initialize: function(options) {
77
+ if (!document.getElementsByTagName){ return; }
78
+
79
+ this.options = $H({
80
+ animate : true, // resizing animations
81
+ autoPlay : true, // should slideshow start automatically
82
+ borderSize : 10, // if you adjust the padding in the CSS, you will need to update this variable
83
+ containerID : document, // lightbox container object
84
+ enableSlideshow : true, // enable slideshow feature
85
+ googleAnalytics : false, // track individual image views using Google Analytics
86
+ imageDataLocation : 'south', // location of image caption information
87
+ initImage : '', // ID of image link to automatically launch when upon script initialization
88
+ loop : true, // whether to continuously loop slideshow images
89
+ overlayDuration : .2, // time to fade in shadow overlay
90
+ overlayOpacity : .8, // transparency of shadow overlay
91
+ prefix : '', // ID prefix for all dynamically created html elements
92
+ relAttribute : 'lightbox', // specifies the rel attribute value that triggers lightbox
93
+ resizeSpeed : 7, // controls the speed of the image resizing (1=slowest and 10=fastest)
94
+ showGroupName : false, // show group name of images in image details
95
+ slideTime : 4, // time to display images during slideshow
96
+ strings : { // allows for localization
97
+ closeLink : 'close',
98
+ loadingMsg : 'loading',
99
+ nextLink : 'next &raquo;',
100
+ prevLink : '&laquo; prev',
101
+ startSlideshow : 'start slideshow',
102
+ stopSlideshow : 'stop slideshow',
103
+ numDisplayPrefix : 'Image',
104
+ numDisplaySeparator : 'of'
105
+ }
106
+ }).merge(options);
107
+
108
+ if(this.options.animate){
109
+ this.overlayDuration = Math.max(this.options.overlayDuration,0);
110
+ this.options.resizeSpeed = Math.max(Math.min(this.options.resizeSpeed,10),1);
111
+ this.resizeDuration = (11 - this.options.resizeSpeed) * 0.15;
112
+ }else{
113
+ this.overlayDuration = 0;
114
+ this.resizeDuration = 0;
115
+ }
116
+
117
+ this.enableSlideshow = this.options.enableSlideshow;
118
+ this.overlayOpacity = Math.max(Math.min(this.options.overlayOpacity,1),0);
119
+ this.playSlides = this.options.autoPlay;
120
+ this.container = $(this.options.containerID);
121
+ this.relAttribute = this.options.relAttribute;
122
+ this.updateImageList();
123
+
124
+ var objBody = this.container != document ? this.container : document.getElementsByTagName('body').item(0);
125
+
126
+ var objOverlay = document.createElement('div');
127
+ objOverlay.setAttribute('id',this.getID('overlay'));
128
+ objOverlay.style.display = 'none';
129
+ objBody.appendChild(objOverlay);
130
+ Event.observe(objOverlay,'click',this.end.bindAsEventListener(this));
131
+
132
+ var objLightbox = document.createElement('div');
133
+ objLightbox.setAttribute('id',this.getID('lightbox'));
134
+ objLightbox.style.display = 'none';
135
+ objBody.appendChild(objLightbox);
136
+
137
+ var objImageDataContainer = document.createElement('div');
138
+ objImageDataContainer.setAttribute('id',this.getID('imageDataContainer'));
139
+ objImageDataContainer.className = this.getID('clearfix');
140
+
141
+ var objImageData = document.createElement('div');
142
+ objImageData.setAttribute('id',this.getID('imageData'));
143
+ objImageDataContainer.appendChild(objImageData);
144
+
145
+ var objImageDetails = document.createElement('div');
146
+ objImageDetails.setAttribute('id',this.getID('imageDetails'));
147
+ objImageData.appendChild(objImageDetails);
148
+
149
+ var objCaption = document.createElement('span');
150
+ objCaption.setAttribute('id',this.getID('caption'));
151
+ objImageDetails.appendChild(objCaption);
152
+
153
+ var objNumberDisplay = document.createElement('span');
154
+ objNumberDisplay.setAttribute('id',this.getID('numberDisplay'));
155
+ objImageDetails.appendChild(objNumberDisplay);
156
+
157
+ var objDetailsNav = document.createElement('span');
158
+ objDetailsNav.setAttribute('id',this.getID('detailsNav'));
159
+ objImageDetails.appendChild(objDetailsNav);
160
+
161
+ var objPrevLink = document.createElement('a');
162
+ objPrevLink.setAttribute('id',this.getID('prevLinkDetails'));
163
+ objPrevLink.setAttribute('href','javascript:void(0);');
164
+ objPrevLink.innerHTML = this.options.strings.prevLink;
165
+ objDetailsNav.appendChild(objPrevLink);
166
+ Event.observe(objPrevLink,'click',this.showPrev.bindAsEventListener(this));
167
+
168
+ var objNextLink = document.createElement('a');
169
+ objNextLink.setAttribute('id',this.getID('nextLinkDetails'));
170
+ objNextLink.setAttribute('href','javascript:void(0);');
171
+ objNextLink.innerHTML = this.options.strings.nextLink;
172
+ objDetailsNav.appendChild(objNextLink);
173
+ Event.observe(objNextLink,'click',this.showNext.bindAsEventListener(this));
174
+
175
+ var objSlideShowControl = document.createElement('a');
176
+ objSlideShowControl.setAttribute('id',this.getID('slideShowControl'));
177
+ objSlideShowControl.setAttribute('href','javascript:void(0);');
178
+ objDetailsNav.appendChild(objSlideShowControl);
179
+ Event.observe(objSlideShowControl,'click',this.toggleSlideShow.bindAsEventListener(this));
180
+
181
+ var objClose = document.createElement('div');
182
+ objClose.setAttribute('id',this.getID('close'));
183
+ objImageData.appendChild(objClose);
184
+
185
+ var objCloseLink = document.createElement('a');
186
+ objCloseLink.setAttribute('id',this.getID('closeLink'));
187
+ objCloseLink.setAttribute('href','javascript:void(0);');
188
+ objCloseLink.innerHTML = this.options.strings.closeLink;
189
+ objClose.appendChild(objCloseLink);
190
+ Event.observe(objCloseLink,'click',this.end.bindAsEventListener(this));
191
+
192
+ if(this.options.imageDataLocation == 'north'){
193
+ objLightbox.appendChild(objImageDataContainer);
194
+ }
195
+
196
+ var objOuterImageContainer = document.createElement('div');
197
+ objOuterImageContainer.setAttribute('id',this.getID('outerImageContainer'));
198
+ objLightbox.appendChild(objOuterImageContainer);
199
+
200
+ var objImageContainer = document.createElement('div');
201
+ objImageContainer.setAttribute('id',this.getID('imageContainer'));
202
+ objOuterImageContainer.appendChild(objImageContainer);
203
+
204
+ var objLightboxImage = document.createElement('img');
205
+ objLightboxImage.setAttribute('id',this.getID('lightboxImage'));
206
+ objImageContainer.appendChild(objLightboxImage);
207
+
208
+ var objHoverNav = document.createElement('div');
209
+ objHoverNav.setAttribute('id',this.getID('hoverNav'));
210
+ objImageContainer.appendChild(objHoverNav);
211
+
212
+ var objPrevLinkImg = document.createElement('a');
213
+ objPrevLinkImg.setAttribute('id',this.getID('prevLinkImg'));
214
+ objPrevLinkImg.setAttribute('href','javascript:void(0);');
215
+ objHoverNav.appendChild(objPrevLinkImg);
216
+ Event.observe(objPrevLinkImg,'click',this.showPrev.bindAsEventListener(this));
217
+
218
+ var objNextLinkImg = document.createElement('a');
219
+ objNextLinkImg.setAttribute('id',this.getID('nextLinkImg'));
220
+ objNextLinkImg.setAttribute('href','javascript:void(0);');
221
+ objHoverNav.appendChild(objNextLinkImg);
222
+ Event.observe(objNextLinkImg,'click',this.showNext.bindAsEventListener(this));
223
+
224
+ var objLoading = document.createElement('div');
225
+ objLoading.setAttribute('id',this.getID('loading'));
226
+ objImageContainer.appendChild(objLoading);
227
+
228
+ var objLoadingLink = document.createElement('a');
229
+ objLoadingLink.setAttribute('id',this.getID('loadingLink'));
230
+ objLoadingLink.setAttribute('href','javascript:void(0);');
231
+ objLoadingLink.innerHTML = this.options.strings.loadingMsg;
232
+ objLoading.appendChild(objLoadingLink);
233
+ Event.observe(objLoadingLink,'click',this.end.bindAsEventListener(this));
234
+
235
+ if(this.options.imageDataLocation != 'north'){
236
+ objLightbox.appendChild(objImageDataContainer);
237
+ }
238
+
239
+ if(this.options.initImage != ''){
240
+ this.start($(this.options.initImage));
241
+ }
242
+ },
243
+
244
+ //
245
+ // updateImageList()
246
+ // Loops through specific tags within 'container' looking for
247
+ // 'lightbox' references and applies onclick events to them.
248
+ //
249
+ updateImageList: function(){
250
+ var el, els, rel;
251
+ for(var i=0; i < this.refTags.length; i++){
252
+ els = this.container.getElementsByTagName(this.refTags[i]);
253
+ for(var j=0; j < els.length; j++){
254
+ el = els[j];
255
+ rel = String(el.getAttribute('rel'));
256
+ if (el.getAttribute('href') && (rel.toLowerCase().match(this.relAttribute))){
257
+ el.onclick = function(){Lightbox.start(this); return false;}
258
+ }
259
+ }
260
+ }
261
+ },
262
+
263
+ //
264
+ // start()
265
+ // Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
266
+ //
267
+ start: function(imageLink) {
268
+
269
+ this.hideBadObjects();
270
+
271
+ // stretch overlay to fill page and fade in
272
+ var pageSize = this.getPageSize();
273
+ $(this.getID('overlay')).setStyle({height:pageSize.pageHeight+'px'});
274
+ new Effect.Appear(this.getID('overlay'), { duration: this.overlayDuration, from: 0, to: this.overlayOpacity });
275
+
276
+ this.imageArray = [];
277
+ this.groupName = null;
278
+
279
+ var rel = imageLink.getAttribute('rel');
280
+ var imageTitle = '';
281
+
282
+ // if image is NOT part of a group..
283
+ if(rel == this.relAttribute){
284
+ // add single image to imageArray
285
+ imageTitle = imageLink.getAttribute('title') ? imageLink.getAttribute('title') : '';
286
+ this.imageArray.push({'link':imageLink.getAttribute('href'), 'title':imageTitle});
287
+ this.startImage = 0;
288
+ } else {
289
+ // if image is part of a group..
290
+ var els = this.container.getElementsByTagName(imageLink.tagName);
291
+ // loop through anchors, find other images in group, and add them to imageArray
292
+ for (var i=0; i<els.length; i++){
293
+ var el = els[i];
294
+ if (el.getAttribute('href') && (el.getAttribute('rel') == rel)){
295
+ imageTitle = el.getAttribute('title') ? el.getAttribute('title') : '';
296
+ this.imageArray.push({'link':el.getAttribute('href'),'title':imageTitle});
297
+ if(el == imageLink){
298
+ this.startImage = this.imageArray.length-1;
299
+ }
300
+ }
301
+ }
302
+ // get group name
303
+ this.groupName = rel.substring(this.relAttribute.length+1,rel.length-1);
304
+ }
305
+
306
+ // calculate top offset for the lightbox and display
307
+ var pageScroll = this.getPageScroll();
308
+ var lightboxTop = pageScroll.y + (pageSize.winHeight / 15);
309
+
310
+ $(this.getID('lightbox')).setStyle({top:lightboxTop+'px'}).show();
311
+ this.changeImage(this.startImage);
312
+ },
313
+
314
+ //
315
+ // changeImage()
316
+ // Hide most elements and preload image in preparation for resizing image container.
317
+ //
318
+ changeImage: function(imageNum){
319
+ this.activeImage = imageNum;
320
+
321
+ this.disableKeyboardNav();
322
+ this.pauseSlideShow();
323
+
324
+ // hide elements during transition
325
+ $(this.getID('loading')).show();
326
+ $(this.getID('lightboxImage')).hide();
327
+ $(this.getID('hoverNav')).hide();
328
+ $(this.getID('imageDataContainer')).hide();
329
+ $(this.getID('numberDisplay')).hide();
330
+ $(this.getID('detailsNav')).hide();
331
+
332
+ var imgPreloader = new Image();
333
+
334
+ // once image is preloaded, resize image container
335
+ imgPreloader.onload=function(){
336
+ $(Lightbox.getID('lightboxImage')).src = imgPreloader.src;
337
+ Lightbox.resizeImageContainer(imgPreloader.width,imgPreloader.height);
338
+ }
339
+ imgPreloader.src = this.imageArray[this.activeImage].link;
340
+
341
+ if(this.options.googleAnalytics){
342
+ urchinTracker(this.imageArray[this.activeImage].link);
343
+ }
344
+ },
345
+
346
+ //
347
+ // resizeImageContainer()
348
+ //
349
+ resizeImageContainer: function(imgWidth,imgHeight) {
350
+ // get current height and width
351
+ var cDims = $(this.getID('outerImageContainer')).getDimensions();
352
+
353
+ // scalars based on change from old to new
354
+ var xScale = ((imgWidth + (this.options.borderSize * 2)) / cDims.width) * 100;
355
+ var yScale = ((imgHeight + (this.options.borderSize * 2)) / cDims.height) * 100;
356
+
357
+ // calculate size difference between new and old image, and resize if necessary
358
+ var wDiff = (cDims.width - this.options.borderSize * 2) - imgWidth;
359
+ var hDiff = (cDims.height - this.options.borderSize * 2) - imgHeight;
360
+
361
+ if(!( hDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); }
362
+ if(!( wDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), xScale, {scaleY: false, delay: this.resizeDuration, duration: this.resizeDuration}); }
363
+
364
+ // if new and old image are same size and no scaling transition is necessary,
365
+ // do a quick pause to prevent image flicker.
366
+ if((hDiff == 0) && (wDiff == 0)){
367
+ if(navigator.appVersion.indexOf('MSIE')!=-1){ this.pause(250); } else { this.pause(100);}
368
+ }
369
+
370
+ $(this.getID('prevLinkImg')).setStyle({height:imgHeight+'px'});
371
+ $(this.getID('nextLinkImg')).setStyle({height:imgHeight+'px'});
372
+ $(this.getID('imageDataContainer')).setStyle({width:(imgWidth+(this.options.borderSize * 2))+'px'});
373
+
374
+ this.showImage();
375
+ },
376
+
377
+ //
378
+ // showImage()
379
+ // Display image and begin preloading neighbors.
380
+ //
381
+ showImage: function(){
382
+ $(this.getID('loading')).hide();
383
+ new Effect.Appear(this.getID('lightboxImage'), { duration: 0.5, queue: 'end', afterFinish: function(){ Lightbox.updateDetails(); } });
384
+ this.preloadNeighborImages();
385
+ },
386
+
387
+ //
388
+ // updateDetails()
389
+ // Display caption, image number, and bottom nav.
390
+ //
391
+ updateDetails: function() {
392
+ $(this.getID('caption')).show();
393
+ $(this.getID('caption')).update(this.imageArray[this.activeImage].title);
394
+
395
+ // if image is part of set display 'Image x of y'
396
+ if(this.imageArray.length > 1){
397
+ var num_display = this.options.strings.numDisplayPrefix + ' ' + eval(this.activeImage + 1) + ' ' + this.options.strings.numDisplaySeparator + ' ' + this.imageArray.length;
398
+ if(this.options.showGroupName && this.groupName != ''){
399
+ num_display += ' '+this.options.strings.numDisplaySeparator+' '+this.groupName;
400
+ }
401
+ $(this.getID('numberDisplay')).update(num_display).show();
402
+ if(!this.enableSlideshow){
403
+ $(this.getID('slideShowControl')).hide();
404
+ }
405
+ $(this.getID('detailsNav')).show();
406
+ }
407
+
408
+ new Effect.Parallel(
409
+ [ new Effect.SlideDown( this.getID('imageDataContainer'), { sync: true }),
410
+ new Effect.Appear(this.getID('imageDataContainer'), { sync: true }) ],
411
+ { duration:.65, afterFinish: function() { Lightbox.updateNav();} }
412
+ );
413
+ },
414
+
415
+ //
416
+ // updateNav()
417
+ // Display appropriate previous and next hover navigation.
418
+ //
419
+ updateNav: function() {
420
+ if(this.imageArray.length > 1){
421
+ $(this.getID('hoverNav')).show();
422
+ if(this.enableSlideshow){
423
+ if(this.playSlides){
424
+ this.startSlideShow();
425
+ } else {
426
+ this.stopSlideShow();
427
+ }
428
+ }
429
+ }
430
+ this.enableKeyboardNav();
431
+ },
432
+ //
433
+ // startSlideShow()
434
+ // Starts the slide show
435
+ //
436
+ startSlideShow: function(){
437
+ this.playSlides = true;
438
+ this.slideShowTimer = new PeriodicalExecuter(function(pe){ Lightbox.showNext(); pe.stop(); },this.options.slideTime);
439
+ $(this.getID('slideShowControl')).update(this.options.strings.stopSlideshow);
440
+ },
441
+
442
+ //
443
+ // stopSlideShow()
444
+ // Stops the slide show
445
+ //
446
+ stopSlideShow: function(){
447
+ this.playSlides = false;
448
+ if(this.slideShowTimer){
449
+ this.slideShowTimer.stop();
450
+ }
451
+ $(this.getID('slideShowControl')).update(this.options.strings.startSlideshow);
452
+ },
453
+
454
+ //
455
+ // stopSlideShow()
456
+ // Stops the slide show
457
+ //
458
+ toggleSlideShow: function(){
459
+ if(this.playSlides){
460
+ this.stopSlideShow();
461
+ }else{
462
+ this.startSlideShow();
463
+ }
464
+ },
465
+
466
+ //
467
+ // pauseSlideShow()
468
+ // Pauses the slide show (doesn't change the value of this.playSlides)
469
+ //
470
+ pauseSlideShow: function(){
471
+ if(this.slideShowTimer){
472
+ this.slideShowTimer.stop();
473
+ }
474
+ },
475
+
476
+ //
477
+ // showNext()
478
+ // Display the next image in a group
479
+ //
480
+ showNext : function(){
481
+ if(this.imageArray.length > 1){
482
+ if(!this.options.loop && ((this.activeImage == this.imageArray.length - 1 && this.startImage == 0) || (this.activeImage+1 == this.startImage))){
483
+ return this.end();
484
+ }
485
+ if(this.activeImage == this.imageArray.length - 1){
486
+ this.changeImage(0);
487
+ }else{
488
+ this.changeImage(this.activeImage+1);
489
+ }
490
+ }
491
+ },
492
+
493
+ //
494
+ // showPrev()
495
+ // Display the next image in a group
496
+ //
497
+ showPrev : function(){
498
+ if(this.imageArray.length > 1){
499
+ if(this.activeImage == 0){
500
+ this.changeImage(this.imageArray.length - 1);
501
+ }else{
502
+ this.changeImage(this.activeImage-1);
503
+ }
504
+ }
505
+ },
506
+
507
+ //
508
+ // showFirst()
509
+ // Display the first image in a group
510
+ //
511
+ showFirst : function(){
512
+ if(this.imageArray.length > 1){
513
+ this.changeImage(0);
514
+ }
515
+ },
516
+
517
+ //
518
+ // showFirst()
519
+ // Display the first image in a group
520
+ //
521
+ showLast : function(){
522
+ if(this.imageArray.length > 1){
523
+ this.changeImage(this.imageArray.length - 1);
524
+ }
525
+ },
526
+
527
+ //
528
+ // enableKeyboardNav()
529
+ //
530
+ enableKeyboardNav: function() {
531
+ document.onkeydown = this.keyboardAction;
532
+ },
533
+
534
+ //
535
+ // disableKeyboardNav()
536
+ //
537
+ disableKeyboardNav: function() {
538
+ document.onkeydown = '';
539
+ },
540
+
541
+ //
542
+ // keyboardAction()
543
+ //
544
+ keyboardAction: function(e) {
545
+ if (e == null) { // ie
546
+ keycode = event.keyCode;
547
+ } else { // mozilla
548
+ keycode = e.which;
549
+ }
550
+
551
+ key = String.fromCharCode(keycode).toLowerCase();
552
+
553
+ if(key == 'x' || key == 'o' || key == 'c'){ // close lightbox
554
+ Lightbox.end();
555
+ } else if(key == 'p' || key == '%'){ // display previous image
556
+ Lightbox.showPrev();
557
+ } else if(key == 'n' || key =='\''){ // display next image
558
+ Lightbox.showNext();
559
+ } else if(key == 'f'){ // display first image
560
+ Lightbox.showFirst();
561
+ } else if(key == 'l'){ // display last image
562
+ Lightbox.showLast();
563
+ } else if(key == 's'){ // toggle slideshow
564
+ if(Lightbox.imageArray.length > 0 && Lightbox.options.enableSlideshow){
565
+ Lightbox.toggleSlideShow();
566
+ }
567
+ }
568
+ },
569
+
570
+ //
571
+ // preloadNeighborImages()
572
+ // Preload previous and next images.
573
+ //
574
+ preloadNeighborImages: function(){
575
+ var nextImageID = this.imageArray.length - 1 == this.activeImage ? 0 : this.activeImage + 1;
576
+ nextImage = new Image();
577
+ nextImage.src = this.imageArray[nextImageID].link
578
+
579
+ var prevImageID = this.activeImage == 0 ? this.imageArray.length - 1 : this.activeImage - 1;
580
+ prevImage = new Image();
581
+ prevImage.src = this.imageArray[prevImageID].link;
582
+ },
583
+
584
+ //
585
+ // end()
586
+ //
587
+ end: function() {
588
+ this.disableKeyboardNav();
589
+ this.pauseSlideShow();
590
+ $(this.getID('lightbox')).hide();
591
+ new Effect.Fade(this.getID('overlay'), { duration:this.overlayDuration });
592
+ this.showBadObjects();
593
+ },
594
+
595
+ //
596
+ // showBadObjects()
597
+ //
598
+ showBadObjects: function (){
599
+ var els;
600
+ var tags = Lightbox.badObjects;
601
+ for(var i=0; i<tags.length; i++){
602
+ els = document.getElementsByTagName(tags[i]);
603
+ for(var j=0; j<els.length; j++){
604
+ $(els[j]).setStyle({visibility:'visible'});
605
+ }
606
+ }
607
+ },
608
+
609
+ //
610
+ // hideBadObjects()
611
+ //
612
+ hideBadObjects: function (){
613
+ var els;
614
+ var tags = Lightbox.badObjects;
615
+ for(var i=0; i<tags.length; i++){
616
+ els = document.getElementsByTagName(tags[i]);
617
+ for(var j=0; j<els.length; j++){
618
+ $(els[j]).setStyle({visibility:'hidden'});
619
+ }
620
+ }
621
+ },
622
+
623
+ //
624
+ // pause(numberMillis)
625
+ // Pauses code execution for specified time. Uses busy code, not good.
626
+ // Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
627
+ //
628
+ pause: function(numberMillis) {
629
+ var now = new Date();
630
+ var exitTime = now.getTime() + numberMillis;
631
+ while(true){
632
+ now = new Date();
633
+ if (now.getTime() > exitTime)
634
+ return;
635
+ }
636
+ },
637
+
638
+ //
639
+ // getPageScroll()
640
+ // Returns array with x,y page scroll values.
641
+ // Core code from - quirksmode.org
642
+ //
643
+ getPageScroll: function(){
644
+ var x,y;
645
+ if (self.pageYOffset) {
646
+ x = self.pageXOffset;
647
+ y = self.pageYOffset;
648
+ } else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict
649
+ x = document.documentElement.scrollLeft;
650
+ y = document.documentElement.scrollTop;
651
+ } else if (document.body) {// all other Explorers
652
+ x = document.body.scrollLeft;
653
+ y = document.body.scrollTop;
654
+ }
655
+ return {x:x,y:y};
656
+ },
657
+
658
+ //
659
+ // getPageSize()
660
+ // Returns array with page width, height and window width, height
661
+ // Core code from - quirksmode.org
662
+ // Edit for Firefox by pHaez
663
+ //
664
+ getPageSize: function(){
665
+ var scrollX,scrollY,windowX,windowY,pageX,pageY;
666
+ if (window.innerHeight && window.scrollMaxY) {
667
+ scrollX = document.body.scrollWidth;
668
+ scrollY = window.innerHeight + window.scrollMaxY;
669
+ } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
670
+ scrollX = document.body.scrollWidth;
671
+ scrollY = document.body.scrollHeight;
672
+ } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
673
+ scrollX = document.body.offsetWidth;
674
+ scrollY = document.body.offsetHeight;
675
+ }
676
+
677
+ if (self.innerHeight) { // all except Explorer
678
+ windowX = self.innerWidth;
679
+ windowY = self.innerHeight;
680
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
681
+ windowX = document.documentElement.clientWidth;
682
+ windowY = document.documentElement.clientHeight;
683
+ } else if (document.body) { // other Explorers
684
+ windowX = document.body.clientWidth;
685
+ windowY = document.body.clientHeight;
686
+ }
687
+
688
+ pageY = (scrollY < windowY) ? windowY : scrollY; // for small pages with total height less then height of the viewport
689
+ pageX = (scrollX < windowX) ? windowX : scrollX; // for small pages with total width less then width of the viewport
690
+
691
+ return {pageWidth:pageX,pageHeight:pageY,winWidth:windowX,winHeight:windowY};
692
+ },
693
+
694
+ //
695
+ // getID()
696
+ // Returns formatted Lightbox element ID
697
+ //
698
+ getID: function(id){
699
+ return this.options.prefix+id;
700
+ }
701
+ }
702
+
703
+ // -----------------------------------------------------------------------------------
704
+
705
+ //Event.observe(window,'load',function(){ Lightbox.initialize(); });
js/dev/prototype.js ADDED
@@ -0,0 +1,3271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Prototype JavaScript framework, version 1.5.1
2
+ * (c) 2005-2007 Sam Stephenson
3
+ *
4
+ * Prototype is freely distributable under the terms of an MIT-style license.
5
+ * For details, see the Prototype web site: http://www.prototypejs.org/
6
+ *
7
+ /*--------------------------------------------------------------------------*/
8
+
9
+ var Prototype = {
10
+ Version: '1.5.1',
11
+
12
+ Browser: {
13
+ IE: !!(window.attachEvent && !window.opera),
14
+ Opera: !!window.opera,
15
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
17
+ },
18
+
19
+ BrowserFeatures: {
20
+ XPath: !!document.evaluate,
21
+ ElementExtensions: !!window.HTMLElement,
22
+ SpecificElementExtensions:
23
+ (document.createElement('div').__proto__ !==
24
+ document.createElement('form').__proto__)
25
+ },
26
+
27
+ ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
28
+ JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
29
+
30
+ emptyFunction: function() { },
31
+ K: function(x) { return x }
32
+ }
33
+
34
+ var Class = {
35
+ create: function() {
36
+ return function() {
37
+ this.initialize.apply(this, arguments);
38
+ }
39
+ }
40
+ }
41
+
42
+ var Abstract = new Object();
43
+
44
+ Object.extend = function(destination, source) {
45
+ for (var property in source) {
46
+ destination[property] = source[property];
47
+ }
48
+ return destination;
49
+ }
50
+
51
+ Object.extend(Object, {
52
+ inspect: function(object) {
53
+ try {
54
+ if (object === undefined) return 'undefined';
55
+ if (object === null) return 'null';
56
+ return object.inspect ? object.inspect() : object.toString();
57
+ } catch (e) {
58
+ if (e instanceof RangeError) return '...';
59
+ throw e;
60
+ }
61
+ },
62
+
63
+ toJSON: function(object) {
64
+ var type = typeof object;
65
+ switch(type) {
66
+ case 'undefined':
67
+ case 'function':
68
+ case 'unknown': return;
69
+ case 'boolean': return object.toString();
70
+ }
71
+ if (object === null) return 'null';
72
+ if (object.toJSON) return object.toJSON();
73
+ if (object.ownerDocument === document) return;
74
+ var results = [];
75
+ for (var property in object) {
76
+ var value = Object.toJSON(object[property]);
77
+ if (value !== undefined)
78
+ results.push(property.toJSON() + ': ' + value);
79
+ }
80
+ return '{' + results.join(', ') + '}';
81
+ },
82
+
83
+ keys: function(object) {
84
+ var keys = [];
85
+ for (var property in object)
86
+ keys.push(property);
87
+ return keys;
88
+ },
89
+
90
+ values: function(object) {
91
+ var values = [];
92
+ for (var property in object)
93
+ values.push(object[property]);
94
+ return values;
95
+ },
96
+
97
+ clone: function(object) {
98
+ return Object.extend({}, object);
99
+ }
100
+ });
101
+
102
+ Function.prototype.bind = function() {
103
+ var __method = this, args = $A(arguments), object = args.shift();
104
+ return function() {
105
+ return __method.apply(object, args.concat($A(arguments)));
106
+ }
107
+ }
108
+
109
+ Function.prototype.bindAsEventListener = function(object) {
110
+ var __method = this, args = $A(arguments), object = args.shift();
111
+ return function(event) {
112
+ return __method.apply(object, [event || window.event].concat(args));
113
+ }
114
+ }
115
+
116
+ Object.extend(Number.prototype, {
117
+ toColorPart: function() {
118
+ return this.toPaddedString(2, 16);
119
+ },
120
+
121
+ succ: function() {
122
+ return this + 1;
123
+ },
124
+
125
+ times: function(iterator) {
126
+ $R(0, this, true).each(iterator);
127
+ return this;
128
+ },
129
+
130
+ toPaddedString: function(length, radix) {
131
+ var string = this.toString(radix || 10);
132
+ return '0'.times(length - string.length) + string;
133
+ },
134
+
135
+ toJSON: function() {
136
+ return isFinite(this) ? this.toString() : 'null';
137
+ }
138
+ });
139
+
140
+ Date.prototype.toJSON = function() {
141
+ return '"' + this.getFullYear() + '-' +
142
+ (this.getMonth() + 1).toPaddedString(2) + '-' +
143
+ this.getDate().toPaddedString(2) + 'T' +
144
+ this.getHours().toPaddedString(2) + ':' +
145
+ this.getMinutes().toPaddedString(2) + ':' +
146
+ this.getSeconds().toPaddedString(2) + '"';
147
+ };
148
+
149
+ var Try = {
150
+ these: function() {
151
+ var returnValue;
152
+
153
+ for (var i = 0, length = arguments.length; i < length; i++) {
154
+ var lambda = arguments[i];
155
+ try {
156
+ returnValue = lambda();
157
+ break;
158
+ } catch (e) {}
159
+ }
160
+
161
+ return returnValue;
162
+ }
163
+ }
164
+
165
+ /*--------------------------------------------------------------------------*/
166
+
167
+ var PeriodicalExecuter = Class.create();
168
+ PeriodicalExecuter.prototype = {
169
+ initialize: function(callback, frequency) {
170
+ this.callback = callback;
171
+ this.frequency = frequency;
172
+ this.currentlyExecuting = false;
173
+
174
+ this.registerCallback();
175
+ },
176
+
177
+ registerCallback: function() {
178
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
179
+ },
180
+
181
+ stop: function() {
182
+ if (!this.timer) return;
183
+ clearInterval(this.timer);
184
+ this.timer = null;
185
+ },
186
+
187
+ onTimerEvent: function() {
188
+ if (!this.currentlyExecuting) {
189
+ try {
190
+ this.currentlyExecuting = true;
191
+ this.callback(this);
192
+ } finally {
193
+ this.currentlyExecuting = false;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ Object.extend(String, {
199
+ interpret: function(value) {
200
+ return value == null ? '' : String(value);
201
+ },
202
+ specialChar: {
203
+ '\b': '\\b',
204
+ '\t': '\\t',
205
+ '\n': '\\n',
206
+ '\f': '\\f',
207
+ '\r': '\\r',
208
+ '\\': '\\\\'
209
+ }
210
+ });
211
+
212
+ Object.extend(String.prototype, {
213
+ gsub: function(pattern, replacement) {
214
+ var result = '', source = this, match;
215
+ replacement = arguments.callee.prepareReplacement(replacement);
216
+
217
+ while (source.length > 0) {
218
+ if (match = source.match(pattern)) {
219
+ result += source.slice(0, match.index);
220
+ result += String.interpret(replacement(match));
221
+ source = source.slice(match.index + match[0].length);
222
+ } else {
223
+ result += source, source = '';
224
+ }
225
+ }
226
+ return result;
227
+ },
228
+
229
+ sub: function(pattern, replacement, count) {
230
+ replacement = this.gsub.prepareReplacement(replacement);
231
+ count = count === undefined ? 1 : count;
232
+
233
+ return this.gsub(pattern, function(match) {
234
+ if (--count < 0) return match[0];
235
+ return replacement(match);
236
+ });
237
+ },
238
+
239
+ scan: function(pattern, iterator) {
240
+ this.gsub(pattern, iterator);
241
+ return this;
242
+ },
243
+
244
+ truncate: function(length, truncation) {
245
+ length = length || 30;
246
+ truncation = truncation === undefined ? '...' : truncation;
247
+ return this.length > length ?
248
+ this.slice(0, length - truncation.length) + truncation : this;
249
+ },
250
+
251
+ strip: function() {
252
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
253
+ },
254
+
255
+ stripTags: function() {
256
+ return this.replace(/<\/?[^>]+>/gi, '');
257
+ },
258
+
259
+ stripScripts: function() {
260
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
261
+ },
262
+
263
+ extractScripts: function() {
264
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
265
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
266
+ return (this.match(matchAll) || []).map(function(scriptTag) {
267
+ return (scriptTag.match(matchOne) || ['', ''])[1];
268
+ });
269
+ },
270
+
271
+ evalScripts: function() {
272
+ return this.extractScripts().map(function(script) { return eval(script) });
273
+ },
274
+
275
+ escapeHTML: function() {
276
+ var self = arguments.callee;
277
+ self.text.data = this;
278
+ return self.div.innerHTML;
279
+ },
280
+
281
+ unescapeHTML: function() {
282
+ var div = document.createElement('div');
283
+ div.innerHTML = this.stripTags();
284
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
285
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
286
+ div.childNodes[0].nodeValue) : '';
287
+ },
288
+
289
+ toQueryParams: function(separator) {
290
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
291
+ if (!match) return {};
292
+
293
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
294
+ if ((pair = pair.split('='))[0]) {
295
+ var key = decodeURIComponent(pair.shift());
296
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
297
+ if (value != undefined) value = decodeURIComponent(value);
298
+
299
+ if (key in hash) {
300
+ if (hash[key].constructor != Array) hash[key] = [hash[key]];
301
+ hash[key].push(value);
302
+ }
303
+ else hash[key] = value;
304
+ }
305
+ return hash;
306
+ });
307
+ },
308
+
309
+ toArray: function() {
310
+ return this.split('');
311
+ },
312
+
313
+ succ: function() {
314
+ return this.slice(0, this.length - 1) +
315
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
316
+ },
317
+
318
+ times: function(count) {
319
+ var result = '';
320
+ for (var i = 0; i < count; i++) result += this;
321
+ return result;
322
+ },
323
+
324
+ camelize: function() {
325
+ var parts = this.split('-'), len = parts.length;
326
+ if (len == 1) return parts[0];
327
+
328
+ var camelized = this.charAt(0) == '-'
329
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
330
+ : parts[0];
331
+
332
+ for (var i = 1; i < len; i++)
333
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
334
+
335
+ return camelized;
336
+ },
337
+
338
+ capitalize: function() {
339
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
340
+ },
341
+
342
+ underscore: function() {
343
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
344
+ },
345
+
346
+ dasherize: function() {
347
+ return this.gsub(/_/,'-');
348
+ },
349
+
350
+ inspect: function(useDoubleQuotes) {
351
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
352
+ var character = String.specialChar[match[0]];
353
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
354
+ });
355
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
356
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
357
+ },
358
+
359
+ toJSON: function() {
360
+ return this.inspect(true);
361
+ },
362
+
363
+ unfilterJSON: function(filter) {
364
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
365
+ },
366
+
367
+ evalJSON: function(sanitize) {
368
+ var json = this.unfilterJSON();
369
+ try {
370
+ if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
371
+ return eval('(' + json + ')');
372
+ } catch (e) { }
373
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
374
+ },
375
+
376
+ include: function(pattern) {
377
+ return this.indexOf(pattern) > -1;
378
+ },
379
+
380
+ startsWith: function(pattern) {
381
+ return this.indexOf(pattern) === 0;
382
+ },
383
+
384
+ endsWith: function(pattern) {
385
+ var d = this.length - pattern.length;
386
+ return d >= 0 && this.lastIndexOf(pattern) === d;
387
+ },
388
+
389
+ empty: function() {
390
+ return this == '';
391
+ },
392
+
393
+ blank: function() {
394
+ return /^\s*$/.test(this);
395
+ }
396
+ });
397
+
398
+ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
399
+ escapeHTML: function() {
400
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
401
+ },
402
+ unescapeHTML: function() {
403
+ return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
404
+ }
405
+ });
406
+
407
+ String.prototype.gsub.prepareReplacement = function(replacement) {
408
+ if (typeof replacement == 'function') return replacement;
409
+ var template = new Template(replacement);
410
+ return function(match) { return template.evaluate(match) };
411
+ }
412
+
413
+ String.prototype.parseQuery = String.prototype.toQueryParams;
414
+
415
+ Object.extend(String.prototype.escapeHTML, {
416
+ div: document.createElement('div'),
417
+ text: document.createTextNode('')
418
+ });
419
+
420
+ with (String.prototype.escapeHTML) div.appendChild(text);
421
+
422
+ var Template = Class.create();
423
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
424
+ Template.prototype = {
425
+ initialize: function(template, pattern) {
426
+ this.template = template.toString();
427
+ this.pattern = pattern || Template.Pattern;
428
+ },
429
+
430
+ evaluate: function(object) {
431
+ return this.template.gsub(this.pattern, function(match) {
432
+ var before = match[1];
433
+ if (before == '\\') return match[2];
434
+ return before + String.interpret(object[match[3]]);
435
+ });
436
+ }
437
+ }
438
+
439
+ var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
440
+
441
+ var Enumerable = {
442
+ each: function(iterator) {
443
+ var index = 0;
444
+ try {
445
+ this._each(function(value) {
446
+ iterator(value, index++);
447
+ });
448
+ } catch (e) {
449
+ if (e != $break) throw e;
450
+ }
451
+ return this;
452
+ },
453
+
454
+ eachSlice: function(number, iterator) {
455
+ var index = -number, slices = [], array = this.toArray();
456
+ while ((index += number) < array.length)
457
+ slices.push(array.slice(index, index+number));
458
+ return slices.map(iterator);
459
+ },
460
+
461
+ all: function(iterator) {
462
+ var result = true;
463
+ this.each(function(value, index) {
464
+ result = result && !!(iterator || Prototype.K)(value, index);
465
+ if (!result) throw $break;
466
+ });
467
+ return result;
468
+ },
469
+
470
+ any: function(iterator) {
471
+ var result = false;
472
+ this.each(function(value, index) {
473
+ if (result = !!(iterator || Prototype.K)(value, index))
474
+ throw $break;
475
+ });
476
+ return result;
477
+ },
478
+
479
+ collect: function(iterator) {
480
+ var results = [];
481
+ this.each(function(value, index) {
482
+ results.push((iterator || Prototype.K)(value, index));
483
+ });
484
+ return results;
485
+ },
486
+
487
+ detect: function(iterator) {
488
+ var result;
489
+ this.each(function(value, index) {
490
+ if (iterator(value, index)) {
491
+ result = value;
492
+ throw $break;
493
+ }
494
+ });
495
+ return result;
496
+ },
497
+
498
+ findAll: function(iterator) {
499
+ var results = [];
500
+ this.each(function(value, index) {
501
+ if (iterator(value, index))
502
+ results.push(value);
503
+ });
504
+ return results;
505
+ },
506
+
507
+ grep: function(pattern, iterator) {
508
+ var results = [];
509
+ this.each(function(value, index) {
510
+ var stringValue = value.toString();
511
+ if (stringValue.match(pattern))
512
+ results.push((iterator || Prototype.K)(value, index));
513
+ })
514
+ return results;
515
+ },
516
+
517
+ include: function(object) {
518
+ var found = false;
519
+ this.each(function(value) {
520
+ if (value == object) {
521
+ found = true;
522
+ throw $break;
523
+ }
524
+ });
525
+ return found;
526
+ },
527
+
528
+ inGroupsOf: function(number, fillWith) {
529
+ fillWith = fillWith === undefined ? null : fillWith;
530
+ return this.eachSlice(number, function(slice) {
531
+ while(slice.length < number) slice.push(fillWith);
532
+ return slice;
533
+ });
534
+ },
535
+
536
+ inject: function(memo, iterator) {
537
+ this.each(function(value, index) {
538
+ memo = iterator(memo, value, index);
539
+ });
540
+ return memo;
541
+ },
542
+
543
+ invoke: function(method) {
544
+ var args = $A(arguments).slice(1);
545
+ return this.map(function(value) {
546
+ return value[method].apply(value, args);
547
+ });
548
+ },
549
+
550
+ max: function(iterator) {
551
+ var result;
552
+ this.each(function(value, index) {
553
+ value = (iterator || Prototype.K)(value, index);
554
+ if (result == undefined || value >= result)
555
+ result = value;
556
+ });
557
+ return result;
558
+ },
559
+
560
+ min: function(iterator) {
561
+ var result;
562
+ this.each(function(value, index) {
563
+ value = (iterator || Prototype.K)(value, index);
564
+ if (result == undefined || value < result)
565
+ result = value;
566
+ });
567
+ return result;
568
+ },
569
+
570
+ partition: function(iterator) {
571
+ var trues = [], falses = [];
572
+ this.each(function(value, index) {
573
+ ((iterator || Prototype.K)(value, index) ?
574
+ trues : falses).push(value);
575
+ });
576
+ return [trues, falses];
577
+ },
578
+
579
+ pluck: function(property) {
580
+ var results = [];
581
+ this.each(function(value, index) {
582
+ results.push(value[property]);
583
+ });
584
+ return results;
585
+ },
586
+
587
+ reject: function(iterator) {
588
+ var results = [];
589
+ this.each(function(value, index) {
590
+ if (!iterator(value, index))
591
+ results.push(value);
592
+ });
593
+ return results;
594
+ },
595
+
596
+ sortBy: function(iterator) {
597
+ return this.map(function(value, index) {
598
+ return {value: value, criteria: iterator(value, index)};
599
+ }).sort(function(left, right) {
600
+ var a = left.criteria, b = right.criteria;
601
+ return a < b ? -1 : a > b ? 1 : 0;
602
+ }).pluck('value');
603
+ },
604
+
605
+ toArray: function() {
606
+ return this.map();
607
+ },
608
+
609
+ zip: function() {
610
+ var iterator = Prototype.K, args = $A(arguments);
611
+ if (typeof args.last() == 'function')
612
+ iterator = args.pop();
613
+
614
+ var collections = [this].concat(args).map($A);
615
+ return this.map(function(value, index) {
616
+ return iterator(collections.pluck(index));
617
+ });
618
+ },
619
+
620
+ size: function() {
621
+ return this.toArray().length;
622
+ },
623
+
624
+ inspect: function() {
625
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
626
+ }
627
+ }
628
+
629
+ Object.extend(Enumerable, {
630
+ map: Enumerable.collect,
631
+ find: Enumerable.detect,
632
+ select: Enumerable.findAll,
633
+ member: Enumerable.include,
634
+ entries: Enumerable.toArray
635
+ });
636
+ var $A = Array.from = function(iterable) {
637
+ if (!iterable) return [];
638
+ if (iterable.toArray) {
639
+ return iterable.toArray();
640
+ } else {
641
+ var results = [];
642
+ for (var i = 0, length = iterable.length; i < length; i++)
643
+ results.push(iterable[i]);
644
+ return results;
645
+ }
646
+ }
647
+
648
+ if (Prototype.Browser.WebKit) {
649
+ $A = Array.from = function(iterable) {
650
+ if (!iterable) return [];
651
+ if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
652
+ iterable.toArray) {
653
+ return iterable.toArray();
654
+ } else {
655
+ var results = [];
656
+ for (var i = 0, length = iterable.length; i < length; i++)
657
+ results.push(iterable[i]);
658
+ return results;
659
+ }
660
+ }
661
+ }
662
+
663
+ Object.extend(Array.prototype, Enumerable);
664
+
665
+ if (!Array.prototype._reverse)
666
+ Array.prototype._reverse = Array.prototype.reverse;
667
+
668
+ Object.extend(Array.prototype, {
669
+ _each: function(iterator) {
670
+ for (var i = 0, length = this.length; i < length; i++)
671
+ iterator(this[i]);
672
+ },
673
+
674
+ clear: function() {
675
+ this.length = 0;
676
+ return this;
677
+ },
678
+
679
+ first: function() {
680
+ return this[0];
681
+ },
682
+
683
+ last: function() {
684
+ return this[this.length - 1];
685
+ },
686
+
687
+ compact: function() {
688
+ return this.select(function(value) {
689
+ return value != null;
690
+ });
691
+ },
692
+
693
+ flatten: function() {
694
+ return this.inject([], function(array, value) {
695
+ return array.concat(value && value.constructor == Array ?
696
+ value.flatten() : [value]);
697
+ });
698
+ },
699
+
700
+ without: function() {
701
+ var values = $A(arguments);
702
+ return this.select(function(value) {
703
+ return !values.include(value);
704
+ });
705
+ },
706
+
707
+ indexOf: function(object) {
708
+ for (var i = 0, length = this.length; i < length; i++)
709
+ if (this[i] == object) return i;
710
+ return -1;
711
+ },
712
+
713
+ reverse: function(inline) {
714
+ return (inline !== false ? this : this.toArray())._reverse();
715
+ },
716
+
717
+ reduce: function() {
718
+ return this.length > 1 ? this : this[0];
719
+ },
720
+
721
+ uniq: function(sorted) {
722
+ return this.inject([], function(array, value, index) {
723
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
724
+ array.push(value);
725
+ return array;
726
+ });
727
+ },
728
+
729
+ clone: function() {
730
+ return [].concat(this);
731
+ },
732
+
733
+ size: function() {
734
+ return this.length;
735
+ },
736
+
737
+ inspect: function() {
738
+ return '[' + this.map(Object.inspect).join(', ') + ']';
739
+ },
740
+
741
+ toJSON: function() {
742
+ var results = [];
743
+ this.each(function(object) {
744
+ var value = Object.toJSON(object);
745
+ if (value !== undefined) results.push(value);
746
+ });
747
+ return '[' + results.join(', ') + ']';
748
+ }
749
+ });
750
+
751
+ Array.prototype.toArray = Array.prototype.clone;
752
+
753
+ function $w(string) {
754
+ string = string.strip();
755
+ return string ? string.split(/\s+/) : [];
756
+ }
757
+
758
+ if (Prototype.Browser.Opera){
759
+ Array.prototype.concat = function() {
760
+ var array = [];
761
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
762
+ for (var i = 0, length = arguments.length; i < length; i++) {
763
+ if (arguments[i].constructor == Array) {
764
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
765
+ array.push(arguments[i][j]);
766
+ } else {
767
+ array.push(arguments[i]);
768
+ }
769
+ }
770
+ return array;
771
+ }
772
+ }
773
+ var Hash = function(object) {
774
+ if (object instanceof Hash) this.merge(object);
775
+ else Object.extend(this, object || {});
776
+ };
777
+
778
+ Object.extend(Hash, {
779
+ toQueryString: function(obj) {
780
+ var parts = [];
781
+ parts.add = arguments.callee.addPair;
782
+
783
+ this.prototype._each.call(obj, function(pair) {
784
+ if (!pair.key) return;
785
+ var value = pair.value;
786
+
787
+ if (value && typeof value == 'object') {
788
+ if (value.constructor == Array) value.each(function(value) {
789
+ parts.add(pair.key, value);
790
+ });
791
+ return;
792
+ }
793
+ parts.add(pair.key, value);
794
+ });
795
+
796
+ return parts.join('&');
797
+ },
798
+
799
+ toJSON: function(object) {
800
+ var results = [];
801
+ this.prototype._each.call(object, function(pair) {
802
+ var value = Object.toJSON(pair.value);
803
+ if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
804
+ });
805
+ return '{' + results.join(', ') + '}';
806
+ }
807
+ });
808
+
809
+ Hash.toQueryString.addPair = function(key, value, prefix) {
810
+ key = encodeURIComponent(key);
811
+ if (value === undefined) this.push(key);
812
+ else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
813
+ }
814
+
815
+ Object.extend(Hash.prototype, Enumerable);
816
+ Object.extend(Hash.prototype, {
817
+ _each: function(iterator) {
818
+ for (var key in this) {
819
+ var value = this[key];
820
+ if (value && value == Hash.prototype[key]) continue;
821
+
822
+ var pair = [key, value];
823
+ pair.key = key;
824
+ pair.value = value;
825
+ iterator(pair);
826
+ }
827
+ },
828
+
829
+ keys: function() {
830
+ return this.pluck('key');
831
+ },
832
+
833
+ values: function() {
834
+ return this.pluck('value');
835
+ },
836
+
837
+ merge: function(hash) {
838
+ return $H(hash).inject(this, function(mergedHash, pair) {
839
+ mergedHash[pair.key] = pair.value;
840
+ return mergedHash;
841
+ });
842
+ },
843
+
844
+ remove: function() {
845
+ var result;
846
+ for(var i = 0, length = arguments.length; i < length; i++) {
847
+ var value = this[arguments[i]];
848
+ if (value !== undefined){
849
+ if (result === undefined) result = value;
850
+ else {
851
+ if (result.constructor != Array) result = [result];
852
+ result.push(value)
853
+ }
854
+ }
855
+ delete this[arguments[i]];
856
+ }
857
+ return result;
858
+ },
859
+
860
+ toQueryString: function() {
861
+ return Hash.toQueryString(this);
862
+ },
863
+
864
+ inspect: function() {
865
+ return '#<Hash:{' + this.map(function(pair) {
866
+ return pair.map(Object.inspect).join(': ');
867
+ }).join(', ') + '}>';
868
+ },
869
+
870
+ toJSON: function() {
871
+ return Hash.toJSON(this);
872
+ }
873
+ });
874
+
875
+ function $H(object) {
876
+ if (object instanceof Hash) return object;
877
+ return new Hash(object);
878
+ };
879
+
880
+ // Safari iterates over shadowed properties
881
+ if (function() {
882
+ var i = 0, Test = function(value) { this.key = value };
883
+ Test.prototype.key = 'foo';
884
+ for (var property in new Test('bar')) i++;
885
+ return i > 1;
886
+ }()) Hash.prototype._each = function(iterator) {
887
+ var cache = [];
888
+ for (var key in this) {
889
+ var value = this[key];
890
+ if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
891
+ cache.push(key);
892
+ var pair = [key, value];
893
+ pair.key = key;
894
+ pair.value = value;
895
+ iterator(pair);
896
+ }
897
+ };
898
+ ObjectRange = Class.create();
899
+ Object.extend(ObjectRange.prototype, Enumerable);
900
+ Object.extend(ObjectRange.prototype, {
901
+ initialize: function(start, end, exclusive) {
902
+ this.start = start;
903
+ this.end = end;
904
+ this.exclusive = exclusive;
905
+ },
906
+
907
+ _each: function(iterator) {
908
+ var value = this.start;
909
+ while (this.include(value)) {
910
+ iterator(value);
911
+ value = value.succ();
912
+ }
913
+ },
914
+
915
+ include: function(value) {
916
+ if (value < this.start)
917
+ return false;
918
+ if (this.exclusive)
919
+ return value < this.end;
920
+ return value <= this.end;
921
+ }
922
+ });
923
+
924
+ var $R = function(start, end, exclusive) {
925
+ return new ObjectRange(start, end, exclusive);
926
+ }
927
+
928
+ var Ajax = {
929
+ getTransport: function() {
930
+ return Try.these(
931
+ function() {return new XMLHttpRequest()},
932
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
933
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
934
+ ) || false;
935
+ },
936
+
937
+ activeRequestCount: 0
938
+ }
939
+
940
+ Ajax.Responders = {
941
+ responders: [],
942
+
943
+ _each: function(iterator) {
944
+ this.responders._each(iterator);
945
+ },
946
+
947
+ register: function(responder) {
948
+ if (!this.include(responder))
949
+ this.responders.push(responder);
950
+ },
951
+
952
+ unregister: function(responder) {
953
+ this.responders = this.responders.without(responder);
954
+ },
955
+
956
+ dispatch: function(callback, request, transport, json) {
957
+ this.each(function(responder) {
958
+ if (typeof responder[callback] == 'function') {
959
+ try {
960
+ responder[callback].apply(responder, [request, transport, json]);
961
+ } catch (e) {}
962
+ }
963
+ });
964
+ }
965
+ };
966
+
967
+ Object.extend(Ajax.Responders, Enumerable);
968
+
969
+ Ajax.Responders.register({
970
+ onCreate: function() {
971
+ Ajax.activeRequestCount++;
972
+ },
973
+ onComplete: function() {
974
+ Ajax.activeRequestCount--;
975
+ }
976
+ });
977
+
978
+ Ajax.Base = function() {};
979
+ Ajax.Base.prototype = {
980
+ setOptions: function(options) {
981
+ this.options = {
982
+ method: 'post',
983
+ asynchronous: true,
984
+ contentType: 'application/x-www-form-urlencoded',
985
+ encoding: 'UTF-8',
986
+ parameters: ''
987
+ }
988
+ Object.extend(this.options, options || {});
989
+
990
+ this.options.method = this.options.method.toLowerCase();
991
+ if (typeof this.options.parameters == 'string')
992
+ this.options.parameters = this.options.parameters.toQueryParams();
993
+ }
994
+ }
995
+
996
+ Ajax.Request = Class.create();
997
+ Ajax.Request.Events =
998
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
999
+
1000
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1001
+ _complete: false,
1002
+
1003
+ initialize: function(url, options) {
1004
+ this.transport = Ajax.getTransport();
1005
+ this.setOptions(options);
1006
+ this.request(url);
1007
+ },
1008
+
1009
+ request: function(url) {
1010
+ this.url = url;
1011
+ this.method = this.options.method;
1012
+ var params = Object.clone(this.options.parameters);
1013
+
1014
+ if (!['get', 'post'].include(this.method)) {
1015
+ // simulate other verbs over post
1016
+ params['_method'] = this.method;
1017
+ this.method = 'post';
1018
+ }
1019
+
1020
+ this.parameters = params;
1021
+
1022
+ if (params = Hash.toQueryString(params)) {
1023
+ // when GET, append parameters to URL
1024
+ if (this.method == 'get')
1025
+ this.url += (this.url.include('?') ? '&' : '?') + params;
1026
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1027
+ params += '&_=';
1028
+ }
1029
+
1030
+ try {
1031
+ if (this.options.onCreate) this.options.onCreate(this.transport);
1032
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
1033
+
1034
+ this.transport.open(this.method.toUpperCase(), this.url,
1035
+ this.options.asynchronous);
1036
+
1037
+ if (this.options.asynchronous)
1038
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1039
+
1040
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
1041
+ this.setRequestHeaders();
1042
+
1043
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1044
+ this.transport.send(this.body);
1045
+
1046
+ /* Force Firefox to handle ready state 4 for synchronous requests */
1047
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
1048
+ this.onStateChange();
1049
+
1050
+ }
1051
+ catch (e) {
1052
+ this.dispatchException(e);
1053
+ }
1054
+ },
1055
+
1056
+ onStateChange: function() {
1057
+ var readyState = this.transport.readyState;
1058
+ if (readyState > 1 && !((readyState == 4) && this._complete))
1059
+ this.respondToReadyState(this.transport.readyState);
1060
+ },
1061
+
1062
+ setRequestHeaders: function() {
1063
+ var headers = {
1064
+ 'X-Requested-With': 'XMLHttpRequest',
1065
+ 'X-Prototype-Version': Prototype.Version,
1066
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1067
+ };
1068
+
1069
+ if (this.method == 'post') {
1070
+ headers['Content-type'] = this.options.contentType +
1071
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
1072
+
1073
+ /* Force "Connection: close" for older Mozilla browsers to work
1074
+ * around a bug where XMLHttpRequest sends an incorrect
1075
+ * Content-length header. See Mozilla Bugzilla #246651.
1076
+ */
1077
+ if (this.transport.overrideMimeType &&
1078
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1079
+ headers['Connection'] = 'close';
1080
+ }
1081
+
1082
+ // user-defined headers
1083
+ if (typeof this.options.requestHeaders == 'object') {
1084
+ var extras = this.options.requestHeaders;
1085
+
1086
+ if (typeof extras.push == 'function')
1087
+ for (var i = 0, length = extras.length; i < length; i += 2)
1088
+ headers[extras[i]] = extras[i+1];
1089
+ else
1090
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1091
+ }
1092
+
1093
+ for (var name in headers)
1094
+ this.transport.setRequestHeader(name, headers[name]);
1095
+ },
1096
+
1097
+ success: function() {
1098
+ return !this.transport.status
1099
+ || (this.transport.status >= 200 && this.transport.status < 300);
1100
+ },
1101
+
1102
+ respondToReadyState: function(readyState) {
1103
+ var state = Ajax.Request.Events[readyState];
1104
+ var transport = this.transport, json = this.evalJSON();
1105
+
1106
+ if (state == 'Complete') {
1107
+ try {
1108
+ this._complete = true;
1109
+ (this.options['on' + this.transport.status]
1110
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1111
+ || Prototype.emptyFunction)(transport, json);
1112
+ } catch (e) {
1113
+ this.dispatchException(e);
1114
+ }
1115
+
1116
+ var contentType = this.getHeader('Content-type');
1117
+ if (contentType && contentType.strip().
1118
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1119
+ this.evalResponse();
1120
+ }
1121
+
1122
+ try {
1123
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1124
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
1125
+ } catch (e) {
1126
+ this.dispatchException(e);
1127
+ }
1128
+
1129
+ if (state == 'Complete') {
1130
+ // avoid memory leak in MSIE: clean up
1131
+ this.transport.onreadystatechange = Prototype.emptyFunction;
1132
+ }
1133
+ },
1134
+
1135
+ getHeader: function(name) {
1136
+ try {
1137
+ return this.transport.getResponseHeader(name);
1138
+ } catch (e) { return null }
1139
+ },
1140
+
1141
+ evalJSON: function() {
1142
+ try {
1143
+ var json = this.getHeader('X-JSON');
1144
+ return json ? json.evalJSON() : null;
1145
+ } catch (e) { return null }
1146
+ },
1147
+
1148
+ evalResponse: function() {
1149
+ try {
1150
+ return eval((this.transport.responseText || '').unfilterJSON());
1151
+ } catch (e) {
1152
+ this.dispatchException(e);
1153
+ }
1154
+ },
1155
+
1156
+ dispatchException: function(exception) {
1157
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
1158
+ Ajax.Responders.dispatch('onException', this, exception);
1159
+ }
1160
+ });
1161
+
1162
+ Ajax.Updater = Class.create();
1163
+
1164
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1165
+ initialize: function(container, url, options) {
1166
+ this.container = {
1167
+ success: (container.success || container),
1168
+ failure: (container.failure || (container.success ? null : container))
1169
+ }
1170
+
1171
+ this.transport = Ajax.getTransport();
1172
+ this.setOptions(options);
1173
+
1174
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
1175
+ this.options.onComplete = (function(transport, param) {
1176
+ this.updateContent();
1177
+ onComplete(transport, param);
1178
+ }).bind(this);
1179
+
1180
+ this.request(url);
1181
+ },
1182
+
1183
+ updateContent: function() {
1184
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
1185
+ var response = this.transport.responseText;
1186
+
1187
+ if (!this.options.evalScripts) response = response.stripScripts();
1188
+
1189
+ if (receiver = $(receiver)) {
1190
+ if (this.options.insertion)
1191
+ new this.options.insertion(receiver, response);
1192
+ else
1193
+ receiver.update(response);
1194
+ }
1195
+
1196
+ if (this.success()) {
1197
+ if (this.onComplete)
1198
+ setTimeout(this.onComplete.bind(this), 10);
1199
+ }
1200
+ }
1201
+ });
1202
+
1203
+ Ajax.PeriodicalUpdater = Class.create();
1204
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1205
+ initialize: function(container, url, options) {
1206
+ this.setOptions(options);
1207
+ this.onComplete = this.options.onComplete;
1208
+
1209
+ this.frequency = (this.options.frequency || 2);
1210
+ this.decay = (this.options.decay || 1);
1211
+
1212
+ this.updater = {};
1213
+ this.container = container;
1214
+ this.url = url;
1215
+
1216
+ this.start();
1217
+ },
1218
+
1219
+ start: function() {
1220
+ this.options.onComplete = this.updateComplete.bind(this);
1221
+ this.onTimerEvent();
1222
+ },
1223
+
1224
+ stop: function() {
1225
+ this.updater.options.onComplete = undefined;
1226
+ clearTimeout(this.timer);
1227
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1228
+ },
1229
+
1230
+ updateComplete: function(request) {
1231
+ if (this.options.decay) {
1232
+ this.decay = (request.responseText == this.lastText ?
1233
+ this.decay * this.options.decay : 1);
1234
+
1235
+ this.lastText = request.responseText;
1236
+ }
1237
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
1238
+ this.decay * this.frequency * 1000);
1239
+ },
1240
+
1241
+ onTimerEvent: function() {
1242
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
1243
+ }
1244
+ });
1245
+ function $(element) {
1246
+ if (arguments.length > 1) {
1247
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1248
+ elements.push($(arguments[i]));
1249
+ return elements;
1250
+ }
1251
+ if (typeof element == 'string')
1252
+ element = document.getElementById(element);
1253
+ return Element.extend(element);
1254
+ }
1255
+
1256
+ if (Prototype.BrowserFeatures.XPath) {
1257
+ document._getElementsByXPath = function(expression, parentElement) {
1258
+ var results = [];
1259
+ var query = document.evaluate(expression, $(parentElement) || document,
1260
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1261
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
1262
+ results.push(query.snapshotItem(i));
1263
+ return results;
1264
+ };
1265
+
1266
+ document.getElementsByClassName = function(className, parentElement) {
1267
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1268
+ return document._getElementsByXPath(q, parentElement);
1269
+ }
1270
+
1271
+ } else document.getElementsByClassName = function(className, parentElement) {
1272
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
1273
+ var elements = [], child;
1274
+ for (var i = 0, length = children.length; i < length; i++) {
1275
+ child = children[i];
1276
+ if (Element.hasClassName(child, className))
1277
+ elements.push(Element.extend(child));
1278
+ }
1279
+ return elements;
1280
+ };
1281
+
1282
+ /*--------------------------------------------------------------------------*/
1283
+
1284
+ if (!window.Element) var Element = {};
1285
+
1286
+ Element.extend = function(element) {
1287
+ var F = Prototype.BrowserFeatures;
1288
+ if (!element || !element.tagName || element.nodeType == 3 ||
1289
+ element._extended || F.SpecificElementExtensions || element == window)
1290
+ return element;
1291
+
1292
+ var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1293
+ T = Element.Methods.ByTag;
1294
+
1295
+ // extend methods for all tags (Safari doesn't need this)
1296
+ if (!F.ElementExtensions) {
1297
+ Object.extend(methods, Element.Methods),
1298
+ Object.extend(methods, Element.Methods.Simulated);
1299
+ }
1300
+
1301
+ // extend methods for specific tags
1302
+ if (T[tagName]) Object.extend(methods, T[tagName]);
1303
+
1304
+ for (var property in methods) {
1305
+ var value = methods[property];
1306
+ if (typeof value == 'function' && !(property in element))
1307
+ element[property] = cache.findOrStore(value);
1308
+ }
1309
+
1310
+ element._extended = Prototype.emptyFunction;
1311
+ return element;
1312
+ };
1313
+
1314
+ Element.extend.cache = {
1315
+ findOrStore: function(value) {
1316
+ return this[value] = this[value] || function() {
1317
+ return value.apply(null, [this].concat($A(arguments)));
1318
+ }
1319
+ }
1320
+ };
1321
+
1322
+ Element.Methods = {
1323
+ visible: function(element) {
1324
+ return $(element).style.display != 'none';
1325
+ },
1326
+
1327
+ toggle: function(element) {
1328
+ element = $(element);
1329
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
1330
+ return element;
1331
+ },
1332
+
1333
+ hide: function(element) {
1334
+ $(element).style.display = 'none';
1335
+ return element;
1336
+ },
1337
+
1338
+ show: function(element) {
1339
+ $(element).style.display = '';
1340
+ return element;
1341
+ },
1342
+
1343
+ remove: function(element) {
1344
+ element = $(element);
1345
+ element.parentNode.removeChild(element);
1346
+ return element;
1347
+ },
1348
+
1349
+ update: function(element, html) {
1350
+ html = typeof html == 'undefined' ? '' : html.toString();
1351
+ $(element).innerHTML = html.stripScripts();
1352
+ setTimeout(function() {html.evalScripts()}, 10);
1353
+ return element;
1354
+ },
1355
+
1356
+ replace: function(element, html) {
1357
+ element = $(element);
1358
+ html = typeof html == 'undefined' ? '' : html.toString();
1359
+ if (element.outerHTML) {
1360
+ element.outerHTML = html.stripScripts();
1361
+ } else {
1362
+ var range = element.ownerDocument.createRange();
1363
+ range.selectNodeContents(element);
1364
+ element.parentNode.replaceChild(
1365
+ range.createContextualFragment(html.stripScripts()), element);
1366
+ }
1367
+ setTimeout(function() {html.evalScripts()}, 10);
1368
+ return element;
1369
+ },
1370
+
1371
+ inspect: function(element) {
1372
+ element = $(element);
1373
+ var result = '<' + element.tagName.toLowerCase();
1374
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1375
+ var property = pair.first(), attribute = pair.last();
1376
+ var value = (element[property] || '').toString();
1377
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
1378
+ });
1379
+ return result + '>';
1380
+ },
1381
+
1382
+ recursivelyCollect: function(element, property) {
1383
+ element = $(element);
1384
+ var elements = [];
1385
+ while (element = element[property])
1386
+ if (element.nodeType == 1)
1387
+ elements.push(Element.extend(element));
1388
+ return elements;
1389
+ },
1390
+
1391
+ ancestors: function(element) {
1392
+ return $(element).recursivelyCollect('parentNode');
1393
+ },
1394
+
1395
+ descendants: function(element) {
1396
+ return $A($(element).getElementsByTagName('*')).each(Element.extend);
1397
+ },
1398
+
1399
+ firstDescendant: function(element) {
1400
+ element = $(element).firstChild;
1401
+ while (element && element.nodeType != 1) element = element.nextSibling;
1402
+ return $(element);
1403
+ },
1404
+
1405
+ immediateDescendants: function(element) {
1406
+ if (!(element = $(element).firstChild)) return [];
1407
+ while (element && element.nodeType != 1) element = element.nextSibling;
1408
+ if (element) return [element].concat($(element).nextSiblings());
1409
+ return [];
1410
+ },
1411
+
1412
+ previousSiblings: function(element) {
1413
+ return $(element).recursivelyCollect('previousSibling');
1414
+ },
1415
+
1416
+ nextSiblings: function(element) {
1417
+ return $(element).recursivelyCollect('nextSibling');
1418
+ },
1419
+
1420
+ siblings: function(element) {
1421
+ element = $(element);
1422
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
1423
+ },
1424
+
1425
+ match: function(element, selector) {
1426
+ if (typeof selector == 'string')
1427
+ selector = new Selector(selector);
1428
+ return selector.match($(element));
1429
+ },
1430
+
1431
+ up: function(element, expression, index) {
1432
+ element = $(element);
1433
+ if (arguments.length == 1) return $(element.parentNode);
1434
+ var ancestors = element.ancestors();
1435
+ return expression ? Selector.findElement(ancestors, expression, index) :
1436
+ ancestors[index || 0];
1437
+ },
1438
+
1439
+ down: function(element, expression, index) {
1440
+ element = $(element);
1441
+ if (arguments.length == 1) return element.firstDescendant();
1442
+ var descendants = element.descendants();
1443
+ return expression ? Selector.findElement(descendants, expression, index) :
1444
+ descendants[index || 0];
1445
+ },
1446
+
1447
+ previous: function(element, expression, index) {
1448
+ element = $(element);
1449
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1450
+ var previousSiblings = element.previousSiblings();
1451
+ return expression ? Selector.findElement(previousSiblings, expression, index) :
1452
+ previousSiblings[index || 0];
1453
+ },
1454
+
1455
+ next: function(element, expression, index) {
1456
+ element = $(element);
1457
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1458
+ var nextSiblings = element.nextSiblings();
1459
+ return expression ? Selector.findElement(nextSiblings, expression, index) :
1460
+ nextSiblings[index || 0];
1461
+ },
1462
+
1463
+ getElementsBySelector: function() {
1464
+ var args = $A(arguments), element = $(args.shift());
1465
+ return Selector.findChildElements(element, args);
1466
+ },
1467
+
1468
+ getElementsByClassName: function(element, className) {
1469
+ return document.getElementsByClassName(className, element);
1470
+ },
1471
+
1472
+ readAttribute: function(element, name) {
1473
+ element = $(element);
1474
+ if (Prototype.Browser.IE) {
1475
+ if (!element.attributes) return null;
1476
+ var t = Element._attributeTranslations;
1477
+ if (t.values[name]) return t.values[name](element, name);
1478
+ if (t.names[name]) name = t.names[name];
1479
+ var attribute = element.attributes[name];
1480
+ return attribute ? attribute.nodeValue : null;
1481
+ }
1482
+ return element.getAttribute(name);
1483
+ },
1484
+
1485
+ getHeight: function(element) {
1486
+ return $(element).getDimensions().height;
1487
+ },
1488
+
1489
+ getWidth: function(element) {
1490
+ return $(element).getDimensions().width;
1491
+ },
1492
+
1493
+ classNames: function(element) {
1494
+ return new Element.ClassNames(element);
1495
+ },
1496
+
1497
+ hasClassName: function(element, className) {
1498
+ if (!(element = $(element))) return;
1499
+ var elementClassName = element.className;
1500
+ if (elementClassName.length == 0) return false;
1501
+ if (elementClassName == className ||
1502
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1503
+ return true;
1504
+ return false;
1505
+ },
1506
+
1507
+ addClassName: function(element, className) {
1508
+ if (!(element = $(element))) return;
1509
+ Element.classNames(element).add(className);
1510
+ return element;
1511
+ },
1512
+
1513
+ removeClassName: function(element, className) {
1514
+ if (!(element = $(element))) return;
1515
+ Element.classNames(element).remove(className);
1516
+ return element;
1517
+ },
1518
+
1519
+ toggleClassName: function(element, className) {
1520
+ if (!(element = $(element))) return;
1521
+ Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1522
+ return element;
1523
+ },
1524
+
1525
+ observe: function() {
1526
+ Event.observe.apply(Event, arguments);
1527
+ return $A(arguments).first();
1528
+ },
1529
+
1530
+ stopObserving: function() {
1531
+ Event.stopObserving.apply(Event, arguments);
1532
+ return $A(arguments).first();
1533
+ },
1534
+
1535
+ // removes whitespace-only text node children
1536
+ cleanWhitespace: function(element) {
1537
+ element = $(element);
1538
+ var node = element.firstChild;
1539
+ while (node) {
1540
+ var nextNode = node.nextSibling;
1541
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1542
+ element.removeChild(node);
1543
+ node = nextNode;
1544
+ }
1545
+ return element;
1546
+ },
1547
+
1548
+ empty: function(element) {
1549
+ return $(element).innerHTML.blank();
1550
+ },
1551
+
1552
+ descendantOf: function(element, ancestor) {
1553
+ element = $(element), ancestor = $(ancestor);
1554
+ while (element = element.parentNode)
1555
+ if (element == ancestor) return true;
1556
+ return false;
1557
+ },
1558
+
1559
+ scrollTo: function(element) {
1560
+ element = $(element);
1561
+ var pos = Position.cumulativeOffset(element);
1562
+ window.scrollTo(pos[0], pos[1]);
1563
+ return element;
1564
+ },
1565
+
1566
+ getStyle: function(element, style) {
1567
+ element = $(element);
1568
+ style = style == 'float' ? 'cssFloat' : style.camelize();
1569
+ var value = element.style[style];
1570
+ if (!value) {
1571
+ var css = document.defaultView.getComputedStyle(element, null);
1572
+ value = css ? css[style] : null;
1573
+ }
1574
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1575
+ return value == 'auto' ? null : value;
1576
+ },
1577
+
1578
+ getOpacity: function(element) {
1579
+ return $(element).getStyle('opacity');
1580
+ },
1581
+
1582
+ setStyle: function(element, styles, camelized) {
1583
+ element = $(element);
1584
+ var elementStyle = element.style;
1585
+
1586
+ for (var property in styles)
1587
+ if (property == 'opacity') element.setOpacity(styles[property])
1588
+ else
1589
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
1590
+ (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1591
+ (camelized ? property : property.camelize())] = styles[property];
1592
+
1593
+ return element;
1594
+ },
1595
+
1596
+ setOpacity: function(element, value) {
1597
+ element = $(element);
1598
+ element.style.opacity = (value == 1 || value === '') ? '' :
1599
+ (value < 0.00001) ? 0 : value;
1600
+ return element;
1601
+ },
1602
+
1603
+ getDimensions: function(element) {
1604
+ element = $(element);
1605
+ var display = $(element).getStyle('display');
1606
+ if (display != 'none' && display != null) // Safari bug
1607
+ return {width: element.offsetWidth, height: element.offsetHeight};
1608
+
1609
+ // All *Width and *Height properties give 0 on elements with display none,
1610
+ // so enable the element temporarily
1611
+ var els = element.style;
1612
+ var originalVisibility = els.visibility;
1613
+ var originalPosition = els.position;
1614
+ var originalDisplay = els.display;
1615
+ els.visibility = 'hidden';
1616
+ els.position = 'absolute';
1617
+ els.display = 'block';
1618
+ var originalWidth = element.clientWidth;
1619
+ var originalHeight = element.clientHeight;
1620
+ els.display = originalDisplay;
1621
+ els.position = originalPosition;
1622
+ els.visibility = originalVisibility;
1623
+ return {width: originalWidth, height: originalHeight};
1624
+ },
1625
+
1626
+ makePositioned: function(element) {
1627
+ element = $(element);
1628
+ var pos = Element.getStyle(element, 'position');
1629
+ if (pos == 'static' || !pos) {
1630
+ element._madePositioned = true;
1631
+ element.style.position = 'relative';
1632
+ // Opera returns the offset relative to the positioning context, when an
1633
+ // element is position relative but top and left have not been defined
1634
+ if (window.opera) {
1635
+ element.style.top = 0;
1636
+ element.style.left = 0;
1637
+ }
1638
+ }
1639
+ return element;
1640
+ },
1641
+
1642
+ undoPositioned: function(element) {
1643
+ element = $(element);
1644
+ if (element._madePositioned) {
1645
+ element._madePositioned = undefined;
1646
+ element.style.position =
1647
+ element.style.top =
1648
+ element.style.left =
1649
+ element.style.bottom =
1650
+ element.style.right = '';
1651
+ }
1652
+ return element;
1653
+ },
1654
+
1655
+ makeClipping: function(element) {
1656
+ element = $(element);
1657
+ if (element._overflow) return element;
1658
+ element._overflow = element.style.overflow || 'auto';
1659
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1660
+ element.style.overflow = 'hidden';
1661
+ return element;
1662
+ },
1663
+
1664
+ undoClipping: function(element) {
1665
+ element = $(element);
1666
+ if (!element._overflow) return element;
1667
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1668
+ element._overflow = null;
1669
+ return element;
1670
+ }
1671
+ };
1672
+
1673
+ Object.extend(Element.Methods, {
1674
+ childOf: Element.Methods.descendantOf,
1675
+ childElements: Element.Methods.immediateDescendants
1676
+ });
1677
+
1678
+ if (Prototype.Browser.Opera) {
1679
+ Element.Methods._getStyle = Element.Methods.getStyle;
1680
+ Element.Methods.getStyle = function(element, style) {
1681
+ switch(style) {
1682
+ case 'left':
1683
+ case 'top':
1684
+ case 'right':
1685
+ case 'bottom':
1686
+ if (Element._getStyle(element, 'position') == 'static') return null;
1687
+ default: return Element._getStyle(element, style);
1688
+ }
1689
+ };
1690
+ }
1691
+ else if (Prototype.Browser.IE) {
1692
+ Element.Methods.getStyle = function(element, style) {
1693
+ element = $(element);
1694
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
1695
+ var value = element.style[style];
1696
+ if (!value && element.currentStyle) value = element.currentStyle[style];
1697
+
1698
+ if (style == 'opacity') {
1699
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1700
+ if (value[1]) return parseFloat(value[1]) / 100;
1701
+ return 1.0;
1702
+ }
1703
+
1704
+ if (value == 'auto') {
1705
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1706
+ return element['offset'+style.capitalize()] + 'px';
1707
+ return null;
1708
+ }
1709
+ return value;
1710
+ };
1711
+
1712
+ Element.Methods.setOpacity = function(element, value) {
1713
+ element = $(element);
1714
+ var filter = element.getStyle('filter'), style = element.style;
1715
+ if (value == 1 || value === '') {
1716
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
1717
+ return element;
1718
+ } else if (value < 0.00001) value = 0;
1719
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1720
+ 'alpha(opacity=' + (value * 100) + ')';
1721
+ return element;
1722
+ };
1723
+
1724
+ // IE is missing .innerHTML support for TABLE-related elements
1725
+ Element.Methods.update = function(element, html) {
1726
+ element = $(element);
1727
+ html = typeof html == 'undefined' ? '' : html.toString();
1728
+ var tagName = element.tagName.toUpperCase();
1729
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1730
+ var div = document.createElement('div');
1731
+ switch (tagName) {
1732
+ case 'THEAD':
1733
+ case 'TBODY':
1734
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1735
+ depth = 2;
1736
+ break;
1737
+ case 'TR':
1738
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1739
+ depth = 3;
1740
+ break;
1741
+ case 'TD':
1742
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1743
+ depth = 4;
1744
+ }
1745
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
1746
+ depth.times(function() { div = div.firstChild });
1747
+ $A(div.childNodes).each(function(node) { element.appendChild(node) });
1748
+ } else {
1749
+ element.innerHTML = html.stripScripts();
1750
+ }
1751
+ setTimeout(function() { html.evalScripts() }, 10);
1752
+ return element;
1753
+ }
1754
+ }
1755
+ else if (Prototype.Browser.Gecko) {
1756
+ Element.Methods.setOpacity = function(element, value) {
1757
+ element = $(element);
1758
+ element.style.opacity = (value == 1) ? 0.999999 :
1759
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
1760
+ return element;
1761
+ };
1762
+ }
1763
+
1764
+ Element._attributeTranslations = {
1765
+ names: {
1766
+ colspan: "colSpan",
1767
+ rowspan: "rowSpan",
1768
+ valign: "vAlign",
1769
+ datetime: "dateTime",
1770
+ accesskey: "accessKey",
1771
+ tabindex: "tabIndex",
1772
+ enctype: "encType",
1773
+ maxlength: "maxLength",
1774
+ readonly: "readOnly",
1775
+ longdesc: "longDesc"
1776
+ },
1777
+ values: {
1778
+ _getAttr: function(element, attribute) {
1779
+ return element.getAttribute(attribute, 2);
1780
+ },
1781
+ _flag: function(element, attribute) {
1782
+ return $(element).hasAttribute(attribute) ? attribute : null;
1783
+ },
1784
+ style: function(element) {
1785
+ return element.style.cssText.toLowerCase();
1786
+ },
1787
+ title: function(element) {
1788
+ var node = element.getAttributeNode('title');
1789
+ return node.specified ? node.nodeValue : null;
1790
+ }
1791
+ }
1792
+ };
1793
+
1794
+ (function() {
1795
+ Object.extend(this, {
1796
+ href: this._getAttr,
1797
+ src: this._getAttr,
1798
+ type: this._getAttr,
1799
+ disabled: this._flag,
1800
+ checked: this._flag,
1801
+ readonly: this._flag,
1802
+ multiple: this._flag
1803
+ });
1804
+ }).call(Element._attributeTranslations.values);
1805
+
1806
+ Element.Methods.Simulated = {
1807
+ hasAttribute: function(element, attribute) {
1808
+ var t = Element._attributeTranslations, node;
1809
+ attribute = t.names[attribute] || attribute;
1810
+ node = $(element).getAttributeNode(attribute);
1811
+ return node && node.specified;
1812
+ }
1813
+ };
1814
+
1815
+ Element.Methods.ByTag = {};
1816
+
1817
+ Object.extend(Element, Element.Methods);
1818
+
1819
+ if (!Prototype.BrowserFeatures.ElementExtensions &&
1820
+ document.createElement('div').__proto__) {
1821
+ window.HTMLElement = {};
1822
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
1823
+ Prototype.BrowserFeatures.ElementExtensions = true;
1824
+ }
1825
+
1826
+ Element.hasAttribute = function(element, attribute) {
1827
+ if (element.hasAttribute) return element.hasAttribute(attribute);
1828
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
1829
+ };
1830
+
1831
+ Element.addMethods = function(methods) {
1832
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
1833
+
1834
+ if (!methods) {
1835
+ Object.extend(Form, Form.Methods);
1836
+ Object.extend(Form.Element, Form.Element.Methods);
1837
+ Object.extend(Element.Methods.ByTag, {
1838
+ "FORM": Object.clone(Form.Methods),
1839
+ "INPUT": Object.clone(Form.Element.Methods),
1840
+ "SELECT": Object.clone(Form.Element.Methods),
1841
+ "TEXTAREA": Object.clone(Form.Element.Methods)
1842
+ });
1843
+ }
1844
+
1845
+ if (arguments.length == 2) {
1846
+ var tagName = methods;
1847
+ methods = arguments[1];
1848
+ }
1849
+
1850
+ if (!tagName) Object.extend(Element.Methods, methods || {});
1851
+ else {
1852
+ if (tagName.constructor == Array) tagName.each(extend);
1853
+ else extend(tagName);
1854
+ }
1855
+
1856
+ function extend(tagName) {
1857
+ tagName = tagName.toUpperCase();
1858
+ if (!Element.Methods.ByTag[tagName])
1859
+ Element.Methods.ByTag[tagName] = {};
1860
+ Object.extend(Element.Methods.ByTag[tagName], methods);
1861
+ }
1862
+
1863
+ function copy(methods, destination, onlyIfAbsent) {
1864
+ onlyIfAbsent = onlyIfAbsent || false;
1865
+ var cache = Element.extend.cache;
1866
+ for (var property in methods) {
1867
+ var value = methods[property];
1868
+ if (!onlyIfAbsent || !(property in destination))
1869
+ destination[property] = cache.findOrStore(value);
1870
+ }
1871
+ }
1872
+
1873
+ function findDOMClass(tagName) {
1874
+ var klass;
1875
+ var trans = {
1876
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
1877
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
1878
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
1879
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
1880
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
1881
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
1882
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
1883
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
1884
+ "FrameSet", "IFRAME": "IFrame"
1885
+ };
1886
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
1887
+ if (window[klass]) return window[klass];
1888
+ klass = 'HTML' + tagName + 'Element';
1889
+ if (window[klass]) return window[klass];
1890
+ klass = 'HTML' + tagName.capitalize() + 'Element';
1891
+ if (window[klass]) return window[klass];
1892
+
1893
+ window[klass] = {};
1894
+ window[klass].prototype = document.createElement(tagName).__proto__;
1895
+ return window[klass];
1896
+ }
1897
+
1898
+ if (F.ElementExtensions) {
1899
+ copy(Element.Methods, HTMLElement.prototype);
1900
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1901
+ }
1902
+
1903
+ if (F.SpecificElementExtensions) {
1904
+ for (var tag in Element.Methods.ByTag) {
1905
+ var klass = findDOMClass(tag);
1906
+ if (typeof klass == "undefined") continue;
1907
+ copy(T[tag], klass.prototype);
1908
+ }
1909
+ }
1910
+
1911
+ Object.extend(Element, Element.Methods);
1912
+ delete Element.ByTag;
1913
+ };
1914
+
1915
+ var Toggle = { display: Element.toggle };
1916
+
1917
+ /*--------------------------------------------------------------------------*/
1918
+
1919
+ Abstract.Insertion = function(adjacency) {
1920
+ this.adjacency = adjacency;
1921
+ }
1922
+
1923
+ Abstract.Insertion.prototype = {
1924
+ initialize: function(element, content) {
1925
+ this.element = $(element);
1926
+ this.content = content.stripScripts();
1927
+
1928
+ if (this.adjacency && this.element.insertAdjacentHTML) {
1929
+ try {
1930
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
1931
+ } catch (e) {
1932
+ var tagName = this.element.tagName.toUpperCase();
1933
+ if (['TBODY', 'TR'].include(tagName)) {
1934
+ this.insertContent(this.contentFromAnonymousTable());
1935
+ } else {
1936
+ throw e;
1937
+ }
1938
+ }
1939
+ } else {
1940
+ this.range = this.element.ownerDocument.createRange();
1941
+ if (this.initializeRange) this.initializeRange();
1942
+ this.insertContent([this.range.createContextualFragment(this.content)]);
1943
+ }
1944
+
1945
+ setTimeout(function() {content.evalScripts()}, 10);
1946
+ },
1947
+
1948
+ contentFromAnonymousTable: function() {
1949
+ var div = document.createElement('div');
1950
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1951
+ return $A(div.childNodes[0].childNodes[0].childNodes);
1952
+ }
1953
+ }
1954
+
1955
+ var Insertion = new Object();
1956
+
1957
+ Insertion.Before = Class.create();
1958
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1959
+ initializeRange: function() {
1960
+ this.range.setStartBefore(this.element);
1961
+ },
1962
+
1963
+ insertContent: function(fragments) {
1964
+ fragments.each((function(fragment) {
1965
+ this.element.parentNode.insertBefore(fragment, this.element);
1966
+ }).bind(this));
1967
+ }
1968
+ });
1969
+
1970
+ Insertion.Top = Class.create();
1971
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1972
+ initializeRange: function() {
1973
+ this.range.selectNodeContents(this.element);
1974
+ this.range.collapse(true);
1975
+ },
1976
+
1977
+ insertContent: function(fragments) {
1978
+ fragments.reverse(false).each((function(fragment) {
1979
+ this.element.insertBefore(fragment, this.element.firstChild);
1980
+ }).bind(this));
1981
+ }
1982
+ });
1983
+
1984
+ Insertion.Bottom = Class.create();
1985
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1986
+ initializeRange: function() {
1987
+ this.range.selectNodeContents(this.element);
1988
+ this.range.collapse(this.element);
1989
+ },
1990
+
1991
+ insertContent: function(fragments) {
1992
+ fragments.each((function(fragment) {
1993
+ this.element.appendChild(fragment);
1994
+ }).bind(this));
1995
+ }
1996
+ });
1997
+
1998
+ Insertion.After = Class.create();
1999
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
2000
+ initializeRange: function() {
2001
+ this.range.setStartAfter(this.element);
2002
+ },
2003
+
2004
+ insertContent: function(fragments) {
2005
+ fragments.each((function(fragment) {
2006
+ this.element.parentNode.insertBefore(fragment,
2007
+ this.element.nextSibling);
2008
+ }).bind(this));
2009
+ }
2010
+ });
2011
+
2012
+ /*--------------------------------------------------------------------------*/
2013
+
2014
+ Element.ClassNames = Class.create();
2015
+ Element.ClassNames.prototype = {
2016
+ initialize: function(element) {
2017
+ this.element = $(element);
2018
+ },
2019
+
2020
+ _each: function(iterator) {
2021
+ this.element.className.split(/\s+/).select(function(name) {
2022
+ return name.length > 0;
2023
+ })._each(iterator);
2024
+ },
2025
+
2026
+ set: function(className) {
2027
+ this.element.className = className;
2028
+ },
2029
+
2030
+ add: function(classNameToAdd) {
2031
+ if (this.include(classNameToAdd)) return;
2032
+ this.set($A(this).concat(classNameToAdd).join(' '));
2033
+ },
2034
+
2035
+ remove: function(classNameToRemove) {
2036
+ if (!this.include(classNameToRemove)) return;
2037
+ this.set($A(this).without(classNameToRemove).join(' '));
2038
+ },
2039
+
2040
+ toString: function() {
2041
+ return $A(this).join(' ');
2042
+ }
2043
+ };
2044
+
2045
+ Object.extend(Element.ClassNames.prototype, Enumerable);
2046
+ /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2047
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2048
+ * license. Please see http://www.yui-ext.com/ for more information. */
2049
+
2050
+ var Selector = Class.create();
2051
+
2052
+ Selector.prototype = {
2053
+ initialize: function(expression) {
2054
+ this.expression = expression.strip();
2055
+ this.compileMatcher();
2056
+ },
2057
+
2058
+ compileMatcher: function() {
2059
+ // Selectors with namespaced attributes can't use the XPath version
2060
+ if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
2061
+ return this.compileXPathMatcher();
2062
+
2063
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2064
+ c = Selector.criteria, le, p, m;
2065
+
2066
+ if (Selector._cache[e]) {
2067
+ this.matcher = Selector._cache[e]; return;
2068
+ }
2069
+ this.matcher = ["this.matcher = function(root) {",
2070
+ "var r = root, h = Selector.handlers, c = false, n;"];
2071
+
2072
+ while (e && le != e && (/\S/).test(e)) {
2073
+ le = e;
2074
+ for (var i in ps) {
2075
+ p = ps[i];
2076
+ if (m = e.match(p)) {
2077
+ this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
2078
+ new Template(c[i]).evaluate(m));
2079
+ e = e.replace(m[0], '');
2080
+ break;
2081
+ }
2082
+ }
2083
+ }
2084
+
2085
+ this.matcher.push("return h.unique(n);\n}");
2086
+ eval(this.matcher.join('\n'));
2087
+ Selector._cache[this.expression] = this.matcher;
2088
+ },
2089
+
2090
+ compileXPathMatcher: function() {
2091
+ var e = this.expression, ps = Selector.patterns,
2092
+ x = Selector.xpath, le, m;
2093
+
2094
+ if (Selector._cache[e]) {
2095
+ this.xpath = Selector._cache[e]; return;
2096
+ }
2097
+
2098
+ this.matcher = ['.//*'];
2099
+ while (e && le != e && (/\S/).test(e)) {
2100
+ le = e;
2101
+ for (var i in ps) {
2102
+ if (m = e.match(ps[i])) {
2103
+ this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
2104
+ new Template(x[i]).evaluate(m));
2105
+ e = e.replace(m[0], '');
2106
+ break;
2107
+ }
2108
+ }
2109
+ }
2110
+
2111
+ this.xpath = this.matcher.join('');
2112
+ Selector._cache[this.expression] = this.xpath;
2113
+ },
2114
+
2115
+ findElements: function(root) {
2116
+ root = root || document;
2117
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2118
+ return this.matcher(root);
2119
+ },
2120
+
2121
+ match: function(element) {
2122
+ return this.findElements(document).include(element);
2123
+ },
2124
+
2125
+ toString: function() {
2126
+ return this.expression;
2127
+ },
2128
+
2129
+ inspect: function() {
2130
+ return "#<Selector:" + this.expression.inspect() + ">";
2131
+ }
2132
+ };
2133
+
2134
+ Object.extend(Selector, {
2135
+ _cache: {},
2136
+
2137
+ xpath: {
2138
+ descendant: "//*",
2139
+ child: "/*",
2140
+ adjacent: "/following-sibling::*[1]",
2141
+ laterSibling: '/following-sibling::*',
2142
+ tagName: function(m) {
2143
+ if (m[1] == '*') return '';
2144
+ return "[local-name()='" + m[1].toLowerCase() +
2145
+ "' or local-name()='" + m[1].toUpperCase() + "']";
2146
+ },
2147
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2148
+ id: "[@id='#{1}']",
2149
+ attrPresence: "[@#{1}]",
2150
+ attr: function(m) {
2151
+ m[3] = m[5] || m[6];
2152
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2153
+ },
2154
+ pseudo: function(m) {
2155
+ var h = Selector.xpath.pseudos[m[1]];
2156
+ if (!h) return '';
2157
+ if (typeof h === 'function') return h(m);
2158
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2159
+ },
2160
+ operators: {
2161
+ '=': "[@#{1}='#{3}']",
2162
+ '!=': "[@#{1}!='#{3}']",
2163
+ '^=': "[starts-with(@#{1}, '#{3}')]",
2164
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2165
+ '*=': "[contains(@#{1}, '#{3}')]",
2166
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2167
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2168
+ },
2169
+ pseudos: {
2170
+ 'first-child': '[not(preceding-sibling::*)]',
2171
+ 'last-child': '[not(following-sibling::*)]',
2172
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2173
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2174
+ 'checked': "[@checked]",
2175
+ 'disabled': "[@disabled]",
2176
+ 'enabled': "[not(@disabled)]",
2177
+ 'not': function(m) {
2178
+ var e = m[6], p = Selector.patterns,
2179
+ x = Selector.xpath, le, m, v;
2180
+
2181
+ var exclusion = [];
2182
+ while (e && le != e && (/\S/).test(e)) {
2183
+ le = e;
2184
+ for (var i in p) {
2185
+ if (m = e.match(p[i])) {
2186
+ v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
2187
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2188
+ e = e.replace(m[0], '');
2189
+ break;
2190
+ }
2191
+ }
2192
+ }
2193
+ return "[not(" + exclusion.join(" and ") + ")]";
2194
+ },
2195
+ 'nth-child': function(m) {
2196
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2197
+ },
2198
+ 'nth-last-child': function(m) {
2199
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2200
+ },
2201
+ 'nth-of-type': function(m) {
2202
+ return Selector.xpath.pseudos.nth("position() ", m);
2203
+ },
2204
+ 'nth-last-of-type': function(m) {
2205
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2206
+ },
2207
+ 'first-of-type': function(m) {
2208
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2209
+ },
2210
+ 'last-of-type': function(m) {
2211
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2212
+ },
2213
+ 'only-of-type': function(m) {
2214
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2215
+ },
2216
+ nth: function(fragment, m) {
2217
+ var mm, formula = m[6], predicate;
2218
+ if (formula == 'even') formula = '2n+0';
2219
+ if (formula == 'odd') formula = '2n+1';
2220
+ if (mm = formula.match(/^(\d+)$/)) // digit only
2221
+ return '[' + fragment + "= " + mm[1] + ']';
2222
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2223
+ if (mm[1] == "-") mm[1] = -1;
2224
+ var a = mm[1] ? Number(mm[1]) : 1;
2225
+ var b = mm[2] ? Number(mm[2]) : 0;
2226
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2227
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
2228
+ return new Template(predicate).evaluate({
2229
+ fragment: fragment, a: a, b: b });
2230
+ }
2231
+ }
2232
+ }
2233
+ },
2234
+
2235
+ criteria: {
2236
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2237
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
2238
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
2239
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2240
+ attr: function(m) {
2241
+ m[3] = (m[5] || m[6]);
2242
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2243
+ },
2244
+ pseudo: function(m) {
2245
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2246
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2247
+ },
2248
+ descendant: 'c = "descendant";',
2249
+ child: 'c = "child";',
2250
+ adjacent: 'c = "adjacent";',
2251
+ laterSibling: 'c = "laterSibling";'
2252
+ },
2253
+
2254
+ patterns: {
2255
+ // combinators must be listed first
2256
+ // (and descendant needs to be last combinator)
2257
+ laterSibling: /^\s*~\s*/,
2258
+ child: /^\s*>\s*/,
2259
+ adjacent: /^\s*\+\s*/,
2260
+ descendant: /^\s/,
2261
+
2262
+ // selectors follow
2263
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2264
+ id: /^#([\w\-\*]+)(\b|$)/,
2265
+ className: /^\.([\w\-\*]+)(\b|$)/,
2266
+ pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
2267
+ attrPresence: /^\[([\w]+)\]/,
2268
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
2269
+ },
2270
+
2271
+ handlers: {
2272
+ // UTILITY FUNCTIONS
2273
+ // joins two collections
2274
+ concat: function(a, b) {
2275
+ for (var i = 0, node; node = b[i]; i++)
2276
+ a.push(node);
2277
+ return a;
2278
+ },
2279
+
2280
+ // marks an array of nodes for counting
2281
+ mark: function(nodes) {
2282
+ for (var i = 0, node; node = nodes[i]; i++)
2283
+ node._counted = true;
2284
+ return nodes;
2285
+ },
2286
+
2287
+ unmark: function(nodes) {
2288
+ for (var i = 0, node; node = nodes[i]; i++)
2289
+ node._counted = undefined;
2290
+ return nodes;
2291
+ },
2292
+
2293
+ // mark each child node with its position (for nth calls)
2294
+ // "ofType" flag indicates whether we're indexing for nth-of-type
2295
+ // rather than nth-child
2296
+ index: function(parentNode, reverse, ofType) {
2297
+ parentNode._counted = true;
2298
+ if (reverse) {
2299
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2300
+ node = nodes[i];
2301
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2302
+ }
2303
+ } else {
2304
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
2305
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2306
+ }
2307
+ },
2308
+
2309
+ // filters out duplicates and extends all nodes
2310
+ unique: function(nodes) {
2311
+ if (nodes.length == 0) return nodes;
2312
+ var results = [], n;
2313
+ for (var i = 0, l = nodes.length; i < l; i++)
2314
+ if (!(n = nodes[i])._counted) {
2315
+ n._counted = true;
2316
+ results.push(Element.extend(n));
2317
+ }
2318
+ return Selector.handlers.unmark(results);
2319
+ },
2320
+
2321
+ // COMBINATOR FUNCTIONS
2322
+ descendant: function(nodes) {
2323
+ var h = Selector.handlers;
2324
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2325
+ h.concat(results, node.getElementsByTagName('*'));
2326
+ return results;
2327
+ },
2328
+
2329
+ child: function(nodes) {
2330
+ var h = Selector.handlers;
2331
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2332
+ for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
2333
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
2334
+ }
2335
+ return results;
2336
+ },
2337
+
2338
+ adjacent: function(nodes) {
2339
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2340
+ var next = this.nextElementSibling(node);
2341
+ if (next) results.push(next);
2342
+ }
2343
+ return results;
2344
+ },
2345
+
2346
+ laterSibling: function(nodes) {
2347
+ var h = Selector.handlers;
2348
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2349
+ h.concat(results, Element.nextSiblings(node));
2350
+ return results;
2351
+ },
2352
+
2353
+ nextElementSibling: function(node) {
2354
+ while (node = node.nextSibling)
2355
+ if (node.nodeType == 1) return node;
2356
+ return null;
2357
+ },
2358
+
2359
+ previousElementSibling: function(node) {
2360
+ while (node = node.previousSibling)
2361
+ if (node.nodeType == 1) return node;
2362
+ return null;
2363
+ },
2364
+
2365
+ // TOKEN FUNCTIONS
2366
+ tagName: function(nodes, root, tagName, combinator) {
2367
+ tagName = tagName.toUpperCase();
2368
+ var results = [], h = Selector.handlers;
2369
+ if (nodes) {
2370
+ if (combinator) {
2371
+ // fastlane for ordinary descendant combinators
2372
+ if (combinator == "descendant") {
2373
+ for (var i = 0, node; node = nodes[i]; i++)
2374
+ h.concat(results, node.getElementsByTagName(tagName));
2375
+ return results;
2376
+ } else nodes = this[combinator](nodes);
2377
+ if (tagName == "*") return nodes;
2378
+ }
2379
+ for (var i = 0, node; node = nodes[i]; i++)
2380
+ if (node.tagName.toUpperCase() == tagName) results.push(node);
2381
+ return results;
2382
+ } else return root.getElementsByTagName(tagName);
2383
+ },
2384
+
2385
+ id: function(nodes, root, id, combinator) {
2386
+ var targetNode = $(id), h = Selector.handlers;
2387
+ if (!nodes && root == document) return targetNode ? [targetNode] : [];
2388
+ if (nodes) {
2389
+ if (combinator) {
2390
+ if (combinator == 'child') {
2391
+ for (var i = 0, node; node = nodes[i]; i++)
2392
+ if (targetNode.parentNode == node) return [targetNode];
2393
+ } else if (combinator == 'descendant') {
2394
+ for (var i = 0, node; node = nodes[i]; i++)
2395
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
2396
+ } else if (combinator == 'adjacent') {
2397
+ for (var i = 0, node; node = nodes[i]; i++)
2398
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
2399
+ return [targetNode];
2400
+ } else nodes = h[combinator](nodes);
2401
+ }
2402
+ for (var i = 0, node; node = nodes[i]; i++)
2403
+ if (node == targetNode) return [targetNode];
2404
+ return [];
2405
+ }
2406
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
2407
+ },
2408
+
2409
+ className: function(nodes, root, className, combinator) {
2410
+ if (nodes && combinator) nodes = this[combinator](nodes);
2411
+ return Selector.handlers.byClassName(nodes, root, className);
2412
+ },
2413
+
2414
+ byClassName: function(nodes, root, className) {
2415
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
2416
+ var needle = ' ' + className + ' ';
2417
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
2418
+ nodeClassName = node.className;
2419
+ if (nodeClassName.length == 0) continue;
2420
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
2421
+ results.push(node);
2422
+ }
2423
+ return results;
2424
+ },
2425
+
2426
+ attrPresence: function(nodes, root, attr) {
2427
+ var results = [];
2428
+ for (var i = 0, node; node = nodes[i]; i++)
2429
+ if (Element.hasAttribute(node, attr)) results.push(node);
2430
+ return results;
2431
+ },
2432
+
2433
+ attr: function(nodes, root, attr, value, operator) {
2434
+ if (!nodes) nodes = root.getElementsByTagName("*");
2435
+ var handler = Selector.operators[operator], results = [];
2436
+ for (var i = 0, node; node = nodes[i]; i++) {
2437
+ var nodeValue = Element.readAttribute(node, attr);
2438
+ if (nodeValue === null) continue;
2439
+ if (handler(nodeValue, value)) results.push(node);
2440
+ }
2441
+ return results;
2442
+ },
2443
+
2444
+ pseudo: function(nodes, name, value, root, combinator) {
2445
+ if (nodes && combinator) nodes = this[combinator](nodes);
2446
+ if (!nodes) nodes = root.getElementsByTagName("*");
2447
+ return Selector.pseudos[name](nodes, value, root);
2448
+ }
2449
+ },
2450
+
2451
+ pseudos: {
2452
+ 'first-child': function(nodes, value, root) {
2453
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2454
+ if (Selector.handlers.previousElementSibling(node)) continue;
2455
+ results.push(node);
2456
+ }
2457
+ return results;
2458
+ },
2459
+ 'last-child': function(nodes, value, root) {
2460
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2461
+ if (Selector.handlers.nextElementSibling(node)) continue;
2462
+ results.push(node);
2463
+ }
2464
+ return results;
2465
+ },
2466
+ 'only-child': function(nodes, value, root) {
2467
+ var h = Selector.handlers;
2468
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2469
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
2470
+ results.push(node);
2471
+ return results;
2472
+ },
2473
+ 'nth-child': function(nodes, formula, root) {
2474
+ return Selector.pseudos.nth(nodes, formula, root);
2475
+ },
2476
+ 'nth-last-child': function(nodes, formula, root) {
2477
+ return Selector.pseudos.nth(nodes, formula, root, true);
2478
+ },
2479
+ 'nth-of-type': function(nodes, formula, root) {
2480
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
2481
+ },
2482
+ 'nth-last-of-type': function(nodes, formula, root) {
2483
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
2484
+ },
2485
+ 'first-of-type': function(nodes, formula, root) {
2486
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
2487
+ },
2488
+ 'last-of-type': function(nodes, formula, root) {
2489
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
2490
+ },
2491
+ 'only-of-type': function(nodes, formula, root) {
2492
+ var p = Selector.pseudos;
2493
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
2494
+ },
2495
+
2496
+ // handles the an+b logic
2497
+ getIndices: function(a, b, total) {
2498
+ if (a == 0) return b > 0 ? [b] : [];
2499
+ return $R(1, total).inject([], function(memo, i) {
2500
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
2501
+ return memo;
2502
+ });
2503
+ },
2504
+
2505
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
2506
+ nth: function(nodes, formula, root, reverse, ofType) {
2507
+ if (nodes.length == 0) return [];
2508
+ if (formula == 'even') formula = '2n+0';
2509
+ if (formula == 'odd') formula = '2n+1';
2510
+ var h = Selector.handlers, results = [], indexed = [], m;
2511
+ h.mark(nodes);
2512
+ for (var i = 0, node; node = nodes[i]; i++) {
2513
+ if (!node.parentNode._counted) {
2514
+ h.index(node.parentNode, reverse, ofType);
2515
+ indexed.push(node.parentNode);
2516
+ }
2517
+ }
2518
+ if (formula.match(/^\d+$/)) { // just a number
2519
+ formula = Number(formula);
2520
+ for (var i = 0, node; node = nodes[i]; i++)
2521
+ if (node.nodeIndex == formula) results.push(node);
2522
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2523
+ if (m[1] == "-") m[1] = -1;
2524
+ var a = m[1] ? Number(m[1]) : 1;
2525
+ var b = m[2] ? Number(m[2]) : 0;
2526
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
2527
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
2528
+ for (var j = 0; j < l; j++)
2529
+ if (node.nodeIndex == indices[j]) results.push(node);
2530
+ }
2531
+ }
2532
+ h.unmark(nodes);
2533
+ h.unmark(indexed);
2534
+ return results;
2535
+ },
2536
+
2537
+ 'empty': function(nodes, value, root) {
2538
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2539
+ // IE treats comments as element nodes
2540
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
2541
+ results.push(node);
2542
+ }
2543
+ return results;
2544
+ },
2545
+
2546
+ 'not': function(nodes, selector, root) {
2547
+ var h = Selector.handlers, selectorType, m;
2548
+ var exclusions = new Selector(selector).findElements(root);
2549
+ h.mark(exclusions);
2550
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2551
+ if (!node._counted) results.push(node);
2552
+ h.unmark(exclusions);
2553
+ return results;
2554
+ },
2555
+
2556
+ 'enabled': function(nodes, value, root) {
2557
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2558
+ if (!node.disabled) results.push(node);
2559
+ return results;
2560
+ },
2561
+
2562
+ 'disabled': function(nodes, value, root) {
2563
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2564
+ if (node.disabled) results.push(node);
2565
+ return results;
2566
+ },
2567
+
2568
+ 'checked': function(nodes, value, root) {
2569
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2570
+ if (node.checked) results.push(node);
2571
+ return results;
2572
+ }
2573
+ },
2574
+
2575
+ operators: {
2576
+ '=': function(nv, v) { return nv == v; },
2577
+ '!=': function(nv, v) { return nv != v; },
2578
+ '^=': function(nv, v) { return nv.startsWith(v); },
2579
+ '$=': function(nv, v) { return nv.endsWith(v); },
2580
+ '*=': function(nv, v) { return nv.include(v); },
2581
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
2582
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
2583
+ },
2584
+
2585
+ matchElements: function(elements, expression) {
2586
+ var matches = new Selector(expression).findElements(), h = Selector.handlers;
2587
+ h.mark(matches);
2588
+ for (var i = 0, results = [], element; element = elements[i]; i++)
2589
+ if (element._counted) results.push(element);
2590
+ h.unmark(matches);
2591
+ return results;
2592
+ },
2593
+
2594
+ findElement: function(elements, expression, index) {
2595
+ if (typeof expression == 'number') {
2596
+ index = expression; expression = false;
2597
+ }
2598
+ return Selector.matchElements(elements, expression || '*')[index || 0];
2599
+ },
2600
+
2601
+ findChildElements: function(element, expressions) {
2602
+ var exprs = expressions.join(','), expressions = [];
2603
+ exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
2604
+ expressions.push(m[1].strip());
2605
+ });
2606
+ var results = [], h = Selector.handlers;
2607
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
2608
+ selector = new Selector(expressions[i].strip());
2609
+ h.concat(results, selector.findElements(element));
2610
+ }
2611
+ return (l > 1) ? h.unique(results) : results;
2612
+ }
2613
+ });
2614
+
2615
+ function $$() {
2616
+ return Selector.findChildElements(document, $A(arguments));
2617
+ }
2618
+ var Form = {
2619
+ reset: function(form) {
2620
+ $(form).reset();
2621
+ return form;
2622
+ },
2623
+
2624
+ serializeElements: function(elements, getHash) {
2625
+ var data = elements.inject({}, function(result, element) {
2626
+ if (!element.disabled && element.name) {
2627
+ var key = element.name, value = $(element).getValue();
2628
+ if (value != null) {
2629
+ if (key in result) {
2630
+ if (result[key].constructor != Array) result[key] = [result[key]];
2631
+ result[key].push(value);
2632
+ }
2633
+ else result[key] = value;
2634
+ }
2635
+ }
2636
+ return result;
2637
+ });
2638
+
2639
+ return getHash ? data : Hash.toQueryString(data);
2640
+ }
2641
+ };
2642
+
2643
+ Form.Methods = {
2644
+ serialize: function(form, getHash) {
2645
+ return Form.serializeElements(Form.getElements(form), getHash);
2646
+ },
2647
+
2648
+ getElements: function(form) {
2649
+ return $A($(form).getElementsByTagName('*')).inject([],
2650
+ function(elements, child) {
2651
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
2652
+ elements.push(Element.extend(child));
2653
+ return elements;
2654
+ }
2655
+ );
2656
+ },
2657
+
2658
+ getInputs: function(form, typeName, name) {
2659
+ form = $(form);
2660
+ var inputs = form.getElementsByTagName('input');
2661
+
2662
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
2663
+
2664
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2665
+ var input = inputs[i];
2666
+ if ((typeName && input.type != typeName) || (name && input.name != name))
2667
+ continue;
2668
+ matchingInputs.push(Element.extend(input));
2669
+ }
2670
+
2671
+ return matchingInputs;
2672
+ },
2673
+
2674
+ disable: function(form) {
2675
+ form = $(form);
2676
+ Form.getElements(form).invoke('disable');
2677
+ return form;
2678
+ },
2679
+
2680
+ enable: function(form) {
2681
+ form = $(form);
2682
+ Form.getElements(form).invoke('enable');
2683
+ return form;
2684
+ },
2685
+
2686
+ findFirstElement: function(form) {
2687
+ return $(form).getElements().find(function(element) {
2688
+ return element.type != 'hidden' && !element.disabled &&
2689
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
2690
+ });
2691
+ },
2692
+
2693
+ focusFirstElement: function(form) {
2694
+ form = $(form);
2695
+ form.findFirstElement().activate();
2696
+ return form;
2697
+ },
2698
+
2699
+ request: function(form, options) {
2700
+ form = $(form), options = Object.clone(options || {});
2701
+
2702
+ var params = options.parameters;
2703
+ options.parameters = form.serialize(true);
2704
+
2705
+ if (params) {
2706
+ if (typeof params == 'string') params = params.toQueryParams();
2707
+ Object.extend(options.parameters, params);
2708
+ }
2709
+
2710
+ if (form.hasAttribute('method') && !options.method)
2711
+ options.method = form.method;
2712
+
2713
+ return new Ajax.Request(form.readAttribute('action'), options);
2714
+ }
2715
+ }
2716
+
2717
+ /*--------------------------------------------------------------------------*/
2718
+
2719
+ Form.Element = {
2720
+ focus: function(element) {
2721
+ $(element).focus();
2722
+ return element;
2723
+ },
2724
+
2725
+ select: function(element) {
2726
+ $(element).select();
2727
+ return element;
2728
+ }
2729
+ }
2730
+
2731
+ Form.Element.Methods = {
2732
+ serialize: function(element) {
2733
+ element = $(element);
2734
+ if (!element.disabled && element.name) {
2735
+ var value = element.getValue();
2736
+ if (value != undefined) {
2737
+ var pair = {};
2738
+ pair[element.name] = value;
2739
+ return Hash.toQueryString(pair);
2740
+ }
2741
+ }
2742
+ return '';
2743
+ },
2744
+
2745
+ getValue: function(element) {
2746
+ element = $(element);
2747
+ var method = element.tagName.toLowerCase();
2748
+ return Form.Element.Serializers[method](element);
2749
+ },
2750
+
2751
+ clear: function(element) {
2752
+ $(element).value = '';
2753
+ return element;
2754
+ },
2755
+
2756
+ present: function(element) {
2757
+ return $(element).value != '';
2758
+ },
2759
+
2760
+ activate: function(element) {
2761
+ element = $(element);
2762
+ try {
2763
+ element.focus();
2764
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
2765
+ !['button', 'reset', 'submit'].include(element.type)))
2766
+ element.select();
2767
+ } catch (e) {}
2768
+ return element;
2769
+ },
2770
+
2771
+ disable: function(element) {
2772
+ element = $(element);
2773
+ element.blur();
2774
+ element.disabled = true;
2775
+ return element;
2776
+ },
2777
+
2778
+ enable: function(element) {
2779
+ element = $(element);
2780
+ element.disabled = false;
2781
+ return element;
2782
+ }
2783
+ }
2784
+
2785
+ /*--------------------------------------------------------------------------*/
2786
+
2787
+ var Field = Form.Element;
2788
+ var $F = Form.Element.Methods.getValue;
2789
+
2790
+ /*--------------------------------------------------------------------------*/
2791
+
2792
+ Form.Element.Serializers = {
2793
+ input: function(element) {
2794
+ switch (element.type.toLowerCase()) {
2795
+ case 'checkbox':
2796
+ case 'radio':
2797
+ return Form.Element.Serializers.inputSelector(element);
2798
+ default:
2799
+ return Form.Element.Serializers.textarea(element);
2800
+ }
2801
+ },
2802
+
2803
+ inputSelector: function(element) {
2804
+ return element.checked ? element.value : null;
2805
+ },
2806
+
2807
+ textarea: function(element) {
2808
+ return element.value;
2809
+ },
2810
+
2811
+ select: function(element) {
2812
+ return this[element.type == 'select-one' ?
2813
+ 'selectOne' : 'selectMany'](element);
2814
+ },
2815
+
2816
+ selectOne: function(element) {
2817
+ var index = element.selectedIndex;
2818
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
2819
+ },
2820
+
2821
+ selectMany: function(element) {
2822
+ var values, length = element.length;
2823
+ if (!length) return null;
2824
+
2825
+ for (var i = 0, values = []; i < length; i++) {
2826
+ var opt = element.options[i];
2827
+ if (opt.selected) values.push(this.optionValue(opt));
2828
+ }
2829
+ return values;
2830
+ },
2831
+
2832
+ optionValue: function(opt) {
2833
+ // extend element because hasAttribute may not be native
2834
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2835
+ }
2836
+ }
2837
+
2838
+ /*--------------------------------------------------------------------------*/
2839
+
2840
+ Abstract.TimedObserver = function() {}
2841
+ Abstract.TimedObserver.prototype = {
2842
+ initialize: function(element, frequency, callback) {
2843
+ this.frequency = frequency;
2844
+ this.element = $(element);
2845
+ this.callback = callback;
2846
+
2847
+ this.lastValue = this.getValue();
2848
+ this.registerCallback();
2849
+ },
2850
+
2851
+ registerCallback: function() {
2852
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2853
+ },
2854
+
2855
+ onTimerEvent: function() {
2856
+ var value = this.getValue();
2857
+ var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2858
+ ? this.lastValue != value : String(this.lastValue) != String(value));
2859
+ if (changed) {
2860
+ this.callback(this.element, value);
2861
+ this.lastValue = value;
2862
+ }
2863
+ }
2864
+ }
2865
+
2866
+ Form.Element.Observer = Class.create();
2867
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2868
+ getValue: function() {
2869
+ return Form.Element.getValue(this.element);
2870
+ }
2871
+ });
2872
+
2873
+ Form.Observer = Class.create();
2874
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2875
+ getValue: function() {
2876
+ return Form.serialize(this.element);
2877
+ }
2878
+ });
2879
+
2880
+ /*--------------------------------------------------------------------------*/
2881
+
2882
+ Abstract.EventObserver = function() {}
2883
+ Abstract.EventObserver.prototype = {
2884
+ initialize: function(element, callback) {
2885
+ this.element = $(element);
2886
+ this.callback = callback;
2887
+
2888
+ this.lastValue = this.getValue();
2889
+ if (this.element.tagName.toLowerCase() == 'form')
2890
+ this.registerFormCallbacks();
2891
+ else
2892
+ this.registerCallback(this.element);
2893
+ },
2894
+
2895
+ onElementEvent: function() {
2896
+ var value = this.getValue();
2897
+ if (this.lastValue != value) {
2898
+ this.callback(this.element, value);
2899
+ this.lastValue = value;
2900
+ }
2901
+ },
2902
+
2903
+ registerFormCallbacks: function() {
2904
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
2905
+ },
2906
+
2907
+ registerCallback: function(element) {
2908
+ if (element.type) {
2909
+ switch (element.type.toLowerCase()) {
2910
+ case 'checkbox':
2911
+ case 'radio':
2912
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
2913
+ break;
2914
+ default:
2915
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
2916
+ break;
2917
+ }
2918
+ }
2919
+ }
2920
+ }
2921
+
2922
+ Form.Element.EventObserver = Class.create();
2923
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2924
+ getValue: function() {
2925
+ return Form.Element.getValue(this.element);
2926
+ }
2927
+ });
2928
+
2929
+ Form.EventObserver = Class.create();
2930
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2931
+ getValue: function() {
2932
+ return Form.serialize(this.element);
2933
+ }
2934
+ });
2935
+ if (!window.Event) {
2936
+ var Event = new Object();
2937
+ }
2938
+
2939
+ Object.extend(Event, {
2940
+ KEY_BACKSPACE: 8,
2941
+ KEY_TAB: 9,
2942
+ KEY_RETURN: 13,
2943
+ KEY_ESC: 27,
2944
+ KEY_LEFT: 37,
2945
+ KEY_UP: 38,
2946
+ KEY_RIGHT: 39,
2947
+ KEY_DOWN: 40,
2948
+ KEY_DELETE: 46,
2949
+ KEY_HOME: 36,
2950
+ KEY_END: 35,
2951
+ KEY_PAGEUP: 33,
2952
+ KEY_PAGEDOWN: 34,
2953
+
2954
+ element: function(event) {
2955
+ return $(event.target || event.srcElement);
2956
+ },
2957
+
2958
+ isLeftClick: function(event) {
2959
+ return (((event.which) && (event.which == 1)) ||
2960
+ ((event.button) && (event.button == 1)));
2961
+ },
2962
+
2963
+ pointerX: function(event) {
2964
+ return event.pageX || (event.clientX +
2965
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
2966
+ },
2967
+
2968
+ pointerY: function(event) {
2969
+ return event.pageY || (event.clientY +
2970
+ (document.documentElement.scrollTop || document.body.scrollTop));
2971
+ },
2972
+
2973
+ stop: function(event) {
2974
+ if (event.preventDefault) {
2975
+ event.preventDefault();
2976
+ event.stopPropagation();
2977
+ } else {
2978
+ event.returnValue = false;
2979
+ event.cancelBubble = true;
2980
+ }
2981
+ },
2982
+
2983
+ // find the first node with the given tagName, starting from the
2984
+ // node the event was triggered on; traverses the DOM upwards
2985
+ findElement: function(event, tagName) {
2986
+ var element = Event.element(event);
2987
+ while (element.parentNode && (!element.tagName ||
2988
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
2989
+ element = element.parentNode;
2990
+ return element;
2991
+ },
2992
+
2993
+ observers: false,
2994
+
2995
+ _observeAndCache: function(element, name, observer, useCapture) {
2996
+ if (!this.observers) this.observers = [];
2997
+ if (element.addEventListener) {
2998
+ this.observers.push([element, name, observer, useCapture]);
2999
+ element.addEventListener(name, observer, useCapture);
3000
+ } else if (element.attachEvent) {
3001
+ this.observers.push([element, name, observer, useCapture]);
3002
+ element.attachEvent('on' + name, observer);
3003
+ }
3004
+ },
3005
+
3006
+ unloadCache: function() {
3007
+ if (!Event.observers) return;
3008
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
3009
+ Event.stopObserving.apply(this, Event.observers[i]);
3010
+ Event.observers[i][0] = null;
3011
+ }
3012
+ Event.observers = false;
3013
+ },
3014
+
3015
+ observe: function(element, name, observer, useCapture) {
3016
+ element = $(element);
3017
+ useCapture = useCapture || false;
3018
+
3019
+ if (name == 'keypress' &&
3020
+ (Prototype.Browser.WebKit || element.attachEvent))
3021
+ name = 'keydown';
3022
+
3023
+ Event._observeAndCache(element, name, observer, useCapture);
3024
+ },
3025
+
3026
+ stopObserving: function(element, name, observer, useCapture) {
3027
+ element = $(element);
3028
+ useCapture = useCapture || false;
3029
+
3030
+ if (name == 'keypress' &&
3031
+ (Prototype.Browser.WebKit || element.attachEvent))
3032
+ name = 'keydown';
3033
+
3034
+ if (element.removeEventListener) {
3035
+ element.removeEventListener(name, observer, useCapture);
3036
+ } else if (element.detachEvent) {
3037
+ try {
3038
+ element.detachEvent('on' + name, observer);
3039
+ } catch (e) {}
3040
+ }
3041
+ }
3042
+ });
3043
+
3044
+ /* prevent memory leaks in IE */
3045
+ if (Prototype.Browser.IE)
3046
+ Event.observe(window, 'unload', Event.unloadCache, false);
3047
+ var Position = {
3048
+ // set to true if needed, warning: firefox performance problems
3049
+ // NOT neeeded for page scrolling, only if draggable contained in
3050
+ // scrollable elements
3051
+ includeScrollOffsets: false,
3052
+
3053
+ // must be called before calling withinIncludingScrolloffset, every time the
3054
+ // page is scrolled
3055
+ prepare: function() {
3056
+ this.deltaX = window.pageXOffset
3057
+ || document.documentElement.scrollLeft
3058
+ || document.body.scrollLeft
3059
+ || 0;
3060
+ this.deltaY = window.pageYOffset
3061
+ || document.documentElement.scrollTop
3062
+ || document.body.scrollTop
3063
+ || 0;
3064
+ },
3065
+
3066
+ realOffset: function(element) {
3067
+ var valueT = 0, valueL = 0;
3068
+ do {
3069
+ valueT += element.scrollTop || 0;
3070
+ valueL += element.scrollLeft || 0;
3071
+ element = element.parentNode;
3072
+ } while (element);
3073
+ return [valueL, valueT];
3074
+ },
3075
+
3076
+ cumulativeOffset: function(element) {
3077
+ var valueT = 0, valueL = 0;
3078
+ do {
3079
+ valueT += element.offsetTop || 0;
3080
+ valueL += element.offsetLeft || 0;
3081
+ element = element.offsetParent;
3082
+ } while (element);
3083
+ return [valueL, valueT];
3084
+ },
3085
+
3086
+ positionedOffset: function(element) {
3087
+ var valueT = 0, valueL = 0;
3088
+ do {
3089
+ valueT += element.offsetTop || 0;
3090
+ valueL += element.offsetLeft || 0;
3091
+ element = element.offsetParent;
3092
+ if (element) {
3093
+ if(element.tagName=='BODY') break;
3094
+ var p = Element.getStyle(element, 'position');
3095
+ if (p == 'relative' || p == 'absolute') break;
3096
+ }
3097
+ } while (element);
3098
+ return [valueL, valueT];
3099
+ },
3100
+
3101
+ offsetParent: function(element) {
3102
+ if (element.offsetParent) return element.offsetParent;
3103
+ if (element == document.body) return element;
3104
+
3105
+ while ((element = element.parentNode) && element != document.body)
3106
+ if (Element.getStyle(element, 'position') != 'static')
3107
+ return element;
3108
+
3109
+ return document.body;
3110
+ },
3111
+
3112
+ // caches x/y coordinate pair to use with overlap
3113
+ within: function(element, x, y) {
3114
+ if (this.includeScrollOffsets)
3115
+ return this.withinIncludingScrolloffsets(element, x, y);
3116
+ this.xcomp = x;
3117
+ this.ycomp = y;
3118
+ this.offset = this.cumulativeOffset(element);
3119
+
3120
+ return (y >= this.offset[1] &&
3121
+ y < this.offset[1] + element.offsetHeight &&
3122
+ x >= this.offset[0] &&
3123
+ x < this.offset[0] + element.offsetWidth);
3124
+ },
3125
+
3126
+ withinIncludingScrolloffsets: function(element, x, y) {
3127
+ var offsetcache = this.realOffset(element);
3128
+
3129
+ this.xcomp = x + offsetcache[0] - this.deltaX;
3130
+ this.ycomp = y + offsetcache[1] - this.deltaY;
3131
+ this.offset = this.cumulativeOffset(element);
3132
+
3133
+ return (this.ycomp >= this.offset[1] &&
3134
+ this.ycomp < this.offset[1] + element.offsetHeight &&
3135
+ this.xcomp >= this.offset[0] &&
3136
+ this.xcomp < this.offset[0] + element.offsetWidth);
3137
+ },
3138
+
3139
+ // within must be called directly before
3140
+ overlap: function(mode, element) {
3141
+ if (!mode) return 0;
3142
+ if (mode == 'vertical')
3143
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
3144
+ element.offsetHeight;
3145
+ if (mode == 'horizontal')
3146
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
3147
+ element.offsetWidth;
3148
+ },
3149
+
3150
+ page: function(forElement) {
3151
+ var valueT = 0, valueL = 0;
3152
+
3153
+ var element = forElement;
3154
+ do {
3155
+ valueT += element.offsetTop || 0;
3156
+ valueL += element.offsetLeft || 0;
3157
+
3158
+ // Safari fix
3159
+ if (element.offsetParent == document.body)
3160
+ if (Element.getStyle(element,'position')=='absolute') break;
3161
+
3162
+ } while (element = element.offsetParent);
3163
+
3164
+ element = forElement;
3165
+ do {
3166
+ if (!window.opera || element.tagName=='BODY') {
3167
+ valueT -= element.scrollTop || 0;
3168
+ valueL -= element.scrollLeft || 0;
3169
+ }
3170
+ } while (element = element.parentNode);
3171
+
3172
+ return [valueL, valueT];
3173
+ },
3174
+
3175
+ clone: function(source, target) {
3176
+ var options = Object.extend({
3177
+ setLeft: true,
3178
+ setTop: true,
3179
+ setWidth: true,
3180
+ setHeight: true,
3181
+ offsetTop: 0,
3182
+ offsetLeft: 0
3183
+ }, arguments[2] || {})
3184
+
3185
+ // find page position of source
3186
+ source = $(source);
3187
+ var p = Position.page(source);
3188
+
3189
+ // find coordinate system to use
3190
+ target = $(target);
3191
+ var delta = [0, 0];
3192
+ var parent = null;
3193
+ // delta [0,0] will do fine with position: fixed elements,
3194
+ // position:absolute needs offsetParent deltas
3195
+ if (Element.getStyle(target,'position') == 'absolute') {
3196
+ parent = Position.offsetParent(target);
3197
+ delta = Position.page(parent);
3198
+ }
3199
+
3200
+ // correct by body offsets (fixes Safari)
3201
+ if (parent == document.body) {
3202
+ delta[0] -= document.body.offsetLeft;
3203
+ delta[1] -= document.body.offsetTop;
3204
+ }
3205
+
3206
+ // set position
3207
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
3208
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
3209
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
3210
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
3211
+ },
3212
+
3213
+ absolutize: function(element) {
3214
+ element = $(element);
3215
+ if (element.style.position == 'absolute') return;
3216
+ Position.prepare();
3217
+
3218
+ var offsets = Position.positionedOffset(element);
3219
+ var top = offsets[1];
3220
+ var left = offsets[0];
3221
+ var width = element.clientWidth;
3222
+ var height = element.clientHeight;
3223
+
3224
+ element._originalLeft = left - parseFloat(element.style.left || 0);
3225
+ element._originalTop = top - parseFloat(element.style.top || 0);
3226
+ element._originalWidth = element.style.width;
3227
+ element._originalHeight = element.style.height;
3228
+
3229
+ element.style.position = 'absolute';
3230
+ element.style.top = top + 'px';
3231
+ element.style.left = left + 'px';
3232
+ element.style.width = width + 'px';
3233
+ element.style.height = height + 'px';
3234
+ },
3235
+
3236
+ relativize: function(element) {
3237
+ element = $(element);
3238
+ if (element.style.position == 'relative') return;
3239
+ Position.prepare();
3240
+
3241
+ element.style.position = 'relative';
3242
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
3243
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
3244
+
3245
+ element.style.top = top + 'px';
3246
+ element.style.left = left + 'px';
3247
+ element.style.height = element._originalHeight;
3248
+ element.style.width = element._originalWidth;
3249
+ }
3250
+ }
3251
+
3252
+ // Safari returns margins on body which is incorrect if the child is absolutely
3253
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
3254
+ // KHTML/WebKit only.
3255
+ if (Prototype.Browser.WebKit) {
3256
+ Position.cumulativeOffset = function(element) {
3257
+ var valueT = 0, valueL = 0;
3258
+ do {
3259
+ valueT += element.offsetTop || 0;
3260
+ valueL += element.offsetLeft || 0;
3261
+ if (element.offsetParent == document.body)
3262
+ if (Element.getStyle(element, 'position') == 'absolute') break;
3263
+
3264
+ element = element.offsetParent;
3265
+ } while (element);
3266
+
3267
+ return [valueL, valueT];
3268
+ }
3269
+ }
3270
+
3271
+ Element.addMethods();
js/dev/scriptaculous.js ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // script.aculo.us scriptaculous.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007
2
+
3
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ //
5
+ // Permission is hereby granted, free of charge, to any person obtaining
6
+ // a copy of this software and associated documentation files (the
7
+ // "Software"), to deal in the Software without restriction, including
8
+ // without limitation the rights to use, copy, modify, merge, publish,
9
+ // distribute, sublicense, and/or sell copies of the Software, and to
10
+ // permit persons to whom the Software is furnished to do so, subject to
11
+ // the following conditions:
12
+ //
13
+ // The above copyright notice and this permission notice shall be
14
+ // included in all copies or substantial portions of the Software.
15
+ //
16
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ //
24
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
25
+
26
+ var Scriptaculous = {
27
+ Version: '1.7.1_beta3',
28
+ require: function(libraryName) {
29
+ // inserting via DOM fails in Safari 2.0, so brute force approach
30
+ document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
31
+ },
32
+ REQUIRED_PROTOTYPE: '1.5.1',
33
+ load: function() {
34
+ function convertVersionString(versionString){
35
+ var r = versionString.split('.');
36
+ return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
37
+ }
38
+
39
+ if((typeof Prototype=='undefined') ||
40
+ (typeof Element == 'undefined') ||
41
+ (typeof Element.Methods=='undefined') ||
42
+ (convertVersionString(Prototype.Version) <
43
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
44
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
45
+ Scriptaculous.REQUIRED_PROTOTYPE);
46
+
47
+ $A(document.getElementsByTagName("script")).findAll( function(s) {
48
+ return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
49
+ }).each( function(s) {
50
+ var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
51
+ var includes = s.src.match(/\?.*load=([a-z,]*)/);
52
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
53
+ function(include) { Scriptaculous.require(path+include+'.js') });
54
+ });
55
+ }
56
+ }
57
+
58
+ Scriptaculous.load();
js/lib.js ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var Prototype={Version:"1.5.1",Browser:{IE:!!(window.attachEvent&&!window.opera),Opera:!!window.opera,WebKit:navigator.userAgent.indexOf("AppleWebKit/")>-1,Gecko:navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("KHTML")==-1},BrowserFeatures:{XPath:!!document.evaluate,ElementExtensions:!!window.HTMLElement,SpecificElementExtensions:document.createElement("div").__proto__!==document.createElement("form").__proto__},ScriptFragment:"<script[^>]*>([\u0001-\uffff]*?)<\/script>",JSONFilter:/^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
2
+ emptyFunction:function(){},K:function(a){return a}},Class={create:function(){return function(){this.initialize.apply(this,arguments)}}},Abstract={};Object.extend=function(a,b){for(var c in b)a[c]=b[c];return a};
3
+ Object.extend(Object,{inspect:function(a){try{if(a===undefined)return"undefined";if(a===null)return"null";return a.inspect?a.inspect():a.toString()}catch(b){if(b instanceof RangeError)return"...";throw b;}},toJSON:function(a){switch(typeof a){case "undefined":case "function":case "unknown":return;case "boolean":return a.toString()}if(a===null)return"null";if(a.toJSON)return a.toJSON();if(a.ownerDocument!==document){var b=[];for(var c in a){var d=Object.toJSON(a[c]);d!==undefined&&b.push(c.toJSON()+
4
+ ": "+d)}return"{"+b.join(", ")+"}"}},keys:function(a){var b=[];for(var c in a)b.push(c);return b},values:function(a){var b=[];for(var c in a)b.push(a[c]);return b},clone:function(a){return Object.extend({},a)}});Function.prototype.bind=function(){var a=this,b=$A(arguments),c=b.shift();return function(){return a.apply(c,b.concat($A(arguments)))}};Function.prototype.bindAsEventListener=function(a){var b=this,c=$A(arguments);a=c.shift();return function(d){return b.apply(a,[d||window.event].concat(c))}};
5
+ Object.extend(Number.prototype,{toColorPart:function(){return this.toPaddedString(2,16)},succ:function(){return this+1},times:function(a){$R(0,this,true).each(a);return this},toPaddedString:function(a,b){var c=this.toString(b||10);return"0".times(a-c.length)+c},toJSON:function(){return isFinite(this)?this.toString():"null"}});
6
+ Date.prototype.toJSON=function(){return'"'+this.getFullYear()+"-"+(this.getMonth()+1).toPaddedString(2)+"-"+this.getDate().toPaddedString(2)+"T"+this.getHours().toPaddedString(2)+":"+this.getMinutes().toPaddedString(2)+":"+this.getSeconds().toPaddedString(2)+'"'};var Try={these:function(){for(var a,b=0,c=arguments.length;b<c;b++){var d=arguments[b];try{a=d();break}catch(e){}}return a}},PeriodicalExecuter=Class.create();
7
+ PeriodicalExecuter.prototype={initialize:function(a,b){this.callback=a;this.frequency=b;this.currentlyExecuting=false;this.registerCallback()},registerCallback:function(){this.timer=setInterval(this.onTimerEvent.bind(this),this.frequency*1E3)},stop:function(){if(this.timer){clearInterval(this.timer);this.timer=null}},onTimerEvent:function(){if(!this.currentlyExecuting)try{this.currentlyExecuting=true;this.callback(this)}finally{this.currentlyExecuting=false}}};
8
+ Object.extend(String,{interpret:function(a){return a==null?"":String(a)},specialChar:{"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r","\\":"\\\\"}});
9
+ Object.extend(String.prototype,{gsub:function(a,b){var c="",d=this,e;for(b=arguments.callee.prepareReplacement(b);d.length>0;)if(e=d.match(a)){c+=d.slice(0,e.index);c+=String.interpret(b(e));d=d.slice(e.index+e[0].length)}else{c+=d;d=""}return c},sub:function(a,b,c){b=this.gsub.prepareReplacement(b);c=c===undefined?1:c;return this.gsub(a,function(d){if(--c<0)return d[0];return b(d)})},scan:function(a,b){this.gsub(a,b);return this},truncate:function(a,b){a=a||30;b=b===undefined?"...":b;return this.length>
10
+ a?this.slice(0,a-b.length)+b:this},strip:function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,"")},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,"img"),"")},extractScripts:function(){var a=new RegExp(Prototype.ScriptFragment,"img"),b=new RegExp(Prototype.ScriptFragment,"im");return(this.match(a)||[]).map(function(c){return(c.match(b)||["",""])[1]})},evalScripts:function(){return this.extractScripts().map(function(a){return eval(a)})},
11
+ escapeHTML:function(){var a=arguments.callee;a.text.data=this;return a.div.innerHTML},unescapeHTML:function(){var a=document.createElement("div");a.innerHTML=this.stripTags();return a.childNodes[0]?a.childNodes.length>1?$A(a.childNodes).inject("",function(b,c){return b+c.nodeValue}):a.childNodes[0].nodeValue:""},toQueryParams:function(a){var b=this.strip().match(/([^?#]*)(#.*)?$/);if(!b)return{};return b[1].split(a||"&").inject({},function(c,d){if((d=d.split("="))[0]){var e=decodeURIComponent(d.shift()),
12
+ f=d.length>1?d.join("="):d[0];if(f!=undefined)f=decodeURIComponent(f);if(e in c){if(c[e].constructor!=Array)c[e]=[c[e]];c[e].push(f)}else c[e]=f}return c})},toArray:function(){return this.split("")},succ:function(){return this.slice(0,this.length-1)+String.fromCharCode(this.charCodeAt(this.length-1)+1)},times:function(a){for(var b="",c=0;c<a;c++)b+=this;return b},camelize:function(){var a=this.split("-"),b=a.length;if(b==1)return a[0];for(var c=this.charAt(0)=="-"?a[0].charAt(0).toUpperCase()+a[0].substring(1):
13
+ a[0],d=1;d<b;d++)c+=a[d].charAt(0).toUpperCase()+a[d].substring(1);return c},capitalize:function(){return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase()},underscore:function(){return this.gsub(/::/,"/").gsub(/([A-Z]+)([A-Z][a-z])/,"#{1}_#{2}").gsub(/([a-z\d])([A-Z])/,"#{1}_#{2}").gsub(/-/,"_").toLowerCase()},dasherize:function(){return this.gsub(/_/,"-")},inspect:function(a){var b=this.gsub(/[\x00-\x1f\\]/,function(c){var d=String.specialChar[c[0]];return d?d:"\\u00"+c[0].charCodeAt().toPaddedString(2,
14
+ 16)});if(a)return'"'+b.replace(/"/g,'\\"')+'"';return"'"+b.replace(/'/g,"\\'")+"'"},toJSON:function(){return this.inspect(true)},unfilterJSON:function(a){return this.sub(a||Prototype.JSONFilter,"#{1}")},evalJSON:function(a){var b=this.unfilterJSON();try{if(!a||/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(b))return eval("("+b+")")}catch(c){}throw new SyntaxError("Badly formed JSON string: "+this.inspect());},include:function(a){return this.indexOf(a)>-1},startsWith:function(a){return this.indexOf(a)===
15
+ 0},endsWith:function(a){var b=this.length-a.length;return b>=0&&this.lastIndexOf(a)===b},empty:function(){return this==""},blank:function(){return/^\s*$/.test(this)}});if(Prototype.Browser.WebKit||Prototype.Browser.IE)Object.extend(String.prototype,{escapeHTML:function(){return this.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},unescapeHTML:function(){return this.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}});
16
+ String.prototype.gsub.prepareReplacement=function(a){if(typeof a=="function")return a;var b=new Template(a);return function(c){return b.evaluate(c)}};String.prototype.parseQuery=String.prototype.toQueryParams;Object.extend(String.prototype.escapeHTML,{div:document.createElement("div"),text:document.createTextNode("")});with(String.prototype.escapeHTML)div.appendChild(text);var Template=Class.create();Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;
17
+ Template.prototype={initialize:function(a,b){this.template=a.toString();this.pattern=b||Template.Pattern},evaluate:function(a){return this.template.gsub(this.pattern,function(b){var c=b[1];if(c=="\\")return b[2];return c+String.interpret(a[b[3]])})}};
18
+ var $break={},$continue=new Error('"throw $continue" is deprecated, use "return" instead'),Enumerable={each:function(a){var b=0;try{this._each(function(d){a(d,b++)})}catch(c){if(c!=$break)throw c;}return this},eachSlice:function(a,b){for(var c=-a,d=[],e=this.toArray();(c+=a)<e.length;)d.push(e.slice(c,c+a));return d.map(b)},all:function(a){var b=true;this.each(function(c,d){b=b&&!!(a||Prototype.K)(c,d);if(!b)throw $break;});return b},any:function(a){var b=false;this.each(function(c,d){if(b=!!(a||
19
+ Prototype.K)(c,d))throw $break;});return b},collect:function(a){var b=[];this.each(function(c,d){b.push((a||Prototype.K)(c,d))});return b},detect:function(a){var b;this.each(function(c,d){if(a(c,d)){b=c;throw $break;}});return b},findAll:function(a){var b=[];this.each(function(c,d){a(c,d)&&b.push(c)});return b},grep:function(a,b){var c=[];this.each(function(d,e){if(d.toString().match(a))c.push((b||Prototype.K)(d,e))});return c},include:function(a){var b=false;this.each(function(c){if(c==a){b=true;
20
+ throw $break;}});return b},inGroupsOf:function(a,b){b=b===undefined?null:b;return this.eachSlice(a,function(c){for(;c.length<a;)c.push(b);return c})},inject:function(a,b){this.each(function(c,d){a=b(a,c,d)});return a},invoke:function(a){var b=$A(arguments).slice(1);return this.map(function(c){return c[a].apply(c,b)})},max:function(a){var b;this.each(function(c,d){c=(a||Prototype.K)(c,d);if(b==undefined||c>=b)b=c});return b},min:function(a){var b;this.each(function(c,d){c=(a||Prototype.K)(c,d);if(b==
21
+ undefined||c<b)b=c});return b},partition:function(a){var b=[],c=[];this.each(function(d,e){((a||Prototype.K)(d,e)?b:c).push(d)});return[b,c]},pluck:function(a){var b=[];this.each(function(c){b.push(c[a])});return b},reject:function(a){var b=[];this.each(function(c,d){a(c,d)||b.push(c)});return b},sortBy:function(a){return this.map(function(b,c){return{value:b,criteria:a(b,c)}}).sort(function(b,c){var d=b.criteria,e=c.criteria;return d<e?-1:d>e?1:0}).pluck("value")},toArray:function(){return this.map()},
22
+ zip:function(){var a=Prototype.K,b=$A(arguments);if(typeof b.last()=="function")a=b.pop();var c=[this].concat(b).map($A);return this.map(function(d,e){return a(c.pluck(e))})},size:function(){return this.toArray().length},inspect:function(){return"#<Enumerable:"+this.toArray().inspect()+">"}};Object.extend(Enumerable,{map:Enumerable.collect,find:Enumerable.detect,select:Enumerable.findAll,member:Enumerable.include,entries:Enumerable.toArray});
23
+ var $A=Array.from=function(a){if(!a)return[];if(a.toArray)return a.toArray();else{for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b}};if(Prototype.Browser.WebKit)$A=Array.from=function(a){if(!a)return[];if(!(typeof a=="function"&&a=="[object NodeList]")&&a.toArray)return a.toArray();else{for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b}};Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse)Array.prototype._reverse=Array.prototype.reverse;
24
+ Object.extend(Array.prototype,{_each:function(a){for(var b=0,c=this.length;b<c;b++)a(this[b])},clear:function(){this.length=0;return this},first:function(){return this[0]},last:function(){return this[this.length-1]},compact:function(){return this.select(function(a){return a!=null})},flatten:function(){return this.inject([],function(a,b){return a.concat(b&&b.constructor==Array?b.flatten():[b])})},without:function(){var a=$A(arguments);return this.select(function(b){return!a.include(b)})},indexOf:function(a){for(var b=
25
+ 0,c=this.length;b<c;b++)if(this[b]==a)return b;return-1},reverse:function(a){return(a!==false?this:this.toArray())._reverse()},reduce:function(){return this.length>1?this:this[0]},uniq:function(a){return this.inject([],function(b,c,d){if(0==d||(a?b.last()!=c:!b.include(c)))b.push(c);return b})},clone:function(){return[].concat(this)},size:function(){return this.length},inspect:function(){return"["+this.map(Object.inspect).join(", ")+"]"},toJSON:function(){var a=[];this.each(function(b){b=Object.toJSON(b);
26
+ b!==undefined&&a.push(b)});return"["+a.join(", ")+"]"}});Array.prototype.toArray=Array.prototype.clone;function $w(a){return(a=a.strip())?a.split(/\s+/):[]}if(Prototype.Browser.Opera)Array.prototype.concat=function(){for(var a=[],b=0,c=this.length;b<c;b++)a.push(this[b]);b=0;for(c=arguments.length;b<c;b++)if(arguments[b].constructor==Array)for(var d=0,e=arguments[b].length;d<e;d++)a.push(arguments[b][d]);else a.push(arguments[b]);return a};
27
+ var Hash=function(a){a instanceof Hash?this.merge(a):Object.extend(this,a||{})};
28
+ Object.extend(Hash,{toQueryString:function(a){var b=[];b.add=arguments.callee.addPair;this.prototype._each.call(a,function(c){if(c.key){var d=c.value;if(d&&typeof d=="object")d.constructor==Array&&d.each(function(e){b.add(c.key,e)});else b.add(c.key,d)}});return b.join("&")},toJSON:function(a){var b=[];this.prototype._each.call(a,function(c){var d=Object.toJSON(c.value);d!==undefined&&b.push(c.key.toJSON()+": "+d)});return"{"+b.join(", ")+"}"}});
29
+ Hash.toQueryString.addPair=function(a,b){a=encodeURIComponent(a);b===undefined?this.push(a):this.push(a+"="+(b==null?"":encodeURIComponent(b)))};Object.extend(Hash.prototype,Enumerable);
30
+ Object.extend(Hash.prototype,{_each:function(a){for(var b in this){var c=this[b];if(!(c&&c==Hash.prototype[b])){var d=[b,c];d.key=b;d.value=c;a(d)}}},keys:function(){return this.pluck("key")},values:function(){return this.pluck("value")},merge:function(a){return $H(a).inject(this,function(b,c){b[c.key]=c.value;return b})},remove:function(){for(var a,b=0,c=arguments.length;b<c;b++){var d=this[arguments[b]];if(d!==undefined)if(a===undefined)a=d;else{if(a.constructor!=Array)a=[a];a.push(d)}delete this[arguments[b]]}return a},
31
+ toQueryString:function(){return Hash.toQueryString(this)},inspect:function(){return"#<Hash:{"+this.map(function(a){return a.map(Object.inspect).join(": ")}).join(", ")+"}>"},toJSON:function(){return Hash.toJSON(this)}});function $H(a){if(a instanceof Hash)return a;return new Hash(a)}
32
+ if(function(){var a=0,b=function(d){this.key=d};b.prototype.key="foo";for(var c in new b("bar"))a++;return a>1}())Hash.prototype._each=function(a){var b=[];for(var c in this){var d=this[c];if(!(d&&d==Hash.prototype[c]||b.include(c))){b.push(c);var e=[c,d];e.key=c;e.value=d;a(e)}}};ObjectRange=Class.create();Object.extend(ObjectRange.prototype,Enumerable);
33
+ Object.extend(ObjectRange.prototype,{initialize:function(a,b,c){this.start=a;this.end=b;this.exclusive=c},_each:function(a){for(var b=this.start;this.include(b);){a(b);b=b.succ()}},include:function(a){if(a<this.start)return false;if(this.exclusive)return a<this.end;return a<=this.end}});
34
+ var $R=function(a,b,c){return new ObjectRange(a,b,c)},Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")})||false},activeRequestCount:0};
35
+ Ajax.Responders={responders:[],_each:function(a){this.responders._each(a)},register:function(a){this.include(a)||this.responders.push(a)},unregister:function(a){this.responders=this.responders.without(a)},dispatch:function(a,b,c,d){this.each(function(e){if(typeof e[a]=="function")try{e[a].apply(e,[b,c,d])}catch(f){}})}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++},onComplete:function(){Ajax.activeRequestCount--}});Ajax.Base=function(){};
36
+ Ajax.Base.prototype={setOptions:function(a){this.options={method:"post",asynchronous:true,contentType:"application/x-www-form-urlencoded",encoding:"UTF-8",parameters:""};Object.extend(this.options,a||{});this.options.method=this.options.method.toLowerCase();if(typeof this.options.parameters=="string")this.options.parameters=this.options.parameters.toQueryParams()}};Ajax.Request=Class.create();Ajax.Request.Events=["Uninitialized","Loading","Loaded","Interactive","Complete"];
37
+ Ajax.Request.prototype=Object.extend(new Ajax.Base,{_complete:false,initialize:function(a,b){this.transport=Ajax.getTransport();this.setOptions(b);this.request(a)},request:function(a){this.url=a;this.method=this.options.method;a=Object.clone(this.options.parameters);if(!["get","post"].include(this.method)){a._method=this.method;this.method="post"}this.parameters=a;if(a=Hash.toQueryString(a))if(this.method=="get")this.url+=(this.url.include("?")?"&":"?")+a;else if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))a+=
38
+ "&_=";try{this.options.onCreate&&this.options.onCreate(this.transport);Ajax.Responders.dispatch("onCreate",this,this.transport);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);this.options.asynchronous&&setTimeout(function(){this.respondToReadyState(1)}.bind(this),10);this.transport.onreadystatechange=this.onStateChange.bind(this);this.setRequestHeaders();this.body=this.method=="post"?this.options.postBody||a:null;this.transport.send(this.body);!this.options.asynchronous&&
39
+ this.transport.overrideMimeType&&this.onStateChange()}catch(b){this.dispatchException(b)}},onStateChange:function(){var a=this.transport.readyState;a>1&&!(a==4&&this._complete)&&this.respondToReadyState(this.transport.readyState)},setRequestHeaders:function(){var a={"X-Requested-With":"XMLHttpRequest","X-Prototype-Version":Prototype.Version,Accept:"text/javascript, text/html, application/xml, text/xml, */*"};if(this.method=="post"){a["Content-type"]=this.options.contentType+(this.options.encoding?
40
+ "; charset="+this.options.encoding:"");if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005)a.Connection="close"}if(typeof this.options.requestHeaders=="object"){var b=this.options.requestHeaders;if(typeof b.push=="function")for(var c=0,d=b.length;c<d;c+=2)a[b[c]]=b[c+1];else $H(b).each(function(f){a[f.key]=f.value})}for(var e in a)this.transport.setRequestHeader(e,a[e])},success:function(){return!this.transport.status||this.transport.status>=200&&this.transport.status<
41
+ 300},respondToReadyState:function(a){a=Ajax.Request.Events[a];var b=this.transport,c=this.evalJSON();if(a=="Complete"){try{this._complete=true;(this.options["on"+this.transport.status]||this.options["on"+(this.success()?"Success":"Failure")]||Prototype.emptyFunction)(b,c)}catch(d){this.dispatchException(d)}var e=this.getHeader("Content-type");e&&e.strip().match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)&&this.evalResponse()}try{(this.options["on"+a]||Prototype.emptyFunction)(b,c);Ajax.Responders.dispatch("on"+
42
+ a,this,b,c)}catch(f){this.dispatchException(f)}if(a=="Complete")this.transport.onreadystatechange=Prototype.emptyFunction},getHeader:function(a){try{return this.transport.getResponseHeader(a)}catch(b){return null}},evalJSON:function(){try{var a=this.getHeader("X-JSON");return a?a.evalJSON():null}catch(b){return null}},evalResponse:function(){try{return eval((this.transport.responseText||"").unfilterJSON())}catch(a){this.dispatchException(a)}},dispatchException:function(a){(this.options.onException||
43
+ Prototype.emptyFunction)(this,a);Ajax.Responders.dispatch("onException",this,a)}});Ajax.Updater=Class.create();
44
+ Object.extend(Object.extend(Ajax.Updater.prototype,Ajax.Request.prototype),{initialize:function(a,b,c){this.container={success:a.success||a,failure:a.failure||(a.success?null:a)};this.transport=Ajax.getTransport();this.setOptions(c);var d=this.options.onComplete||Prototype.emptyFunction;this.options.onComplete=function(e,f){this.updateContent();d(e,f)}.bind(this);this.request(b)},updateContent:function(){var a=this.container[this.success()?"success":"failure"],b=this.transport.responseText;this.options.evalScripts||
45
+ (b=b.stripScripts());if(a=$(a))if(this.options.insertion)new this.options.insertion(a,b);else a.update(b);this.success()&&this.onComplete&&setTimeout(this.onComplete.bind(this),10)}});Ajax.PeriodicalUpdater=Class.create();
46
+ Ajax.PeriodicalUpdater.prototype=Object.extend(new Ajax.Base,{initialize:function(a,b,c){this.setOptions(c);this.onComplete=this.options.onComplete;this.frequency=this.options.frequency||2;this.decay=this.options.decay||1;this.updater={};this.container=a;this.url=b;this.start()},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent()},stop:function(){this.updater.options.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,
47
+ arguments)},updateComplete:function(a){if(this.options.decay){this.decay=a.responseText==this.lastText?this.decay*this.options.decay:1;this.lastText=a.responseText}this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1E3)},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options)}});
48
+ function $(a){if(arguments.length>1){for(var b=0,c=[],d=arguments.length;b<d;b++)c.push($(arguments[b]));return c}if(typeof a=="string")a=document.getElementById(a);return Element.extend(a)}
49
+ if(Prototype.BrowserFeatures.XPath){document._getElementsByXPath=function(a,b){for(var c=[],d=document.evaluate(a,$(b)||document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null),e=0,f=d.snapshotLength;e<f;e++)c.push(d.snapshotItem(e));return c};document.getElementsByClassName=function(a,b){return document._getElementsByXPath(".//*[contains(concat(' ', @class, ' '), ' "+a+" ')]",b)}}else document.getElementsByClassName=function(a,b){for(var c=($(b)||document.body).getElementsByTagName("*"),d=[],e,
50
+ f=0,g=c.length;f<g;f++){e=c[f];Element.hasClassName(e,a)&&d.push(Element.extend(e))}return d};if(!window.Element)var Element={};
51
+ Element.extend=function(a){var b=Prototype.BrowserFeatures;if(!a||!a.tagName||a.nodeType==3||a._extended||b.SpecificElementExtensions||a==window)return a;var c={},d=a.tagName,e=Element.extend.cache,f=Element.Methods.ByTag;if(!b.ElementExtensions){Object.extend(c,Element.Methods);Object.extend(c,Element.Methods.Simulated)}f[d]&&Object.extend(c,f[d]);for(var g in c){b=c[g];if(typeof b=="function"&&!(g in a))a[g]=e.findOrStore(b)}a._extended=Prototype.emptyFunction;return a};
52
+ Element.extend.cache={findOrStore:function(a){return this[a]=this[a]||function(){return a.apply(null,[this].concat($A(arguments)))}}};
53
+ Element.Methods={visible:function(a){return $(a).style.display!="none"},toggle:function(a){a=$(a);Element[Element.visible(a)?"hide":"show"](a);return a},hide:function(a){$(a).style.display="none";return a},show:function(a){$(a).style.display="";return a},remove:function(a){a=$(a);a.parentNode.removeChild(a);return a},update:function(a,b){b=typeof b=="undefined"?"":b.toString();$(a).innerHTML=b.stripScripts();setTimeout(function(){b.evalScripts()},10);return a},replace:function(a,b){a=$(a);b=typeof b==
54
+ "undefined"?"":b.toString();if(a.outerHTML)a.outerHTML=b.stripScripts();else{var c=a.ownerDocument.createRange();c.selectNodeContents(a);a.parentNode.replaceChild(c.createContextualFragment(b.stripScripts()),a)}setTimeout(function(){b.evalScripts()},10);return a},inspect:function(a){a=$(a);var b="<"+a.tagName.toLowerCase();$H({id:"id",className:"class"}).each(function(c){var d=c.first();c=c.last();if(d=(a[d]||"").toString())b+=" "+c+"="+d.inspect(true)});return b+">"},recursivelyCollect:function(a,
55
+ b){a=$(a);for(var c=[];a=a[b];)a.nodeType==1&&c.push(Element.extend(a));return c},ancestors:function(a){return $(a).recursivelyCollect("parentNode")},descendants:function(a){return $A($(a).getElementsByTagName("*")).each(Element.extend)},firstDescendant:function(a){for(a=$(a).firstChild;a&&a.nodeType!=1;)a=a.nextSibling;return $(a)},immediateDescendants:function(a){if(!(a=$(a).firstChild))return[];for(;a&&a.nodeType!=1;)a=a.nextSibling;if(a)return[a].concat($(a).nextSiblings());return[]},previousSiblings:function(a){return $(a).recursivelyCollect("previousSibling")},
56
+ nextSiblings:function(a){return $(a).recursivelyCollect("nextSibling")},siblings:function(a){a=$(a);return a.previousSiblings().reverse().concat(a.nextSiblings())},match:function(a,b){if(typeof b=="string")b=new Selector(b);return b.match($(a))},up:function(a,b,c){a=$(a);if(arguments.length==1)return $(a.parentNode);var d=a.ancestors();return b?Selector.findElement(d,b,c):d[c||0]},down:function(a,b,c){a=$(a);if(arguments.length==1)return a.firstDescendant();var d=a.descendants();return b?Selector.findElement(d,
57
+ b,c):d[c||0]},previous:function(a,b,c){a=$(a);if(arguments.length==1)return $(Selector.handlers.previousElementSibling(a));var d=a.previousSiblings();return b?Selector.findElement(d,b,c):d[c||0]},next:function(a,b,c){a=$(a);if(arguments.length==1)return $(Selector.handlers.nextElementSibling(a));var d=a.nextSiblings();return b?Selector.findElement(d,b,c):d[c||0]},getElementsBySelector:function(){var a=$A(arguments),b=$(a.shift());return Selector.findChildElements(b,a)},getElementsByClassName:function(a,
58
+ b){return document.getElementsByClassName(b,a)},readAttribute:function(a,b){a=$(a);if(Prototype.Browser.IE){if(!a.attributes)return null;var c=Element._attributeTranslations;if(c.values[b])return c.values[b](a,b);if(c.names[b])b=c.names[b];return(c=a.attributes[b])?c.nodeValue:null}return a.getAttribute(b)},getHeight:function(a){return $(a).getDimensions().height},getWidth:function(a){return $(a).getDimensions().width},classNames:function(a){return new Element.ClassNames(a)},hasClassName:function(a,
59
+ b){if(a=$(a)){var c=a.className;if(c.length==0)return false;if(c==b||c.match(new RegExp("(^|\\s)"+b+"(\\s|$)")))return true;return false}},addClassName:function(a,b){if(a=$(a)){Element.classNames(a).add(b);return a}},removeClassName:function(a,b){if(a=$(a)){Element.classNames(a).remove(b);return a}},toggleClassName:function(a,b){if(a=$(a)){Element.classNames(a)[a.hasClassName(b)?"remove":"add"](b);return a}},observe:function(){Event.observe.apply(Event,arguments);return $A(arguments).first()},stopObserving:function(){Event.stopObserving.apply(Event,
60
+ arguments);return $A(arguments).first()},cleanWhitespace:function(a){a=$(a);for(var b=a.firstChild;b;){var c=b.nextSibling;b.nodeType==3&&!/\S/.test(b.nodeValue)&&a.removeChild(b);b=c}return a},empty:function(a){return $(a).innerHTML.blank()},descendantOf:function(a,b){a=$(a);for(b=$(b);a=a.parentNode;)if(a==b)return true;return false},scrollTo:function(a){a=$(a);var b=Position.cumulativeOffset(a);window.scrollTo(b[0],b[1]);return a},getStyle:function(a,b){a=$(a);b=b=="float"?"cssFloat":b.camelize();
61
+ var c=a.style[b];if(!c)c=(c=document.defaultView.getComputedStyle(a,null))?c[b]:null;if(b=="opacity")return c?parseFloat(c):1;return c=="auto"?null:c},getOpacity:function(a){return $(a).getStyle("opacity")},setStyle:function(a,b,c){a=$(a);var d=a.style;for(var e in b)if(e=="opacity")a.setOpacity(b[e]);else d[e=="float"||e=="cssFloat"?d.styleFloat===undefined?"cssFloat":"styleFloat":c?e:e.camelize()]=b[e];return a},setOpacity:function(a,b){a=$(a);a.style.opacity=b==1||b===""?"":b<1.0E-5?0:b;return a},
62
+ getDimensions:function(a){a=$(a);var b=$(a).getStyle("display");if(b!="none"&&b!=null)return{width:a.offsetWidth,height:a.offsetHeight};b=a.style;var c=b.visibility,d=b.position,e=b.display;b.visibility="hidden";b.position="absolute";b.display="block";var f=a.clientWidth;a=a.clientHeight;b.display=e;b.position=d;b.visibility=c;return{width:f,height:a}},makePositioned:function(a){a=$(a);var b=Element.getStyle(a,"position");if(b=="static"||!b){a._madePositioned=true;a.style.position="relative";if(window.opera){a.style.top=
63
+ 0;a.style.left=0}}return a},undoPositioned:function(a){a=$(a);if(a._madePositioned){a._madePositioned=undefined;a.style.position=a.style.top=a.style.left=a.style.bottom=a.style.right=""}return a},makeClipping:function(a){a=$(a);if(a._overflow)return a;a._overflow=a.style.overflow||"auto";if((Element.getStyle(a,"overflow")||"visible")!="hidden")a.style.overflow="hidden";return a},undoClipping:function(a){a=$(a);if(!a._overflow)return a;a.style.overflow=a._overflow=="auto"?"":a._overflow;a._overflow=
64
+ null;return a}};Object.extend(Element.Methods,{childOf:Element.Methods.descendantOf,childElements:Element.Methods.immediateDescendants});
65
+ if(Prototype.Browser.Opera){Element.Methods._getStyle=Element.Methods.getStyle;Element.Methods.getStyle=function(a,b){switch(b){case "left":case "top":case "right":case "bottom":if(Element._getStyle(a,"position")=="static")return null;default:return Element._getStyle(a,b)}}}else if(Prototype.Browser.IE){Element.Methods.getStyle=function(a,b){a=$(a);b=b=="float"||b=="cssFloat"?"styleFloat":b.camelize();var c=a.style[b];if(!c&&a.currentStyle)c=a.currentStyle[b];if(b=="opacity"){if(c=(a.getStyle("filter")||
66
+ "").match(/alpha\(opacity=(.*)\)/))if(c[1])return parseFloat(c[1])/100;return 1}if(c=="auto"){if((b=="width"||b=="height")&&a.getStyle("display")!="none")return a["offset"+b.capitalize()]+"px";return null}return c};Element.Methods.setOpacity=function(a,b){a=$(a);var c=a.getStyle("filter"),d=a.style;if(b==1||b===""){d.filter=c.replace(/alpha\([^\)]*\)/gi,"");return a}else if(b<1.0E-5)b=0;d.filter=c.replace(/alpha\([^\)]*\)/gi,"")+"alpha(opacity="+b*100+")";return a};Element.Methods.update=function(a,
67
+ b){a=$(a);b=typeof b=="undefined"?"":b.toString();var c=a.tagName.toUpperCase();if(["THEAD","TBODY","TR","TD"].include(c)){var d=document.createElement("div");switch(c){case "THEAD":case "TBODY":d.innerHTML="<table><tbody>"+b.stripScripts()+"</tbody></table>";depth=2;break;case "TR":d.innerHTML="<table><tbody><tr>"+b.stripScripts()+"</tr></tbody></table>";depth=3;break;case "TD":d.innerHTML="<table><tbody><tr><td>"+b.stripScripts()+"</td></tr></tbody></table>";depth=4}$A(a.childNodes).each(function(e){a.removeChild(e)});
68
+ depth.times(function(){d=d.firstChild});$A(d.childNodes).each(function(e){a.appendChild(e)})}else a.innerHTML=b.stripScripts();setTimeout(function(){b.evalScripts()},10);return a}}else if(Prototype.Browser.Gecko)Element.Methods.setOpacity=function(a,b){a=$(a);a.style.opacity=b==1?0.999999:b===""?"":b<1.0E-5?0:b;return a};
69
+ Element._attributeTranslations={names:{colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",datetime:"dateTime",accesskey:"accessKey",tabindex:"tabIndex",enctype:"encType",maxlength:"maxLength",readonly:"readOnly",longdesc:"longDesc"},values:{_getAttr:function(a,b){return a.getAttribute(b,2)},_flag:function(a,b){return $(a).hasAttribute(b)?b:null},style:function(a){return a.style.cssText.toLowerCase()},title:function(a){a=a.getAttributeNode("title");return a.specified?a.nodeValue:null}}};
70
+ (function(){Object.extend(this,{href:this._getAttr,src:this._getAttr,type:this._getAttr,disabled:this._flag,checked:this._flag,readonly:this._flag,multiple:this._flag})}).call(Element._attributeTranslations.values);Element.Methods.Simulated={hasAttribute:function(a,b){var c;b=Element._attributeTranslations.names[b]||b;return(c=$(a).getAttributeNode(b))&&c.specified}};Element.Methods.ByTag={};Object.extend(Element,Element.Methods);
71
+ if(!Prototype.BrowserFeatures.ElementExtensions&&document.createElement("div").__proto__){window.HTMLElement={};window.HTMLElement.prototype=document.createElement("div").__proto__;Prototype.BrowserFeatures.ElementExtensions=true}Element.hasAttribute=function(a,b){if(a.hasAttribute)return a.hasAttribute(b);return Element.Methods.Simulated.hasAttribute(a,b)};
72
+ Element.addMethods=function(a){function b(i){i=i.toUpperCase();Element.Methods.ByTag[i]||(Element.Methods.ByTag[i]={});Object.extend(Element.Methods.ByTag[i],a)}function c(i,j,k){var m=Element.extend.cache;for(var l in i){var n=i[l];if(!(k||false)||!(l in j))j[l]=m.findOrStore(n)}}function d(i){var j,k={OPTGROUP:"OptGroup",TEXTAREA:"TextArea",P:"Paragraph",FIELDSET:"FieldSet",UL:"UList",OL:"OList",DL:"DList",DIR:"Directory",H1:"Heading",H2:"Heading",H3:"Heading",H4:"Heading",H5:"Heading",H6:"Heading",
73
+ Q:"Quote",INS:"Mod",DEL:"Mod",A:"Anchor",IMG:"Image",CAPTION:"TableCaption",COL:"TableCol",COLGROUP:"TableCol",THEAD:"TableSection",TFOOT:"TableSection",TBODY:"TableSection",TR:"TableRow",TH:"TableCell",TD:"TableCell",FRAMESET:"FrameSet",IFRAME:"IFrame"};if(k[i])j="HTML"+k[i]+"Element";if(window[j])return window[j];j="HTML"+i+"Element";if(window[j])return window[j];j="HTML"+i.capitalize()+"Element";if(window[j])return window[j];window[j]={};window[j].prototype=document.createElement(i).__proto__;
74
+ return window[j]}var e=Prototype.BrowserFeatures,f=Element.Methods.ByTag;if(!a){Object.extend(Form,Form.Methods);Object.extend(Form.Element,Form.Element.Methods);Object.extend(Element.Methods.ByTag,{FORM:Object.clone(Form.Methods),INPUT:Object.clone(Form.Element.Methods),SELECT:Object.clone(Form.Element.Methods),TEXTAREA:Object.clone(Form.Element.Methods)})}if(arguments.length==2){var g=a;a=arguments[1]}if(g)g.constructor==Array?g.each(b):b(g);else Object.extend(Element.Methods,a||{});if(e.ElementExtensions){c(Element.Methods,
75
+ HTMLElement.prototype);c(Element.Methods.Simulated,HTMLElement.prototype,true)}if(e.SpecificElementExtensions)for(var h in Element.Methods.ByTag){e=d(h);typeof e!="undefined"&&c(f[h],e.prototype)}Object.extend(Element,Element.Methods);delete Element.ByTag};var Toggle={display:Element.toggle};Abstract.Insertion=function(a){this.adjacency=a};
76
+ Abstract.Insertion.prototype={initialize:function(a,b){this.element=$(a);this.content=b.stripScripts();if(this.adjacency&&this.element.insertAdjacentHTML)try{this.element.insertAdjacentHTML(this.adjacency,this.content)}catch(c){if(["TBODY","TR"].include(this.element.tagName.toUpperCase()))this.insertContent(this.contentFromAnonymousTable());else throw c;}else{this.range=this.element.ownerDocument.createRange();this.initializeRange&&this.initializeRange();this.insertContent([this.range.createContextualFragment(this.content)])}setTimeout(function(){b.evalScripts()},
77
+ 10)},contentFromAnonymousTable:function(){var a=document.createElement("div");a.innerHTML="<table><tbody>"+this.content+"</tbody></table>";return $A(a.childNodes[0].childNodes[0].childNodes)}};var Insertion={};Insertion.Before=Class.create();Insertion.Before.prototype=Object.extend(new Abstract.Insertion("beforeBegin"),{initializeRange:function(){this.range.setStartBefore(this.element)},insertContent:function(a){a.each(function(b){this.element.parentNode.insertBefore(b,this.element)}.bind(this))}});
78
+ Insertion.Top=Class.create();Insertion.Top.prototype=Object.extend(new Abstract.Insertion("afterBegin"),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(true)},insertContent:function(a){a.reverse(false).each(function(b){this.element.insertBefore(b,this.element.firstChild)}.bind(this))}});Insertion.Bottom=Class.create();
79
+ Insertion.Bottom.prototype=Object.extend(new Abstract.Insertion("beforeEnd"),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(this.element)},insertContent:function(a){a.each(function(b){this.element.appendChild(b)}.bind(this))}});Insertion.After=Class.create();
80
+ Insertion.After.prototype=Object.extend(new Abstract.Insertion("afterEnd"),{initializeRange:function(){this.range.setStartAfter(this.element)},insertContent:function(a){a.each(function(b){this.element.parentNode.insertBefore(b,this.element.nextSibling)}.bind(this))}});Element.ClassNames=Class.create();
81
+ Element.ClassNames.prototype={initialize:function(a){this.element=$(a)},_each:function(a){this.element.className.split(/\s+/).select(function(b){return b.length>0})._each(a)},set:function(a){this.element.className=a},add:function(a){this.include(a)||this.set($A(this).concat(a).join(" "))},remove:function(a){this.include(a)&&this.set($A(this).without(a).join(" "))},toString:function(){return $A(this).join(" ")}};Object.extend(Element.ClassNames.prototype,Enumerable);var Selector=Class.create();
82
+ Selector.prototype={initialize:function(a){this.expression=a.strip();this.compileMatcher()},compileMatcher:function(){if(Prototype.BrowserFeatures.XPath&&!/\[[\w-]*?:/.test(this.expression))return this.compileXPathMatcher();var a=this.expression,b=Selector.patterns,c=Selector.criteria,d,e;if(Selector._cache[a])this.matcher=Selector._cache[a];else{for(this.matcher=["this.matcher = function(root) {","var r = root, h = Selector.handlers, c = false, n;"];a&&d!=a&&/\S/.test(a);){d=a;for(var f in b){e=
83
+ b[f];if(e=a.match(e)){this.matcher.push(typeof c[f]=="function"?c[f](e):(new Template(c[f])).evaluate(e));a=a.replace(e[0],"");break}}}this.matcher.push("return h.unique(n);\n}");eval(this.matcher.join("\n"));Selector._cache[this.expression]=this.matcher}},compileXPathMatcher:function(){var a=this.expression,b=Selector.patterns,c=Selector.xpath,d,e;if(Selector._cache[a])this.xpath=Selector._cache[a];else{for(this.matcher=[".//*"];a&&d!=a&&/\S/.test(a);){d=a;for(var f in b)if(e=a.match(b[f])){this.matcher.push(typeof c[f]==
84
+ "function"?c[f](e):(new Template(c[f])).evaluate(e));a=a.replace(e[0],"");break}}this.xpath=this.matcher.join("");Selector._cache[this.expression]=this.xpath}},findElements:function(a){a=a||document;if(this.xpath)return document._getElementsByXPath(this.xpath,a);return this.matcher(a)},match:function(a){return this.findElements(document).include(a)},toString:function(){return this.expression},inspect:function(){return"#<Selector:"+this.expression.inspect()+">"}};
85
+ Object.extend(Selector,{_cache:{},xpath:{descendant:"//*",child:"/*",adjacent:"/following-sibling::*[1]",laterSibling:"/following-sibling::*",tagName:function(a){if(a[1]=="*")return"";return"[local-name()='"+a[1].toLowerCase()+"' or local-name()='"+a[1].toUpperCase()+"']"},className:"[contains(concat(' ', @class, ' '), ' #{1} ')]",id:"[@id='#{1}']",attrPresence:"[@#{1}]",attr:function(a){a[3]=a[5]||a[6];return(new Template(Selector.xpath.operators[a[2]])).evaluate(a)},pseudo:function(a){var b=Selector.xpath.pseudos[a[1]];
86
+ if(!b)return"";if(typeof b==="function")return b(a);return(new Template(Selector.xpath.pseudos[a[1]])).evaluate(a)},operators:{"=":"[@#{1}='#{3}']","!=":"[@#{1}!='#{3}']","^=":"[starts-with(@#{1}, '#{3}')]","$=":"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']","*=":"[contains(@#{1}, '#{3}')]","~=":"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]","|=":"[contains(concat('-', @#{1}, '-'), '-#{3}-')]"},pseudos:{"first-child":"[not(preceding-sibling::*)]","last-child":"[not(following-sibling::*)]",
87
+ "only-child":"[not(preceding-sibling::* or following-sibling::*)]",empty:"[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",checked:"[@checked]",disabled:"[@disabled]",enabled:"[not(@disabled)]",not:function(a){for(var b=a[6],c=Selector.patterns,d=Selector.xpath,e,f,g=[];b&&e!=b&&/\S/.test(b);){e=b;for(var h in c)if(a=b.match(c[h])){f=typeof d[h]=="function"?d[h](a):(new Template(d[h])).evaluate(a);g.push("("+f.substring(1,f.length-1)+")");b=b.replace(a[0],"");break}}return"[not("+
88
+ g.join(" and ")+")]"},"nth-child":function(a){return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ",a)},"nth-last-child":function(a){return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ",a)},"nth-of-type":function(a){return Selector.xpath.pseudos.nth("position() ",a)},"nth-last-of-type":function(a){return Selector.xpath.pseudos.nth("(last() + 1 - position()) ",a)},"first-of-type":function(a){a[6]="1";return Selector.xpath.pseudos["nth-of-type"](a)},"last-of-type":function(a){a[6]=
89
+ "1";return Selector.xpath.pseudos["nth-last-of-type"](a)},"only-of-type":function(a){var b=Selector.xpath.pseudos;return b["first-of-type"](a)+b["last-of-type"](a)},nth:function(a,b){var c,d=b[6];if(d=="even")d="2n+0";if(d=="odd")d="2n+1";if(c=d.match(/^(\d+)$/))return"["+a+"= "+c[1]+"]";if(c=d.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(c[1]=="-")c[1]=-1;d=c[1]?Number(c[1]):1;c=c[2]?Number(c[2]):0;return(new Template("[((#{fragment} - #{b}) mod #{a} = 0) and ((#{fragment} - #{b}) div #{a} >= 0)]")).evaluate({fragment:a,
90
+ a:d,b:c})}}}},criteria:{tagName:'n = h.tagName(n, r, "#{1}", c); c = false;',className:'n = h.className(n, r, "#{1}", c); c = false;',id:'n = h.id(n, r, "#{1}", c); c = false;',attrPresence:'n = h.attrPresence(n, r, "#{1}"); c = false;',attr:function(a){a[3]=a[5]||a[6];return(new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;')).evaluate(a)},pseudo:function(a){if(a[6])a[6]=a[6].replace(/"/g,'\\"');return(new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;')).evaluate(a)},
91
+ descendant:'c = "descendant";',child:'c = "child";',adjacent:'c = "adjacent";',laterSibling:'c = "laterSibling";'},patterns:{laterSibling:/^\s*~\s*/,child:/^\s*>\s*/,adjacent:/^\s*\+\s*/,descendant:/^\s/,tagName:/^\s*(\*|[\w\-]+)(\b|$)?/,id:/^#([\w\-\*]+)(\b|$)/,className:/^\.([\w\-\*]+)(\b|$)/,pseudo:/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,attrPresence:/^\[([\w]+)\]/,attr:/\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/},
92
+ handlers:{concat:function(a,b){for(var c=0,d;d=b[c];c++)a.push(d);return a},mark:function(a){for(var b=0,c;c=a[b];b++)c._counted=true;return a},unmark:function(a){for(var b=0,c;c=a[b];b++)c._counted=undefined;return a},index:function(a,b,c){a._counted=true;if(b){a=a.childNodes;b=a.length-1;for(var d=1;b>=0;b--){node=a[b];if(node.nodeType==1&&(!c||node._counted))node.nodeIndex=d++}}else{b=0;d=1;for(a=a.childNodes;node=a[b];b++)if(node.nodeType==1&&(!c||node._counted))node.nodeIndex=d++}},unique:function(a){if(a.length==
93
+ 0)return a;for(var b=[],c,d=0,e=a.length;d<e;d++)if(!(c=a[d])._counted){c._counted=true;b.push(Element.extend(c))}return Selector.handlers.unmark(b)},descendant:function(a){for(var b=Selector.handlers,c=0,d=[],e;e=a[c];c++)b.concat(d,e.getElementsByTagName("*"));return d},child:function(a){for(var b=0,c=[],d;d=a[b];b++)for(var e=0,f;f=d.childNodes[e];e++)f.nodeType==1&&f.tagName!="!"&&c.push(f);return c},adjacent:function(a){for(var b=0,c=[],d;d=a[b];b++)(d=this.nextElementSibling(d))&&c.push(d);
94
+ return c},laterSibling:function(a){for(var b=Selector.handlers,c=0,d=[],e;e=a[c];c++)b.concat(d,Element.nextSiblings(e));return d},nextElementSibling:function(a){for(;a=a.nextSibling;)if(a.nodeType==1)return a;return null},previousElementSibling:function(a){for(;a=a.previousSibling;)if(a.nodeType==1)return a;return null},tagName:function(a,b,c,d){c=c.toUpperCase();var e=[],f=Selector.handlers;if(a){if(d){if(d=="descendant"){for(b=0;d=a[b];b++)f.concat(e,d.getElementsByTagName(c));return e}else a=
95
+ this[d](a);if(c=="*")return a}for(b=0;d=a[b];b++)d.tagName.toUpperCase()==c&&e.push(d);return e}else return b.getElementsByTagName(c)},id:function(a,b,c,d){c=$(c);var e=Selector.handlers;if(!a&&b==document)return c?[c]:[];if(a){if(d)if(d=="child")for(b=0;d=a[b];b++){if(c.parentNode==d)return[c]}else if(d=="descendant")for(b=0;d=a[b];b++){if(Element.descendantOf(c,d))return[c]}else if(d=="adjacent")for(b=0;d=a[b];b++){if(Selector.handlers.previousElementSibling(c)==d)return[c]}else a=e[d](a);for(b=
96
+ 0;d=a[b];b++)if(d==c)return[c];return[]}return c&&Element.descendantOf(c,b)?[c]:[]},className:function(a,b,c,d){if(a&&d)a=this[d](a);return Selector.handlers.byClassName(a,b,c)},byClassName:function(a,b,c){a||(a=Selector.handlers.descendant([b]));b=0;for(var d=[],e,f;e=a[b];b++){f=e.className;if(f.length!=0)if(f==c||(" "+f+" ").include(" "+c+" "))d.push(e)}return d},attrPresence:function(a,b,c){b=[];for(var d=0,e;e=a[d];d++)Element.hasAttribute(e,c)&&b.push(e);return b},attr:function(a,b,c,d,e){a||
97
+ (a=b.getElementsByTagName("*"));b=Selector.operators[e];e=[];for(var f=0,g;g=a[f];f++){var h=Element.readAttribute(g,c);h!==null&&b(h,d)&&e.push(g)}return e},pseudo:function(a,b,c,d,e){if(a&&e)a=this[e](a);a||(a=d.getElementsByTagName("*"));return Selector.pseudos[b](a,c,d)}},pseudos:{"first-child":function(a){for(var b=0,c=[],d;d=a[b];b++)Selector.handlers.previousElementSibling(d)||c.push(d);return c},"last-child":function(a){for(var b=0,c=[],d;d=a[b];b++)Selector.handlers.nextElementSibling(d)||
98
+ c.push(d);return c},"only-child":function(a){for(var b=Selector.handlers,c=0,d=[],e;e=a[c];c++)!b.previousElementSibling(e)&&!b.nextElementSibling(e)&&d.push(e);return d},"nth-child":function(a,b,c){return Selector.pseudos.nth(a,b,c)},"nth-last-child":function(a,b,c){return Selector.pseudos.nth(a,b,c,true)},"nth-of-type":function(a,b,c){return Selector.pseudos.nth(a,b,c,false,true)},"nth-last-of-type":function(a,b,c){return Selector.pseudos.nth(a,b,c,true,true)},"first-of-type":function(a,b,c){return Selector.pseudos.nth(a,
99
+ "1",c,false,true)},"last-of-type":function(a,b,c){return Selector.pseudos.nth(a,"1",c,true,true)},"only-of-type":function(a,b,c){var d=Selector.pseudos;return d["last-of-type"](d["first-of-type"](a,b,c),b,c)},getIndices:function(a,b,c){if(a==0)return b>0?[b]:[];return $R(1,c).inject([],function(d,e){0==(e-b)%a&&(e-b)/a>=0&&d.push(e);return d})},nth:function(a,b,c,d,e){if(a.length==0)return[];if(b=="even")b="2n+0";if(b=="odd")b="2n+1";c=Selector.handlers;var f=[],g=[],h;c.mark(a);for(var i=0;h=a[i];i++)if(!h.parentNode._counted){c.index(h.parentNode,
100
+ d,e);g.push(h.parentNode)}if(b.match(/^\d+$/)){b=Number(b);for(i=0;h=a[i];i++)h.nodeIndex==b&&f.push(h)}else if(h=b.match(/^(-?\d*)?n(([+-])(\d+))?/)){if(h[1]=="-")h[1]=-1;i=h[1]?Number(h[1]):1;h=h[2]?Number(h[2]):0;b=Selector.pseudos.getIndices(i,h,a.length);i=0;for(d=b.length;h=a[i];i++)for(e=0;e<d;e++)h.nodeIndex==b[e]&&f.push(h)}c.unmark(a);c.unmark(g);return f},empty:function(a){for(var b=0,c=[],d;d=a[b];b++)d.tagName=="!"||d.firstChild&&!d.innerHTML.match(/^\s*$/)||c.push(d);return c},not:function(a,
101
+ b,c){var d=Selector.handlers;b=(new Selector(b)).findElements(c);d.mark(b);c=0;for(var e=[],f;f=a[c];c++)f._counted||e.push(f);d.unmark(b);return e},enabled:function(a){for(var b=0,c=[],d;d=a[b];b++)d.disabled||c.push(d);return c},disabled:function(a){for(var b=0,c=[],d;d=a[b];b++)d.disabled&&c.push(d);return c},checked:function(a){for(var b=0,c=[],d;d=a[b];b++)d.checked&&c.push(d);return c}},operators:{"=":function(a,b){return a==b},"!=":function(a,b){return a!=b},"^=":function(a,b){return a.startsWith(b)},
102
+ "$=":function(a,b){return a.endsWith(b)},"*=":function(a,b){return a.include(b)},"~=":function(a,b){return(" "+a+" ").include(" "+b+" ")},"|=":function(a,b){return("-"+a.toUpperCase()+"-").include("-"+b.toUpperCase()+"-")}},matchElements:function(a,b){var c=(new Selector(b)).findElements(),d=Selector.handlers;d.mark(c);for(var e=0,f=[],g;g=a[e];e++)g._counted&&f.push(g);d.unmark(c);return f},findElement:function(a,b,c){if(typeof b=="number"){c=b;b=false}return Selector.matchElements(a,b||"*")[c||
103
+ 0]},findChildElements:function(a,b){var c=b.join(",");b=[];c.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/,function(h){b.push(h[1].strip())});c=[];for(var d=Selector.handlers,e=0,f=b.length,g;e<f;e++){g=new Selector(b[e].strip());d.concat(c,g.findElements(a))}return f>1?d.unique(c):c}});function $$(){return Selector.findChildElements(document,$A(arguments))}
104
+ var Form={reset:function(a){$(a).reset();return a},serializeElements:function(a,b){var c=a.inject({},function(d,e){if(!e.disabled&&e.name){var f=e.name,g=$(e).getValue();if(g!=null)if(f in d){if(d[f].constructor!=Array)d[f]=[d[f]];d[f].push(g)}else d[f]=g}return d});return b?c:Hash.toQueryString(c)}};
105
+ Form.Methods={serialize:function(a,b){return Form.serializeElements(Form.getElements(a),b)},getElements:function(a){return $A($(a).getElementsByTagName("*")).inject([],function(b,c){Form.Element.Serializers[c.tagName.toLowerCase()]&&b.push(Element.extend(c));return b})},getInputs:function(a,b,c){a=$(a);a=a.getElementsByTagName("input");if(!b&&!c)return $A(a).map(Element.extend);for(var d=0,e=[],f=a.length;d<f;d++){var g=a[d];b&&g.type!=b||c&&g.name!=c||e.push(Element.extend(g))}return e},disable:function(a){a=
106
+ $(a);Form.getElements(a).invoke("disable");return a},enable:function(a){a=$(a);Form.getElements(a).invoke("enable");return a},findFirstElement:function(a){return $(a).getElements().find(function(b){return b.type!="hidden"&&!b.disabled&&["input","select","textarea"].include(b.tagName.toLowerCase())})},focusFirstElement:function(a){a=$(a);a.findFirstElement().activate();return a},request:function(a,b){a=$(a);b=Object.clone(b||{});var c=b.parameters;b.parameters=a.serialize(true);if(c){if(typeof c==
107
+ "string")c=c.toQueryParams();Object.extend(b.parameters,c)}if(a.hasAttribute("method")&&!b.method)b.method=a.method;return new Ajax.Request(a.readAttribute("action"),b)}};Form.Element={focus:function(a){$(a).focus();return a},select:function(a){$(a).select();return a}};
108
+ Form.Element.Methods={serialize:function(a){a=$(a);if(!a.disabled&&a.name){var b=a.getValue();if(b!=undefined){var c={};c[a.name]=b;return Hash.toQueryString(c)}}return""},getValue:function(a){a=$(a);var b=a.tagName.toLowerCase();return Form.Element.Serializers[b](a)},clear:function(a){$(a).value="";return a},present:function(a){return $(a).value!=""},activate:function(a){a=$(a);try{a.focus();if(a.select&&(a.tagName.toLowerCase()!="input"||!["button","reset","submit"].include(a.type)))a.select()}catch(b){}return a},
109
+ disable:function(a){a=$(a);a.blur();a.disabled=true;return a},enable:function(a){a=$(a);a.disabled=false;return a}};var Field=Form.Element,$F=Form.Element.Methods.getValue;
110
+ Form.Element.Serializers={input:function(a){switch(a.type.toLowerCase()){case "checkbox":case "radio":return Form.Element.Serializers.inputSelector(a);default:return Form.Element.Serializers.textarea(a)}},inputSelector:function(a){return a.checked?a.value:null},textarea:function(a){return a.value},select:function(a){return this[a.type=="select-one"?"selectOne":"selectMany"](a)},selectOne:function(a){var b=a.selectedIndex;return b>=0?this.optionValue(a.options[b]):null},selectMany:function(a){var b,
111
+ c=a.length;if(!c)return null;var d=0;for(b=[];d<c;d++){var e=a.options[d];e.selected&&b.push(this.optionValue(e))}return b},optionValue:function(a){return Element.extend(a).hasAttribute("value")?a.value:a.text}};Abstract.TimedObserver=function(){};
112
+ Abstract.TimedObserver.prototype={initialize:function(a,b,c){this.frequency=b;this.element=$(a);this.callback=c;this.lastValue=this.getValue();this.registerCallback()},registerCallback:function(){setInterval(this.onTimerEvent.bind(this),this.frequency*1E3)},onTimerEvent:function(){var a=this.getValue();if("string"==typeof this.lastValue&&"string"==typeof a?this.lastValue!=a:String(this.lastValue)!=String(a)){this.callback(this.element,a);this.lastValue=a}}};Form.Element.Observer=Class.create();
113
+ Form.Element.Observer.prototype=Object.extend(new Abstract.TimedObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.Observer=Class.create();Form.Observer.prototype=Object.extend(new Abstract.TimedObserver,{getValue:function(){return Form.serialize(this.element)}});Abstract.EventObserver=function(){};
114
+ Abstract.EventObserver.prototype={initialize:function(a,b){this.element=$(a);this.callback=b;this.lastValue=this.getValue();this.element.tagName.toLowerCase()=="form"?this.registerFormCallbacks():this.registerCallback(this.element)},onElementEvent:function(){var a=this.getValue();if(this.lastValue!=a){this.callback(this.element,a);this.lastValue=a}},registerFormCallbacks:function(){Form.getElements(this.element).each(this.registerCallback.bind(this))},registerCallback:function(a){if(a.type)switch(a.type.toLowerCase()){case "checkbox":case "radio":Event.observe(a,
115
+ "click",this.onElementEvent.bind(this));break;default:Event.observe(a,"change",this.onElementEvent.bind(this));break}}};Form.Element.EventObserver=Class.create();Form.Element.EventObserver.prototype=Object.extend(new Abstract.EventObserver,{getValue:function(){return Form.Element.getValue(this.element)}});Form.EventObserver=Class.create();Form.EventObserver.prototype=Object.extend(new Abstract.EventObserver,{getValue:function(){return Form.serialize(this.element)}});if(!window.Event)var Event={};
116
+ Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_HOME:36,KEY_END:35,KEY_PAGEUP:33,KEY_PAGEDOWN:34,element:function(a){return $(a.target||a.srcElement)},isLeftClick:function(a){return a.which&&a.which==1||a.button&&a.button==1},pointerX:function(a){return a.pageX||a.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft)},pointerY:function(a){return a.pageY||a.clientY+(document.documentElement.scrollTop||
117
+ document.body.scrollTop)},stop:function(a){if(a.preventDefault){a.preventDefault();a.stopPropagation()}else{a.returnValue=false;a.cancelBubble=true}},findElement:function(a,b){for(var c=Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observers:false,_observeAndCache:function(a,b,c,d){if(!this.observers)this.observers=[];if(a.addEventListener){this.observers.push([a,b,c,d]);a.addEventListener(b,c,d)}else if(a.attachEvent){this.observers.push([a,
118
+ b,c,d]);a.attachEvent("on"+b,c)}},unloadCache:function(){if(Event.observers){for(var a=0,b=Event.observers.length;a<b;a++){Event.stopObserving.apply(this,Event.observers[a]);Event.observers[a][0]=null}Event.observers=false}},observe:function(a,b,c,d){a=$(a);if(b=="keypress"&&(Prototype.Browser.WebKit||a.attachEvent))b="keydown";Event._observeAndCache(a,b,c,d||false)},stopObserving:function(a,b,c,d){a=$(a);d=d||false;if(b=="keypress"&&(Prototype.Browser.WebKit||a.attachEvent))b="keydown";if(a.removeEventListener)a.removeEventListener(b,
119
+ c,d);else if(a.detachEvent)try{a.detachEvent("on"+b,c)}catch(e){}}});Prototype.Browser.IE&&Event.observe(window,"unload",Event.unloadCache,false);
120
+ var Position={includeScrollOffsets:false,prepare:function(){this.deltaX=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;this.deltaY=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},realOffset:function(a){var b=0,c=0;do{b+=a.scrollTop||0;c+=a.scrollLeft||0;a=a.parentNode}while(a);return[c,b]},cumulativeOffset:function(a){var b=0,c=0;do{b+=a.offsetTop||0;c+=a.offsetLeft||0;a=a.offsetParent}while(a);return[c,b]},positionedOffset:function(a){var b=
121
+ 0,c=0;do{b+=a.offsetTop||0;c+=a.offsetLeft||0;if(a=a.offsetParent){if(a.tagName=="BODY")break;var d=Element.getStyle(a,"position");if(d=="relative"||d=="absolute")break}}while(a);return[c,b]},offsetParent:function(a){if(a.offsetParent)return a.offsetParent;if(a==document.body)return a;for(;(a=a.parentNode)&&a!=document.body;)if(Element.getStyle(a,"position")!="static")return a;return document.body},within:function(a,b,c){if(this.includeScrollOffsets)return this.withinIncludingScrolloffsets(a,b,c);
122
+ this.xcomp=b;this.ycomp=c;this.offset=this.cumulativeOffset(a);return c>=this.offset[1]&&c<this.offset[1]+a.offsetHeight&&b>=this.offset[0]&&b<this.offset[0]+a.offsetWidth},withinIncludingScrolloffsets:function(a,b,c){var d=this.realOffset(a);this.xcomp=b+d[0]-this.deltaX;this.ycomp=c+d[1]-this.deltaY;this.offset=this.cumulativeOffset(a);return this.ycomp>=this.offset[1]&&this.ycomp<this.offset[1]+a.offsetHeight&&this.xcomp>=this.offset[0]&&this.xcomp<this.offset[0]+a.offsetWidth},overlap:function(a,
123
+ b){if(!a)return 0;if(a=="vertical")return(this.offset[1]+b.offsetHeight-this.ycomp)/b.offsetHeight;if(a=="horizontal")return(this.offset[0]+b.offsetWidth-this.xcomp)/b.offsetWidth},page:function(a){var b=0,c=0,d=a;do{b+=d.offsetTop||0;c+=d.offsetLeft||0;if(d.offsetParent==document.body)if(Element.getStyle(d,"position")=="absolute")break}while(d=d.offsetParent);d=a;do if(!window.opera||d.tagName=="BODY"){b-=d.scrollTop||0;c-=d.scrollLeft||0}while(d=d.parentNode);return[c,b]},clone:function(a,b,c){c=
124
+ Object.extend({setLeft:true,setTop:true,setWidth:true,setHeight:true,offsetTop:0,offsetLeft:0},c||{});a=$(a);var d=Position.page(a);b=$(b);var e=[0,0],f=null;if(Element.getStyle(b,"position")=="absolute"){f=Position.offsetParent(b);e=Position.page(f)}if(f==document.body){e[0]-=document.body.offsetLeft;e[1]-=document.body.offsetTop}if(c.setLeft)b.style.left=d[0]-e[0]+c.offsetLeft+"px";if(c.setTop)b.style.top=d[1]-e[1]+c.offsetTop+"px";if(c.setWidth)b.style.width=a.offsetWidth+"px";if(c.setHeight)b.style.height=
125
+ a.offsetHeight+"px"},absolutize:function(a){a=$(a);if(a.style.position!="absolute"){Position.prepare();var b=Position.positionedOffset(a),c=b[1];b=b[0];var d=a.clientWidth,e=a.clientHeight;a._originalLeft=b-parseFloat(a.style.left||0);a._originalTop=c-parseFloat(a.style.top||0);a._originalWidth=a.style.width;a._originalHeight=a.style.height;a.style.position="absolute";a.style.top=c+"px";a.style.left=b+"px";a.style.width=d+"px";a.style.height=e+"px"}},relativize:function(a){a=$(a);if(a.style.position!=
126
+ "relative"){Position.prepare();a.style.position="relative";var b=parseFloat(a.style.top||0)-(a._originalTop||0),c=parseFloat(a.style.left||0)-(a._originalLeft||0);a.style.top=b+"px";a.style.left=c+"px";a.style.height=a._originalHeight;a.style.width=a._originalWidth}}};
127
+ if(Prototype.Browser.WebKit)Position.cumulativeOffset=function(a){var b=0,c=0;do{b+=a.offsetTop||0;c+=a.offsetLeft||0;if(a.offsetParent==document.body)if(Element.getStyle(a,"position")=="absolute")break;a=a.offsetParent}while(a);return[c,b]};Element.addMethods();String.prototype.parseColor=function(a){var b="#";if(this.slice(0,4)=="rgb("){var c=this.slice(4,this.length-1).split(","),d=0;do b+=parseInt(c[d]).toColorPart();while(++d<3)}else if(this.slice(0,1)=="#"){if(this.length==4)for(d=1;d<4;d++)b+=(this.charAt(d)+this.charAt(d)).toLowerCase();if(this.length==7)b=this.toLowerCase()}return b.length==7?b:a||this};
128
+ Element.collectTextNodes=function(a){return $A($(a).childNodes).collect(function(b){return b.nodeType==3?b.nodeValue:b.hasChildNodes()?Element.collectTextNodes(b):""}).flatten().join("")};Element.collectTextNodesIgnoreClass=function(a,b){return $A($(a).childNodes).collect(function(c){return c.nodeType==3?c.nodeValue:c.hasChildNodes()&&!Element.hasClassName(c,b)?Element.collectTextNodesIgnoreClass(c,b):""}).flatten().join("")};
129
+ Element.setContentZoom=function(a,b){a=$(a);a.setStyle({fontSize:b/100+"em"});Prototype.Browser.WebKit&&window.scrollBy(0,0);return a};Element.getInlineOpacity=function(a){return $(a).style.opacity||""};Element.forceRerendering=function(a){try{a=$(a);var b=document.createTextNode(" ");a.appendChild(b);a.removeChild(b)}catch(c){}};Array.prototype.call=function(){var a=arguments;this.each(function(b){b.apply(this,a)})};
130
+ var Effect={_elementDoesNotExistError:{name:"ElementDoesNotExistError",message:"The specified DOM element does not exist, but is required for this effect to operate"},tagifyText:function(a){if(typeof Builder=="undefined")throw"Effect.tagifyText requires including script.aculo.us' builder.js library";var b="position:relative";if(Prototype.Browser.IE)b+=";zoom:1";a=$(a);$A(a.childNodes).each(function(c){if(c.nodeType==3){c.nodeValue.toArray().each(function(d){a.insertBefore(Builder.node("span",{style:b},
131
+ d==" "?String.fromCharCode(160):d),c)});Element.remove(c)}})},multiple:function(a,b,c){a=(typeof a=="object"||typeof a=="function")&&a.length?a:$(a).childNodes;var d=Object.extend({speed:0.1,delay:0},c||{}),e=d.delay;$A(a).each(function(f,g){new b(f,Object.extend(d,{delay:g*d.speed+e}))})},PAIRS:{slide:["SlideDown","SlideUp"],blind:["BlindDown","BlindUp"],appear:["Appear","Fade"]},toggle:function(a,b,c){a=$(a);b=(b||"appear").toLowerCase();c=Object.extend({queue:{position:"end",scope:a.id||"global",
132
+ limit:1}},c||{});Effect[a.visible()?Effect.PAIRS[b][1]:Effect.PAIRS[b][0]](a,c)}},Effect2=Effect;Effect.Transitions={linear:Prototype.K,sinoidal:function(a){return-Math.cos(a*Math.PI)/2+0.5},reverse:function(a){return 1-a},flicker:function(a){a=-Math.cos(a*Math.PI)/4+0.75+Math.random()/4;return a>1?1:a},wobble:function(a){return-Math.cos(a*Math.PI*9*a)/2+0.5},pulse:function(a,b){b=b||5;return Math.round(a%(1/b)*b)==0?a*b*2-Math.floor(a*b*2):1-(a*b*2-Math.floor(a*b*2))},none:function(){return 0},full:function(){return 1}};
133
+ Effect.ScopedQueue=Class.create();
134
+ Object.extend(Object.extend(Effect.ScopedQueue.prototype,Enumerable),{initialize:function(){this.effects=[];this.interval=null},_each:function(a){this.effects._each(a)},add:function(a){var b=(new Date).getTime();switch(typeof a.options.queue=="string"?a.options.queue:a.options.queue.position){case "front":this.effects.findAll(function(c){return c.state=="idle"}).each(function(c){c.startOn+=a.finishOn;c.finishOn+=a.finishOn});break;case "with-last":b=this.effects.pluck("startOn").max()||b;break;case "end":b=
135
+ this.effects.pluck("finishOn").max()||b;break}a.startOn+=b;a.finishOn+=b;if(!a.options.queue.limit||this.effects.length<a.options.queue.limit)this.effects.push(a);if(!this.interval)this.interval=setInterval(this.loop.bind(this),15)},remove:function(a){this.effects=this.effects.reject(function(b){return b==a});if(this.effects.length==0){clearInterval(this.interval);this.interval=null}},loop:function(){for(var a=(new Date).getTime(),b=0,c=this.effects.length;b<c;b++)this.effects[b]&&this.effects[b].loop(a)}});
136
+ Effect.Queues={instances:$H(),get:function(a){if(typeof a!="string")return a;this.instances[a]||(this.instances[a]=new Effect.ScopedQueue);return this.instances[a]}};Effect.Queue=Effect.Queues.get("global");Effect.DefaultOptions={transition:Effect.Transitions.sinoidal,duration:1,fps:100,sync:false,from:0,to:1,delay:0,queue:"parallel"};Effect.Base=function(){};
137
+ Effect.Base.prototype={position:null,start:function(a){function b(c,d){return(c[d+"Internal"]?"this.options."+d+"Internal(this);":"")+(c[d]?"this.options."+d+"(this);":"")}if(a.transition===false)a.transition=Effect.Transitions.linear;this.options=Object.extend(Object.extend({},Effect.DefaultOptions),a||{});this.currentFrame=0;this.state="idle";this.startOn=this.options.delay*1E3;this.finishOn=this.startOn+this.options.duration*1E3;this.fromToDelta=this.options.to-this.options.from;this.totalTime=
138
+ this.finishOn-this.startOn;this.totalFrames=this.options.fps*this.options.duration;eval('this.render = function(pos){ if(this.state=="idle"){this.state="running";'+b(a,"beforeSetup")+(this.setup?"this.setup();":"")+b(a,"afterSetup")+'};if(this.state=="running"){pos=this.options.transition(pos)*'+this.fromToDelta+"+"+this.options.from+";this.position=pos;"+b(a,"beforeUpdate")+(this.update?"this.update(pos);":"")+b(a,"afterUpdate")+"}}");this.event("beforeStart");this.options.sync||Effect.Queues.get(typeof this.options.queue==
139
+ "string"?"global":this.options.queue.scope).add(this)},loop:function(a){if(a>=this.startOn)if(a>=this.finishOn){this.render(1);this.cancel();this.event("beforeFinish");this.finish&&this.finish();this.event("afterFinish")}else{a=(a-this.startOn)/this.totalTime;var b=Math.round(a*this.totalFrames);if(b>this.currentFrame){this.render(a);this.currentFrame=b}}},cancel:function(){this.options.sync||Effect.Queues.get(typeof this.options.queue=="string"?"global":this.options.queue.scope).remove(this);this.state=
140
+ "finished"},event:function(a){this.options[a+"Internal"]&&this.options[a+"Internal"](this);this.options[a]&&this.options[a](this)},inspect:function(){var a=$H();for(property in this)if(typeof this[property]!="function")a[property]=this[property];return"#<Effect:"+a.inspect()+",options:"+$H(this.options).inspect()+">"}};Effect.Parallel=Class.create();
141
+ Object.extend(Object.extend(Effect.Parallel.prototype,Effect.Base.prototype),{initialize:function(a,b){this.effects=a||[];this.start(b)},update:function(a){this.effects.invoke("render",a)},finish:function(a){this.effects.each(function(b){b.render(1);b.cancel();b.event("beforeFinish");b.finish&&b.finish(a);b.event("afterFinish")})}});Effect.Event=Class.create();
142
+ Object.extend(Object.extend(Effect.Event.prototype,Effect.Base.prototype),{initialize:function(a){this.start(Object.extend({duration:0},a||{}))},update:Prototype.emptyFunction});Effect.Opacity=Class.create();
143
+ Object.extend(Object.extend(Effect.Opacity.prototype,Effect.Base.prototype),{initialize:function(a,b){this.element=$(a);if(!this.element)throw Effect._elementDoesNotExistError;Prototype.Browser.IE&&!this.element.currentStyle.hasLayout&&this.element.setStyle({zoom:1});this.start(Object.extend({from:this.element.getOpacity()||0,to:1},b||{}))},update:function(a){this.element.setOpacity(a)}});Effect.Move=Class.create();
144
+ Object.extend(Object.extend(Effect.Move.prototype,Effect.Base.prototype),{initialize:function(a,b){this.element=$(a);if(!this.element)throw Effect._elementDoesNotExistError;this.start(Object.extend({x:0,y:0,mode:"relative"},b||{}))},setup:function(){this.element.makePositioned();this.originalLeft=parseFloat(this.element.getStyle("left")||"0");this.originalTop=parseFloat(this.element.getStyle("top")||"0");if(this.options.mode=="absolute"){this.options.x-=this.originalLeft;this.options.y-=this.originalTop}},
145
+ update:function(a){this.element.setStyle({left:Math.round(this.options.x*a+this.originalLeft)+"px",top:Math.round(this.options.y*a+this.originalTop)+"px"})}});Effect.MoveBy=function(a,b,c,d){return new Effect.Move(a,Object.extend({x:c,y:b},d||{}))};Effect.Scale=Class.create();
146
+ Object.extend(Object.extend(Effect.Scale.prototype,Effect.Base.prototype),{initialize:function(a,b,c){this.element=$(a);if(!this.element)throw Effect._elementDoesNotExistError;this.start(Object.extend({scaleX:true,scaleY:true,scaleContent:true,scaleFromCenter:false,scaleMode:"box",scaleFrom:100,scaleTo:b},c||{}))},setup:function(){this.restoreAfterFinish=this.options.restoreAfterFinish||false;this.elementPositioning=this.element.getStyle("position");this.originalStyle={};["top","left","width","height",
147
+ "fontSize"].each(function(b){this.originalStyle[b]=this.element.style[b]}.bind(this));this.originalTop=this.element.offsetTop;this.originalLeft=this.element.offsetLeft;var a=this.element.getStyle("font-size")||"100%";["em","px","%","pt"].each(function(b){if(a.indexOf(b)>0){this.fontSize=parseFloat(a);this.fontSizeType=b}}.bind(this));this.factor=(this.options.scaleTo-this.options.scaleFrom)/100;this.dims=null;if(this.options.scaleMode=="box")this.dims=[this.element.offsetHeight,this.element.offsetWidth];
148
+ if(/^content/.test(this.options.scaleMode))this.dims=[this.element.scrollHeight,this.element.scrollWidth];if(!this.dims)this.dims=[this.options.scaleMode.originalHeight,this.options.scaleMode.originalWidth]},update:function(a){a=this.options.scaleFrom/100+this.factor*a;this.options.scaleContent&&this.fontSize&&this.element.setStyle({fontSize:this.fontSize*a+this.fontSizeType});this.setDimensions(this.dims[0]*a,this.dims[1]*a)},finish:function(){this.restoreAfterFinish&&this.element.setStyle(this.originalStyle)},
149
+ setDimensions:function(a,b){var c={};if(this.options.scaleX)c.width=Math.round(b)+"px";if(this.options.scaleY)c.height=Math.round(a)+"px";if(this.options.scaleFromCenter){var d=(a-this.dims[0])/2,e=(b-this.dims[1])/2;if(this.elementPositioning=="absolute"){if(this.options.scaleY)c.top=this.originalTop-d+"px";if(this.options.scaleX)c.left=this.originalLeft-e+"px"}else{if(this.options.scaleY)c.top=-d+"px";if(this.options.scaleX)c.left=-e+"px"}}this.element.setStyle(c)}});Effect.Highlight=Class.create();
150
+ Object.extend(Object.extend(Effect.Highlight.prototype,Effect.Base.prototype),{initialize:function(a,b){this.element=$(a);if(!this.element)throw Effect._elementDoesNotExistError;this.start(Object.extend({startcolor:"#ffff99"},b||{}))},setup:function(){if(this.element.getStyle("display")=="none")this.cancel();else{this.oldStyle={};if(!this.options.keepBackgroundImage){this.oldStyle.backgroundImage=this.element.getStyle("background-image");this.element.setStyle({backgroundImage:"none"})}if(!this.options.endcolor)this.options.endcolor=
151
+ this.element.getStyle("background-color").parseColor("#ffffff");if(!this.options.restorecolor)this.options.restorecolor=this.element.getStyle("background-color");this._base=$R(0,2).map(function(a){return parseInt(this.options.startcolor.slice(a*2+1,a*2+3),16)}.bind(this));this._delta=$R(0,2).map(function(a){return parseInt(this.options.endcolor.slice(a*2+1,a*2+3),16)-this._base[a]}.bind(this))}},update:function(a){this.element.setStyle({backgroundColor:$R(0,2).inject("#",function(b,c,d){return b+
152
+ Math.round(this._base[d]+this._delta[d]*a).toColorPart()}.bind(this))})},finish:function(){this.element.setStyle(Object.extend(this.oldStyle,{backgroundColor:this.options.restorecolor}))}});Effect.ScrollTo=Class.create();
153
+ Object.extend(Object.extend(Effect.ScrollTo.prototype,Effect.Base.prototype),{initialize:function(a,b){this.element=$(a);this.start(b||{})},setup:function(){Position.prepare();var a=Position.cumulativeOffset(this.element);if(this.options.offset)a[1]+=this.options.offset;var b=window.innerHeight?window.height-window.innerHeight:document.body.scrollHeight-(document.documentElement.clientHeight?document.documentElement.clientHeight:document.body.clientHeight);this.scrollStart=Position.deltaY;this.delta=
154
+ (a[1]>b?b:a[1])-this.scrollStart},update:function(a){Position.prepare();window.scrollTo(Position.deltaX,this.scrollStart+a*this.delta)}});Effect.Fade=function(a,b){a=$(a);var c=a.getInlineOpacity(),d=Object.extend({from:a.getOpacity()||1,to:0,afterFinishInternal:function(e){e.options.to==0&&e.element.hide().setStyle({opacity:c})}},b||{});return new Effect.Opacity(a,d)};
155
+ Effect.Appear=function(a,b){a=$(a);var c=Object.extend({from:a.getStyle("display")=="none"?0:a.getOpacity()||0,to:1,afterFinishInternal:function(d){d.element.forceRerendering()},beforeSetup:function(d){d.element.setOpacity(d.options.from).show()}},b||{});return new Effect.Opacity(a,c)};
156
+ Effect.Puff=function(a,b){a=$(a);var c={opacity:a.getInlineOpacity(),position:a.getStyle("position"),top:a.style.top,left:a.style.left,width:a.style.width,height:a.style.height};return new Effect.Parallel([new Effect.Scale(a,200,{sync:true,scaleFromCenter:true,scaleContent:true,restoreAfterFinish:true}),new Effect.Opacity(a,{sync:true,to:0})],Object.extend({duration:1,beforeSetupInternal:function(d){Position.absolutize(d.effects[0].element)},afterFinishInternal:function(d){d.effects[0].element.hide().setStyle(c)}},
157
+ b||{}))};Effect.BlindUp=function(a,b){a=$(a);a.makeClipping();return new Effect.Scale(a,0,Object.extend({scaleContent:false,scaleX:false,restoreAfterFinish:true,afterFinishInternal:function(c){c.element.hide().undoClipping()}},b||{}))};
158
+ Effect.BlindDown=function(a,b){a=$(a);var c=a.getDimensions();return new Effect.Scale(a,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:0,scaleMode:{originalHeight:c.height,originalWidth:c.width},restoreAfterFinish:true,afterSetup:function(d){d.element.makeClipping().setStyle({height:"0px"}).show()},afterFinishInternal:function(d){d.element.undoClipping()}},b||{}))};
159
+ Effect.SwitchOff=function(a,b){a=$(a);var c=a.getInlineOpacity();return new Effect.Appear(a,Object.extend({duration:0.4,from:0,transition:Effect.Transitions.flicker,afterFinishInternal:function(d){new Effect.Scale(d.element,1,{duration:0.3,scaleFromCenter:true,scaleX:false,scaleContent:false,restoreAfterFinish:true,beforeSetup:function(e){e.element.makePositioned().makeClipping()},afterFinishInternal:function(e){e.element.hide().undoClipping().undoPositioned().setStyle({opacity:c})}})}},b||{}))};
160
+ Effect.DropOut=function(a,b){a=$(a);var c={top:a.getStyle("top"),left:a.getStyle("left"),opacity:a.getInlineOpacity()};return new Effect.Parallel([new Effect.Move(a,{x:0,y:100,sync:true}),new Effect.Opacity(a,{sync:true,to:0})],Object.extend({duration:0.5,beforeSetup:function(d){d.effects[0].element.makePositioned()},afterFinishInternal:function(d){d.effects[0].element.hide().undoPositioned().setStyle(c)}},b||{}))};
161
+ Effect.Shake=function(a){a=$(a);var b={top:a.getStyle("top"),left:a.getStyle("left")};return new Effect.Move(a,{x:20,y:0,duration:0.05,afterFinishInternal:function(c){new Effect.Move(c.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(d){new Effect.Move(d.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(e){new Effect.Move(e.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(f){new Effect.Move(f.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(g){new Effect.Move(g.element,
162
+ {x:-20,y:0,duration:0.05,afterFinishInternal:function(h){h.element.undoPositioned().setStyle(b)}})}})}})}})}})}})};
163
+ Effect.SlideDown=function(a,b){a=$(a).cleanWhitespace();var c=a.down().getStyle("bottom"),d=a.getDimensions();return new Effect.Scale(a,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:window.opera?0:1,scaleMode:{originalHeight:d.height,originalWidth:d.width},restoreAfterFinish:true,afterSetup:function(e){e.element.makePositioned();e.element.down().makePositioned();window.opera&&e.element.setStyle({top:""});e.element.makeClipping().setStyle({height:"0px"}).show()},afterUpdateInternal:function(e){e.element.down().setStyle({bottom:e.dims[0]-
164
+ e.element.clientHeight+"px"})},afterFinishInternal:function(e){e.element.undoClipping().undoPositioned();e.element.down().undoPositioned().setStyle({bottom:c})}},b||{}))};
165
+ Effect.SlideUp=function(a,b){a=$(a).cleanWhitespace();var c=a.down().getStyle("bottom");return new Effect.Scale(a,window.opera?0:1,Object.extend({scaleContent:false,scaleX:false,scaleMode:"box",scaleFrom:100,restoreAfterFinish:true,beforeStartInternal:function(d){d.element.makePositioned();d.element.down().makePositioned();window.opera&&d.element.setStyle({top:""});d.element.makeClipping().show()},afterUpdateInternal:function(d){d.element.down().setStyle({bottom:d.dims[0]-d.element.clientHeight+"px"})},
166
+ afterFinishInternal:function(d){d.element.hide().undoClipping().undoPositioned().setStyle({bottom:c});d.element.down().undoPositioned()}},b||{}))};Effect.Squish=function(a){return new Effect.Scale(a,window.opera?1:0,{restoreAfterFinish:true,beforeSetup:function(b){b.element.makeClipping()},afterFinishInternal:function(b){b.element.hide().undoClipping()}})};
167
+ Effect.Grow=function(a,b){a=$(a);var c=Object.extend({direction:"center",moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.full},b||{}),d={top:a.style.top,left:a.style.left,height:a.style.height,width:a.style.width,opacity:a.getInlineOpacity()},e=a.getDimensions(),f,g,h,i;switch(c.direction){case "top-left":f=g=h=i=0;break;case "top-right":f=e.width;g=i=0;h=-e.width;break;case "bottom-left":f=h=0;g=e.height;i=-e.height;break;
168
+ case "bottom-right":f=e.width;g=e.height;h=-e.width;i=-e.height;break;case "center":f=e.width/2;g=e.height/2;h=-e.width/2;i=-e.height/2;break}return new Effect.Move(a,{x:f,y:g,duration:0.01,beforeSetup:function(j){j.element.hide().makeClipping().makePositioned()},afterFinishInternal:function(j){new Effect.Parallel([new Effect.Opacity(j.element,{sync:true,to:1,from:0,transition:c.opacityTransition}),new Effect.Move(j.element,{x:h,y:i,sync:true,transition:c.moveTransition}),new Effect.Scale(j.element,
169
+ 100,{scaleMode:{originalHeight:e.height,originalWidth:e.width},sync:true,scaleFrom:window.opera?1:0,transition:c.scaleTransition,restoreAfterFinish:true})],Object.extend({beforeSetup:function(k){k.effects[0].element.setStyle({height:"0px"}).show()},afterFinishInternal:function(k){k.effects[0].element.undoClipping().undoPositioned().setStyle(d)}},c))}})};
170
+ Effect.Shrink=function(a,b){a=$(a);var c=Object.extend({direction:"center",moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.none},b||{}),d={top:a.style.top,left:a.style.left,height:a.style.height,width:a.style.width,opacity:a.getInlineOpacity()},e=a.getDimensions(),f,g;switch(c.direction){case "top-left":f=g=0;break;case "top-right":f=e.width;g=0;break;case "bottom-left":f=0;g=e.height;break;case "bottom-right":f=e.width;g=
171
+ e.height;break;case "center":f=e.width/2;g=e.height/2;break}return new Effect.Parallel([new Effect.Opacity(a,{sync:true,to:0,from:1,transition:c.opacityTransition}),new Effect.Scale(a,window.opera?1:0,{sync:true,transition:c.scaleTransition,restoreAfterFinish:true}),new Effect.Move(a,{x:f,y:g,sync:true,transition:c.moveTransition})],Object.extend({beforeStartInternal:function(h){h.effects[0].element.makePositioned().makeClipping()},afterFinishInternal:function(h){h.effects[0].element.hide().undoClipping().undoPositioned().setStyle(d)}},
172
+ c))};Effect.Pulsate=function(a,b){a=$(a);var c=b||{},d=a.getInlineOpacity(),e=c.transition||Effect.Transitions.sinoidal,f=function(g){return e(1-Effect.Transitions.pulse(g,c.pulses))};f.bind(e);return new Effect.Opacity(a,Object.extend(Object.extend({duration:2,from:0,afterFinishInternal:function(g){g.element.setStyle({opacity:d})}},c),{transition:f}))};
173
+ Effect.Fold=function(a,b){a=$(a);var c={top:a.style.top,left:a.style.left,width:a.style.width,height:a.style.height};a.makeClipping();return new Effect.Scale(a,5,Object.extend({scaleContent:false,scaleX:false,afterFinishInternal:function(){new Effect.Scale(a,1,{scaleContent:false,scaleY:false,afterFinishInternal:function(d){d.element.hide().undoClipping().setStyle(c)}})}},b||{}))};Effect.Morph=Class.create();
174
+ Object.extend(Object.extend(Effect.Morph.prototype,Effect.Base.prototype),{initialize:function(a,b){this.element=$(a);if(!this.element)throw Effect._elementDoesNotExistError;var c=Object.extend({style:{}},b||{});if(typeof c.style=="string")if(c.style.indexOf(":")==-1){var d="",e="."+c.style;$A(document.styleSheets).reverse().each(function(f){if(f.cssRules)cssRules=f.cssRules;else if(f.rules)cssRules=f.rules;$A(cssRules).reverse().each(function(g){if(e==g.selectorText){d=g.style.cssText;throw $break;
175
+ }});if(d)throw $break;});this.style=d.parseStyle();c.afterFinishInternal=function(f){f.element.addClassName(f.options.style);f.transforms.each(function(g){if(g.style!="opacity")f.element.style[g.style]=""})}}else this.style=c.style.parseStyle();else this.style=$H(c.style);this.start(c)},setup:function(){function a(b){if(!b||["rgba(0, 0, 0, 0)","transparent"].include(b))b="#ffffff";b=b.parseColor();return $R(0,2).map(function(c){return parseInt(b.slice(c*2+1,c*2+3),16)})}this.transforms=this.style.map(function(b){var c=
176
+ b[0];b=b[1];var d=null;if(b.parseColor("#zzzzzz")!="#zzzzzz"){b=b.parseColor();d="color"}else if(c=="opacity"){b=parseFloat(b);Prototype.Browser.IE&&!this.element.currentStyle.hasLayout&&this.element.setStyle({zoom:1})}else if(Element.CSS_LENGTH.test(b)){d=b.match(/^([\+\-]?[0-9\.]+)(.*)$/);b=parseFloat(d[1]);d=d.length==3?d[2]:null}var e=this.element.getStyle(c);return{style:c.camelize(),originalValue:d=="color"?a(e):parseFloat(e||0),targetValue:d=="color"?a(b):b,unit:d}}.bind(this)).reject(function(b){return b.originalValue==
177
+ b.targetValue||b.unit!="color"&&(isNaN(b.originalValue)||isNaN(b.targetValue))})},update:function(a){for(var b={},c,d=this.transforms.length;d--;)b[(c=this.transforms[d]).style]=c.unit=="color"?"#"+Math.round(c.originalValue[0]+(c.targetValue[0]-c.originalValue[0])*a).toColorPart()+Math.round(c.originalValue[1]+(c.targetValue[1]-c.originalValue[1])*a).toColorPart()+Math.round(c.originalValue[2]+(c.targetValue[2]-c.originalValue[2])*a).toColorPart():c.originalValue+Math.round((c.targetValue-c.originalValue)*
178
+ a*1E3)/1E3+c.unit;this.element.setStyle(b,true)}});Effect.Transform=Class.create();
179
+ Object.extend(Effect.Transform.prototype,{initialize:function(a,b){this.tracks=[];this.options=b||{};this.addTracks(a)},addTracks:function(a){a.each(function(b){var c=$H(b).values().first();this.tracks.push($H({ids:$H(b).keys().first(),effect:Effect.Morph,options:{style:c}}))}.bind(this));return this},play:function(){return new Effect.Parallel(this.tracks.map(function(a){return[$(a.ids)||$$(a.ids)].flatten().map(function(b){return new a.effect(b,Object.extend({sync:true},a.options))})}).flatten(),
180
+ this.options)}});Element.CSS_PROPERTIES=$w("backgroundColor backgroundPosition borderBottomColor borderBottomStyle borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth borderRightColor borderRightStyle borderRightWidth borderSpacing borderTopColor borderTopStyle borderTopWidth bottom clip color fontSize fontWeight height left letterSpacing lineHeight marginBottom marginLeft marginRight marginTop markerOffset maxHeight maxWidth minHeight minWidth opacity outlineColor outlineOffset outlineWidth paddingBottom paddingLeft paddingRight paddingTop right textIndent top width wordSpacing zIndex");
181
+ Element.CSS_LENGTH=/^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;String.prototype.parseStyle=function(){var a=document.createElement("div");a.innerHTML='<div style="'+this+'"></div>';var b=a.childNodes[0].style,c=$H();Element.CSS_PROPERTIES.each(function(d){if(b[d])c[d]=b[d]});if(Prototype.Browser.IE&&this.indexOf("opacity")>-1)c.opacity=this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];return c};Element.morph=function(a,b,c){new Effect.Morph(a,Object.extend({style:b},c||{}));return a};
182
+ ["getInlineOpacity","forceRerendering","setContentZoom","collectTextNodes","collectTextNodesIgnoreClass","morph"].each(function(a){Element.Methods[a]=Element[a]});Element.Methods.visualEffect=function(a,b,c){s=b.dasherize().camelize();effect_class=s.charAt(0).toUpperCase()+s.substring(1);new Effect[effect_class](a,c);return $(a)};Element.addMethods();var Scriptaculous={Version:"1.7.1_beta3",require:function(a){document.write('<script type="text/javascript" src="'+a+'"><\/script>')},REQUIRED_PROTOTYPE:"1.5.1",load:function(){function a(b){b=b.split(".");return parseInt(b[0])*1E5+parseInt(b[1])*1E3+parseInt(b[2])}if(typeof Prototype=="undefined"||typeof Element=="undefined"||typeof Element.Methods=="undefined"||a(Prototype.Version)<a(Scriptaculous.REQUIRED_PROTOTYPE))throw"script.aculo.us requires the Prototype JavaScript framework >= "+Scriptaculous.REQUIRED_PROTOTYPE;
183
+ $A(document.getElementsByTagName("script")).findAll(function(b){return b.src&&b.src.match(/scriptaculous\.js(\?.*)?$/)}).each(function(b){var c=b.src.replace(/scriptaculous\.js(\?.*)?$/,"");b=b.src.match(/\?.*load=([a-z,]*)/);(b?b[1]:"builder,effects,dragdrop,controls,slider,sound").split(",").each(function(d){Scriptaculous.require(c+d+".js")})})}};Scriptaculous.load();var Lightbox={activeImage:null,badObjects:["select","object","embed"],container:null,enableSlideshow:null,groupName:null,imageArray:[],options:null,overlayDuration:null,overlayOpacity:null,playSlides:null,refTags:["a","area"],relAttribute:null,resizeDuration:null,slideShowTimer:null,startImage:null,initialize:function(a){if(document.getElementsByTagName){this.options=$H({animate:true,autoPlay:true,borderSize:10,containerID:document,enableSlideshow:true,googleAnalytics:false,imageDataLocation:"south",
184
+ initImage:"",loop:true,overlayDuration:0.2,overlayOpacity:0.8,prefix:"",relAttribute:"lightbox",resizeSpeed:7,showGroupName:false,slideTime:4,strings:{closeLink:"close",loadingMsg:"loading",nextLink:"next &raquo;",prevLink:"&laquo; prev",startSlideshow:"start slideshow",stopSlideshow:"stop slideshow",numDisplayPrefix:"Image",numDisplaySeparator:"of"}}).merge(a);if(this.options.animate){this.overlayDuration=Math.max(this.options.overlayDuration,0);this.options.resizeSpeed=Math.max(Math.min(this.options.resizeSpeed,
185
+ 10),1);this.resizeDuration=(11-this.options.resizeSpeed)*0.15}else this.resizeDuration=this.overlayDuration=0;this.enableSlideshow=this.options.enableSlideshow;this.overlayOpacity=Math.max(Math.min(this.options.overlayOpacity,1),0);this.playSlides=this.options.autoPlay;this.container=$(this.options.containerID);this.relAttribute=this.options.relAttribute;this.updateImageList();var b=this.container!=document?this.container:document.getElementsByTagName("body").item(0);a=document.createElement("div");
186
+ a.setAttribute("id",this.getID("overlay"));a.style.display="none";b.appendChild(a);Event.observe(a,"click",this.end.bindAsEventListener(this));a=document.createElement("div");a.setAttribute("id",this.getID("lightbox"));a.style.display="none";b.appendChild(a);b=document.createElement("div");b.setAttribute("id",this.getID("imageDataContainer"));b.className=this.getID("clearfix");var c=document.createElement("div");c.setAttribute("id",this.getID("imageData"));b.appendChild(c);var d=document.createElement("div");
187
+ d.setAttribute("id",this.getID("imageDetails"));c.appendChild(d);var e=document.createElement("span");e.setAttribute("id",this.getID("caption"));d.appendChild(e);e=document.createElement("span");e.setAttribute("id",this.getID("numberDisplay"));d.appendChild(e);e=document.createElement("span");e.setAttribute("id",this.getID("detailsNav"));d.appendChild(e);d=document.createElement("a");d.setAttribute("id",this.getID("prevLinkDetails"));d.setAttribute("href","javascript:void(0);");d.innerHTML=this.options.strings.prevLink;
188
+ e.appendChild(d);Event.observe(d,"click",this.showPrev.bindAsEventListener(this));d=document.createElement("a");d.setAttribute("id",this.getID("nextLinkDetails"));d.setAttribute("href","javascript:void(0);");d.innerHTML=this.options.strings.nextLink;e.appendChild(d);Event.observe(d,"click",this.showNext.bindAsEventListener(this));d=document.createElement("a");d.setAttribute("id",this.getID("slideShowControl"));d.setAttribute("href","javascript:void(0);");e.appendChild(d);Event.observe(d,"click",this.toggleSlideShow.bindAsEventListener(this));
189
+ e=document.createElement("div");e.setAttribute("id",this.getID("close"));c.appendChild(e);c=document.createElement("a");c.setAttribute("id",this.getID("closeLink"));c.setAttribute("href","javascript:void(0);");c.innerHTML=this.options.strings.closeLink;e.appendChild(c);Event.observe(c,"click",this.end.bindAsEventListener(this));this.options.imageDataLocation=="north"&&a.appendChild(b);e=document.createElement("div");e.setAttribute("id",this.getID("outerImageContainer"));a.appendChild(e);c=document.createElement("div");
190
+ c.setAttribute("id",this.getID("imageContainer"));e.appendChild(c);e=document.createElement("img");e.setAttribute("id",this.getID("lightboxImage"));c.appendChild(e);e=document.createElement("div");e.setAttribute("id",this.getID("hoverNav"));c.appendChild(e);d=document.createElement("a");d.setAttribute("id",this.getID("prevLinkImg"));d.setAttribute("href","javascript:void(0);");e.appendChild(d);Event.observe(d,"click",this.showPrev.bindAsEventListener(this));d=document.createElement("a");d.setAttribute("id",
191
+ this.getID("nextLinkImg"));d.setAttribute("href","javascript:void(0);");e.appendChild(d);Event.observe(d,"click",this.showNext.bindAsEventListener(this));e=document.createElement("div");e.setAttribute("id",this.getID("loading"));c.appendChild(e);c=document.createElement("a");c.setAttribute("id",this.getID("loadingLink"));c.setAttribute("href","javascript:void(0);");c.innerHTML=this.options.strings.loadingMsg;e.appendChild(c);Event.observe(c,"click",this.end.bindAsEventListener(this));this.options.imageDataLocation!=
192
+ "north"&&a.appendChild(b);this.options.initImage!=""&&this.start($(this.options.initImage))}},updateImageList:function(){for(var a,b,c,d=0;d<this.refTags.length;d++){b=this.container.getElementsByTagName(this.refTags[d]);for(var e=0;e<b.length;e++){a=b[e];c=String(a.getAttribute("rel"));if(a.getAttribute("href")&&c.toLowerCase().match(this.relAttribute))a.onclick=function(){Lightbox.start(this);return false}}}},start:function(a){this.hideBadObjects();var b=this.getPageSize();$(this.getID("overlay")).setStyle({height:b.pageHeight+
193
+ "px"});new Effect.Appear(this.getID("overlay"),{duration:this.overlayDuration,from:0,to:this.overlayOpacity});this.imageArray=[];this.groupName=null;var c=a.getAttribute("rel"),d="";if(c==this.relAttribute){d=a.getAttribute("title")?a.getAttribute("title"):"";this.imageArray.push({link:a.getAttribute("href"),title:d});this.startImage=0}else{for(var e=this.container.getElementsByTagName(a.tagName),f=0;f<e.length;f++){var g=e[f];if(g.getAttribute("href")&&g.getAttribute("rel")==c){d=g.getAttribute("title")?
194
+ g.getAttribute("title"):"";this.imageArray.push({link:g.getAttribute("href"),title:d});if(g==a)this.startImage=this.imageArray.length-1}}this.groupName=c.substring(this.relAttribute.length+1,c.length-1)}a=this.getPageScroll().y+b.winHeight/15;$(this.getID("lightbox")).setStyle({top:a+"px"}).show();this.changeImage(this.startImage)},changeImage:function(a){this.activeImage=a;this.disableKeyboardNav();this.pauseSlideShow();$(this.getID("loading")).show();$(this.getID("lightboxImage")).hide();$(this.getID("hoverNav")).hide();
195
+ $(this.getID("imageDataContainer")).hide();$(this.getID("numberDisplay")).hide();$(this.getID("detailsNav")).hide();var b=new Image;b.onload=function(){$(Lightbox.getID("lightboxImage")).src=b.src;Lightbox.resizeImageContainer(b.width,b.height)};b.src=this.imageArray[this.activeImage].link;this.options.googleAnalytics&&urchinTracker(this.imageArray[this.activeImage].link)},resizeImageContainer:function(a,b){var c=$(this.getID("outerImageContainer")).getDimensions(),d=(a+this.options.borderSize*2)/
196
+ c.width*100,e=(b+this.options.borderSize*2)/c.height*100,f=c.width-this.options.borderSize*2-a;c=c.height-this.options.borderSize*2-b;c!=0&&new Effect.Scale(this.getID("outerImageContainer"),e,{scaleX:false,duration:this.resizeDuration,queue:"front"});f!=0&&new Effect.Scale(this.getID("outerImageContainer"),d,{scaleY:false,delay:this.resizeDuration,duration:this.resizeDuration});if(c==0&&f==0)navigator.appVersion.indexOf("MSIE")!=-1?this.pause(250):this.pause(100);$(this.getID("prevLinkImg")).setStyle({height:b+
197
+ "px"});$(this.getID("nextLinkImg")).setStyle({height:b+"px"});$(this.getID("imageDataContainer")).setStyle({width:a+this.options.borderSize*2+"px"});this.showImage()},showImage:function(){$(this.getID("loading")).hide();new Effect.Appear(this.getID("lightboxImage"),{duration:0.5,queue:"end",afterFinish:function(){Lightbox.updateDetails()}});this.preloadNeighborImages()},updateDetails:function(){$(this.getID("caption")).show();$(this.getID("caption")).update(this.imageArray[this.activeImage].title);
198
+ if(this.imageArray.length>1){var a=this.options.strings.numDisplayPrefix+" "+eval(this.activeImage+1)+" "+this.options.strings.numDisplaySeparator+" "+this.imageArray.length;if(this.options.showGroupName&&this.groupName!="")a+=" "+this.options.strings.numDisplaySeparator+" "+this.groupName;$(this.getID("numberDisplay")).update(a).show();this.enableSlideshow||$(this.getID("slideShowControl")).hide();$(this.getID("detailsNav")).show()}new Effect.Parallel([new Effect.SlideDown(this.getID("imageDataContainer"),
199
+ {sync:true}),new Effect.Appear(this.getID("imageDataContainer"),{sync:true})],{duration:0.65,afterFinish:function(){Lightbox.updateNav()}})},updateNav:function(){if(this.imageArray.length>1){$(this.getID("hoverNav")).show();if(this.enableSlideshow)this.playSlides?this.startSlideShow():this.stopSlideShow()}this.enableKeyboardNav()},startSlideShow:function(){this.playSlides=true;this.slideShowTimer=new PeriodicalExecuter(function(a){Lightbox.showNext();a.stop()},this.options.slideTime);$(this.getID("slideShowControl")).update(this.options.strings.stopSlideshow)},
200
+ stopSlideShow:function(){this.playSlides=false;this.slideShowTimer&&this.slideShowTimer.stop();$(this.getID("slideShowControl")).update(this.options.strings.startSlideshow)},toggleSlideShow:function(){this.playSlides?this.stopSlideShow():this.startSlideShow()},pauseSlideShow:function(){this.slideShowTimer&&this.slideShowTimer.stop()},showNext:function(){if(this.imageArray.length>1){if(!this.options.loop&&(this.activeImage==this.imageArray.length-1&&this.startImage==0||this.activeImage+1==this.startImage))return this.end();
201
+ this.activeImage==this.imageArray.length-1?this.changeImage(0):this.changeImage(this.activeImage+1)}},showPrev:function(){if(this.imageArray.length>1)this.activeImage==0?this.changeImage(this.imageArray.length-1):this.changeImage(this.activeImage-1)},showFirst:function(){this.imageArray.length>1&&this.changeImage(0)},showLast:function(){this.imageArray.length>1&&this.changeImage(this.imageArray.length-1)},enableKeyboardNav:function(){document.onkeydown=this.keyboardAction},disableKeyboardNav:function(){document.onkeydown=
202
+ ""},keyboardAction:function(a){keycode=a==null?event.keyCode:a.which;key=String.fromCharCode(keycode).toLowerCase();if(key=="x"||key=="o"||key=="c")Lightbox.end();else if(key=="p"||key=="%")Lightbox.showPrev();else if(key=="n"||key=="'")Lightbox.showNext();else if(key=="f")Lightbox.showFirst();else if(key=="l")Lightbox.showLast();else key=="s"&&Lightbox.imageArray.length>0&&Lightbox.options.enableSlideshow&&Lightbox.toggleSlideShow()},preloadNeighborImages:function(){var a=this.imageArray.length-
203
+ 1==this.activeImage?0:this.activeImage+1;nextImage=new Image;nextImage.src=this.imageArray[a].link;a=this.activeImage==0?this.imageArray.length-1:this.activeImage-1;prevImage=new Image;prevImage.src=this.imageArray[a].link},end:function(){this.disableKeyboardNav();this.pauseSlideShow();$(this.getID("lightbox")).hide();new Effect.Fade(this.getID("overlay"),{duration:this.overlayDuration});this.showBadObjects()},showBadObjects:function(){for(var a,b=Lightbox.badObjects,c=0;c<b.length;c++){a=document.getElementsByTagName(b[c]);
204
+ for(var d=0;d<a.length;d++)$(a[d]).setStyle({visibility:"visible"})}},hideBadObjects:function(){for(var a,b=Lightbox.badObjects,c=0;c<b.length;c++){a=document.getElementsByTagName(b[c]);for(var d=0;d<a.length;d++)$(a[d]).setStyle({visibility:"hidden"})}},pause:function(a){var b=new Date;for(a=b.getTime()+a;;){b=new Date;if(b.getTime()>a)return}},getPageScroll:function(){var a,b;if(self.pageYOffset){a=self.pageXOffset;b=self.pageYOffset}else if(document.documentElement&&document.documentElement.scrollTop){a=
205
+ document.documentElement.scrollLeft;b=document.documentElement.scrollTop}else if(document.body){a=document.body.scrollLeft;b=document.body.scrollTop}return{x:a,y:b}},getPageSize:function(){var a,b,c,d;if(window.innerHeight&&window.scrollMaxY){a=document.body.scrollWidth;b=window.innerHeight+window.scrollMaxY}else if(document.body.scrollHeight>document.body.offsetHeight){a=document.body.scrollWidth;b=document.body.scrollHeight}else{a=document.body.offsetWidth;b=document.body.offsetHeight}if(self.innerHeight){c=
206
+ self.innerWidth;d=self.innerHeight}else if(document.documentElement&&document.documentElement.clientHeight){c=document.documentElement.clientWidth;d=document.documentElement.clientHeight}else if(document.body){c=document.body.clientWidth;d=document.body.clientHeight}return{pageWidth:a<c?c:a,pageHeight:b<d?d:b,winWidth:c,winHeight:d}},getID:function(a){return this.options.prefix+a}};
main.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Simple Lightbox
4
+ Plugin URI:
5
+ Description: Customizable Lightbox for Wordpress
6
+ Version: 1.1
7
+ Author: Archetyped
8
+ Author URI: http://archetyped.com
9
+ */
10
+ /*
11
+ Copyright 2010 Solomon Marchessault (wp@archetyped.com)
12
+
13
+ This program is free software; you can redistribute it and/or
14
+ modify it under the terms of the GNU General Public License
15
+ as published by the Free Software Foundation; either version 2
16
+ of the License, or (at your option) any later version.
17
+
18
+ This program is distributed in the hope that it will be useful,
19
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ GNU General Public License for more details.
22
+
23
+ You should have received a copy of the GNU General Public License
24
+ along with this program; if not, write to the Free Software
25
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26
+ */
27
+
28
+ require_once 'model.php';
29
+
30
+ $slb =& new SLB_Lightbox();
31
+
32
+ function slb_enabled() {
33
+ global $slb;
34
+ return $slb->is_enabled();
35
+ }
36
+
37
+ ?>
model.php ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'includes/class.base.php';
4
+
5
+ /**
6
+ * Lightbox functionality class
7
+ * @package Simple Lightbox
8
+ * @author Archetyped
9
+ */
10
+ class SLB_Lightbox extends SLB_Base {
11
+
12
+ /*-** Properties **-*/
13
+
14
+ /**
15
+ * Page that plugin options are on
16
+ * @var string
17
+ */
18
+ var $options_admin_page = 'options-media.php';
19
+
20
+ /**
21
+ * Page that processes options
22
+ * @var string
23
+ */
24
+ var $options_admin_form = 'options.php';
25
+
26
+ /**
27
+ * Default options
28
+ * 0: Value
29
+ * 1: Label
30
+ * @var array
31
+ */
32
+ var $options_default = array (
33
+ 'enabled' => array(true, 'Enable Lightbox Functionality'),
34
+ 'enabled_home' => array(true, 'Enable on Home page'),
35
+ 'enabled_single' => array(true, 'Enable on Single Posts/Pages'),
36
+ 'enabled_archive' => array(true, 'Enable on Archive Pages (tags, categories, etc.)'),
37
+ 'activate_links' => array(true, 'Automatically setup for all links to images on page'),
38
+ 'autostart' => array(true, 'Automatically Start Slideshow'),
39
+ 'duration' => array(6, 'Slide Duration (Seconds)', array('size' => 3, 'maxlength' => 3)),
40
+ 'loop' => array(true, 'Loop through images'),
41
+ 'overlay_opacity' => array(0.8, 'Overlay Opacity (0 - 1)', array('size' => 3, 'maxlength' => 3)),
42
+ );
43
+
44
+ /*-** Init **-*/
45
+
46
+ function SLB_Lightbox() {
47
+ $this->__construct();
48
+ }
49
+
50
+ function __construct() {
51
+ parent::__construct();
52
+ $this->init();
53
+ }
54
+
55
+ function init() {
56
+ $this->register_hooks();
57
+ }
58
+
59
+ function register_hooks() {
60
+ register_activation_hook($this->util->get_plugin_base_file(), $this->m('activate'));
61
+ //Init lightbox admin
62
+ add_action('admin_init', $this->m('admin_settings'));
63
+
64
+ //Init lightbox (client-side)
65
+ add_action('wp_enqueue_scripts', $this->m('enqueue_files'));
66
+ add_action('wp_head', $this->m('client_init'));
67
+ add_filter('plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m('admin_plugin_action_links'), 10, 4);
68
+
69
+ }
70
+
71
+ function activate() {
72
+ //Set default options (if not yet set)
73
+ $this->reset_options(false);
74
+ }
75
+
76
+ /**
77
+ * Resets option values to their default values
78
+ * @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE
79
+ */
80
+ function reset_options($hard = true) {
81
+ foreach ( $this->options_default as $id => $data ) {
82
+ $opt = $this->add_prefix($id);
83
+ if ( !$hard && !is_null(get_option($opt, null)) ) {
84
+ continue;
85
+ }
86
+ update_option($opt, $data[0]);
87
+ }
88
+ }
89
+
90
+ /*-** Helpers **-*/
91
+
92
+ /**
93
+ * Checks whether lightbox is currently enabled/disabled
94
+ * @return bool TRUE if lightbox is currently enabled, FALSE otherwise
95
+ */
96
+ function is_enabled($check_request = true) {
97
+ $ret = ( get_option($this->add_prefix('enabled')) ) ? true : false;
98
+ if ( $ret && !! $check_request ) {
99
+ $opt = '';
100
+ //Determine option to check
101
+ if ( is_home() )
102
+ $opt = 'home';
103
+ elseif ( is_single() )
104
+ $opt = 'single';
105
+ elseif ( is_archive() || is_search() )
106
+ $opt = 'archive';
107
+ //Check option
108
+ if ( ! empty($opt) && ( $opt = 'enabled_' . $opt ) && isset($this->options_default[$opt]) ) {
109
+ $ret = ( get_option($this->add_prefix($opt)) ) ? true : false;
110
+ }
111
+ }
112
+ return $ret;
113
+ }
114
+
115
+ /**
116
+ * Builds object of option data
117
+ * Properties:
118
+ * > id: Option ID
119
+ * > value: Option's value (uses default value if option not yet set)
120
+ * > value_default: Option's default value (formatted)
121
+ *
122
+ * @param string $option Option name
123
+ * @return object Option data
124
+ */
125
+ function get_option($option) {
126
+ $ret = new stdClass();
127
+ $ret->id = $this->add_prefix($option);
128
+ $ret->value = get_option($ret->id, $this->get_default_value($option, false));
129
+ $ret->value_default = $this->get_default_value($option, false);
130
+ $ret->value_default_formatted = $this->get_default_value($option);
131
+ $ret->attr = $this->get_default_attr($option);
132
+ return $ret;
133
+ }
134
+
135
+ /**
136
+ * Retrieve an option's value
137
+ * @param string $option Option name
138
+ * @return mixed Option value
139
+ */
140
+ function get_option_value($option) {
141
+ $opt = $this->get_option($option);
142
+ return $opt->value;
143
+ }
144
+
145
+ /**
146
+ * Retrieve default attributes for an option
147
+ * @param string $option Option name
148
+ * @return array Default attributes
149
+ */
150
+ function get_default_attr($option) {
151
+ $ret = array();
152
+ if ( isset($this->options_default[$option][2]) )
153
+ $ret = $this->options_default[$option][2];
154
+ return $ret;
155
+ }
156
+
157
+ /**
158
+ * Retrieve default value for specified option
159
+ * @param string $option Option name
160
+ * @param bool $formatted Whether to return formatted value (e.g. for use in admin UI)
161
+ * @return mixed Option default value
162
+ */
163
+ function get_default_value($option, $formatted = true) {
164
+ $ret = '';
165
+ if ( isset($this->options_default[$option][0]) ) {
166
+ $ret = $this->options_default[$option][0];
167
+ //Format value (if required)
168
+ if ( $formatted ) {
169
+ if ( is_bool($ret) || ( is_string($ret) && 'on' == $ret ) )
170
+ $ret = ( $ret ) ? 'Enabled' : 'Disabled';
171
+ if ( is_numeric($ret) )
172
+ $ret = strval($ret);
173
+ }
174
+ }
175
+ return $ret;
176
+ }
177
+
178
+ /*-** Frontend **-*/
179
+
180
+ /**
181
+ * Enqueue files in template head
182
+ */
183
+ function enqueue_files() {
184
+ if ( ! $this->is_enabled() )
185
+ return;
186
+ wp_enqueue_script($this->add_prefix('lib'), $this->util->get_file_url('js/lib.js'));
187
+ wp_enqueue_style($this->add_prefix('lightbox_css'), $this->util->get_file_url('css/lightbox.css'));
188
+ }
189
+
190
+ /**
191
+ * Sets options/settings to initialize lightbox functionality on page load
192
+ * @return void
193
+ */
194
+ function client_init() {
195
+ if ( ! $this->is_enabled() )
196
+ return;
197
+
198
+ $options = array();
199
+ $out = array();
200
+ $out['script_start'] = '<script type="text/javascript">Event.observe(window,"load",function(){';
201
+ $out['script_end'] = '});</script>';
202
+ $js_code = array();
203
+ //Activate links on page
204
+ if ( $this->get_option_value('activate_links') ) {
205
+ ob_start();
206
+ ?>
207
+ $$('a[href$=".jpg"]:not([rel~="lightbox"])','a[href$=".jpeg"]:not([rel~="lightbox"])','a[href$=".gif"]:not([rel~="lightbox"])','a[href$=".png"]:not([rel~="lightbox"])').each(function(el){var rel=(el.rel.length > 0) ? el.rel + ' ' : '';el.rel=rel + 'lightbox';});
208
+ <?php
209
+ $js_code[] = ob_get_clean();
210
+ }
211
+ //Get options
212
+ $options['autoPlay'] = get_option($this->add_prefix('autostart'));
213
+ $options['slideTime'] = get_option($this->add_prefix('duration'));
214
+ $options['loop'] = get_option($this->add_prefix('loop'));
215
+ $options['overlayOpacity'] = get_option($this->add_prefix('overlay_opacity'));
216
+ $lb_obj = array();
217
+ foreach ($options as $option => $val) {
218
+ if ($val === TRUE || $val == 'on')
219
+ $val = 'true';
220
+ elseif ($val === FALSE || empty($val))
221
+ $val = 'false';
222
+ $lb_obj[] = "'{$option}':{$val}";
223
+ }
224
+ $js_code[] = 'Lightbox.initialize({' . implode(',', $lb_obj) . '});';
225
+ echo $out['script_start'] . implode('', $js_code) . $out['script_end'];
226
+ }
227
+
228
+
229
+ /*-** Admin **-*/
230
+
231
+ /**
232
+ * Adds custom links below plugin on plugin listing page
233
+ * @param $actions
234
+ * @param $plugin_file
235
+ * @param $plugin_data
236
+ * @param $context
237
+ */
238
+ function admin_plugin_action_links($actions, $plugin_file, $plugin_data, $context) {
239
+ //Add link to settings (only if active)
240
+ if ( is_plugin_active($this->util->get_plugin_base_name()) ) {
241
+ array_unshift($actions, '<a href="options-media.php#' . $this->admin_get_settings_section() . '" title="' . __('Settings') . '">' . __('Settings') . '</a>');
242
+ }
243
+ return $actions;
244
+ }
245
+
246
+ /**
247
+ * Adds settings section for Lightbox functionality
248
+ * Section is added to Settings > Media Admin menu
249
+ */
250
+ function admin_settings() {
251
+ $page = $this->options_admin_page;
252
+ $form = $this->options_admin_form;
253
+ $curr = basename($_SERVER['SCRIPT_NAME']);
254
+ if ( $curr != $page && $curr != $form ) {
255
+ return;
256
+ }
257
+
258
+ $page = 'media';
259
+ $section = $this->get_prefix();
260
+ //Section
261
+ add_settings_section($section, '<span id="' . $this->admin_get_settings_section() . '">' . __('Lightbox Settings') . '</span>', $this->m('admin_section'), $page);
262
+ //Fields
263
+ foreach ($this->options_default as $key => $defaults) {
264
+ $id = $this->add_prefix($key);
265
+ $func = 'admin_field_' . $key;
266
+ $callback = ( method_exists($this, $func) ) ? $this->m($func) : $this->m('admin_field_default');
267
+ //Add option to DB if not yet set
268
+ if ( is_null(get_option($id, null)) )
269
+ update_option($id, $defaults[0]);
270
+ add_settings_field($id, __($defaults[1]), $callback, $page, $section, array('label_for' => $id, 'opt' => $key));
271
+ register_setting($page, $id);
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Get ID of settings section on admin page
277
+ * @return string ID of settings section
278
+ */
279
+ function admin_get_settings_section() {
280
+ return $this->add_prefix('settings');
281
+ }
282
+
283
+ /**
284
+ * Placeholder function for lightbox admin settings
285
+ * Required because setting init function requires a callback
286
+ */
287
+ function admin_section() { }
288
+
289
+ /**
290
+ * General field builder
291
+ * @param string $option Option name to build field for
292
+ * @param string $format Field markup (using sprintf specifiers)
293
+ * @param string $type (optional) Type of field being build (e.g. checkbox, text, etc.)
294
+ * Specifiers:
295
+ * 1. Field ID
296
+ * 2. Field Value
297
+ * 3. Field Default Value (formatted)
298
+ * 4. Field Type
299
+ */
300
+ function admin_the_field($option, $format = '', $type = '') {
301
+ $opt = $this->get_option($option);
302
+ $format_default = '<input id="%1$s" name="%1$s" %4$s class="code" /> (Default: %3$s)';
303
+ if ( empty($format) )
304
+ $format = $format_default;
305
+ if ( empty($type) || !is_string($type) ) {
306
+ $type_default = 'text';
307
+ $type = ( is_bool($opt->value_default) ) ? 'checkbox' : $type_default;
308
+ }
309
+ //Adjust type and value formatting based on type
310
+ switch ( $type ) {
311
+ case 'checkbox' :
312
+ if ( $opt->value )
313
+ $opt->attr['checked'] = 'checked';
314
+ break;
315
+ case 'text' :
316
+ if ( $format == $format_default )
317
+ $format = str_replace('%4$s', '%4$s value="%2$s"', $format);
318
+ break;
319
+ }
320
+ $opt->attr['type'] = $type;
321
+ //Build attribute string
322
+ $attr = '';
323
+ if ( ! empty($opt->attr) ) {
324
+ $attr = $this->util->build_attribute_string($opt->attr);
325
+ }
326
+
327
+ echo sprintf($format, $opt->id, $opt->value, $opt->value_default_formatted, $attr);
328
+ }
329
+
330
+ /**
331
+ * Default field output generator
332
+ * @param array $args Arguments set in admin_settings
333
+ */
334
+ function admin_field_default($args = array()) {
335
+ $opt = ( isset($args['opt']) ) ? $args['opt'] : '';
336
+ $this->admin_the_field($opt);
337
+ }
338
+ }
339
+
340
+ ?>
readme.txt ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: archetyped
3
+ Tags: lightbox, gallery, photography, images
4
+ Requires at least: 2.9.2
5
+ Tested up to: 2.9.2
6
+ Stable tag: trunk
7
+
8
+ A simple and customizable Lightbox for Wordpress
9
+
10
+ == Description ==
11
+
12
+ Simple Lightbox is a very simple and customizable lightbox that is easy to add to your Wordpress website
13
+
14
+ #### Customization
15
+ Options for customizing the lightbox behavior are located in the **Settings > Media** admin menu in the **Lightbox Settings** section (or just click the **Settings** link below the plugin's name when viewing the list of installed plugins)
16
+
17
+ * Enable/Disable Lightbox Functionality (Default: Enabled)
18
+ * Enable Lightbox depending on Page Type (Home, Pages, Archive, etc.)
19
+ * Automatically activate lightbox for links to images on page (no need to add `rel="lightbox"` attribute to link)
20
+ * Automatically Start Slideshow (Default: Enabled)
21
+ * Slide Duration (Seconds) (Default: 6)
22
+ * Loop through images (Default: Enabled)
23
+ * Overlay Opacity (0 - 1) (Default: 0.8)
24
+
25
+ #### Usage
26
+ * The necessary Javascript and CSS files will be automatically added to the page as long as `wp_head()` is called in the theme
27
+ * That's it!
28
+
29
+ == Installation ==
30
+
31
+ 1. Upload `simple-lightbox` folder to the `/wp-content/plugins/` directory
32
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
33
+ 1. Verify that your theme uses the `wp_head()` template tag (this is where the necessary files will be added to your theme output)
34
+ 1. Let plugin automatically add lightbox functionality for links to images or manually add `rel="lightbox"` to any image links that you want to be displayed in a lightbox
35
+
36
+ == Upgrade Notice ==
37
+
38
+ No upgrade notices
39
+
40
+ == Frequently Asked Questions ==
41
+
42
+ Send your questions to wp@archetyped.com
43
+
44
+ == Screenshots ==
45
+
46
+ 1. Lightbox Options
47
+
48
+ == Changelog ==
49
+ = 1.1 =
50
+ * Added: Enable/disable lightbox functionality by page type (Home, Pages/Posts, Archive, etc.)
51
+ * Added: Automatically activate lightbox functionality for image links
52
+ * Added: Link to settings menu on plugin listing page
53
+ * Optimized: Options menu field building
54
+ * Optimized: Loading of default values for plugin options
55
+ * Optimized: General code optimizations
56
+ = 1.0 =
57
+ * Initial release
screenshot-1.gif ADDED
Binary file