1//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License. 2 3MooTools.More = { 4 'version': '1.2.3.1' 5}; 6 7/* 8Script: Log.js 9 Provides basic logging functionality for plugins to implement. 10 11 License: 12 MIT-style license. 13 14 Authors: 15 Guillermo Rauch 16*/ 17 18var Log = new Class({ 19 20 log: function(){ 21 Log.logger.call(this, arguments); 22 } 23 24}); 25 26Log.logged = []; 27 28Log.logger = function(){ 29 if(window.console && console.log) console.log.apply(console, arguments); 30 else Log.logged.push(arguments); 31}; 32 33/* 34Script: Class.Refactor.js 35 Extends a class onto itself with new property, preserving any items attached to the class's namespace. 36 37 License: 38 MIT-style license. 39 40 Authors: 41 Aaron Newton 42*/ 43 44Class.refactor = function(original, refactors){ 45 46 $each(refactors, function(item, name){ 47 var origin = original.prototype[name]; 48 if (origin && (origin = origin._origin) && typeof item == 'function') original.implement(name, function(){ 49 var old = this.previous; 50 this.previous = origin; 51 var value = item.apply(this, arguments); 52 this.previous = old; 53 return value; 54 }); else original.implement(name, item); 55 }); 56 57 return original; 58 59}; 60 61/* 62Script: Class.Binds.js 63 Automagically binds specified methods in a class to the instance of the class. 64 65 License: 66 MIT-style license. 67 68 Authors: 69 Aaron Newton 70*/ 71 72Class.Mutators.Binds = function(binds){ 73 return binds; 74}; 75 76Class.Mutators.initialize = function(initialize){ 77 return function(){ 78 $splat(this.Binds).each(function(name){ 79 var original = this[name]; 80 if (original) this[name] = original.bind(this); 81 }, this); 82 return initialize.apply(this, arguments); 83 }; 84}; 85 86/* 87Script: Drag.js 88 The base Drag Class. Can be used to drag and resize Elements using mouse events. 89 90 License: 91 MIT-style license. 92 93 Authors: 94 Valerio Proietti 95 Tom Occhinno 96 Jan Kassens 97*/ 98 99var Drag = new Class({ 100 101 Implements: [Events, Options], 102 103 options: {/* 104 onBeforeStart: $empty(thisElement), 105 onStart: $empty(thisElement, event), 106 onSnap: $empty(thisElement) 107 onDrag: $empty(thisElement, event), 108 onCancel: $empty(thisElement), 109 onComplete: $empty(thisElement, event),*/ 110 snap: 6, 111 unit: 'px', 112 grid: false, 113 style: true, 114 limit: false, 115 handle: false, 116 invert: false, 117 preventDefault: false, 118 modifiers: {x: 'left', y: 'top'} 119 }, 120 121 initialize: function(){ 122 var params = Array.link(arguments, {'options': Object.type, 'element': $defined}); 123 this.element = document.id(params.element); 124 this.document = this.element.getDocument(); 125 this.setOptions(params.options || {}); 126 var htype = $type(this.options.handle); 127 this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element; 128 this.mouse = {'now': {}, 'pos': {}}; 129 this.value = {'start': {}, 'now': {}}; 130 131 this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown'; 132 133 this.bound = { 134 start: this.start.bind(this), 135 check: this.check.bind(this), 136 drag: this.drag.bind(this), 137 stop: this.stop.bind(this), 138 cancel: this.cancel.bind(this), 139 eventStop: $lambda(false) 140 }; 141 this.attach(); 142 }, 143 144 attach: function(){ 145 this.handles.addEvent('mousedown', this.bound.start); 146 return this; 147 }, 148 149 detach: function(){ 150 this.handles.removeEvent('mousedown', this.bound.start); 151 return this; 152 }, 153 154 start: function(event){ 155 if (this.options.preventDefault) event.preventDefault(); 156 this.mouse.start = event.page; 157 this.fireEvent('beforeStart', this.element); 158 var limit = this.options.limit; 159 this.limit = {x: [], y: []}; 160 for (var z in this.options.modifiers){ 161 if (!this.options.modifiers[z]) continue; 162 if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt(); 163 else this.value.now[z] = this.element[this.options.modifiers[z]]; 164 if (this.options.invert) this.value.now[z] *= -1; 165 this.mouse.pos[z] = event.page[z] - this.value.now[z]; 166 if (limit && limit[z]){ 167 for (var i = 2; i--; i){ 168 if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])(); 169 } 170 } 171 } 172 if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid}; 173 this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel}); 174 this.document.addEvent(this.selection, this.bound.eventStop); 175 }, 176 177 check: function(event){ 178 if (this.options.preventDefault) event.preventDefault(); 179 var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); 180 if (distance > this.options.snap){ 181 this.cancel(); 182 this.document.addEvents({ 183 mousemove: this.bound.drag, 184 mouseup: this.bound.stop 185 }); 186 this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element); 187 } 188 }, 189 190 drag: function(event){ 191 if (this.options.preventDefault) event.preventDefault(); 192 this.mouse.now = event.page; 193 for (var z in this.options.modifiers){ 194 if (!this.options.modifiers[z]) continue; 195 this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; 196 if (this.options.invert) this.value.now[z] *= -1; 197 if (this.options.limit && this.limit[z]){ 198 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ 199 this.value.now[z] = this.limit[z][1]; 200 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ 201 this.value.now[z] = this.limit[z][0]; 202 } 203 } 204 if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]); 205 if (this.options.style) this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); 206 else this.element[this.options.modifiers[z]] = this.value.now[z]; 207 } 208 209 this.fireEvent('drag', [this.element, event]); 210 }, 211 212 cancel: function(event){ 213 this.document.removeEvent('mousemove', this.bound.check); 214 this.document.removeEvent('mouseup', this.bound.cancel); 215 if (event){ 216 this.document.removeEvent(this.selection, this.bound.eventStop); 217 this.fireEvent('cancel', this.element); 218 } 219 }, 220 221 stop: function(event){ 222 this.document.removeEvent(this.selection, this.bound.eventStop); 223 this.document.removeEvent('mousemove', this.bound.drag); 224 this.document.removeEvent('mouseup', this.bound.stop); 225 if (event) this.fireEvent('complete', [this.element, event]); 226 } 227 228}); 229 230Element.implement({ 231 232 makeResizable: function(options){ 233 var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options)); 234 this.store('resizer', drag); 235 return drag.addEvent('drag', function(){ 236 this.fireEvent('resize', drag); 237 }.bind(this)); 238 } 239 240}); 241 242 243/* 244Script: Drag.Move.js 245 A Drag extension that provides support for the constraining of draggables to containers and droppables. 246 247 License: 248 MIT-style license. 249 250 Authors: 251 Valerio Proietti 252 Tom Occhinno 253 Jan Kassens*/ 254 255Drag.Move = new Class({ 256 257 Extends: Drag, 258 259 options: {/* 260 onEnter: $empty(thisElement, overed), 261 onLeave: $empty(thisElement, overed), 262 onDrop: $empty(thisElement, overed, event),*/ 263 droppables: [], 264 container: false, 265 precalculate: false, 266 includeMargins: true, 267 checkDroppables: true 268 }, 269 270 initialize: function(element, options){ 271 this.parent(element, options); 272 this.droppables = $$(this.options.droppables); 273 this.container = document.id(this.options.container); 274 if (this.container && $type(this.container) != 'element') this.container = document.id(this.container.getDocument().body); 275 276 var position = this.element.getStyle('position'); 277 if (position=='static') position = 'absolute'; 278 if ([this.element.getStyle('left'), this.element.getStyle('top')].contains('auto')) this.element.position(this.element.getPosition(this.element.offsetParent)); 279 this.element.setStyle('position', position); 280 281 this.addEvent('start', this.checkDroppables, true); 282 283 this.overed = null; 284 }, 285 286 start: function(event){ 287 if (this.container){ 288 var ccoo = this.container.getCoordinates(this.element.getOffsetParent()), cbs = {}, ems = {}; 289 290 ['top', 'right', 'bottom', 'left'].each(function(pad){
291 cbs[pad] = this.container.getStyle('border-' + pad).toInt(); 292 ems[pad] = this.element.getStyle('margin-' + pad).toInt(); 293 }, this); 294 295 var width = this.element.offsetWidth + ems.left + ems.right; 296 var height = this.element.offsetHeight + ems.top + ems.bottom; 297 298 if (this.options.includeMargins) { 299 $each(ems, function(value, key) { 300 ems[key] = 0; 301 }); 302 } 303 if (this.container == this.element.getOffsetParent()) { 304 this.options.limit = { 305 x: [0 - ems.left, ccoo.right - cbs.left - cbs.right - width + ems.right], 306 y: [0 - ems.top, ccoo.bottom - cbs.top - cbs.bottom - height + ems.bottom] 307 }; 308 } else { 309 this.options.limit = { 310 x: [ccoo.left + cbs.left - ems.left, ccoo.right - cbs.right - width + ems.right], 311 y: [ccoo.top + cbs.top - ems.top, ccoo.bottom - cbs.bottom - height + ems.bottom] 312 }; 313 } 314 315 } 316 if (this.options.precalculate){ 317 this.positions = this.droppables.map(function(el) { 318 return el.getCoordinates(); 319 }); 320 } 321 this.parent(event); 322 }, 323 324 checkAgainst: function(el, i){ 325 el = (this.positions) ? this.positions[i] : el.getCoordinates(); 326 var now = this.mouse.now; 327 return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top); 328 }, 329 330 checkDroppables: function(){ 331 var overed = this.droppables.filter(this.checkAgainst, this).getLast(); 332 if (this.overed != overed){ 333 if (this.overed) this.fireEvent('leave', [this.element, this.overed]); 334 if (overed) this.fireEvent('enter', [this.element, overed]); 335 this.overed = overed; 336 } 337 }, 338 339 drag: function(event){ 340 this.parent(event); 341 if (this.options.checkDroppables && this.droppables.length) this.checkDroppables(); 342 }, 343 344 stop: function(event){ 345 this.checkDroppables(); 346 this.fireEvent('drop', [this.element, this.overed, event]); 347 this.overed = null; 348 return this.parent(event); 349 } 350 351}); 352 353Element.implement({ 354 355 makeDraggable: function(options){ 356 var drag = new Drag.Move(this, options); 357 this.store('dragger', drag); 358 return drag; 359 } 360 361}); 362 363 364/* 365Script: Slider.js 366 Class for creating horizontal and vertical slider controls. 367 368 License: 369 MIT-style license. 370 371 Authors: 372 Valerio Proietti 373*/ 374 375var Slider = new Class({ 376 377 Implements: [Events, Options], 378 379 Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'], 380 381 options: {/* 382 onTick: $empty(intPosition), 383 onChange: $empty(intStep), 384 onComplete: $empty(strStep),*/ 385 onTick: function(position){ 386 if (this.options.snap) position = this.toPosition(this.step); 387 this.knob.setStyle(this.property, position); 388 }, 389 snap: false, 390 offset: 0, 391 range: false, 392 wheel: false, 393 steps: 100, 394 mode: 'horizontal' 395 }, 396 397 initialize: function(element, knob, options){ 398 this.setOptions(options); 399 this.element = document.id(element); 400 this.knob = document.id(knob); 401 this.previousChange = this.previousEnd = this.step = -1; 402 var offset, limit = {}, modifiers = {'x': false, 'y': false}; 403 switch (this.options.mode){ 404 case 'vertical': 405 this.axis = 'y'; 406 this.property = 'top'; 407 offset = 'offsetHeight'; 408 break; 409 case 'horizontal': 410 this.axis = 'x'; 411 this.property = 'left'; 412 offset = 'offsetWidth'; 413 } 414 415 this.half = this.knob[offset] / 2; 416 this.full = this.element[offset] - this.knob[offset] + (this.options.offset * 2); 417 this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0; 418 this.max = $chk(this.options.range[1]) ? this.options.range[1] : this.options.steps; 419 this.range = this.max - this.min; 420 this.steps = this.options.steps || this.full; 421 this.stepSize = Math.abs(this.range) / this.steps; 422 this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ; 423 424 this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset); 425 modifiers[this.axis] = this.property; 426 limit[this.axis] = [- this.options.offset, this.full - this.options.offset]; 427 428 this.bound = { 429 clickedElement: this.clickedElement.bind(this), 430 scrolledElement: this.scrolledElement.bindWithEvent(this), 431 draggedKnob: this.draggedKnob.bind(this) 432 }; 433 434 var dragOptions = { 435 snap: 0, 436 limit: limit, 437 modifiers: modifiers, 438 onDrag: (function(){ 439 this.draggedKnob(); 440 this.end(); 441 }).bind(this),//this.bound.draggedKnob, 442 onStart: this.bound.draggedKnob, 443 onBeforeStart: (function(){ 444 this.isDragging = true; 445 }).bind(this), 446 onComplete: function(){ 447 this.isDragging = false;
448 this.draggedKnob(); 449 this.end(); 450 }.bind(this) 451 }; 452 if (this.options.snap){ 453 dragOptions.grid = Math.ceil(this.stepWidth); 454 dragOptions.limit[this.axis][1] = this.full; 455 } 456 457 this.drag = new Drag(this.knob, dragOptions); 458 this.attach(); 459 }, 460 461 attach: function(){ 462 this.element.addEvent('mousedown', this.bound.clickedElement); 463 if (this.options.wheel) this.element.addEvent('mousewheel', this.bound.scrolledElement); 464 this.drag.attach(); 465 return this; 466 }, 467 468 detach: function(){ 469 this.element.removeEvent('mousedown', this.bound.clickedElement); 470 this.element.removeEvent('mousewheel', this.bound.scrolledElement); 471 this.drag.detach(); 472 return this; 473 }, 474 475 set: function(step){ 476 if (!((this.range > 0) ^ (step < this.min))) step = this.min; 477 if (!((this.range > 0) ^ (step > this.max))) step = this.max; 478 479 this.step = Math.round(step); 480 this.checkStep(); 481 this.fireEvent('tick', this.toPosition(this.step)); 482 this.end(); 483 return this; 484 }, 485 486 clickedElement: function(event){ 487 if (this.isDragging || event.target == this.knob) return; 488 489 var dir = this.range < 0 ? -1 : 1; 490 var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half; 491 position = position.limit(-this.options.offset, this.full -this.options.offset); 492 493 this.step = Math.round(this.min + dir * this.toStep(position)); 494 this.checkStep(); 495 this.fireEvent('tick', position); 496 this.end(); 497 }, 498 499 scrolledElement: function(event){ 500 var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0); 501 this.set(mode ? this.step - this.stepSize : this.step + this.stepSize); 502 event.stop(); 503 }, 504 505 draggedKnob: function(){ 506 var dir = this.range < 0 ? -1 : 1; 507 var position = this.drag.value.now[this.axis]; 508 position = position.limit(-this.options.offset, this.full -this.options.offset); 509 this.step = Math.round(this.min + dir * this.toStep(position)); 510 this.checkStep(); 511 }, 512 513 checkStep: function(){ 514 if (this.previousChange != this.step){ 515 this.previousChange = this.step; 516 this.fireEvent('change', this.step); 517 } 518 }, 519 520 end: function(){ 521 if (this.previousEnd !== this.step){ 522 this.previousEnd = this.step; 523 this.fireEvent('complete', this.step + ''); 524 } 525 }, 526 527 toStep: function(position){ 528 var step = (position + this.options.offset) * this.stepSize / this.full * this.steps; 529 return this.options.steps ? Math.round(step -= step % this.stepSize) : step; 530 }, 531 532 toPosition: function(step){ 533 return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset; 534 } 535 536}); 537 538/* 539Script: Sortables.js 540 Class for creating a drag and drop sorting interface for lists of items. 541 542 License: 543 MIT-style license. 544 545 Authors: 546 Tom Occhino 547*/ 548 549var Sortables = new Class({ 550 551 Implements: [Events, Options], 552 553 options: {/* 554 onSort: $empty(element, clone), 555 onStart: $empty(element, clone), 556 onComplete: $empty(element),*/ 557 snap: 4, 558 opacity: 1, 559 clone: false, 560 revert: false, 561 handle: false, 562 constrain: false 563 }, 564 565 initialize: function(lists, options){ 566 this.setOptions(options); 567 this.elements = []; 568 this.lists = []; 569 this.idle = true; 570 571 this.addLists($$(document.id(lists) || lists)); 572 if (!this.options.clone) this.options.revert = false; 573 if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert)); 574 }, 575 576 attach: function(){ 577 this.addLists(this.lists); 578 return this; 579 }, 580 581 detach: function(){ 582 this.lists = this.removeLists(this.lists); 583 return this; 584 }, 585 586 addItems: function(){ 587 Array.flatten(arguments).each(function(element){ 588 this.elements.push(element); 589 var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element)); 590 (this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start); 591 }, this); 592 return this; 593 }, 594 595 addLists: function(){ 596 Array.flatten(arguments).each(function(list){ 597 this.lists.push(list); 598 this.addItems(list.getChildren()); 599 }, this); 600 return this; 601 }, 602 603 removeItems: function(){ 604 return $$(Array.flatten(arguments).map(function(element){ 605 this.elements.erase(element); 606 var start = element.retrieve('sortables:start'); 607 (this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start); 608 609 return element; 610 }, this)); 611 }, 612 613 removeLists: function(){ 614 return $$(Array.flatten(arguments).map(function(list){ 615 this.lists.erase(list); 616 this.removeItems(list.getChildren()); 617 618 return list; 619 }, this)); 620 }, 621 622 getClone: function(event, element){ 623 if (!this.options.clone) return new Element('div').inject(document.body); 624 if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list); 625 return element.clone(true).setStyles({ 626 margin: '0px', 627 position: 'absolute', 628 visibility: 'hidden', 629 'width': element.getStyle('width') 630 }).inject(this.list).position(element.getPosition(element.getOffsetParent())); 631 }, 632 633 getDroppables: function(){ 634 var droppables = this.list.getChildren(); 635 if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list); 636 return droppables.erase(this.clone).erase(this.element); 637 }, 638 639 insert: function(dragging, element){ 640 var where = 'inside'; 641 if (this.lists.contains(element)){ 642 this.list = element; 643 this.drag.droppables = this.getDroppables(); 644 } else { 645 where = this.element.getAllPrevious().contains(element) ? 'before' : 'after'; 646 } 647 this.element.inject(element, where); 648 this.fireEvent('sort', [this.element, this.clone]); 649 }, 650 651 start: function(event, element){ 652 if (!this.idle) return; 653 this.idle = false;
654 this.element = element; 655 this.opacity = element.get('opacity'); 656 this.list = element.getParent(); 657 this.clone = this.getClone(event, element); 658 659 this.drag = new Drag.Move(this.clone, { 660 snap: this.options.snap, 661 container: this.options.constrain && this.element.getParent(), 662 droppables: this.getDroppables(), 663 onSnap: function(){ 664 event.stop(); 665 this.clone.setStyle('visibility', 'visible'); 666 this.element.set('opacity', this.options.opacity || 0); 667 this.fireEvent('start', [this.element, this.clone]); 668 }.bind(this), 669 onEnter: this.insert.bind(this), 670 onCancel: this.reset.bind(this), 671 onComplete: this.end.bind(this) 672 }); 673 674 this.clone.inject(this.element, 'before'); 675 this.drag.start(event); 676 }, 677 678 end: function(){ 679 this.drag.detach(); 680 this.element.set('opacity', this.opacity); 681 if (this.effect){ 682 var dim = this.element.getStyles('width', 'height'); 683 var pos = this.clone.computePosition(this.element.getPosition(this.clone.offsetParent)); 684 this.effect.element = this.clone; 685 this.effect.start({ 686 top: pos.top, 687 left: pos.left, 688 width: dim.width, 689 height: dim.height, 690 opacity: 0.25 691 }).chain(this.reset.bind(this)); 692 } else { 693 this.reset(); 694 } 695 }, 696 697 reset: function(){ 698 this.idle = true; 699 this.clone.destroy(); 700 this.fireEvent('complete', this.element); 701 }, 702 703 serialize: function(){ 704 var params = Array.link(arguments, {modifier: Function.type, index: $defined}); 705 var serial = this.lists.map(function(list){ 706 return list.getChildren().map(params.modifier || function(element){ 707 return element.get('id'); 708 }, this); 709 }, this); 710 711 var index = params.index; 712 if (this.lists.length == 1) index = 0; 713 return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial; 714 } 715 716}); 717 718 719/* 720Script: Request.JSONP.js 721 Defines Request.JSONP, a class for cross domain javascript via script injection. 722 723 License: 724 MIT-style license. 725 726 Authors: 727 Aaron Newton 728 Guillermo Rauch 729*/ 730 731Request.JSONP = new Class({ 732 733 Implements: [Chain, Events, Options, Log], 734 735 options: {/* 736 onRetry: $empty(intRetries), 737 onRequest: $empty(scriptElement), 738 onComplete: $empty(data), 739 onSuccess: $empty(data), 740 onCancel: $empty(),*/ 741 url: '', 742 data: {}, 743 retries: 0, 744 timeout: 0, 745 link: 'ignore', 746 callbackKey: 'callback', 747 injectScript: document.head 748 }, 749 750 initialize: function(options){ 751 this.setOptions(options); 752 this.running = false; 753 this.requests = 0; 754 this.triesRemaining = []; 755 }, 756 757 check: function(){ 758 if (!this.running) return true; 759 switch (this.options.link){ 760 case 'cancel': this.cancel(); return true; 761 case 'chain': this.chain(this.caller.bind(this, arguments)); return false; 762 } 763 return false; 764 }, 765 766 send: function(options){ 767 if (!$chk(arguments[1]) && !this.check(options)) return this; 768 769 var type = $type(options), old = this.options, index = $chk(arguments[1]) ? arguments[1] : this.requests++; 770 if (type == 'string' || type == 'element') options = {data: options}; 771 772 options = $extend({data: old.data, url: old.url}, options); 773 774 if (!$chk(this.triesRemaining[index])) this.triesRemaining[index] = this.options.retries; 775 var remaining = this.triesRemaining[index]; 776 777 (function(){ 778 var script = this.getScript(options); 779 this.log('JSONP retrieving script with url: ' + script.get('src')); 780 this.fireEvent('request', script); 781 this.running = true; 782 783 (function(){ 784 if (remaining){ 785 this.triesRemaining[index] = remaining - 1; 786 if (script){ 787 script.destroy(); 788 this.send(options, index); 789 this.fireEvent('retry', this.triesRemaining[index]); 790 } 791 } else if(script && this.options.timeout){ 792 script.destroy(); 793 this.cancel(); 794 this.fireEvent('failure'); 795 } 796 }).delay(this.options.timeout, this); 797 }).delay(Browser.Engine.trident ? 50 : 0, this); 798 return this; 799 }, 800 801 cancel: function(){ 802 if (!this.running) return this; 803 this.running = false; 804 this.fireEvent('cancel'); 805 return this; 806 }, 807 808 getScript: function(options){ 809 var index = Request.JSONP.counter, data; 810 Request.JSONP.counter++; 811 812 switch ($type(options.data)){ 813 case 'element': data = document.id(options.data).toQueryString(); break; 814 case 'object': case 'hash': data = Hash.toQueryString(options.data); 815 } 816 817 var src = options.url + 818 (options.url.test('\\?') ? '&' :'?') + 819 (options.callbackKey || this.options.callbackKey) + 820 '=Request.JSONP.request_map.request_'+ index + 821 (data ? '&' + data : ''); 822 if (src.length > 2083) this.log('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs'); 823 824 var script = new Element('script', {type: 'text/javascript', src: src}); 825 Request.JSONP.request_map['request_' + index] = function(data){ this.success(data, script); }.bind(this); 826 return script.inject(this.options.injectScript); 827 }, 828 829 success: function(data, script){ 830 if (script) script.destroy(); 831 this.running = false;
832 this.log('JSONP successfully retrieved: ', data); 833 this.fireEvent('complete', [data]).fireEvent('success', [data]).callChain(); 834 } 835 836}); 837 838Request.JSONP.counter = 0; 839Request.JSONP.request_map = {}; 840 841/* 842Script: Request.Queue.js 843 Controls several instances of Request and its variants to run only one request at a time. 844 845 License: 846 MIT-style license. 847 848 Authors: 849 Aaron Newton 850*/ 851 852Request.Queue = new Class({ 853 854 Implements: [Options, Events], 855 856 Binds: ['attach', 'request', 'complete', 'cancel', 'success', 'failure', 'exception'], 857 858 options: {/* 859 onRequest: $empty(argsPassedToOnRequest), 860 onSuccess: $empty(argsPassedToOnSuccess), 861 onComplete: $empty(argsPassedToOnComplete), 862 onCancel: $empty(argsPassedToOnCancel), 863 onException: $empty(argsPassedToOnException), 864 onFailure: $empty(argsPassedToOnFailure),*/ 865 stopOnFailure: true, 866 autoAdvance: true, 867 concurrent: 1, 868 requests: {} 869 }, 870 871 initialize: function(options){ 872 this.setOptions(options); 873 this.requests = new Hash; 874 this.addRequests(this.options.requests); 875 this.queue = []; 876 this.reqBinders = {}; 877 }, 878 879 addRequest: function(name, request){ 880 this.requests.set(name, request); 881 this.attach(name, request); 882 return this; 883 }, 884 885 addRequests: function(obj){ 886 $each(obj, function(req, name){ 887 this.addRequest(name, req); 888 }, this); 889 return this; 890 }, 891 892 getName: function(req){ 893 return this.requests.keyOf(req); 894 }, 895 896 attach: function(name, req){ 897 if (req._groupSend) return this; 898 ['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){ 899 if(!this.reqBinders[name]) this.reqBinders[name] = {}; 900 this.reqBinders[name][evt] = function(){ 901 this['on' + evt.capitalize()].apply(this, [name, req].extend(arguments)); 902 }.bind(this); 903 req.addEvent(evt, this.reqBinders[name][evt]); 904 }, this); 905 req._groupSend = req.send; 906 req.send = function(options){ 907 this.send(name, options); 908 return req; 909 }.bind(this); 910 return this; 911 }, 912 913 removeRequest: function(req){ 914 var name = $type(req) == 'object' ? this.getName(req) : req; 915 if (!name && $type(name) != 'string') return this; 916 req = this.requests.get(name); 917 if (!req) return this; 918 ['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){ 919 req.removeEvent(evt, this.reqBinders[name][evt]); 920 }, this); 921 req.send = req._groupSend; 922 delete req._groupSend; 923 return this; 924 }, 925 926 getRunning: function(){ 927 return this.requests.filter(function(r){ return r.running; }); 928 }, 929 930 isRunning: function(){ 931 return !!this.getRunning().getKeys().length; 932 }, 933 934 send: function(name, options){ 935 var q = function(){ 936 this.requests.get(name)._groupSend(options); 937 this.queue.erase(q); 938 }.bind(this); 939 q.name = name; 940 if (this.getRunning().getKeys().length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q); 941 else q(); 942 return this; 943 }, 944 945 hasNext: function(name){ 946 return (!name) ? !!this.queue.length : !!this.queue.filter(function(q){ return q.name == name; }).length; 947 }, 948 949 resume: function(){ 950 this.error = false; 951 (this.options.concurrent - this.getRunning().getKeys().length).times(this.runNext, this); 952 return this; 953 }, 954 955 runNext: function(name){ 956 if (!this.queue.length) return this; 957 if (!name){ 958 this.queue[0](); 959 } else { 960 var found; 961 this.queue.each(function(q){ 962 if (!found && q.name == name){ 963 found = true; 964 q(); 965 } 966 }); 967 } 968 return this; 969 }, 970 971 runAll: function() { 972 this.queue.each(function(q) { 973 q(); 974 }); 975 return this; 976 }, 977 978 clear: function(name){ 979 if (!name){ 980 this.queue.empty(); 981 } else { 982 this.queue = this.queue.map(function(q){ 983 if (q.name != name) return q; 984 else return false; 985 }).filter(function(q){ return q; }); 986 } 987 return this; 988 }, 989 990 cancel: function(name){ 991 this.requests.get(name).cancel(); 992 return this; 993 }, 994 995 onRequest: function(){ 996 this.fireEvent('request', arguments); 997 }, 998 999 onComplete: function(){ 1000 this.fireEvent('complete', arguments); 1001 }, 1002 1003 onCancel: function(){ 1004 if (this.options.autoAdvance && !this.error) this.runNext(); 1005 this.fireEvent('cancel', arguments); 1006 }, 1007 1008 onSuccess: function(){
1009 if (this.options.autoAdvance && !this.error) this.runNext(); 1010 this.fireEvent('success', arguments); 1011 }, 1012 1013 onFailure: function(){ 1014 this.error = true; 1015 if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext(); 1016 this.fireEvent('failure', arguments); 1017 }, 1018 1019 onException: function(){ 1020 this.error = true; 1021 if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext(); 1022 this.fireEvent('exception', arguments); 1023 } 1024 1025}); 1026 1027 1028/* 1029Script: Request.Periodical.js 1030 Requests the same url at a time interval that increases when no data is returned from the requested server 1031 1032 License: 1033 MIT-style license. 1034 1035 Authors: 1036 Christoph Pojer 1037 1038*/ 1039 1040Request.implement({ 1041 1042 options: { 1043 initialDelay: 5000, 1044 delay: 5000, 1045 limit: 60000 1046 }, 1047 1048 startTimer: function(data){ 1049 var fn = (function(){ 1050 if (!this.running) this.send({data: data}); 1051 }); 1052 this.timer = fn.delay(this.options.initialDelay, this); 1053 this.lastDelay = this.options.initialDelay; 1054 this.completeCheck = function(j){ 1055 $clear(this.timer); 1056 if (j) this.lastDelay = this.options.delay; 1057 else this.lastDelay = (this.lastDelay+this.options.delay).min(this.options.limit); 1058 this.timer = fn.delay(this.lastDelay, this); 1059 }; 1060 this.addEvent('complete', this.completeCheck); 1061 return this; 1062 }, 1063 1064 stopTimer: function(){ 1065 $clear(this.timer); 1066 this.removeEvent('complete', this.completeCheck); 1067 return this; 1068 } 1069 1070}); 1071 1072/* 1073Script: Scroller.js 1074 Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries. 1075 1076 License: 1077 MIT-style license. 1078 1079 Authors: 1080 Valerio Proietti 1081*/ 1082 1083var Scroller = new Class({ 1084 1085 Implements: [Events, Options], 1086 1087 options: { 1088 area: 20, 1089 velocity: 1, 1090 onChange: function(x, y){ 1091 this.element.scrollTo(x, y); 1092 }, 1093 fps: 50 1094 }, 1095 1096 initialize: function(element, options){ 1097 this.setOptions(options); 1098 this.element = document.id(element); 1099 this.listener = ($type(this.element) != 'element') ? document.id(this.element.getDocument().body) : this.element; 1100 this.timer = null; 1101 this.bound = { 1102 attach: this.attach.bind(this), 1103 detach: this.detach.bind(this), 1104 getCoords: this.getCoords.bind(this) 1105 }; 1106 }, 1107 1108 start: function(){ 1109 this.listener.addEvents({ 1110 mouseenter: this.bound.attach, 1111 mouseleave: this.bound.detach 1112 }); 1113 }, 1114 1115 stop: function(){ 1116 this.listener.removeEvents({ 1117 mouseenter: this.bound.attach, 1118 mouseleave: this.bound.detach 1119 }); 1120 this.timer = $clear(this.timer); 1121 }, 1122 1123 attach: function(){ 1124 this.listener.addEvent('mousemove', this.bound.getCoords); 1125 }, 1126 1127 detach: function(){ 1128 this.listener.removeEvent('mousemove', this.bound.getCoords); 1129 this.timer = $clear(this.timer); 1130 }, 1131 1132 getCoords: function(event){ 1133 this.page = (this.listener.get('tag') == 'body') ? event.client : event.page; 1134 if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this); 1135 }, 1136 1137 scroll: function(){ 1138 var size = this.element.getSize(), 1139 scroll = this.element.getScroll(), 1140 pos = this.element.getOffsets(), 1141 scrollSize = this.element.getScrollSize(), 1142 change = {x: 0, y: 0}; 1143 for (var z in this.page){ 1144 if (this.page[z] < (this.options.area + pos[z]) && scroll[z] != 0) 1145 change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity; 1146 else if (this.page[z] + this.options.area > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]) 1147 change[z] = (this.page[z] - size[z] + this.options.area - pos[z]) * this.options.velocity; 1148 } 1149 if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]); 1150 } 1151 1152}); 1153 1154var Asset={javascript:function(f,d){d=$extend({onload:$empty,document:document,check:$lambda(true)},d);var b=new Element("script",{src:f,type:"text/javascript"}); 1155var e=d.onload.bind(b),a=d.check,g=d.document;delete d.onload;delete d.check;delete d.document;b.addEvents({load:e,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){e(); 1156}}}).set(d);if(Browser.Engine.webkit419){var c=(function(){if(!$try(a)){return;}$clear(c);e();}).periodical(50);}return b.inject(g.head);},css:function(b,a){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:b},a)).inject(document.head); 1157}
1157,image:function(c,b){b=$merge({onload:$empty,onabort:$empty,onerror:$empty},b);var d=new Image();var a=document.id(d)||new Element("img");["load","abort","error"].each(function(e){var f="on"+e; 1158var g=b[f];delete b[f];d[f]=function(){if(!d){return;}if(!a.parentNode){a.width=d.width;a.height=d.height;}d=d.onload=d.onabort=d.onerror=null;g.delay(1,a,a); 1159a.fireEvent(e,a,1);};});d.src=a.src=c;if(d&&d.complete){d.onload.delay(1);}return a.set(b);},images:function(d,c){c=$merge({onComplete:$empty,onProgress:$empty,onError:$empty,properties:{}},c); 1160d=$splat(d);var a=[];var b=0;return new Elements(d.map(function(e){return Asset.image(e,$extend(c.properties,{onload:function(){c.onProgress.call(this,b,d.indexOf(e)); 1161b++;if(b==d.length){c.onComplete();}},onerror:function(){c.onError.call(this,b,d.indexOf(e));b++;if(b==d.length){c.onComplete();}}}));}));}};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.