scruffy 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +8 -0
- data/History.txt +104 -0
- data/License.txt +20 -0
- data/Manifest.txt +105 -0
- data/PostInstall.txt +6 -0
- data/README.txt +66 -0
- data/Rakefile +108 -104
- data/config/hoe.rb +78 -0
- data/config/requirements.rb +15 -0
- data/lib/scruffy.rb +8 -6
- data/lib/scruffy/components/base.rb +4 -0
- data/lib/scruffy/components/legend.rb +65 -30
- data/lib/scruffy/components/viewport.rb +14 -17
- data/lib/scruffy/formatters.rb +1 -1
- data/lib/scruffy/graph.rb +18 -7
- data/lib/scruffy/graph_state.rb +24 -0
- data/lib/scruffy/helpers.rb +2 -1
- data/lib/scruffy/helpers/canvas.rb +19 -17
- data/lib/scruffy/helpers/layer_container.rb +8 -3
- data/lib/scruffy/helpers/meta.rb +5 -5
- data/lib/scruffy/helpers/point_container.rb +70 -0
- data/lib/scruffy/layers.rb +2 -0
- data/lib/scruffy/layers/average.rb +6 -1
- data/lib/scruffy/layers/bar.rb +1 -0
- data/lib/scruffy/layers/base.rb +38 -14
- data/lib/scruffy/layers/pie.rb +123 -0
- data/lib/scruffy/layers/pie_slice.rb +114 -0
- data/lib/scruffy/layers/scatter.rb +21 -0
- data/lib/scruffy/layers/sparkline_bar.rb +1 -0
- data/lib/scruffy/layers/stacked.rb +2 -5
- data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +1 -2
- data/lib/scruffy/renderers.rb +2 -1
- data/lib/scruffy/renderers/base.rb +6 -4
- data/lib/scruffy/renderers/pie.rb +20 -0
- data/lib/scruffy/themes.rb +54 -4
- data/lib/scruffy/version.rb +8 -2
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/spec/scruffy/graph_spec.rb +175 -0
- data/spec/scruffy/layers/base_spec.rb +30 -0
- data/spec/{layers → scruffy/layers}/line_spec.rb +2 -1
- data/spec/spec_helper.rb +8 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/graph_creation_test.rb +101 -0
- data/test/test_helper.rb +2 -0
- data/test/test_scruffy.rb +11 -0
- data/website/images/blank.gif.html +7 -0
- data/website/images/graphs/all_smiles.png +0 -0
- data/website/images/graphs/bar_test.png +0 -0
- data/website/images/graphs/bar_test.svg +71 -0
- data/website/images/graphs/line_test.png +0 -0
- data/website/images/graphs/line_test.svg +60 -0
- data/website/images/graphs/multi_test.png +0 -0
- data/website/images/graphs/multi_test.svg +296 -0
- data/website/images/graphs/pie_test.png +0 -0
- data/website/images/graphs/pie_test.svg +40 -0
- data/website/images/graphs/split_test.png +0 -0
- data/website/images/graphs/split_test.svg +295 -0
- data/website/images/graphs/stacking_test.png +0 -0
- data/website/images/graphs/stacking_test.svg +146 -0
- data/website/images/header.png +0 -0
- data/website/images/header_gradient.png +0 -0
- data/website/images/overlay.png +0 -0
- data/website/images/scruffy.png +0 -0
- data/website/index.html +294 -0
- data/website/index.txt +199 -0
- data/website/javascripts/application.js +2 -0
- data/website/javascripts/controls.js +815 -0
- data/website/javascripts/dragdrop.js +913 -0
- data/website/javascripts/effects.js +958 -0
- data/website/javascripts/lightbox.js +437 -0
- data/website/javascripts/prototype.js +2006 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/lightbox.css +27 -0
- data/website/stylesheets/screen.css +147 -0
- data/website/stylesheets/scruffy.css +227 -0
- data/website/template.html.erb +47 -0
- metadata +135 -55
- data/spec/graph_spec.rb +0 -162
@@ -0,0 +1,437 @@
|
|
1
|
+
/*
|
2
|
+
Lightbox JS: Fullsize Image Overlays
|
3
|
+
by Lokesh Dhakar - http://www.huddletogether.com
|
4
|
+
|
5
|
+
For more information on this script, visit:
|
6
|
+
http://huddletogether.com/projects/lightbox/
|
7
|
+
|
8
|
+
Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
|
9
|
+
(basically, do anything you want, just leave my name and link)
|
10
|
+
|
11
|
+
Table of Contents
|
12
|
+
-----------------
|
13
|
+
Configuration
|
14
|
+
|
15
|
+
Functions
|
16
|
+
- getPageScroll()
|
17
|
+
- getPageSize()
|
18
|
+
- pause()
|
19
|
+
- getKey()
|
20
|
+
- listenKey()
|
21
|
+
- showLightbox()
|
22
|
+
- hideLightbox()
|
23
|
+
- initLightbox()
|
24
|
+
- addLoadEvent()
|
25
|
+
|
26
|
+
Function Calls
|
27
|
+
- addLoadEvent(initLightbox)
|
28
|
+
|
29
|
+
*/
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
//
|
34
|
+
// Configuration
|
35
|
+
//
|
36
|
+
|
37
|
+
// If you would like to use a custom loading image or close button reference them in the next two lines.
|
38
|
+
var loadingImage = 'loading.gif';
|
39
|
+
var closeButton = 'close.gif';
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
//
|
46
|
+
// getPageScroll()
|
47
|
+
// Returns array with x,y page scroll values.
|
48
|
+
// Core code from - quirksmode.org
|
49
|
+
//
|
50
|
+
function getPageScroll(){
|
51
|
+
|
52
|
+
var yScroll;
|
53
|
+
|
54
|
+
if (self.pageYOffset) {
|
55
|
+
yScroll = self.pageYOffset;
|
56
|
+
} else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict
|
57
|
+
yScroll = document.documentElement.scrollTop;
|
58
|
+
} else if (document.body) {// all other Explorers
|
59
|
+
yScroll = document.body.scrollTop;
|
60
|
+
}
|
61
|
+
|
62
|
+
arrayPageScroll = new Array('',yScroll)
|
63
|
+
return arrayPageScroll;
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
//
|
69
|
+
// getPageSize()
|
70
|
+
// Returns array with page width, height and window width, height
|
71
|
+
// Core code from - quirksmode.org
|
72
|
+
// Edit for Firefox by pHaez
|
73
|
+
//
|
74
|
+
function getPageSize(){
|
75
|
+
|
76
|
+
var xScroll, yScroll;
|
77
|
+
|
78
|
+
if (window.innerHeight && window.scrollMaxY) {
|
79
|
+
xScroll = document.body.scrollWidth;
|
80
|
+
yScroll = window.innerHeight + window.scrollMaxY;
|
81
|
+
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
|
82
|
+
xScroll = document.body.scrollWidth;
|
83
|
+
yScroll = document.body.scrollHeight;
|
84
|
+
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
|
85
|
+
xScroll = document.body.offsetWidth;
|
86
|
+
yScroll = document.body.offsetHeight;
|
87
|
+
}
|
88
|
+
|
89
|
+
var windowWidth, windowHeight;
|
90
|
+
if (self.innerHeight) { // all except Explorer
|
91
|
+
windowWidth = self.innerWidth;
|
92
|
+
windowHeight = self.innerHeight;
|
93
|
+
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
|
94
|
+
windowWidth = document.documentElement.clientWidth;
|
95
|
+
windowHeight = document.documentElement.clientHeight;
|
96
|
+
} else if (document.body) { // other Explorers
|
97
|
+
windowWidth = document.body.clientWidth;
|
98
|
+
windowHeight = document.body.clientHeight;
|
99
|
+
}
|
100
|
+
|
101
|
+
// for small pages with total height less then height of the viewport
|
102
|
+
if(yScroll < windowHeight){
|
103
|
+
pageHeight = windowHeight;
|
104
|
+
} else {
|
105
|
+
pageHeight = yScroll;
|
106
|
+
}
|
107
|
+
|
108
|
+
// for small pages with total width less then width of the viewport
|
109
|
+
if(xScroll < windowWidth){
|
110
|
+
pageWidth = windowWidth;
|
111
|
+
} else {
|
112
|
+
pageWidth = xScroll;
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
|
117
|
+
return arrayPageSize;
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
//
|
122
|
+
// pause(numberMillis)
|
123
|
+
// Pauses code execution for specified time. Uses busy code, not good.
|
124
|
+
// Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
|
125
|
+
//
|
126
|
+
function pause(numberMillis) {
|
127
|
+
var now = new Date();
|
128
|
+
var exitTime = now.getTime() + numberMillis;
|
129
|
+
while (true) {
|
130
|
+
now = new Date();
|
131
|
+
if (now.getTime() > exitTime)
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
//
|
137
|
+
// getKey(key)
|
138
|
+
// Gets keycode. If 'x' is pressed then it hides the lightbox.
|
139
|
+
//
|
140
|
+
|
141
|
+
function getKey(e){
|
142
|
+
if (e == null) { // ie
|
143
|
+
keycode = event.keyCode;
|
144
|
+
} else { // mozilla
|
145
|
+
keycode = e.which;
|
146
|
+
}
|
147
|
+
key = String.fromCharCode(keycode).toLowerCase();
|
148
|
+
|
149
|
+
if(key == 'x'){ hideLightbox(); }
|
150
|
+
}
|
151
|
+
|
152
|
+
|
153
|
+
//
|
154
|
+
// listenKey()
|
155
|
+
//
|
156
|
+
function listenKey () { document.onkeypress = getKey; }
|
157
|
+
|
158
|
+
|
159
|
+
//
|
160
|
+
// showLightbox()
|
161
|
+
// Preloads images. Pleaces new image in lightbox then centers and displays.
|
162
|
+
//
|
163
|
+
function showLightbox(objLink)
|
164
|
+
{
|
165
|
+
// prep objects
|
166
|
+
var objOverlay = document.getElementById('overlay');
|
167
|
+
var objLightbox = document.getElementById('lightbox');
|
168
|
+
var objCaption = document.getElementById('lightboxCaption');
|
169
|
+
var objImage = document.getElementById('lightboxImage');
|
170
|
+
var objLoadingImage = document.getElementById('loadingImage');
|
171
|
+
var objLightboxDetails = document.getElementById('lightboxDetails');
|
172
|
+
|
173
|
+
|
174
|
+
var arrayPageSize = getPageSize();
|
175
|
+
var arrayPageScroll = getPageScroll();
|
176
|
+
|
177
|
+
// center loadingImage if it exists
|
178
|
+
if (objLoadingImage) {
|
179
|
+
objLoadingImage.style.top = (arrayPageScroll[1] + ((arrayPageSize[3] - 35 - objLoadingImage.height) / 2) + 'px');
|
180
|
+
objLoadingImage.style.left = (((arrayPageSize[0] - 20 - objLoadingImage.width) / 2) + 'px');
|
181
|
+
objLoadingImage.style.display = 'block';
|
182
|
+
}
|
183
|
+
|
184
|
+
// set height of Overlay to take up whole page and show
|
185
|
+
objOverlay.style.height = (arrayPageSize[1] + 'px');
|
186
|
+
objOverlay.style.display = 'block';
|
187
|
+
|
188
|
+
// preload image
|
189
|
+
imgPreload = new Image();
|
190
|
+
|
191
|
+
imgPreload.onload=function(){
|
192
|
+
objImage.src = objLink.href;
|
193
|
+
|
194
|
+
// center lightbox and make sure that the top and left values are not negative
|
195
|
+
// and the image placed outside the viewport
|
196
|
+
var lightboxTop = arrayPageScroll[1] + ((arrayPageSize[3] - 35 - imgPreload.height) / 2);
|
197
|
+
var lightboxLeft = ((arrayPageSize[0] - 20 - imgPreload.width) / 2);
|
198
|
+
|
199
|
+
objLightbox.style.top = (lightboxTop < 0) ? "0px" : lightboxTop + "px";
|
200
|
+
objLightbox.style.left = (lightboxLeft < 0) ? "0px" : lightboxLeft + "px";
|
201
|
+
|
202
|
+
|
203
|
+
objLightboxDetails.style.width = imgPreload.width + 'px';
|
204
|
+
|
205
|
+
if(objLink.getAttribute('title')){
|
206
|
+
objCaption.style.display = 'block';
|
207
|
+
//objCaption.style.width = imgPreload.width + 'px';
|
208
|
+
objCaption.innerHTML = objLink.getAttribute('title');
|
209
|
+
} else {
|
210
|
+
objCaption.style.display = 'none';
|
211
|
+
}
|
212
|
+
|
213
|
+
// A small pause between the image loading and displaying is required with IE,
|
214
|
+
// this prevents the previous image displaying for a short burst causing flicker.
|
215
|
+
if (navigator.appVersion.indexOf("MSIE")!=-1){
|
216
|
+
pause(250);
|
217
|
+
}
|
218
|
+
|
219
|
+
if (objLoadingImage) { objLoadingImage.style.display = 'none'; }
|
220
|
+
|
221
|
+
// Hide select boxes as they will 'peek' through the image in IE
|
222
|
+
selects = document.getElementsByTagName("select");
|
223
|
+
for (i = 0; i != selects.length; i++) {
|
224
|
+
selects[i].style.visibility = "hidden";
|
225
|
+
}
|
226
|
+
|
227
|
+
|
228
|
+
objLightbox.style.display = 'block';
|
229
|
+
|
230
|
+
// After image is loaded, update the overlay height as the new image might have
|
231
|
+
// increased the overall page height.
|
232
|
+
arrayPageSize = getPageSize();
|
233
|
+
objOverlay.style.height = (arrayPageSize[1] + 'px');
|
234
|
+
|
235
|
+
// Check for 'x' keypress
|
236
|
+
listenKey();
|
237
|
+
|
238
|
+
return false;
|
239
|
+
}
|
240
|
+
|
241
|
+
imgPreload.src = objLink.href;
|
242
|
+
|
243
|
+
}
|
244
|
+
|
245
|
+
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
//
|
250
|
+
// hideLightbox()
|
251
|
+
//
|
252
|
+
function hideLightbox()
|
253
|
+
{
|
254
|
+
// get objects
|
255
|
+
objOverlay = document.getElementById('overlay');
|
256
|
+
objLightbox = document.getElementById('lightbox');
|
257
|
+
|
258
|
+
// hide lightbox and overlay
|
259
|
+
objOverlay.style.display = 'none';
|
260
|
+
objLightbox.style.display = 'none';
|
261
|
+
|
262
|
+
// make select boxes visible
|
263
|
+
selects = document.getElementsByTagName("select");
|
264
|
+
for (i = 0; i != selects.length; i++) {
|
265
|
+
selects[i].style.visibility = "visible";
|
266
|
+
}
|
267
|
+
|
268
|
+
// disable keypress listener
|
269
|
+
document.onkeypress = '';
|
270
|
+
}
|
271
|
+
|
272
|
+
|
273
|
+
|
274
|
+
|
275
|
+
//
|
276
|
+
// initLightbox()
|
277
|
+
// Function runs on window load, going through link tags looking for rel="lightbox".
|
278
|
+
// These links receive onclick events that enable the lightbox display for their targets.
|
279
|
+
// The function also inserts html markup at the top of the page which will be used as a
|
280
|
+
// container for the overlay pattern and the inline image.
|
281
|
+
//
|
282
|
+
function initLightbox()
|
283
|
+
{
|
284
|
+
|
285
|
+
if (!document.getElementsByTagName){ return; }
|
286
|
+
var anchors = document.getElementsByTagName("a");
|
287
|
+
|
288
|
+
// loop through all anchor tags
|
289
|
+
for (var i=0; i<anchors.length; i++){
|
290
|
+
var anchor = anchors[i];
|
291
|
+
|
292
|
+
if (anchor.getAttribute("href") && (anchor.getAttribute("rel") == "lightbox")){
|
293
|
+
anchor.onclick = function () {showLightbox(this); return false;}
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
// the rest of this code inserts html at the top of the page that looks like this:
|
298
|
+
//
|
299
|
+
// <div id="overlay">
|
300
|
+
// <a href="#" onclick="hideLightbox(); return false;"><img id="loadingImage" /></a>
|
301
|
+
// </div>
|
302
|
+
// <div id="lightbox">
|
303
|
+
// <a href="#" onclick="hideLightbox(); return false;" title="Click anywhere to close image">
|
304
|
+
// <img id="closeButton" />
|
305
|
+
// <img id="lightboxImage" />
|
306
|
+
// </a>
|
307
|
+
// <div id="lightboxDetails">
|
308
|
+
// <div id="lightboxCaption"></div>
|
309
|
+
// <div id="keyboardMsg"></div>
|
310
|
+
// </div>
|
311
|
+
// </div>
|
312
|
+
|
313
|
+
var objBody = document.getElementsByTagName("body").item(0);
|
314
|
+
|
315
|
+
// create overlay div and hardcode some functional styles (aesthetic styles are in CSS file)
|
316
|
+
var objOverlay = document.createElement("div");
|
317
|
+
objOverlay.setAttribute('id','overlay');
|
318
|
+
objOverlay.onclick = function () {hideLightbox(); return false;}
|
319
|
+
objOverlay.style.display = 'none';
|
320
|
+
objOverlay.style.position = 'absolute';
|
321
|
+
objOverlay.style.top = '0';
|
322
|
+
objOverlay.style.left = '0';
|
323
|
+
objOverlay.style.zIndex = '90';
|
324
|
+
objOverlay.style.width = '100%';
|
325
|
+
objBody.insertBefore(objOverlay, objBody.firstChild);
|
326
|
+
|
327
|
+
var arrayPageSize = getPageSize();
|
328
|
+
var arrayPageScroll = getPageScroll();
|
329
|
+
|
330
|
+
// preload and create loader image
|
331
|
+
var imgPreloader = new Image();
|
332
|
+
|
333
|
+
// if loader image found, create link to hide lightbox and create loadingimage
|
334
|
+
imgPreloader.onload=function(){
|
335
|
+
|
336
|
+
var objLoadingImageLink = document.createElement("a");
|
337
|
+
objLoadingImageLink.setAttribute('href','#');
|
338
|
+
objLoadingImageLink.onclick = function () {hideLightbox(); return false;}
|
339
|
+
objOverlay.appendChild(objLoadingImageLink);
|
340
|
+
|
341
|
+
var objLoadingImage = document.createElement("img");
|
342
|
+
objLoadingImage.src = loadingImage;
|
343
|
+
objLoadingImage.setAttribute('id','loadingImage');
|
344
|
+
objLoadingImage.style.position = 'absolute';
|
345
|
+
objLoadingImage.style.zIndex = '150';
|
346
|
+
objLoadingImageLink.appendChild(objLoadingImage);
|
347
|
+
|
348
|
+
imgPreloader.onload=function(){}; // clear onLoad, as IE will flip out w/animated gifs
|
349
|
+
|
350
|
+
return false;
|
351
|
+
}
|
352
|
+
|
353
|
+
imgPreloader.src = loadingImage;
|
354
|
+
|
355
|
+
// create lightbox div, same note about styles as above
|
356
|
+
var objLightbox = document.createElement("div");
|
357
|
+
objLightbox.setAttribute('id','lightbox');
|
358
|
+
objLightbox.style.display = 'none';
|
359
|
+
objLightbox.style.position = 'absolute';
|
360
|
+
objLightbox.style.zIndex = '100';
|
361
|
+
objBody.insertBefore(objLightbox, objOverlay.nextSibling);
|
362
|
+
|
363
|
+
// create link
|
364
|
+
var objLink = document.createElement("a");
|
365
|
+
objLink.setAttribute('href','#');
|
366
|
+
objLink.setAttribute('title','Click to close');
|
367
|
+
objLink.onclick = function () {hideLightbox(); return false;}
|
368
|
+
objLightbox.appendChild(objLink);
|
369
|
+
|
370
|
+
// preload and create close button image
|
371
|
+
var imgPreloadCloseButton = new Image();
|
372
|
+
|
373
|
+
// if close button image found,
|
374
|
+
imgPreloadCloseButton.onload=function(){
|
375
|
+
|
376
|
+
var objCloseButton = document.createElement("img");
|
377
|
+
objCloseButton.src = closeButton;
|
378
|
+
objCloseButton.setAttribute('id','closeButton');
|
379
|
+
objCloseButton.style.position = 'absolute';
|
380
|
+
objCloseButton.style.zIndex = '200';
|
381
|
+
objLink.appendChild(objCloseButton);
|
382
|
+
|
383
|
+
return false;
|
384
|
+
}
|
385
|
+
|
386
|
+
imgPreloadCloseButton.src = closeButton;
|
387
|
+
|
388
|
+
// create image
|
389
|
+
var objImage = document.createElement("img");
|
390
|
+
objImage.setAttribute('id','lightboxImage');
|
391
|
+
objLink.appendChild(objImage);
|
392
|
+
|
393
|
+
// create details div, a container for the caption and keyboard message
|
394
|
+
var objLightboxDetails = document.createElement("div");
|
395
|
+
objLightboxDetails.setAttribute('id','lightboxDetails');
|
396
|
+
objLightbox.appendChild(objLightboxDetails);
|
397
|
+
|
398
|
+
// create caption
|
399
|
+
var objCaption = document.createElement("div");
|
400
|
+
objCaption.setAttribute('id','lightboxCaption');
|
401
|
+
objCaption.style.display = 'none';
|
402
|
+
objLightboxDetails.appendChild(objCaption);
|
403
|
+
|
404
|
+
// create keyboard message
|
405
|
+
var objKeyboardMsg = document.createElement("div");
|
406
|
+
objKeyboardMsg.setAttribute('id','keyboardMsg');
|
407
|
+
objKeyboardMsg.innerHTML = 'press <a href="#" onclick="hideLightbox(); return false;"><kbd>x</kbd></a> to close';
|
408
|
+
objLightboxDetails.appendChild(objKeyboardMsg);
|
409
|
+
|
410
|
+
|
411
|
+
}
|
412
|
+
|
413
|
+
|
414
|
+
|
415
|
+
|
416
|
+
//
|
417
|
+
// addLoadEvent()
|
418
|
+
// Adds event to window.onload without overwriting currently assigned onload functions.
|
419
|
+
// Function found at Simon Willison's weblog - http://simon.incutio.com/
|
420
|
+
//
|
421
|
+
function addLoadEvent(func)
|
422
|
+
{
|
423
|
+
var oldonload = window.onload;
|
424
|
+
if (typeof window.onload != 'function'){
|
425
|
+
window.onload = func;
|
426
|
+
} else {
|
427
|
+
window.onload = function(){
|
428
|
+
oldonload();
|
429
|
+
func();
|
430
|
+
}
|
431
|
+
}
|
432
|
+
|
433
|
+
}
|
434
|
+
|
435
|
+
|
436
|
+
|
437
|
+
addLoadEvent(initLightbox); // run initLightbox onLoad
|
@@ -0,0 +1,2006 @@
|
|
1
|
+
/* Prototype JavaScript framework, version 1.5.0_rc0
|
2
|
+
* (c) 2005 Sam Stephenson <sam@conio.net>
|
3
|
+
*
|
4
|
+
* Prototype is freely distributable under the terms of an MIT-style license.
|
5
|
+
* For details, see the Prototype web site: http://prototype.conio.net/
|
6
|
+
*
|
7
|
+
/*--------------------------------------------------------------------------*/
|
8
|
+
|
9
|
+
var Prototype = {
|
10
|
+
Version: '1.5.0_rc0',
|
11
|
+
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
|
12
|
+
|
13
|
+
emptyFunction: function() {},
|
14
|
+
K: function(x) {return x}
|
15
|
+
}
|
16
|
+
|
17
|
+
var Class = {
|
18
|
+
create: function() {
|
19
|
+
return function() {
|
20
|
+
this.initialize.apply(this, arguments);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
var Abstract = new Object();
|
26
|
+
|
27
|
+
Object.extend = function(destination, source) {
|
28
|
+
for (var property in source) {
|
29
|
+
destination[property] = source[property];
|
30
|
+
}
|
31
|
+
return destination;
|
32
|
+
}
|
33
|
+
|
34
|
+
Object.inspect = function(object) {
|
35
|
+
try {
|
36
|
+
if (object == undefined) return 'undefined';
|
37
|
+
if (object == null) return 'null';
|
38
|
+
return object.inspect ? object.inspect() : object.toString();
|
39
|
+
} catch (e) {
|
40
|
+
if (e instanceof RangeError) return '...';
|
41
|
+
throw e;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
Function.prototype.bind = function() {
|
46
|
+
var __method = this, args = $A(arguments), object = args.shift();
|
47
|
+
return function() {
|
48
|
+
return __method.apply(object, args.concat($A(arguments)));
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
Function.prototype.bindAsEventListener = function(object) {
|
53
|
+
var __method = this;
|
54
|
+
return function(event) {
|
55
|
+
return __method.call(object, event || window.event);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
Object.extend(Number.prototype, {
|
60
|
+
toColorPart: function() {
|
61
|
+
var digits = this.toString(16);
|
62
|
+
if (this < 16) return '0' + digits;
|
63
|
+
return digits;
|
64
|
+
},
|
65
|
+
|
66
|
+
succ: function() {
|
67
|
+
return this + 1;
|
68
|
+
},
|
69
|
+
|
70
|
+
times: function(iterator) {
|
71
|
+
$R(0, this, true).each(iterator);
|
72
|
+
return this;
|
73
|
+
}
|
74
|
+
});
|
75
|
+
|
76
|
+
var Try = {
|
77
|
+
these: function() {
|
78
|
+
var returnValue;
|
79
|
+
|
80
|
+
for (var i = 0; i < arguments.length; i++) {
|
81
|
+
var lambda = arguments[i];
|
82
|
+
try {
|
83
|
+
returnValue = lambda();
|
84
|
+
break;
|
85
|
+
} catch (e) {}
|
86
|
+
}
|
87
|
+
|
88
|
+
return returnValue;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
/*--------------------------------------------------------------------------*/
|
93
|
+
|
94
|
+
var PeriodicalExecuter = Class.create();
|
95
|
+
PeriodicalExecuter.prototype = {
|
96
|
+
initialize: function(callback, frequency) {
|
97
|
+
this.callback = callback;
|
98
|
+
this.frequency = frequency;
|
99
|
+
this.currentlyExecuting = false;
|
100
|
+
|
101
|
+
this.registerCallback();
|
102
|
+
},
|
103
|
+
|
104
|
+
registerCallback: function() {
|
105
|
+
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
106
|
+
},
|
107
|
+
|
108
|
+
onTimerEvent: function() {
|
109
|
+
if (!this.currentlyExecuting) {
|
110
|
+
try {
|
111
|
+
this.currentlyExecuting = true;
|
112
|
+
this.callback();
|
113
|
+
} finally {
|
114
|
+
this.currentlyExecuting = false;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
Object.extend(String.prototype, {
|
120
|
+
gsub: function(pattern, replacement) {
|
121
|
+
var result = '', source = this, match;
|
122
|
+
replacement = arguments.callee.prepareReplacement(replacement);
|
123
|
+
|
124
|
+
while (source.length > 0) {
|
125
|
+
if (match = source.match(pattern)) {
|
126
|
+
result += source.slice(0, match.index);
|
127
|
+
result += (replacement(match) || '').toString();
|
128
|
+
source = source.slice(match.index + match[0].length);
|
129
|
+
} else {
|
130
|
+
result += source, source = '';
|
131
|
+
}
|
132
|
+
}
|
133
|
+
return result;
|
134
|
+
},
|
135
|
+
|
136
|
+
sub: function(pattern, replacement, count) {
|
137
|
+
replacement = this.gsub.prepareReplacement(replacement);
|
138
|
+
count = count === undefined ? 1 : count;
|
139
|
+
|
140
|
+
return this.gsub(pattern, function(match) {
|
141
|
+
if (--count < 0) return match[0];
|
142
|
+
return replacement(match);
|
143
|
+
});
|
144
|
+
},
|
145
|
+
|
146
|
+
scan: function(pattern, iterator) {
|
147
|
+
this.gsub(pattern, iterator);
|
148
|
+
return this;
|
149
|
+
},
|
150
|
+
|
151
|
+
truncate: function(length, truncation) {
|
152
|
+
length = length || 30;
|
153
|
+
truncation = truncation === undefined ? '...' : truncation;
|
154
|
+
return this.length > length ?
|
155
|
+
this.slice(0, length - truncation.length) + truncation : this;
|
156
|
+
},
|
157
|
+
|
158
|
+
strip: function() {
|
159
|
+
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
160
|
+
},
|
161
|
+
|
162
|
+
stripTags: function() {
|
163
|
+
return this.replace(/<\/?[^>]+>/gi, '');
|
164
|
+
},
|
165
|
+
|
166
|
+
stripScripts: function() {
|
167
|
+
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
|
168
|
+
},
|
169
|
+
|
170
|
+
extractScripts: function() {
|
171
|
+
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
|
172
|
+
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
|
173
|
+
return (this.match(matchAll) || []).map(function(scriptTag) {
|
174
|
+
return (scriptTag.match(matchOne) || ['', ''])[1];
|
175
|
+
});
|
176
|
+
},
|
177
|
+
|
178
|
+
evalScripts: function() {
|
179
|
+
return this.extractScripts().map(function(script) { return eval(script) });
|
180
|
+
},
|
181
|
+
|
182
|
+
escapeHTML: function() {
|
183
|
+
var div = document.createElement('div');
|
184
|
+
var text = document.createTextNode(this);
|
185
|
+
div.appendChild(text);
|
186
|
+
return div.innerHTML;
|
187
|
+
},
|
188
|
+
|
189
|
+
unescapeHTML: function() {
|
190
|
+
var div = document.createElement('div');
|
191
|
+
div.innerHTML = this.stripTags();
|
192
|
+
return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
|
193
|
+
},
|
194
|
+
|
195
|
+
toQueryParams: function() {
|
196
|
+
var pairs = this.match(/^\??(.*)$/)[1].split('&');
|
197
|
+
return pairs.inject({}, function(params, pairString) {
|
198
|
+
var pair = pairString.split('=');
|
199
|
+
params[pair[0]] = pair[1];
|
200
|
+
return params;
|
201
|
+
});
|
202
|
+
},
|
203
|
+
|
204
|
+
toArray: function() {
|
205
|
+
return this.split('');
|
206
|
+
},
|
207
|
+
|
208
|
+
camelize: function() {
|
209
|
+
var oStringList = this.split('-');
|
210
|
+
if (oStringList.length == 1) return oStringList[0];
|
211
|
+
|
212
|
+
var camelizedString = this.indexOf('-') == 0
|
213
|
+
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
|
214
|
+
: oStringList[0];
|
215
|
+
|
216
|
+
for (var i = 1, len = oStringList.length; i < len; i++) {
|
217
|
+
var s = oStringList[i];
|
218
|
+
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
|
219
|
+
}
|
220
|
+
|
221
|
+
return camelizedString;
|
222
|
+
},
|
223
|
+
|
224
|
+
inspect: function() {
|
225
|
+
return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
|
226
|
+
}
|
227
|
+
});
|
228
|
+
|
229
|
+
String.prototype.gsub.prepareReplacement = function(replacement) {
|
230
|
+
if (typeof replacement == 'function') return replacement;
|
231
|
+
var template = new Template(replacement);
|
232
|
+
return function(match) { return template.evaluate(match) };
|
233
|
+
}
|
234
|
+
|
235
|
+
String.prototype.parseQuery = String.prototype.toQueryParams;
|
236
|
+
|
237
|
+
var Template = Class.create();
|
238
|
+
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
|
239
|
+
Template.prototype = {
|
240
|
+
initialize: function(template, pattern) {
|
241
|
+
this.template = template.toString();
|
242
|
+
this.pattern = pattern || Template.Pattern;
|
243
|
+
},
|
244
|
+
|
245
|
+
evaluate: function(object) {
|
246
|
+
return this.template.gsub(this.pattern, function(match) {
|
247
|
+
var before = match[1];
|
248
|
+
if (before == '\\') return match[2];
|
249
|
+
return before + (object[match[3]] || '').toString();
|
250
|
+
});
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
var $break = new Object();
|
255
|
+
var $continue = new Object();
|
256
|
+
|
257
|
+
var Enumerable = {
|
258
|
+
each: function(iterator) {
|
259
|
+
var index = 0;
|
260
|
+
try {
|
261
|
+
this._each(function(value) {
|
262
|
+
try {
|
263
|
+
iterator(value, index++);
|
264
|
+
} catch (e) {
|
265
|
+
if (e != $continue) throw e;
|
266
|
+
}
|
267
|
+
});
|
268
|
+
} catch (e) {
|
269
|
+
if (e != $break) throw e;
|
270
|
+
}
|
271
|
+
},
|
272
|
+
|
273
|
+
all: function(iterator) {
|
274
|
+
var result = true;
|
275
|
+
this.each(function(value, index) {
|
276
|
+
result = result && !!(iterator || Prototype.K)(value, index);
|
277
|
+
if (!result) throw $break;
|
278
|
+
});
|
279
|
+
return result;
|
280
|
+
},
|
281
|
+
|
282
|
+
any: function(iterator) {
|
283
|
+
var result = true;
|
284
|
+
this.each(function(value, index) {
|
285
|
+
if (result = !!(iterator || Prototype.K)(value, index))
|
286
|
+
throw $break;
|
287
|
+
});
|
288
|
+
return result;
|
289
|
+
},
|
290
|
+
|
291
|
+
collect: function(iterator) {
|
292
|
+
var results = [];
|
293
|
+
this.each(function(value, index) {
|
294
|
+
results.push(iterator(value, index));
|
295
|
+
});
|
296
|
+
return results;
|
297
|
+
},
|
298
|
+
|
299
|
+
detect: function (iterator) {
|
300
|
+
var result;
|
301
|
+
this.each(function(value, index) {
|
302
|
+
if (iterator(value, index)) {
|
303
|
+
result = value;
|
304
|
+
throw $break;
|
305
|
+
}
|
306
|
+
});
|
307
|
+
return result;
|
308
|
+
},
|
309
|
+
|
310
|
+
findAll: function(iterator) {
|
311
|
+
var results = [];
|
312
|
+
this.each(function(value, index) {
|
313
|
+
if (iterator(value, index))
|
314
|
+
results.push(value);
|
315
|
+
});
|
316
|
+
return results;
|
317
|
+
},
|
318
|
+
|
319
|
+
grep: function(pattern, iterator) {
|
320
|
+
var results = [];
|
321
|
+
this.each(function(value, index) {
|
322
|
+
var stringValue = value.toString();
|
323
|
+
if (stringValue.match(pattern))
|
324
|
+
results.push((iterator || Prototype.K)(value, index));
|
325
|
+
})
|
326
|
+
return results;
|
327
|
+
},
|
328
|
+
|
329
|
+
include: function(object) {
|
330
|
+
var found = false;
|
331
|
+
this.each(function(value) {
|
332
|
+
if (value == object) {
|
333
|
+
found = true;
|
334
|
+
throw $break;
|
335
|
+
}
|
336
|
+
});
|
337
|
+
return found;
|
338
|
+
},
|
339
|
+
|
340
|
+
inject: function(memo, iterator) {
|
341
|
+
this.each(function(value, index) {
|
342
|
+
memo = iterator(memo, value, index);
|
343
|
+
});
|
344
|
+
return memo;
|
345
|
+
},
|
346
|
+
|
347
|
+
invoke: function(method) {
|
348
|
+
var args = $A(arguments).slice(1);
|
349
|
+
return this.collect(function(value) {
|
350
|
+
return value[method].apply(value, args);
|
351
|
+
});
|
352
|
+
},
|
353
|
+
|
354
|
+
max: function(iterator) {
|
355
|
+
var result;
|
356
|
+
this.each(function(value, index) {
|
357
|
+
value = (iterator || Prototype.K)(value, index);
|
358
|
+
if (result == undefined || value >= result)
|
359
|
+
result = value;
|
360
|
+
});
|
361
|
+
return result;
|
362
|
+
},
|
363
|
+
|
364
|
+
min: function(iterator) {
|
365
|
+
var result;
|
366
|
+
this.each(function(value, index) {
|
367
|
+
value = (iterator || Prototype.K)(value, index);
|
368
|
+
if (result == undefined || value < result)
|
369
|
+
result = value;
|
370
|
+
});
|
371
|
+
return result;
|
372
|
+
},
|
373
|
+
|
374
|
+
partition: function(iterator) {
|
375
|
+
var trues = [], falses = [];
|
376
|
+
this.each(function(value, index) {
|
377
|
+
((iterator || Prototype.K)(value, index) ?
|
378
|
+
trues : falses).push(value);
|
379
|
+
});
|
380
|
+
return [trues, falses];
|
381
|
+
},
|
382
|
+
|
383
|
+
pluck: function(property) {
|
384
|
+
var results = [];
|
385
|
+
this.each(function(value, index) {
|
386
|
+
results.push(value[property]);
|
387
|
+
});
|
388
|
+
return results;
|
389
|
+
},
|
390
|
+
|
391
|
+
reject: function(iterator) {
|
392
|
+
var results = [];
|
393
|
+
this.each(function(value, index) {
|
394
|
+
if (!iterator(value, index))
|
395
|
+
results.push(value);
|
396
|
+
});
|
397
|
+
return results;
|
398
|
+
},
|
399
|
+
|
400
|
+
sortBy: function(iterator) {
|
401
|
+
return this.collect(function(value, index) {
|
402
|
+
return {value: value, criteria: iterator(value, index)};
|
403
|
+
}).sort(function(left, right) {
|
404
|
+
var a = left.criteria, b = right.criteria;
|
405
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
406
|
+
}).pluck('value');
|
407
|
+
},
|
408
|
+
|
409
|
+
toArray: function() {
|
410
|
+
return this.collect(Prototype.K);
|
411
|
+
},
|
412
|
+
|
413
|
+
zip: function() {
|
414
|
+
var iterator = Prototype.K, args = $A(arguments);
|
415
|
+
if (typeof args.last() == 'function')
|
416
|
+
iterator = args.pop();
|
417
|
+
|
418
|
+
var collections = [this].concat(args).map($A);
|
419
|
+
return this.map(function(value, index) {
|
420
|
+
return iterator(collections.pluck(index));
|
421
|
+
});
|
422
|
+
},
|
423
|
+
|
424
|
+
inspect: function() {
|
425
|
+
return '#<Enumerable:' + this.toArray().inspect() + '>';
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
Object.extend(Enumerable, {
|
430
|
+
map: Enumerable.collect,
|
431
|
+
find: Enumerable.detect,
|
432
|
+
select: Enumerable.findAll,
|
433
|
+
member: Enumerable.include,
|
434
|
+
entries: Enumerable.toArray
|
435
|
+
});
|
436
|
+
var $A = Array.from = function(iterable) {
|
437
|
+
if (!iterable) return [];
|
438
|
+
if (iterable.toArray) {
|
439
|
+
return iterable.toArray();
|
440
|
+
} else {
|
441
|
+
var results = [];
|
442
|
+
for (var i = 0; i < iterable.length; i++)
|
443
|
+
results.push(iterable[i]);
|
444
|
+
return results;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
Object.extend(Array.prototype, Enumerable);
|
449
|
+
|
450
|
+
if (!Array.prototype._reverse)
|
451
|
+
Array.prototype._reverse = Array.prototype.reverse;
|
452
|
+
|
453
|
+
Object.extend(Array.prototype, {
|
454
|
+
_each: function(iterator) {
|
455
|
+
for (var i = 0; i < this.length; i++)
|
456
|
+
iterator(this[i]);
|
457
|
+
},
|
458
|
+
|
459
|
+
clear: function() {
|
460
|
+
this.length = 0;
|
461
|
+
return this;
|
462
|
+
},
|
463
|
+
|
464
|
+
first: function() {
|
465
|
+
return this[0];
|
466
|
+
},
|
467
|
+
|
468
|
+
last: function() {
|
469
|
+
return this[this.length - 1];
|
470
|
+
},
|
471
|
+
|
472
|
+
compact: function() {
|
473
|
+
return this.select(function(value) {
|
474
|
+
return value != undefined || value != null;
|
475
|
+
});
|
476
|
+
},
|
477
|
+
|
478
|
+
flatten: function() {
|
479
|
+
return this.inject([], function(array, value) {
|
480
|
+
return array.concat(value && value.constructor == Array ?
|
481
|
+
value.flatten() : [value]);
|
482
|
+
});
|
483
|
+
},
|
484
|
+
|
485
|
+
without: function() {
|
486
|
+
var values = $A(arguments);
|
487
|
+
return this.select(function(value) {
|
488
|
+
return !values.include(value);
|
489
|
+
});
|
490
|
+
},
|
491
|
+
|
492
|
+
indexOf: function(object) {
|
493
|
+
for (var i = 0; i < this.length; i++)
|
494
|
+
if (this[i] == object) return i;
|
495
|
+
return -1;
|
496
|
+
},
|
497
|
+
|
498
|
+
reverse: function(inline) {
|
499
|
+
return (inline !== false ? this : this.toArray())._reverse();
|
500
|
+
},
|
501
|
+
|
502
|
+
inspect: function() {
|
503
|
+
return '[' + this.map(Object.inspect).join(', ') + ']';
|
504
|
+
}
|
505
|
+
});
|
506
|
+
var Hash = {
|
507
|
+
_each: function(iterator) {
|
508
|
+
for (var key in this) {
|
509
|
+
var value = this[key];
|
510
|
+
if (typeof value == 'function') continue;
|
511
|
+
|
512
|
+
var pair = [key, value];
|
513
|
+
pair.key = key;
|
514
|
+
pair.value = value;
|
515
|
+
iterator(pair);
|
516
|
+
}
|
517
|
+
},
|
518
|
+
|
519
|
+
keys: function() {
|
520
|
+
return this.pluck('key');
|
521
|
+
},
|
522
|
+
|
523
|
+
values: function() {
|
524
|
+
return this.pluck('value');
|
525
|
+
},
|
526
|
+
|
527
|
+
merge: function(hash) {
|
528
|
+
return $H(hash).inject($H(this), function(mergedHash, pair) {
|
529
|
+
mergedHash[pair.key] = pair.value;
|
530
|
+
return mergedHash;
|
531
|
+
});
|
532
|
+
},
|
533
|
+
|
534
|
+
toQueryString: function() {
|
535
|
+
return this.map(function(pair) {
|
536
|
+
return pair.map(encodeURIComponent).join('=');
|
537
|
+
}).join('&');
|
538
|
+
},
|
539
|
+
|
540
|
+
inspect: function() {
|
541
|
+
return '#<Hash:{' + this.map(function(pair) {
|
542
|
+
return pair.map(Object.inspect).join(': ');
|
543
|
+
}).join(', ') + '}>';
|
544
|
+
}
|
545
|
+
}
|
546
|
+
|
547
|
+
function $H(object) {
|
548
|
+
var hash = Object.extend({}, object || {});
|
549
|
+
Object.extend(hash, Enumerable);
|
550
|
+
Object.extend(hash, Hash);
|
551
|
+
return hash;
|
552
|
+
}
|
553
|
+
ObjectRange = Class.create();
|
554
|
+
Object.extend(ObjectRange.prototype, Enumerable);
|
555
|
+
Object.extend(ObjectRange.prototype, {
|
556
|
+
initialize: function(start, end, exclusive) {
|
557
|
+
this.start = start;
|
558
|
+
this.end = end;
|
559
|
+
this.exclusive = exclusive;
|
560
|
+
},
|
561
|
+
|
562
|
+
_each: function(iterator) {
|
563
|
+
var value = this.start;
|
564
|
+
do {
|
565
|
+
iterator(value);
|
566
|
+
value = value.succ();
|
567
|
+
} while (this.include(value));
|
568
|
+
},
|
569
|
+
|
570
|
+
include: function(value) {
|
571
|
+
if (value < this.start)
|
572
|
+
return false;
|
573
|
+
if (this.exclusive)
|
574
|
+
return value < this.end;
|
575
|
+
return value <= this.end;
|
576
|
+
}
|
577
|
+
});
|
578
|
+
|
579
|
+
var $R = function(start, end, exclusive) {
|
580
|
+
return new ObjectRange(start, end, exclusive);
|
581
|
+
}
|
582
|
+
|
583
|
+
var Ajax = {
|
584
|
+
getTransport: function() {
|
585
|
+
return Try.these(
|
586
|
+
function() {return new XMLHttpRequest()},
|
587
|
+
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
|
588
|
+
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
589
|
+
) || false;
|
590
|
+
},
|
591
|
+
|
592
|
+
activeRequestCount: 0
|
593
|
+
}
|
594
|
+
|
595
|
+
Ajax.Responders = {
|
596
|
+
responders: [],
|
597
|
+
|
598
|
+
_each: function(iterator) {
|
599
|
+
this.responders._each(iterator);
|
600
|
+
},
|
601
|
+
|
602
|
+
register: function(responderToAdd) {
|
603
|
+
if (!this.include(responderToAdd))
|
604
|
+
this.responders.push(responderToAdd);
|
605
|
+
},
|
606
|
+
|
607
|
+
unregister: function(responderToRemove) {
|
608
|
+
this.responders = this.responders.without(responderToRemove);
|
609
|
+
},
|
610
|
+
|
611
|
+
dispatch: function(callback, request, transport, json) {
|
612
|
+
this.each(function(responder) {
|
613
|
+
if (responder[callback] && typeof responder[callback] == 'function') {
|
614
|
+
try {
|
615
|
+
responder[callback].apply(responder, [request, transport, json]);
|
616
|
+
} catch (e) {}
|
617
|
+
}
|
618
|
+
});
|
619
|
+
}
|
620
|
+
};
|
621
|
+
|
622
|
+
Object.extend(Ajax.Responders, Enumerable);
|
623
|
+
|
624
|
+
Ajax.Responders.register({
|
625
|
+
onCreate: function() {
|
626
|
+
Ajax.activeRequestCount++;
|
627
|
+
},
|
628
|
+
|
629
|
+
onComplete: function() {
|
630
|
+
Ajax.activeRequestCount--;
|
631
|
+
}
|
632
|
+
});
|
633
|
+
|
634
|
+
Ajax.Base = function() {};
|
635
|
+
Ajax.Base.prototype = {
|
636
|
+
setOptions: function(options) {
|
637
|
+
this.options = {
|
638
|
+
method: 'post',
|
639
|
+
asynchronous: true,
|
640
|
+
contentType: 'application/x-www-form-urlencoded',
|
641
|
+
parameters: ''
|
642
|
+
}
|
643
|
+
Object.extend(this.options, options || {});
|
644
|
+
},
|
645
|
+
|
646
|
+
responseIsSuccess: function() {
|
647
|
+
return this.transport.status == undefined
|
648
|
+
|| this.transport.status == 0
|
649
|
+
|| (this.transport.status >= 200 && this.transport.status < 300);
|
650
|
+
},
|
651
|
+
|
652
|
+
responseIsFailure: function() {
|
653
|
+
return !this.responseIsSuccess();
|
654
|
+
}
|
655
|
+
}
|
656
|
+
|
657
|
+
Ajax.Request = Class.create();
|
658
|
+
Ajax.Request.Events =
|
659
|
+
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
|
660
|
+
|
661
|
+
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
662
|
+
initialize: function(url, options) {
|
663
|
+
this.transport = Ajax.getTransport();
|
664
|
+
this.setOptions(options);
|
665
|
+
this.request(url);
|
666
|
+
},
|
667
|
+
|
668
|
+
request: function(url) {
|
669
|
+
var parameters = this.options.parameters || '';
|
670
|
+
if (parameters.length > 0) parameters += '&_=';
|
671
|
+
|
672
|
+
try {
|
673
|
+
this.url = url;
|
674
|
+
if (this.options.method == 'get' && parameters.length > 0)
|
675
|
+
this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
|
676
|
+
|
677
|
+
Ajax.Responders.dispatch('onCreate', this, this.transport);
|
678
|
+
|
679
|
+
this.transport.open(this.options.method, this.url,
|
680
|
+
this.options.asynchronous);
|
681
|
+
|
682
|
+
if (this.options.asynchronous) {
|
683
|
+
this.transport.onreadystatechange = this.onStateChange.bind(this);
|
684
|
+
setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
|
685
|
+
}
|
686
|
+
|
687
|
+
this.setRequestHeaders();
|
688
|
+
|
689
|
+
var body = this.options.postBody ? this.options.postBody : parameters;
|
690
|
+
this.transport.send(this.options.method == 'post' ? body : null);
|
691
|
+
|
692
|
+
} catch (e) {
|
693
|
+
this.dispatchException(e);
|
694
|
+
}
|
695
|
+
},
|
696
|
+
|
697
|
+
setRequestHeaders: function() {
|
698
|
+
var requestHeaders =
|
699
|
+
['X-Requested-With', 'XMLHttpRequest',
|
700
|
+
'X-Prototype-Version', Prototype.Version,
|
701
|
+
'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
|
702
|
+
|
703
|
+
if (this.options.method == 'post') {
|
704
|
+
requestHeaders.push('Content-type', this.options.contentType);
|
705
|
+
|
706
|
+
/* Force "Connection: close" for Mozilla browsers to work around
|
707
|
+
* a bug where XMLHttpReqeuest sends an incorrect Content-length
|
708
|
+
* header. See Mozilla Bugzilla #246651.
|
709
|
+
*/
|
710
|
+
if (this.transport.overrideMimeType)
|
711
|
+
requestHeaders.push('Connection', 'close');
|
712
|
+
}
|
713
|
+
|
714
|
+
if (this.options.requestHeaders)
|
715
|
+
requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
|
716
|
+
|
717
|
+
for (var i = 0; i < requestHeaders.length; i += 2)
|
718
|
+
this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
|
719
|
+
},
|
720
|
+
|
721
|
+
onStateChange: function() {
|
722
|
+
var readyState = this.transport.readyState;
|
723
|
+
if (readyState != 1)
|
724
|
+
this.respondToReadyState(this.transport.readyState);
|
725
|
+
},
|
726
|
+
|
727
|
+
header: function(name) {
|
728
|
+
try {
|
729
|
+
return this.transport.getResponseHeader(name);
|
730
|
+
} catch (e) {}
|
731
|
+
},
|
732
|
+
|
733
|
+
evalJSON: function() {
|
734
|
+
try {
|
735
|
+
return eval('(' + this.header('X-JSON') + ')');
|
736
|
+
} catch (e) {}
|
737
|
+
},
|
738
|
+
|
739
|
+
evalResponse: function() {
|
740
|
+
try {
|
741
|
+
return eval(this.transport.responseText);
|
742
|
+
} catch (e) {
|
743
|
+
this.dispatchException(e);
|
744
|
+
}
|
745
|
+
},
|
746
|
+
|
747
|
+
respondToReadyState: function(readyState) {
|
748
|
+
var event = Ajax.Request.Events[readyState];
|
749
|
+
var transport = this.transport, json = this.evalJSON();
|
750
|
+
|
751
|
+
if (event == 'Complete') {
|
752
|
+
try {
|
753
|
+
(this.options['on' + this.transport.status]
|
754
|
+
|| this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
|
755
|
+
|| Prototype.emptyFunction)(transport, json);
|
756
|
+
} catch (e) {
|
757
|
+
this.dispatchException(e);
|
758
|
+
}
|
759
|
+
|
760
|
+
if ((this.header('Content-type') || '').match(/^text\/javascript/i))
|
761
|
+
this.evalResponse();
|
762
|
+
}
|
763
|
+
|
764
|
+
try {
|
765
|
+
(this.options['on' + event] || Prototype.emptyFunction)(transport, json);
|
766
|
+
Ajax.Responders.dispatch('on' + event, this, transport, json);
|
767
|
+
} catch (e) {
|
768
|
+
this.dispatchException(e);
|
769
|
+
}
|
770
|
+
|
771
|
+
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
|
772
|
+
if (event == 'Complete')
|
773
|
+
this.transport.onreadystatechange = Prototype.emptyFunction;
|
774
|
+
},
|
775
|
+
|
776
|
+
dispatchException: function(exception) {
|
777
|
+
(this.options.onException || Prototype.emptyFunction)(this, exception);
|
778
|
+
Ajax.Responders.dispatch('onException', this, exception);
|
779
|
+
}
|
780
|
+
});
|
781
|
+
|
782
|
+
Ajax.Updater = Class.create();
|
783
|
+
|
784
|
+
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
|
785
|
+
initialize: function(container, url, options) {
|
786
|
+
this.containers = {
|
787
|
+
success: container.success ? $(container.success) : $(container),
|
788
|
+
failure: container.failure ? $(container.failure) :
|
789
|
+
(container.success ? null : $(container))
|
790
|
+
}
|
791
|
+
|
792
|
+
this.transport = Ajax.getTransport();
|
793
|
+
this.setOptions(options);
|
794
|
+
|
795
|
+
var onComplete = this.options.onComplete || Prototype.emptyFunction;
|
796
|
+
this.options.onComplete = (function(transport, object) {
|
797
|
+
this.updateContent();
|
798
|
+
onComplete(transport, object);
|
799
|
+
}).bind(this);
|
800
|
+
|
801
|
+
this.request(url);
|
802
|
+
},
|
803
|
+
|
804
|
+
updateContent: function() {
|
805
|
+
var receiver = this.responseIsSuccess() ?
|
806
|
+
this.containers.success : this.containers.failure;
|
807
|
+
var response = this.transport.responseText;
|
808
|
+
|
809
|
+
if (!this.options.evalScripts)
|
810
|
+
response = response.stripScripts();
|
811
|
+
|
812
|
+
if (receiver) {
|
813
|
+
if (this.options.insertion) {
|
814
|
+
new this.options.insertion(receiver, response);
|
815
|
+
} else {
|
816
|
+
Element.update(receiver, response);
|
817
|
+
}
|
818
|
+
}
|
819
|
+
|
820
|
+
if (this.responseIsSuccess()) {
|
821
|
+
if (this.onComplete)
|
822
|
+
setTimeout(this.onComplete.bind(this), 10);
|
823
|
+
}
|
824
|
+
}
|
825
|
+
});
|
826
|
+
|
827
|
+
Ajax.PeriodicalUpdater = Class.create();
|
828
|
+
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
|
829
|
+
initialize: function(container, url, options) {
|
830
|
+
this.setOptions(options);
|
831
|
+
this.onComplete = this.options.onComplete;
|
832
|
+
|
833
|
+
this.frequency = (this.options.frequency || 2);
|
834
|
+
this.decay = (this.options.decay || 1);
|
835
|
+
|
836
|
+
this.updater = {};
|
837
|
+
this.container = container;
|
838
|
+
this.url = url;
|
839
|
+
|
840
|
+
this.start();
|
841
|
+
},
|
842
|
+
|
843
|
+
start: function() {
|
844
|
+
this.options.onComplete = this.updateComplete.bind(this);
|
845
|
+
this.onTimerEvent();
|
846
|
+
},
|
847
|
+
|
848
|
+
stop: function() {
|
849
|
+
this.updater.onComplete = undefined;
|
850
|
+
clearTimeout(this.timer);
|
851
|
+
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
|
852
|
+
},
|
853
|
+
|
854
|
+
updateComplete: function(request) {
|
855
|
+
if (this.options.decay) {
|
856
|
+
this.decay = (request.responseText == this.lastText ?
|
857
|
+
this.decay * this.options.decay : 1);
|
858
|
+
|
859
|
+
this.lastText = request.responseText;
|
860
|
+
}
|
861
|
+
this.timer = setTimeout(this.onTimerEvent.bind(this),
|
862
|
+
this.decay * this.frequency * 1000);
|
863
|
+
},
|
864
|
+
|
865
|
+
onTimerEvent: function() {
|
866
|
+
this.updater = new Ajax.Updater(this.container, this.url, this.options);
|
867
|
+
}
|
868
|
+
});
|
869
|
+
function $() {
|
870
|
+
var results = [], element;
|
871
|
+
for (var i = 0; i < arguments.length; i++) {
|
872
|
+
element = arguments[i];
|
873
|
+
if (typeof element == 'string')
|
874
|
+
element = document.getElementById(element);
|
875
|
+
results.push(Element.extend(element));
|
876
|
+
}
|
877
|
+
return results.length < 2 ? results[0] : results;
|
878
|
+
}
|
879
|
+
|
880
|
+
document.getElementsByClassName = function(className, parentElement) {
|
881
|
+
var children = ($(parentElement) || document.body).getElementsByTagName('*');
|
882
|
+
return $A(children).inject([], function(elements, child) {
|
883
|
+
if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
|
884
|
+
elements.push(Element.extend(child));
|
885
|
+
return elements;
|
886
|
+
});
|
887
|
+
}
|
888
|
+
|
889
|
+
/*--------------------------------------------------------------------------*/
|
890
|
+
|
891
|
+
if (!window.Element)
|
892
|
+
var Element = new Object();
|
893
|
+
|
894
|
+
Element.extend = function(element) {
|
895
|
+
if (!element) return;
|
896
|
+
if (_nativeExtensions) return element;
|
897
|
+
|
898
|
+
if (!element._extended && element.tagName && element != window) {
|
899
|
+
var methods = Element.Methods, cache = Element.extend.cache;
|
900
|
+
for (property in methods) {
|
901
|
+
var value = methods[property];
|
902
|
+
if (typeof value == 'function')
|
903
|
+
element[property] = cache.findOrStore(value);
|
904
|
+
}
|
905
|
+
}
|
906
|
+
|
907
|
+
element._extended = true;
|
908
|
+
return element;
|
909
|
+
}
|
910
|
+
|
911
|
+
Element.extend.cache = {
|
912
|
+
findOrStore: function(value) {
|
913
|
+
return this[value] = this[value] || function() {
|
914
|
+
return value.apply(null, [this].concat($A(arguments)));
|
915
|
+
}
|
916
|
+
}
|
917
|
+
}
|
918
|
+
|
919
|
+
Element.Methods = {
|
920
|
+
visible: function(element) {
|
921
|
+
return $(element).style.display != 'none';
|
922
|
+
},
|
923
|
+
|
924
|
+
toggle: function() {
|
925
|
+
for (var i = 0; i < arguments.length; i++) {
|
926
|
+
var element = $(arguments[i]);
|
927
|
+
Element[Element.visible(element) ? 'hide' : 'show'](element);
|
928
|
+
}
|
929
|
+
},
|
930
|
+
|
931
|
+
hide: function() {
|
932
|
+
for (var i = 0; i < arguments.length; i++) {
|
933
|
+
var element = $(arguments[i]);
|
934
|
+
element.style.display = 'none';
|
935
|
+
}
|
936
|
+
},
|
937
|
+
|
938
|
+
show: function() {
|
939
|
+
for (var i = 0; i < arguments.length; i++) {
|
940
|
+
var element = $(arguments[i]);
|
941
|
+
element.style.display = '';
|
942
|
+
}
|
943
|
+
},
|
944
|
+
|
945
|
+
remove: function(element) {
|
946
|
+
element = $(element);
|
947
|
+
element.parentNode.removeChild(element);
|
948
|
+
},
|
949
|
+
|
950
|
+
update: function(element, html) {
|
951
|
+
$(element).innerHTML = html.stripScripts();
|
952
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
953
|
+
},
|
954
|
+
|
955
|
+
replace: function(element, html) {
|
956
|
+
element = $(element);
|
957
|
+
if (element.outerHTML) {
|
958
|
+
element.outerHTML = html.stripScripts();
|
959
|
+
} else {
|
960
|
+
var range = element.ownerDocument.createRange();
|
961
|
+
range.selectNodeContents(element);
|
962
|
+
element.parentNode.replaceChild(
|
963
|
+
range.createContextualFragment(html.stripScripts()), element);
|
964
|
+
}
|
965
|
+
setTimeout(function() {html.evalScripts()}, 10);
|
966
|
+
},
|
967
|
+
|
968
|
+
getHeight: function(element) {
|
969
|
+
element = $(element);
|
970
|
+
return element.offsetHeight;
|
971
|
+
},
|
972
|
+
|
973
|
+
classNames: function(element) {
|
974
|
+
return new Element.ClassNames(element);
|
975
|
+
},
|
976
|
+
|
977
|
+
hasClassName: function(element, className) {
|
978
|
+
if (!(element = $(element))) return;
|
979
|
+
return Element.classNames(element).include(className);
|
980
|
+
},
|
981
|
+
|
982
|
+
addClassName: function(element, className) {
|
983
|
+
if (!(element = $(element))) return;
|
984
|
+
return Element.classNames(element).add(className);
|
985
|
+
},
|
986
|
+
|
987
|
+
removeClassName: function(element, className) {
|
988
|
+
if (!(element = $(element))) return;
|
989
|
+
return Element.classNames(element).remove(className);
|
990
|
+
},
|
991
|
+
|
992
|
+
// removes whitespace-only text node children
|
993
|
+
cleanWhitespace: function(element) {
|
994
|
+
element = $(element);
|
995
|
+
for (var i = 0; i < element.childNodes.length; i++) {
|
996
|
+
var node = element.childNodes[i];
|
997
|
+
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
|
998
|
+
Element.remove(node);
|
999
|
+
}
|
1000
|
+
},
|
1001
|
+
|
1002
|
+
empty: function(element) {
|
1003
|
+
return $(element).innerHTML.match(/^\s*$/);
|
1004
|
+
},
|
1005
|
+
|
1006
|
+
childOf: function(element, ancestor) {
|
1007
|
+
element = $(element), ancestor = $(ancestor);
|
1008
|
+
while (element = element.parentNode)
|
1009
|
+
if (element == ancestor) return true;
|
1010
|
+
return false;
|
1011
|
+
},
|
1012
|
+
|
1013
|
+
scrollTo: function(element) {
|
1014
|
+
element = $(element);
|
1015
|
+
var x = element.x ? element.x : element.offsetLeft,
|
1016
|
+
y = element.y ? element.y : element.offsetTop;
|
1017
|
+
window.scrollTo(x, y);
|
1018
|
+
},
|
1019
|
+
|
1020
|
+
getStyle: function(element, style) {
|
1021
|
+
element = $(element);
|
1022
|
+
var value = element.style[style.camelize()];
|
1023
|
+
if (!value) {
|
1024
|
+
if (document.defaultView && document.defaultView.getComputedStyle) {
|
1025
|
+
var css = document.defaultView.getComputedStyle(element, null);
|
1026
|
+
value = css ? css.getPropertyValue(style) : null;
|
1027
|
+
} else if (element.currentStyle) {
|
1028
|
+
value = element.currentStyle[style.camelize()];
|
1029
|
+
}
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
|
1033
|
+
if (Element.getStyle(element, 'position') == 'static') value = 'auto';
|
1034
|
+
|
1035
|
+
return value == 'auto' ? null : value;
|
1036
|
+
},
|
1037
|
+
|
1038
|
+
setStyle: function(element, style) {
|
1039
|
+
element = $(element);
|
1040
|
+
for (var name in style)
|
1041
|
+
element.style[name.camelize()] = style[name];
|
1042
|
+
},
|
1043
|
+
|
1044
|
+
getDimensions: function(element) {
|
1045
|
+
element = $(element);
|
1046
|
+
if (Element.getStyle(element, 'display') != 'none')
|
1047
|
+
return {width: element.offsetWidth, height: element.offsetHeight};
|
1048
|
+
|
1049
|
+
// All *Width and *Height properties give 0 on elements with display none,
|
1050
|
+
// so enable the element temporarily
|
1051
|
+
var els = element.style;
|
1052
|
+
var originalVisibility = els.visibility;
|
1053
|
+
var originalPosition = els.position;
|
1054
|
+
els.visibility = 'hidden';
|
1055
|
+
els.position = 'absolute';
|
1056
|
+
els.display = '';
|
1057
|
+
var originalWidth = element.clientWidth;
|
1058
|
+
var originalHeight = element.clientHeight;
|
1059
|
+
els.display = 'none';
|
1060
|
+
els.position = originalPosition;
|
1061
|
+
els.visibility = originalVisibility;
|
1062
|
+
return {width: originalWidth, height: originalHeight};
|
1063
|
+
},
|
1064
|
+
|
1065
|
+
makePositioned: function(element) {
|
1066
|
+
element = $(element);
|
1067
|
+
var pos = Element.getStyle(element, 'position');
|
1068
|
+
if (pos == 'static' || !pos) {
|
1069
|
+
element._madePositioned = true;
|
1070
|
+
element.style.position = 'relative';
|
1071
|
+
// Opera returns the offset relative to the positioning context, when an
|
1072
|
+
// element is position relative but top and left have not been defined
|
1073
|
+
if (window.opera) {
|
1074
|
+
element.style.top = 0;
|
1075
|
+
element.style.left = 0;
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
},
|
1079
|
+
|
1080
|
+
undoPositioned: function(element) {
|
1081
|
+
element = $(element);
|
1082
|
+
if (element._madePositioned) {
|
1083
|
+
element._madePositioned = undefined;
|
1084
|
+
element.style.position =
|
1085
|
+
element.style.top =
|
1086
|
+
element.style.left =
|
1087
|
+
element.style.bottom =
|
1088
|
+
element.style.right = '';
|
1089
|
+
}
|
1090
|
+
},
|
1091
|
+
|
1092
|
+
makeClipping: function(element) {
|
1093
|
+
element = $(element);
|
1094
|
+
if (element._overflow) return;
|
1095
|
+
element._overflow = element.style.overflow;
|
1096
|
+
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
|
1097
|
+
element.style.overflow = 'hidden';
|
1098
|
+
},
|
1099
|
+
|
1100
|
+
undoClipping: function(element) {
|
1101
|
+
element = $(element);
|
1102
|
+
if (element._overflow) return;
|
1103
|
+
element.style.overflow = element._overflow;
|
1104
|
+
element._overflow = undefined;
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
Object.extend(Element, Element.Methods);
|
1109
|
+
|
1110
|
+
var _nativeExtensions = false;
|
1111
|
+
|
1112
|
+
if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
|
1113
|
+
var HTMLElement = {}
|
1114
|
+
HTMLElement.prototype = document.createElement('div').__proto__;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
Element.addMethods = function(methods) {
|
1118
|
+
Object.extend(Element.Methods, methods || {});
|
1119
|
+
|
1120
|
+
if(typeof HTMLElement != 'undefined') {
|
1121
|
+
var methods = Element.Methods, cache = Element.extend.cache;
|
1122
|
+
for (property in methods) {
|
1123
|
+
var value = methods[property];
|
1124
|
+
if (typeof value == 'function')
|
1125
|
+
HTMLElement.prototype[property] = cache.findOrStore(value);
|
1126
|
+
}
|
1127
|
+
_nativeExtensions = true;
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
Element.addMethods();
|
1132
|
+
|
1133
|
+
var Toggle = new Object();
|
1134
|
+
Toggle.display = Element.toggle;
|
1135
|
+
|
1136
|
+
/*--------------------------------------------------------------------------*/
|
1137
|
+
|
1138
|
+
Abstract.Insertion = function(adjacency) {
|
1139
|
+
this.adjacency = adjacency;
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
Abstract.Insertion.prototype = {
|
1143
|
+
initialize: function(element, content) {
|
1144
|
+
this.element = $(element);
|
1145
|
+
this.content = content.stripScripts();
|
1146
|
+
|
1147
|
+
if (this.adjacency && this.element.insertAdjacentHTML) {
|
1148
|
+
try {
|
1149
|
+
this.element.insertAdjacentHTML(this.adjacency, this.content);
|
1150
|
+
} catch (e) {
|
1151
|
+
var tagName = this.element.tagName.toLowerCase();
|
1152
|
+
if (tagName == 'tbody' || tagName == 'tr') {
|
1153
|
+
this.insertContent(this.contentFromAnonymousTable());
|
1154
|
+
} else {
|
1155
|
+
throw e;
|
1156
|
+
}
|
1157
|
+
}
|
1158
|
+
} else {
|
1159
|
+
this.range = this.element.ownerDocument.createRange();
|
1160
|
+
if (this.initializeRange) this.initializeRange();
|
1161
|
+
this.insertContent([this.range.createContextualFragment(this.content)]);
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
setTimeout(function() {content.evalScripts()}, 10);
|
1165
|
+
},
|
1166
|
+
|
1167
|
+
contentFromAnonymousTable: function() {
|
1168
|
+
var div = document.createElement('div');
|
1169
|
+
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
|
1170
|
+
return $A(div.childNodes[0].childNodes[0].childNodes);
|
1171
|
+
}
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
var Insertion = new Object();
|
1175
|
+
|
1176
|
+
Insertion.Before = Class.create();
|
1177
|
+
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
|
1178
|
+
initializeRange: function() {
|
1179
|
+
this.range.setStartBefore(this.element);
|
1180
|
+
},
|
1181
|
+
|
1182
|
+
insertContent: function(fragments) {
|
1183
|
+
fragments.each((function(fragment) {
|
1184
|
+
this.element.parentNode.insertBefore(fragment, this.element);
|
1185
|
+
}).bind(this));
|
1186
|
+
}
|
1187
|
+
});
|
1188
|
+
|
1189
|
+
Insertion.Top = Class.create();
|
1190
|
+
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
|
1191
|
+
initializeRange: function() {
|
1192
|
+
this.range.selectNodeContents(this.element);
|
1193
|
+
this.range.collapse(true);
|
1194
|
+
},
|
1195
|
+
|
1196
|
+
insertContent: function(fragments) {
|
1197
|
+
fragments.reverse(false).each((function(fragment) {
|
1198
|
+
this.element.insertBefore(fragment, this.element.firstChild);
|
1199
|
+
}).bind(this));
|
1200
|
+
}
|
1201
|
+
});
|
1202
|
+
|
1203
|
+
Insertion.Bottom = Class.create();
|
1204
|
+
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
|
1205
|
+
initializeRange: function() {
|
1206
|
+
this.range.selectNodeContents(this.element);
|
1207
|
+
this.range.collapse(this.element);
|
1208
|
+
},
|
1209
|
+
|
1210
|
+
insertContent: function(fragments) {
|
1211
|
+
fragments.each((function(fragment) {
|
1212
|
+
this.element.appendChild(fragment);
|
1213
|
+
}).bind(this));
|
1214
|
+
}
|
1215
|
+
});
|
1216
|
+
|
1217
|
+
Insertion.After = Class.create();
|
1218
|
+
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
|
1219
|
+
initializeRange: function() {
|
1220
|
+
this.range.setStartAfter(this.element);
|
1221
|
+
},
|
1222
|
+
|
1223
|
+
insertContent: function(fragments) {
|
1224
|
+
fragments.each((function(fragment) {
|
1225
|
+
this.element.parentNode.insertBefore(fragment,
|
1226
|
+
this.element.nextSibling);
|
1227
|
+
}).bind(this));
|
1228
|
+
}
|
1229
|
+
});
|
1230
|
+
|
1231
|
+
/*--------------------------------------------------------------------------*/
|
1232
|
+
|
1233
|
+
Element.ClassNames = Class.create();
|
1234
|
+
Element.ClassNames.prototype = {
|
1235
|
+
initialize: function(element) {
|
1236
|
+
this.element = $(element);
|
1237
|
+
},
|
1238
|
+
|
1239
|
+
_each: function(iterator) {
|
1240
|
+
this.element.className.split(/\s+/).select(function(name) {
|
1241
|
+
return name.length > 0;
|
1242
|
+
})._each(iterator);
|
1243
|
+
},
|
1244
|
+
|
1245
|
+
set: function(className) {
|
1246
|
+
this.element.className = className;
|
1247
|
+
},
|
1248
|
+
|
1249
|
+
add: function(classNameToAdd) {
|
1250
|
+
if (this.include(classNameToAdd)) return;
|
1251
|
+
this.set(this.toArray().concat(classNameToAdd).join(' '));
|
1252
|
+
},
|
1253
|
+
|
1254
|
+
remove: function(classNameToRemove) {
|
1255
|
+
if (!this.include(classNameToRemove)) return;
|
1256
|
+
this.set(this.select(function(className) {
|
1257
|
+
return className != classNameToRemove;
|
1258
|
+
}).join(' '));
|
1259
|
+
},
|
1260
|
+
|
1261
|
+
toString: function() {
|
1262
|
+
return this.toArray().join(' ');
|
1263
|
+
}
|
1264
|
+
}
|
1265
|
+
|
1266
|
+
Object.extend(Element.ClassNames.prototype, Enumerable);
|
1267
|
+
var Selector = Class.create();
|
1268
|
+
Selector.prototype = {
|
1269
|
+
initialize: function(expression) {
|
1270
|
+
this.params = {classNames: []};
|
1271
|
+
this.expression = expression.toString().strip();
|
1272
|
+
this.parseExpression();
|
1273
|
+
this.compileMatcher();
|
1274
|
+
},
|
1275
|
+
|
1276
|
+
parseExpression: function() {
|
1277
|
+
function abort(message) { throw 'Parse error in selector: ' + message; }
|
1278
|
+
|
1279
|
+
if (this.expression == '') abort('empty expression');
|
1280
|
+
|
1281
|
+
var params = this.params, expr = this.expression, match, modifier, clause, rest;
|
1282
|
+
while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
|
1283
|
+
params.attributes = params.attributes || [];
|
1284
|
+
params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
|
1285
|
+
expr = match[1];
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
if (expr == '*') return this.params.wildcard = true;
|
1289
|
+
|
1290
|
+
while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
|
1291
|
+
modifier = match[1], clause = match[2], rest = match[3];
|
1292
|
+
switch (modifier) {
|
1293
|
+
case '#': params.id = clause; break;
|
1294
|
+
case '.': params.classNames.push(clause); break;
|
1295
|
+
case '':
|
1296
|
+
case undefined: params.tagName = clause.toUpperCase(); break;
|
1297
|
+
default: abort(expr.inspect());
|
1298
|
+
}
|
1299
|
+
expr = rest;
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
if (expr.length > 0) abort(expr.inspect());
|
1303
|
+
},
|
1304
|
+
|
1305
|
+
buildMatchExpression: function() {
|
1306
|
+
var params = this.params, conditions = [], clause;
|
1307
|
+
|
1308
|
+
if (params.wildcard)
|
1309
|
+
conditions.push('true');
|
1310
|
+
if (clause = params.id)
|
1311
|
+
conditions.push('element.id == ' + clause.inspect());
|
1312
|
+
if (clause = params.tagName)
|
1313
|
+
conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
|
1314
|
+
if ((clause = params.classNames).length > 0)
|
1315
|
+
for (var i = 0; i < clause.length; i++)
|
1316
|
+
conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
|
1317
|
+
if (clause = params.attributes) {
|
1318
|
+
clause.each(function(attribute) {
|
1319
|
+
var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
|
1320
|
+
var splitValueBy = function(delimiter) {
|
1321
|
+
return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
|
1322
|
+
}
|
1323
|
+
|
1324
|
+
switch (attribute.operator) {
|
1325
|
+
case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
|
1326
|
+
case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
|
1327
|
+
case '|=': conditions.push(
|
1328
|
+
splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
|
1329
|
+
); break;
|
1330
|
+
case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
|
1331
|
+
case '':
|
1332
|
+
case undefined: conditions.push(value + ' != null'); break;
|
1333
|
+
default: throw 'Unknown operator ' + attribute.operator + ' in selector';
|
1334
|
+
}
|
1335
|
+
});
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
return conditions.join(' && ');
|
1339
|
+
},
|
1340
|
+
|
1341
|
+
compileMatcher: function() {
|
1342
|
+
this.match = new Function('element', 'if (!element.tagName) return false; \
|
1343
|
+
return ' + this.buildMatchExpression());
|
1344
|
+
},
|
1345
|
+
|
1346
|
+
findElements: function(scope) {
|
1347
|
+
var element;
|
1348
|
+
|
1349
|
+
if (element = $(this.params.id))
|
1350
|
+
if (this.match(element))
|
1351
|
+
if (!scope || Element.childOf(element, scope))
|
1352
|
+
return [element];
|
1353
|
+
|
1354
|
+
scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
|
1355
|
+
|
1356
|
+
var results = [];
|
1357
|
+
for (var i = 0; i < scope.length; i++)
|
1358
|
+
if (this.match(element = scope[i]))
|
1359
|
+
results.push(Element.extend(element));
|
1360
|
+
|
1361
|
+
return results;
|
1362
|
+
},
|
1363
|
+
|
1364
|
+
toString: function() {
|
1365
|
+
return this.expression;
|
1366
|
+
}
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
function $$() {
|
1370
|
+
return $A(arguments).map(function(expression) {
|
1371
|
+
return expression.strip().split(/\s+/).inject([null], function(results, expr) {
|
1372
|
+
var selector = new Selector(expr);
|
1373
|
+
return results.map(selector.findElements.bind(selector)).flatten();
|
1374
|
+
});
|
1375
|
+
}).flatten();
|
1376
|
+
}
|
1377
|
+
var Field = {
|
1378
|
+
clear: function() {
|
1379
|
+
for (var i = 0; i < arguments.length; i++)
|
1380
|
+
$(arguments[i]).value = '';
|
1381
|
+
},
|
1382
|
+
|
1383
|
+
focus: function(element) {
|
1384
|
+
$(element).focus();
|
1385
|
+
},
|
1386
|
+
|
1387
|
+
present: function() {
|
1388
|
+
for (var i = 0; i < arguments.length; i++)
|
1389
|
+
if ($(arguments[i]).value == '') return false;
|
1390
|
+
return true;
|
1391
|
+
},
|
1392
|
+
|
1393
|
+
select: function(element) {
|
1394
|
+
$(element).select();
|
1395
|
+
},
|
1396
|
+
|
1397
|
+
activate: function(element) {
|
1398
|
+
element = $(element);
|
1399
|
+
element.focus();
|
1400
|
+
if (element.select)
|
1401
|
+
element.select();
|
1402
|
+
}
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
/*--------------------------------------------------------------------------*/
|
1406
|
+
|
1407
|
+
var Form = {
|
1408
|
+
serialize: function(form) {
|
1409
|
+
var elements = Form.getElements($(form));
|
1410
|
+
var queryComponents = new Array();
|
1411
|
+
|
1412
|
+
for (var i = 0; i < elements.length; i++) {
|
1413
|
+
var queryComponent = Form.Element.serialize(elements[i]);
|
1414
|
+
if (queryComponent)
|
1415
|
+
queryComponents.push(queryComponent);
|
1416
|
+
}
|
1417
|
+
|
1418
|
+
return queryComponents.join('&');
|
1419
|
+
},
|
1420
|
+
|
1421
|
+
getElements: function(form) {
|
1422
|
+
form = $(form);
|
1423
|
+
var elements = new Array();
|
1424
|
+
|
1425
|
+
for (var tagName in Form.Element.Serializers) {
|
1426
|
+
var tagElements = form.getElementsByTagName(tagName);
|
1427
|
+
for (var j = 0; j < tagElements.length; j++)
|
1428
|
+
elements.push(tagElements[j]);
|
1429
|
+
}
|
1430
|
+
return elements;
|
1431
|
+
},
|
1432
|
+
|
1433
|
+
getInputs: function(form, typeName, name) {
|
1434
|
+
form = $(form);
|
1435
|
+
var inputs = form.getElementsByTagName('input');
|
1436
|
+
|
1437
|
+
if (!typeName && !name)
|
1438
|
+
return inputs;
|
1439
|
+
|
1440
|
+
var matchingInputs = new Array();
|
1441
|
+
for (var i = 0; i < inputs.length; i++) {
|
1442
|
+
var input = inputs[i];
|
1443
|
+
if ((typeName && input.type != typeName) ||
|
1444
|
+
(name && input.name != name))
|
1445
|
+
continue;
|
1446
|
+
matchingInputs.push(input);
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
return matchingInputs;
|
1450
|
+
},
|
1451
|
+
|
1452
|
+
disable: function(form) {
|
1453
|
+
var elements = Form.getElements(form);
|
1454
|
+
for (var i = 0; i < elements.length; i++) {
|
1455
|
+
var element = elements[i];
|
1456
|
+
element.blur();
|
1457
|
+
element.disabled = 'true';
|
1458
|
+
}
|
1459
|
+
},
|
1460
|
+
|
1461
|
+
enable: function(form) {
|
1462
|
+
var elements = Form.getElements(form);
|
1463
|
+
for (var i = 0; i < elements.length; i++) {
|
1464
|
+
var element = elements[i];
|
1465
|
+
element.disabled = '';
|
1466
|
+
}
|
1467
|
+
},
|
1468
|
+
|
1469
|
+
findFirstElement: function(form) {
|
1470
|
+
return Form.getElements(form).find(function(element) {
|
1471
|
+
return element.type != 'hidden' && !element.disabled &&
|
1472
|
+
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
|
1473
|
+
});
|
1474
|
+
},
|
1475
|
+
|
1476
|
+
focusFirstElement: function(form) {
|
1477
|
+
Field.activate(Form.findFirstElement(form));
|
1478
|
+
},
|
1479
|
+
|
1480
|
+
reset: function(form) {
|
1481
|
+
$(form).reset();
|
1482
|
+
}
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
Form.Element = {
|
1486
|
+
serialize: function(element) {
|
1487
|
+
element = $(element);
|
1488
|
+
var method = element.tagName.toLowerCase();
|
1489
|
+
var parameter = Form.Element.Serializers[method](element);
|
1490
|
+
|
1491
|
+
if (parameter) {
|
1492
|
+
var key = encodeURIComponent(parameter[0]);
|
1493
|
+
if (key.length == 0) return;
|
1494
|
+
|
1495
|
+
if (parameter[1].constructor != Array)
|
1496
|
+
parameter[1] = [parameter[1]];
|
1497
|
+
|
1498
|
+
return parameter[1].map(function(value) {
|
1499
|
+
return key + '=' + encodeURIComponent(value);
|
1500
|
+
}).join('&');
|
1501
|
+
}
|
1502
|
+
},
|
1503
|
+
|
1504
|
+
getValue: function(element) {
|
1505
|
+
element = $(element);
|
1506
|
+
var method = element.tagName.toLowerCase();
|
1507
|
+
var parameter = Form.Element.Serializers[method](element);
|
1508
|
+
|
1509
|
+
if (parameter)
|
1510
|
+
return parameter[1];
|
1511
|
+
}
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
Form.Element.Serializers = {
|
1515
|
+
input: function(element) {
|
1516
|
+
switch (element.type.toLowerCase()) {
|
1517
|
+
case 'submit':
|
1518
|
+
case 'hidden':
|
1519
|
+
case 'password':
|
1520
|
+
case 'text':
|
1521
|
+
return Form.Element.Serializers.textarea(element);
|
1522
|
+
case 'checkbox':
|
1523
|
+
case 'radio':
|
1524
|
+
return Form.Element.Serializers.inputSelector(element);
|
1525
|
+
}
|
1526
|
+
return false;
|
1527
|
+
},
|
1528
|
+
|
1529
|
+
inputSelector: function(element) {
|
1530
|
+
if (element.checked)
|
1531
|
+
return [element.name, element.value];
|
1532
|
+
},
|
1533
|
+
|
1534
|
+
textarea: function(element) {
|
1535
|
+
return [element.name, element.value];
|
1536
|
+
},
|
1537
|
+
|
1538
|
+
select: function(element) {
|
1539
|
+
return Form.Element.Serializers[element.type == 'select-one' ?
|
1540
|
+
'selectOne' : 'selectMany'](element);
|
1541
|
+
},
|
1542
|
+
|
1543
|
+
selectOne: function(element) {
|
1544
|
+
var value = '', opt, index = element.selectedIndex;
|
1545
|
+
if (index >= 0) {
|
1546
|
+
opt = element.options[index];
|
1547
|
+
value = opt.value || opt.text;
|
1548
|
+
}
|
1549
|
+
return [element.name, value];
|
1550
|
+
},
|
1551
|
+
|
1552
|
+
selectMany: function(element) {
|
1553
|
+
var value = [];
|
1554
|
+
for (var i = 0; i < element.length; i++) {
|
1555
|
+
var opt = element.options[i];
|
1556
|
+
if (opt.selected)
|
1557
|
+
value.push(opt.value || opt.text);
|
1558
|
+
}
|
1559
|
+
return [element.name, value];
|
1560
|
+
}
|
1561
|
+
}
|
1562
|
+
|
1563
|
+
/*--------------------------------------------------------------------------*/
|
1564
|
+
|
1565
|
+
var $F = Form.Element.getValue;
|
1566
|
+
|
1567
|
+
/*--------------------------------------------------------------------------*/
|
1568
|
+
|
1569
|
+
Abstract.TimedObserver = function() {}
|
1570
|
+
Abstract.TimedObserver.prototype = {
|
1571
|
+
initialize: function(element, frequency, callback) {
|
1572
|
+
this.frequency = frequency;
|
1573
|
+
this.element = $(element);
|
1574
|
+
this.callback = callback;
|
1575
|
+
|
1576
|
+
this.lastValue = this.getValue();
|
1577
|
+
this.registerCallback();
|
1578
|
+
},
|
1579
|
+
|
1580
|
+
registerCallback: function() {
|
1581
|
+
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
1582
|
+
},
|
1583
|
+
|
1584
|
+
onTimerEvent: function() {
|
1585
|
+
var value = this.getValue();
|
1586
|
+
if (this.lastValue != value) {
|
1587
|
+
this.callback(this.element, value);
|
1588
|
+
this.lastValue = value;
|
1589
|
+
}
|
1590
|
+
}
|
1591
|
+
}
|
1592
|
+
|
1593
|
+
Form.Element.Observer = Class.create();
|
1594
|
+
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
1595
|
+
getValue: function() {
|
1596
|
+
return Form.Element.getValue(this.element);
|
1597
|
+
}
|
1598
|
+
});
|
1599
|
+
|
1600
|
+
Form.Observer = Class.create();
|
1601
|
+
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
1602
|
+
getValue: function() {
|
1603
|
+
return Form.serialize(this.element);
|
1604
|
+
}
|
1605
|
+
});
|
1606
|
+
|
1607
|
+
/*--------------------------------------------------------------------------*/
|
1608
|
+
|
1609
|
+
Abstract.EventObserver = function() {}
|
1610
|
+
Abstract.EventObserver.prototype = {
|
1611
|
+
initialize: function(element, callback) {
|
1612
|
+
this.element = $(element);
|
1613
|
+
this.callback = callback;
|
1614
|
+
|
1615
|
+
this.lastValue = this.getValue();
|
1616
|
+
if (this.element.tagName.toLowerCase() == 'form')
|
1617
|
+
this.registerFormCallbacks();
|
1618
|
+
else
|
1619
|
+
this.registerCallback(this.element);
|
1620
|
+
},
|
1621
|
+
|
1622
|
+
onElementEvent: function() {
|
1623
|
+
var value = this.getValue();
|
1624
|
+
if (this.lastValue != value) {
|
1625
|
+
this.callback(this.element, value);
|
1626
|
+
this.lastValue = value;
|
1627
|
+
}
|
1628
|
+
},
|
1629
|
+
|
1630
|
+
registerFormCallbacks: function() {
|
1631
|
+
var elements = Form.getElements(this.element);
|
1632
|
+
for (var i = 0; i < elements.length; i++)
|
1633
|
+
this.registerCallback(elements[i]);
|
1634
|
+
},
|
1635
|
+
|
1636
|
+
registerCallback: function(element) {
|
1637
|
+
if (element.type) {
|
1638
|
+
switch (element.type.toLowerCase()) {
|
1639
|
+
case 'checkbox':
|
1640
|
+
case 'radio':
|
1641
|
+
Event.observe(element, 'click', this.onElementEvent.bind(this));
|
1642
|
+
break;
|
1643
|
+
case 'password':
|
1644
|
+
case 'text':
|
1645
|
+
case 'textarea':
|
1646
|
+
case 'select-one':
|
1647
|
+
case 'select-multiple':
|
1648
|
+
Event.observe(element, 'change', this.onElementEvent.bind(this));
|
1649
|
+
break;
|
1650
|
+
}
|
1651
|
+
}
|
1652
|
+
}
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
Form.Element.EventObserver = Class.create();
|
1656
|
+
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
1657
|
+
getValue: function() {
|
1658
|
+
return Form.Element.getValue(this.element);
|
1659
|
+
}
|
1660
|
+
});
|
1661
|
+
|
1662
|
+
Form.EventObserver = Class.create();
|
1663
|
+
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
1664
|
+
getValue: function() {
|
1665
|
+
return Form.serialize(this.element);
|
1666
|
+
}
|
1667
|
+
});
|
1668
|
+
if (!window.Event) {
|
1669
|
+
var Event = new Object();
|
1670
|
+
}
|
1671
|
+
|
1672
|
+
Object.extend(Event, {
|
1673
|
+
KEY_BACKSPACE: 8,
|
1674
|
+
KEY_TAB: 9,
|
1675
|
+
KEY_RETURN: 13,
|
1676
|
+
KEY_ESC: 27,
|
1677
|
+
KEY_LEFT: 37,
|
1678
|
+
KEY_UP: 38,
|
1679
|
+
KEY_RIGHT: 39,
|
1680
|
+
KEY_DOWN: 40,
|
1681
|
+
KEY_DELETE: 46,
|
1682
|
+
|
1683
|
+
element: function(event) {
|
1684
|
+
return event.target || event.srcElement;
|
1685
|
+
},
|
1686
|
+
|
1687
|
+
isLeftClick: function(event) {
|
1688
|
+
return (((event.which) && (event.which == 1)) ||
|
1689
|
+
((event.button) && (event.button == 1)));
|
1690
|
+
},
|
1691
|
+
|
1692
|
+
pointerX: function(event) {
|
1693
|
+
return event.pageX || (event.clientX +
|
1694
|
+
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
1695
|
+
},
|
1696
|
+
|
1697
|
+
pointerY: function(event) {
|
1698
|
+
return event.pageY || (event.clientY +
|
1699
|
+
(document.documentElement.scrollTop || document.body.scrollTop));
|
1700
|
+
},
|
1701
|
+
|
1702
|
+
stop: function(event) {
|
1703
|
+
if (event.preventDefault) {
|
1704
|
+
event.preventDefault();
|
1705
|
+
event.stopPropagation();
|
1706
|
+
} else {
|
1707
|
+
event.returnValue = false;
|
1708
|
+
event.cancelBubble = true;
|
1709
|
+
}
|
1710
|
+
},
|
1711
|
+
|
1712
|
+
// find the first node with the given tagName, starting from the
|
1713
|
+
// node the event was triggered on; traverses the DOM upwards
|
1714
|
+
findElement: function(event, tagName) {
|
1715
|
+
var element = Event.element(event);
|
1716
|
+
while (element.parentNode && (!element.tagName ||
|
1717
|
+
(element.tagName.toUpperCase() != tagName.toUpperCase())))
|
1718
|
+
element = element.parentNode;
|
1719
|
+
return element;
|
1720
|
+
},
|
1721
|
+
|
1722
|
+
observers: false,
|
1723
|
+
|
1724
|
+
_observeAndCache: function(element, name, observer, useCapture) {
|
1725
|
+
if (!this.observers) this.observers = [];
|
1726
|
+
if (element.addEventListener) {
|
1727
|
+
this.observers.push([element, name, observer, useCapture]);
|
1728
|
+
element.addEventListener(name, observer, useCapture);
|
1729
|
+
} else if (element.attachEvent) {
|
1730
|
+
this.observers.push([element, name, observer, useCapture]);
|
1731
|
+
element.attachEvent('on' + name, observer);
|
1732
|
+
}
|
1733
|
+
},
|
1734
|
+
|
1735
|
+
unloadCache: function() {
|
1736
|
+
if (!Event.observers) return;
|
1737
|
+
for (var i = 0; i < Event.observers.length; i++) {
|
1738
|
+
Event.stopObserving.apply(this, Event.observers[i]);
|
1739
|
+
Event.observers[i][0] = null;
|
1740
|
+
}
|
1741
|
+
Event.observers = false;
|
1742
|
+
},
|
1743
|
+
|
1744
|
+
observe: function(element, name, observer, useCapture) {
|
1745
|
+
var element = $(element);
|
1746
|
+
useCapture = useCapture || false;
|
1747
|
+
|
1748
|
+
if (name == 'keypress' &&
|
1749
|
+
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|
1750
|
+
|| element.attachEvent))
|
1751
|
+
name = 'keydown';
|
1752
|
+
|
1753
|
+
this._observeAndCache(element, name, observer, useCapture);
|
1754
|
+
},
|
1755
|
+
|
1756
|
+
stopObserving: function(element, name, observer, useCapture) {
|
1757
|
+
var element = $(element);
|
1758
|
+
useCapture = useCapture || false;
|
1759
|
+
|
1760
|
+
if (name == 'keypress' &&
|
1761
|
+
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|
1762
|
+
|| element.detachEvent))
|
1763
|
+
name = 'keydown';
|
1764
|
+
|
1765
|
+
if (element.removeEventListener) {
|
1766
|
+
element.removeEventListener(name, observer, useCapture);
|
1767
|
+
} else if (element.detachEvent) {
|
1768
|
+
element.detachEvent('on' + name, observer);
|
1769
|
+
}
|
1770
|
+
}
|
1771
|
+
});
|
1772
|
+
|
1773
|
+
/* prevent memory leaks in IE */
|
1774
|
+
if (navigator.appVersion.match(/\bMSIE\b/))
|
1775
|
+
Event.observe(window, 'unload', Event.unloadCache, false);
|
1776
|
+
var Position = {
|
1777
|
+
// set to true if needed, warning: firefox performance problems
|
1778
|
+
// NOT neeeded for page scrolling, only if draggable contained in
|
1779
|
+
// scrollable elements
|
1780
|
+
includeScrollOffsets: false,
|
1781
|
+
|
1782
|
+
// must be called before calling withinIncludingScrolloffset, every time the
|
1783
|
+
// page is scrolled
|
1784
|
+
prepare: function() {
|
1785
|
+
this.deltaX = window.pageXOffset
|
1786
|
+
|| document.documentElement.scrollLeft
|
1787
|
+
|| document.body.scrollLeft
|
1788
|
+
|| 0;
|
1789
|
+
this.deltaY = window.pageYOffset
|
1790
|
+
|| document.documentElement.scrollTop
|
1791
|
+
|| document.body.scrollTop
|
1792
|
+
|| 0;
|
1793
|
+
},
|
1794
|
+
|
1795
|
+
realOffset: function(element) {
|
1796
|
+
var valueT = 0, valueL = 0;
|
1797
|
+
do {
|
1798
|
+
valueT += element.scrollTop || 0;
|
1799
|
+
valueL += element.scrollLeft || 0;
|
1800
|
+
element = element.parentNode;
|
1801
|
+
} while (element);
|
1802
|
+
return [valueL, valueT];
|
1803
|
+
},
|
1804
|
+
|
1805
|
+
cumulativeOffset: function(element) {
|
1806
|
+
var valueT = 0, valueL = 0;
|
1807
|
+
do {
|
1808
|
+
valueT += element.offsetTop || 0;
|
1809
|
+
valueL += element.offsetLeft || 0;
|
1810
|
+
element = element.offsetParent;
|
1811
|
+
} while (element);
|
1812
|
+
return [valueL, valueT];
|
1813
|
+
},
|
1814
|
+
|
1815
|
+
positionedOffset: function(element) {
|
1816
|
+
var valueT = 0, valueL = 0;
|
1817
|
+
do {
|
1818
|
+
valueT += element.offsetTop || 0;
|
1819
|
+
valueL += element.offsetLeft || 0;
|
1820
|
+
element = element.offsetParent;
|
1821
|
+
if (element) {
|
1822
|
+
p = Element.getStyle(element, 'position');
|
1823
|
+
if (p == 'relative' || p == 'absolute') break;
|
1824
|
+
}
|
1825
|
+
} while (element);
|
1826
|
+
return [valueL, valueT];
|
1827
|
+
},
|
1828
|
+
|
1829
|
+
offsetParent: function(element) {
|
1830
|
+
if (element.offsetParent) return element.offsetParent;
|
1831
|
+
if (element == document.body) return element;
|
1832
|
+
|
1833
|
+
while ((element = element.parentNode) && element != document.body)
|
1834
|
+
if (Element.getStyle(element, 'position') != 'static')
|
1835
|
+
return element;
|
1836
|
+
|
1837
|
+
return document.body;
|
1838
|
+
},
|
1839
|
+
|
1840
|
+
// caches x/y coordinate pair to use with overlap
|
1841
|
+
within: function(element, x, y) {
|
1842
|
+
if (this.includeScrollOffsets)
|
1843
|
+
return this.withinIncludingScrolloffsets(element, x, y);
|
1844
|
+
this.xcomp = x;
|
1845
|
+
this.ycomp = y;
|
1846
|
+
this.offset = this.cumulativeOffset(element);
|
1847
|
+
|
1848
|
+
return (y >= this.offset[1] &&
|
1849
|
+
y < this.offset[1] + element.offsetHeight &&
|
1850
|
+
x >= this.offset[0] &&
|
1851
|
+
x < this.offset[0] + element.offsetWidth);
|
1852
|
+
},
|
1853
|
+
|
1854
|
+
withinIncludingScrolloffsets: function(element, x, y) {
|
1855
|
+
var offsetcache = this.realOffset(element);
|
1856
|
+
|
1857
|
+
this.xcomp = x + offsetcache[0] - this.deltaX;
|
1858
|
+
this.ycomp = y + offsetcache[1] - this.deltaY;
|
1859
|
+
this.offset = this.cumulativeOffset(element);
|
1860
|
+
|
1861
|
+
return (this.ycomp >= this.offset[1] &&
|
1862
|
+
this.ycomp < this.offset[1] + element.offsetHeight &&
|
1863
|
+
this.xcomp >= this.offset[0] &&
|
1864
|
+
this.xcomp < this.offset[0] + element.offsetWidth);
|
1865
|
+
},
|
1866
|
+
|
1867
|
+
// within must be called directly before
|
1868
|
+
overlap: function(mode, element) {
|
1869
|
+
if (!mode) return 0;
|
1870
|
+
if (mode == 'vertical')
|
1871
|
+
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
|
1872
|
+
element.offsetHeight;
|
1873
|
+
if (mode == 'horizontal')
|
1874
|
+
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
|
1875
|
+
element.offsetWidth;
|
1876
|
+
},
|
1877
|
+
|
1878
|
+
clone: function(source, target) {
|
1879
|
+
source = $(source);
|
1880
|
+
target = $(target);
|
1881
|
+
target.style.position = 'absolute';
|
1882
|
+
var offsets = this.cumulativeOffset(source);
|
1883
|
+
target.style.top = offsets[1] + 'px';
|
1884
|
+
target.style.left = offsets[0] + 'px';
|
1885
|
+
target.style.width = source.offsetWidth + 'px';
|
1886
|
+
target.style.height = source.offsetHeight + 'px';
|
1887
|
+
},
|
1888
|
+
|
1889
|
+
page: function(forElement) {
|
1890
|
+
var valueT = 0, valueL = 0;
|
1891
|
+
|
1892
|
+
var element = forElement;
|
1893
|
+
do {
|
1894
|
+
valueT += element.offsetTop || 0;
|
1895
|
+
valueL += element.offsetLeft || 0;
|
1896
|
+
|
1897
|
+
// Safari fix
|
1898
|
+
if (element.offsetParent==document.body)
|
1899
|
+
if (Element.getStyle(element,'position')=='absolute') break;
|
1900
|
+
|
1901
|
+
} while (element = element.offsetParent);
|
1902
|
+
|
1903
|
+
element = forElement;
|
1904
|
+
do {
|
1905
|
+
valueT -= element.scrollTop || 0;
|
1906
|
+
valueL -= element.scrollLeft || 0;
|
1907
|
+
} while (element = element.parentNode);
|
1908
|
+
|
1909
|
+
return [valueL, valueT];
|
1910
|
+
},
|
1911
|
+
|
1912
|
+
clone: function(source, target) {
|
1913
|
+
var options = Object.extend({
|
1914
|
+
setLeft: true,
|
1915
|
+
setTop: true,
|
1916
|
+
setWidth: true,
|
1917
|
+
setHeight: true,
|
1918
|
+
offsetTop: 0,
|
1919
|
+
offsetLeft: 0
|
1920
|
+
}, arguments[2] || {})
|
1921
|
+
|
1922
|
+
// find page position of source
|
1923
|
+
source = $(source);
|
1924
|
+
var p = Position.page(source);
|
1925
|
+
|
1926
|
+
// find coordinate system to use
|
1927
|
+
target = $(target);
|
1928
|
+
var delta = [0, 0];
|
1929
|
+
var parent = null;
|
1930
|
+
// delta [0,0] will do fine with position: fixed elements,
|
1931
|
+
// position:absolute needs offsetParent deltas
|
1932
|
+
if (Element.getStyle(target,'position') == 'absolute') {
|
1933
|
+
parent = Position.offsetParent(target);
|
1934
|
+
delta = Position.page(parent);
|
1935
|
+
}
|
1936
|
+
|
1937
|
+
// correct by body offsets (fixes Safari)
|
1938
|
+
if (parent == document.body) {
|
1939
|
+
delta[0] -= document.body.offsetLeft;
|
1940
|
+
delta[1] -= document.body.offsetTop;
|
1941
|
+
}
|
1942
|
+
|
1943
|
+
// set position
|
1944
|
+
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
|
1945
|
+
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
|
1946
|
+
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
|
1947
|
+
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
|
1948
|
+
},
|
1949
|
+
|
1950
|
+
absolutize: function(element) {
|
1951
|
+
element = $(element);
|
1952
|
+
if (element.style.position == 'absolute') return;
|
1953
|
+
Position.prepare();
|
1954
|
+
|
1955
|
+
var offsets = Position.positionedOffset(element);
|
1956
|
+
var top = offsets[1];
|
1957
|
+
var left = offsets[0];
|
1958
|
+
var width = element.clientWidth;
|
1959
|
+
var height = element.clientHeight;
|
1960
|
+
|
1961
|
+
element._originalLeft = left - parseFloat(element.style.left || 0);
|
1962
|
+
element._originalTop = top - parseFloat(element.style.top || 0);
|
1963
|
+
element._originalWidth = element.style.width;
|
1964
|
+
element._originalHeight = element.style.height;
|
1965
|
+
|
1966
|
+
element.style.position = 'absolute';
|
1967
|
+
element.style.top = top + 'px';;
|
1968
|
+
element.style.left = left + 'px';;
|
1969
|
+
element.style.width = width + 'px';;
|
1970
|
+
element.style.height = height + 'px';;
|
1971
|
+
},
|
1972
|
+
|
1973
|
+
relativize: function(element) {
|
1974
|
+
element = $(element);
|
1975
|
+
if (element.style.position == 'relative') return;
|
1976
|
+
Position.prepare();
|
1977
|
+
|
1978
|
+
element.style.position = 'relative';
|
1979
|
+
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
|
1980
|
+
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
|
1981
|
+
|
1982
|
+
element.style.top = top + 'px';
|
1983
|
+
element.style.left = left + 'px';
|
1984
|
+
element.style.height = element._originalHeight;
|
1985
|
+
element.style.width = element._originalWidth;
|
1986
|
+
}
|
1987
|
+
}
|
1988
|
+
|
1989
|
+
// Safari returns margins on body which is incorrect if the child is absolutely
|
1990
|
+
// positioned. For performance reasons, redefine Position.cumulativeOffset for
|
1991
|
+
// KHTML/WebKit only.
|
1992
|
+
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
|
1993
|
+
Position.cumulativeOffset = function(element) {
|
1994
|
+
var valueT = 0, valueL = 0;
|
1995
|
+
do {
|
1996
|
+
valueT += element.offsetTop || 0;
|
1997
|
+
valueL += element.offsetLeft || 0;
|
1998
|
+
if (element.offsetParent == document.body)
|
1999
|
+
if (Element.getStyle(element, 'position') == 'absolute') break;
|
2000
|
+
|
2001
|
+
element = element.offsetParent;
|
2002
|
+
} while (element);
|
2003
|
+
|
2004
|
+
return [valueL, valueT];
|
2005
|
+
}
|
2006
|
+
}
|