/include/js/scriptaculous.php

https://bitbucket.org/icarito/pmc · PHP · 3560 lines · 3064 code · 297 blank · 199 comment · 549 complexity · aa314ae85ddeef1f944fd9cea6e9c166 MD5 · raw file

Large files are truncated click here to view the full file

  1. <?php
  2. ob_start("ob_gzhandler");
  3. header("Content-type: text/javascript; charset=utf-8");
  4. header("Cache-Control: must-revalidate");
  5. $offset = 600 * 60 ;
  6. $ExpStr = "Expires:" .
  7. gmdate("D, d M Y H:i:s",time() + $offset) . "GMT";
  8. header($ExpStr);
  9. ?>
  10. // script.aculo.us scriptaculous.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
  11. // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. // For details, see the script.aculo.us web site: http://script.aculo.us/
  33. var Scriptaculous = {
  34. Version: '1.8.2',
  35. require: function(libraryName) {
  36. // inserting via DOM fails in Safari 2.0, so brute force approach
  37. document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
  38. },
  39. REQUIRED_PROTOTYPE: '1.6.0.3',
  40. load: function() {
  41. function convertVersionString(versionString) {
  42. var v = versionString.replace(/_.*|\./g, '');
  43. v = parseInt(v + '0'.times(4-v.length));
  44. return versionString.indexOf('_') > -1 ? v-1 : v;
  45. }
  46. if((typeof Prototype=='undefined') ||
  47. (typeof Element == 'undefined') ||
  48. (typeof Element.Methods=='undefined') ||
  49. (convertVersionString(Prototype.Version) <
  50. convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
  51. throw("script.aculo.us requires the Prototype JavaScript framework >= " +
  52. Scriptaculous.REQUIRED_PROTOTYPE);
  53. /*
  54. var js = /scriptaculous\.js(\?.*)?$/;
  55. $$('head script[src]').findAll(function(s) {
  56. return s.src.match(js);
  57. }).each(function(s) {
  58. var path = s.src.replace(js, ''),
  59. includes = s.src.match(/\?.*load=([a-z,]*)/);
  60. (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
  61. function(include) { Scriptaculous.require(path+include+'.js') });
  62. });
  63. }*/
  64. }
  65. }
  66. // script.aculo.us effects.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
  67. // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  68. // Contributors:
  69. // Justin Palmer (http://encytemedia.com/)
  70. // Mark Pilgrim (http://diveintomark.org/)
  71. // Martin Bialasinki
  72. //
  73. // script.aculo.us is freely distributable under the terms of an MIT-style license.
  74. // For details, see the script.aculo.us web site: http://script.aculo.us/
  75. // converts rgb() and #xxx to #xxxxxx format,
  76. // returns self (or first argument) if not convertable
  77. String.prototype.parseColor = function() {
  78. var color = '#';
  79. if (this.slice(0,4) == 'rgb(') {
  80. var cols = this.slice(4,this.length-1).split(',');
  81. var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
  82. } else {
  83. if (this.slice(0,1) == '#') {
  84. if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
  85. if (this.length==7) color = this.toLowerCase();
  86. }
  87. }
  88. return (color.length==7 ? color : (arguments[0] || this));
  89. };
  90. /*--------------------------------------------------------------------------*/
  91. Element.collectTextNodes = function(element) {
  92. return $A($(element).childNodes).collect( function(node) {
  93. return (node.nodeType==3 ? node.nodeValue :
  94. (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  95. }).flatten().join('');
  96. };
  97. Element.collectTextNodesIgnoreClass = function(element, className) {
  98. return $A($(element).childNodes).collect( function(node) {
  99. return (node.nodeType==3 ? node.nodeValue :
  100. ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
  101. Element.collectTextNodesIgnoreClass(node, className) : ''));
  102. }).flatten().join('');
  103. };
  104. Element.setContentZoom = function(element, percent) {
  105. element = $(element);
  106. element.setStyle({fontSize: (percent/100) + 'em'});
  107. if (Prototype.Browser.WebKit) window.scrollBy(0,0);
  108. return element;
  109. };
  110. Element.getInlineOpacity = function(element){
  111. return $(element).style.opacity || '';
  112. };
  113. Element.forceRerendering = function(element) {
  114. try {
  115. element = $(element);
  116. var n = document.createTextNode(' ');
  117. element.appendChild(n);
  118. element.removeChild(n);
  119. } catch(e) { }
  120. };
  121. /*--------------------------------------------------------------------------*/
  122. var Effect = {
  123. _elementDoesNotExistError: {
  124. name: 'ElementDoesNotExistError',
  125. message: 'The specified DOM element does not exist, but is required for this effect to operate'
  126. },
  127. Transitions: {
  128. linear: Prototype.K,
  129. sinoidal: function(pos) {
  130. return (-Math.cos(pos*Math.PI)/2) + .5;
  131. },
  132. reverse: function(pos) {
  133. return 1-pos;
  134. },
  135. flicker: function(pos) {
  136. var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
  137. return pos > 1 ? 1 : pos;
  138. },
  139. wobble: function(pos) {
  140. return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
  141. },
  142. pulse: function(pos, pulses) {
  143. return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
  144. },
  145. spring: function(pos) {
  146. return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
  147. },
  148. none: function(pos) {
  149. return 0;
  150. },
  151. full: function(pos) {
  152. return 1;
  153. }
  154. },
  155. DefaultOptions: {
  156. duration: 1.0, // seconds
  157. fps: 100, // 100= assume 66fps max.
  158. sync: false, // true for combining
  159. from: 0.0,
  160. to: 1.0,
  161. delay: 0.0,
  162. queue: 'parallel'
  163. },
  164. tagifyText: function(element) {
  165. var tagifyStyle = 'position:relative';
  166. if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
  167. element = $(element);
  168. $A(element.childNodes).each( function(child) {
  169. if (child.nodeType==3) {
  170. child.nodeValue.toArray().each( function(character) {
  171. element.insertBefore(
  172. new Element('span', {style: tagifyStyle}).update(
  173. character == ' ' ? String.fromCharCode(160) : character),
  174. child);
  175. });
  176. Element.remove(child);
  177. }
  178. });
  179. },
  180. multiple: function(element, effect) {
  181. var elements;
  182. if (((typeof element == 'object') ||
  183. Object.isFunction(element)) &&
  184. (element.length))
  185. elements = element;
  186. else
  187. elements = $(element).childNodes;
  188. var options = Object.extend({
  189. speed: 0.1,
  190. delay: 0.0
  191. }, arguments[2] || { });
  192. var masterDelay = options.delay;
  193. $A(elements).each( function(element, index) {
  194. new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
  195. });
  196. },
  197. PAIRS: {
  198. 'slide': ['SlideDown','SlideUp'],
  199. 'blind': ['BlindDown','BlindUp'],
  200. 'appear': ['Appear','Fade']
  201. },
  202. toggle: function(element, effect) {
  203. element = $(element);
  204. effect = (effect || 'appear').toLowerCase();
  205. var options = Object.extend({
  206. queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
  207. }, arguments[2] || { });
  208. Effect[element.visible() ?
  209. Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  210. }
  211. };
  212. Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
  213. /* ------------- core effects ------------- */
  214. Effect.ScopedQueue = Class.create(Enumerable, {
  215. initialize: function() {
  216. this.effects = [];
  217. this.interval = null;
  218. },
  219. _each: function(iterator) {
  220. this.effects._each(iterator);
  221. },
  222. add: function(effect) {
  223. var timestamp = new Date().getTime();
  224. var position = Object.isString(effect.options.queue) ?
  225. effect.options.queue : effect.options.queue.position;
  226. switch(position) {
  227. case 'front':
  228. // move unstarted effects after this effect
  229. this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
  230. e.startOn += effect.finishOn;
  231. e.finishOn += effect.finishOn;
  232. });
  233. break;
  234. case 'with-last':
  235. timestamp = this.effects.pluck('startOn').max() || timestamp;
  236. break;
  237. case 'end':
  238. // start effect after last queued effect has finished
  239. timestamp = this.effects.pluck('finishOn').max() || timestamp;
  240. break;
  241. }
  242. effect.startOn += timestamp;
  243. effect.finishOn += timestamp;
  244. if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
  245. this.effects.push(effect);
  246. if (!this.interval)
  247. this.interval = setInterval(this.loop.bind(this), 15);
  248. },
  249. remove: function(effect) {
  250. this.effects = this.effects.reject(function(e) { return e==effect });
  251. if (this.effects.length == 0) {
  252. clearInterval(this.interval);
  253. this.interval = null;
  254. }
  255. },
  256. loop: function() {
  257. var timePos = new Date().getTime();
  258. for(var i=0, len=this.effects.length;i<len;i++)
  259. this.effects[i] && this.effects[i].loop(timePos);
  260. }
  261. });
  262. Effect.Queues = {
  263. instances: $H(),
  264. get: function(queueName) {
  265. if (!Object.isString(queueName)) return queueName;
  266. return this.instances.get(queueName) ||
  267. this.instances.set(queueName, new Effect.ScopedQueue());
  268. }
  269. };
  270. Effect.Queue = Effect.Queues.get('global');
  271. Effect.Base = Class.create({
  272. position: null,
  273. start: function(options) {
  274. function codeForEvent(options,eventName){
  275. return (
  276. (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
  277. (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
  278. );
  279. }
  280. if (options && options.transition === false) options.transition = Effect.Transitions.linear;
  281. this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
  282. this.currentFrame = 0;
  283. this.state = 'idle';
  284. this.startOn = this.options.delay*1000;
  285. this.finishOn = this.startOn+(this.options.duration*1000);
  286. this.fromToDelta = this.options.to-this.options.from;
  287. this.totalTime = this.finishOn-this.startOn;
  288. this.totalFrames = this.options.fps*this.options.duration;
  289. this.render = (function() {
  290. function dispatch(effect, eventName) {
  291. if (effect.options[eventName + 'Internal'])
  292. effect.options[eventName + 'Internal'](effect);
  293. if (effect.options[eventName])
  294. effect.options[eventName](effect);
  295. }
  296. return function(pos) {
  297. if (this.state === "idle") {
  298. this.state = "running";
  299. dispatch(this, 'beforeSetup');
  300. if (this.setup) this.setup();
  301. dispatch(this, 'afterSetup');
  302. }
  303. if (this.state === "running") {
  304. pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
  305. this.position = pos;
  306. dispatch(this, 'beforeUpdate');
  307. if (this.update) this.update(pos);
  308. dispatch(this, 'afterUpdate');
  309. }
  310. };
  311. })();
  312. this.event('beforeStart');
  313. if (!this.options.sync)
  314. Effect.Queues.get(Object.isString(this.options.queue) ?
  315. 'global' : this.options.queue.scope).add(this);
  316. },
  317. loop: function(timePos) {
  318. if (timePos >= this.startOn) {
  319. if (timePos >= this.finishOn) {
  320. this.render(1.0);
  321. this.cancel();
  322. this.event('beforeFinish');
  323. if (this.finish) this.finish();
  324. this.event('afterFinish');
  325. return;
  326. }
  327. var pos = (timePos - this.startOn) / this.totalTime,
  328. frame = (pos * this.totalFrames).round();
  329. if (frame > this.currentFrame) {
  330. this.render(pos);
  331. this.currentFrame = frame;
  332. }
  333. }
  334. },
  335. cancel: function() {
  336. if (!this.options.sync)
  337. Effect.Queues.get(Object.isString(this.options.queue) ?
  338. 'global' : this.options.queue.scope).remove(this);
  339. this.state = 'finished';
  340. },
  341. event: function(eventName) {
  342. if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
  343. if (this.options[eventName]) this.options[eventName](this);
  344. },
  345. inspect: function() {
  346. var data = $H();
  347. for(property in this)
  348. if (!Object.isFunction(this[property])) data.set(property, this[property]);
  349. return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
  350. }
  351. });
  352. Effect.Parallel = Class.create(Effect.Base, {
  353. initialize: function(effects) {
  354. this.effects = effects || [];
  355. this.start(arguments[1]);
  356. },
  357. update: function(position) {
  358. this.effects.invoke('render', position);
  359. },
  360. finish: function(position) {
  361. this.effects.each( function(effect) {
  362. effect.render(1.0);
  363. effect.cancel();
  364. effect.event('beforeFinish');
  365. if (effect.finish) effect.finish(position);
  366. effect.event('afterFinish');
  367. });
  368. }
  369. });
  370. Effect.Tween = Class.create(Effect.Base, {
  371. initialize: function(object, from, to) {
  372. object = Object.isString(object) ? $(object) : object;
  373. var args = $A(arguments), method = args.last(),
  374. options = args.length == 5 ? args[3] : null;
  375. this.method = Object.isFunction(method) ? method.bind(object) :
  376. Object.isFunction(object[method]) ? object[method].bind(object) :
  377. function(value) { object[method] = value };
  378. this.start(Object.extend({ from: from, to: to }, options || { }));
  379. },
  380. update: function(position) {
  381. this.method(position);
  382. }
  383. });
  384. Effect.Event = Class.create(Effect.Base, {
  385. initialize: function() {
  386. this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
  387. },
  388. update: Prototype.emptyFunction
  389. });
  390. Effect.Opacity = Class.create(Effect.Base, {
  391. initialize: function(element) {
  392. this.element = $(element);
  393. if (!this.element) throw(Effect._elementDoesNotExistError);
  394. // make this work on IE on elements without 'layout'
  395. if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
  396. this.element.setStyle({zoom: 1});
  397. var options = Object.extend({
  398. from: this.element.getOpacity() || 0.0,
  399. to: 1.0
  400. }, arguments[1] || { });
  401. this.start(options);
  402. },
  403. update: function(position) {
  404. this.element.setOpacity(position);
  405. }
  406. });
  407. Effect.Move = Class.create(Effect.Base, {
  408. initialize: function(element) {
  409. this.element = $(element);
  410. if (!this.element) throw(Effect._elementDoesNotExistError);
  411. var options = Object.extend({
  412. x: 0,
  413. y: 0,
  414. mode: 'relative'
  415. }, arguments[1] || { });
  416. this.start(options);
  417. },
  418. setup: function() {
  419. this.element.makePositioned();
  420. this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
  421. this.originalTop = parseFloat(this.element.getStyle('top') || '0');
  422. if (this.options.mode == 'absolute') {
  423. this.options.x = this.options.x - this.originalLeft;
  424. this.options.y = this.options.y - this.originalTop;
  425. }
  426. },
  427. update: function(position) {
  428. this.element.setStyle({
  429. left: (this.options.x * position + this.originalLeft).round() + 'px',
  430. top: (this.options.y * position + this.originalTop).round() + 'px'
  431. });
  432. }
  433. });
  434. // for backwards compatibility
  435. Effect.MoveBy = function(element, toTop, toLeft) {
  436. return new Effect.Move(element,
  437. Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
  438. };
  439. Effect.Scale = Class.create(Effect.Base, {
  440. initialize: function(element, percent) {
  441. this.element = $(element);
  442. if (!this.element) throw(Effect._elementDoesNotExistError);
  443. var options = Object.extend({
  444. scaleX: true,
  445. scaleY: true,
  446. scaleContent: true,
  447. scaleFromCenter: false,
  448. scaleMode: 'box', // 'box' or 'contents' or { } with provided values
  449. scaleFrom: 100.0,
  450. scaleTo: percent
  451. }, arguments[2] || { });
  452. this.start(options);
  453. },
  454. setup: function() {
  455. this.restoreAfterFinish = this.options.restoreAfterFinish || false;
  456. this.elementPositioning = this.element.getStyle('position');
  457. this.originalStyle = { };
  458. ['top','left','width','height','fontSize'].each( function(k) {
  459. this.originalStyle[k] = this.element.style[k];
  460. }.bind(this));
  461. this.originalTop = this.element.offsetTop;
  462. this.originalLeft = this.element.offsetLeft;
  463. var fontSize = this.element.getStyle('font-size') || '100%';
  464. ['em','px','%','pt'].each( function(fontSizeType) {
  465. if (fontSize.indexOf(fontSizeType)>0) {
  466. this.fontSize = parseFloat(fontSize);
  467. this.fontSizeType = fontSizeType;
  468. }
  469. }.bind(this));
  470. this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
  471. this.dims = null;
  472. if (this.options.scaleMode=='box')
  473. this.dims = [this.element.offsetHeight, this.element.offsetWidth];
  474. if (/^content/.test(this.options.scaleMode))
  475. this.dims = [this.element.scrollHeight, this.element.scrollWidth];
  476. if (!this.dims)
  477. this.dims = [this.options.scaleMode.originalHeight,
  478. this.options.scaleMode.originalWidth];
  479. },
  480. update: function(position) {
  481. var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
  482. if (this.options.scaleContent && this.fontSize)
  483. this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
  484. this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  485. },
  486. finish: function(position) {
  487. if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  488. },
  489. setDimensions: function(height, width) {
  490. var d = { };
  491. if (this.options.scaleX) d.width = width.round() + 'px';
  492. if (this.options.scaleY) d.height = height.round() + 'px';
  493. if (this.options.scaleFromCenter) {
  494. var topd = (height - this.dims[0])/2;
  495. var leftd = (width - this.dims[1])/2;
  496. if (this.elementPositioning == 'absolute') {
  497. if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
  498. if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
  499. } else {
  500. if (this.options.scaleY) d.top = -topd + 'px';
  501. if (this.options.scaleX) d.left = -leftd + 'px';
  502. }
  503. }
  504. this.element.setStyle(d);
  505. }
  506. });
  507. Effect.Highlight = Class.create(Effect.Base, {
  508. initialize: function(element) {
  509. this.element = $(element);
  510. if (!this.element) throw(Effect._elementDoesNotExistError);
  511. var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
  512. this.start(options);
  513. },
  514. setup: function() {
  515. // Prevent executing on elements not in the layout flow
  516. if (this.element.getStyle('display')=='none') { this.cancel(); return; }
  517. // Disable background image during the effect
  518. this.oldStyle = { };
  519. if (!this.options.keepBackgroundImage) {
  520. this.oldStyle.backgroundImage = this.element.getStyle('background-image');
  521. this.element.setStyle({backgroundImage: 'none'});
  522. }
  523. if (!this.options.endcolor)
  524. this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
  525. if (!this.options.restorecolor)
  526. this.options.restorecolor = this.element.getStyle('background-color');
  527. // init color calculations
  528. this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
  529. this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  530. },
  531. update: function(position) {
  532. this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
  533. return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
  534. },
  535. finish: function() {
  536. this.element.setStyle(Object.extend(this.oldStyle, {
  537. backgroundColor: this.options.restorecolor
  538. }));
  539. }
  540. });
  541. Effect.ScrollTo = function(element) {
  542. var options = arguments[1] || { },
  543. scrollOffsets = document.viewport.getScrollOffsets(),
  544. elementOffsets = $(element).cumulativeOffset();
  545. if (options.offset) elementOffsets[1] += options.offset;
  546. return new Effect.Tween(null,
  547. scrollOffsets.top,
  548. elementOffsets[1],
  549. options,
  550. function(p){ scrollTo(scrollOffsets.left, p.round()); }
  551. );
  552. };
  553. /* ------------- combination effects ------------- */
  554. Effect.Fade = function(element) {
  555. element = $(element);
  556. var oldOpacity = element.getInlineOpacity();
  557. var options = Object.extend({
  558. from: element.getOpacity() || 1.0,
  559. to: 0.0,
  560. afterFinishInternal: function(effect) {
  561. if (effect.options.to!=0) return;
  562. effect.element.hide().setStyle({opacity: oldOpacity});
  563. }
  564. }, arguments[1] || { });
  565. return new Effect.Opacity(element,options);
  566. };
  567. Effect.Appear = function(element) {
  568. element = $(element);
  569. var options = Object.extend({
  570. from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  571. to: 1.0,
  572. // force Safari to render floated elements properly
  573. afterFinishInternal: function(effect) {
  574. effect.element.forceRerendering();
  575. },
  576. beforeSetup: function(effect) {
  577. effect.element.setOpacity(effect.options.from).show();
  578. }}, arguments[1] || { });
  579. return new Effect.Opacity(element,options);
  580. };
  581. Effect.Puff = function(element) {
  582. element = $(element);
  583. var oldStyle = {
  584. opacity: element.getInlineOpacity(),
  585. position: element.getStyle('position'),
  586. top: element.style.top,
  587. left: element.style.left,
  588. width: element.style.width,
  589. height: element.style.height
  590. };
  591. return new Effect.Parallel(
  592. [ new Effect.Scale(element, 200,
  593. { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
  594. new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
  595. Object.extend({ duration: 1.0,
  596. beforeSetupInternal: function(effect) {
  597. Position.absolutize(effect.effects[0].element);
  598. },
  599. afterFinishInternal: function(effect) {
  600. effect.effects[0].element.hide().setStyle(oldStyle); }
  601. }, arguments[1] || { })
  602. );
  603. };
  604. Effect.BlindUp = function(element) {
  605. element = $(element);
  606. element.makeClipping();
  607. return new Effect.Scale(element, 0,
  608. Object.extend({ scaleContent: false,
  609. scaleX: false,
  610. restoreAfterFinish: true,
  611. afterFinishInternal: function(effect) {
  612. effect.element.hide().undoClipping();
  613. }
  614. }, arguments[1] || { })
  615. );
  616. };
  617. Effect.BlindDown = function(element) {
  618. element = $(element);
  619. var elementDimensions = element.getDimensions();
  620. return new Effect.Scale(element, 100, Object.extend({
  621. scaleContent: false,
  622. scaleX: false,
  623. scaleFrom: 0,
  624. scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  625. restoreAfterFinish: true,
  626. afterSetup: function(effect) {
  627. effect.element.makeClipping().setStyle({height: '0px'}).show();
  628. },
  629. afterFinishInternal: function(effect) {
  630. effect.element.undoClipping();
  631. }
  632. }, arguments[1] || { }));
  633. };
  634. Effect.SwitchOff = function(element) {
  635. element = $(element);
  636. var oldOpacity = element.getInlineOpacity();
  637. return new Effect.Appear(element, Object.extend({
  638. duration: 0.4,
  639. from: 0,
  640. transition: Effect.Transitions.flicker,
  641. afterFinishInternal: function(effect) {
  642. new Effect.Scale(effect.element, 1, {
  643. duration: 0.3, scaleFromCenter: true,
  644. scaleX: false, scaleContent: false, restoreAfterFinish: true,
  645. beforeSetup: function(effect) {
  646. effect.element.makePositioned().makeClipping();
  647. },
  648. afterFinishInternal: function(effect) {
  649. effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
  650. }
  651. });
  652. }
  653. }, arguments[1] || { }));
  654. };
  655. Effect.DropOut = function(element) {
  656. element = $(element);
  657. var oldStyle = {
  658. top: element.getStyle('top'),
  659. left: element.getStyle('left'),
  660. opacity: element.getInlineOpacity() };
  661. return new Effect.Parallel(
  662. [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
  663. new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
  664. Object.extend(
  665. { duration: 0.5,
  666. beforeSetup: function(effect) {
  667. effect.effects[0].element.makePositioned();
  668. },
  669. afterFinishInternal: function(effect) {
  670. effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
  671. }
  672. }, arguments[1] || { }));
  673. };
  674. Effect.Shake = function(element) {
  675. element = $(element);
  676. var options = Object.extend({
  677. distance: 20,
  678. duration: 0.5
  679. }, arguments[1] || {});
  680. var distance = parseFloat(options.distance);
  681. var split = parseFloat(options.duration) / 10.0;
  682. var oldStyle = {
  683. top: element.getStyle('top'),
  684. left: element.getStyle('left') };
  685. return new Effect.Move(element,
  686. { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
  687. new Effect.Move(effect.element,
  688. { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
  689. new Effect.Move(effect.element,
  690. { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
  691. new Effect.Move(effect.element,
  692. { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
  693. new Effect.Move(effect.element,
  694. { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
  695. new Effect.Move(effect.element,
  696. { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
  697. effect.element.undoPositioned().setStyle(oldStyle);
  698. }}); }}); }}); }}); }}); }});
  699. };
  700. Effect.SlideDown = function(element) {
  701. element = $(element).cleanWhitespace();
  702. // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  703. var oldInnerBottom = element.down().getStyle('bottom');
  704. var elementDimensions = element.getDimensions();
  705. return new Effect.Scale(element, 100, Object.extend({
  706. scaleContent: false,
  707. scaleX: false,
  708. scaleFrom: window.opera ? 0 : 1,
  709. scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  710. restoreAfterFinish: true,
  711. afterSetup: function(effect) {
  712. effect.element.makePositioned();
  713. effect.element.down().makePositioned();
  714. if (window.opera) effect.element.setStyle({top: ''});
  715. effect.element.makeClipping().setStyle({height: '0px'}).show();
  716. },
  717. afterUpdateInternal: function(effect) {
  718. effect.element.down().setStyle({bottom:
  719. (effect.dims[0] - effect.element.clientHeight) + 'px' });
  720. },
  721. afterFinishInternal: function(effect) {
  722. effect.element.undoClipping().undoPositioned();
  723. effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
  724. }, arguments[1] || { })
  725. );
  726. };
  727. Effect.SlideUp = function(element) {
  728. element = $(element).cleanWhitespace();
  729. var oldInnerBottom = element.down().getStyle('bottom');
  730. var elementDimensions = element.getDimensions();
  731. return new Effect.Scale(element, window.opera ? 0 : 1,
  732. Object.extend({ scaleContent: false,
  733. scaleX: false,
  734. scaleMode: 'box',
  735. scaleFrom: 100,
  736. scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  737. restoreAfterFinish: true,
  738. afterSetup: function(effect) {
  739. effect.element.makePositioned();
  740. effect.element.down().makePositioned();
  741. if (window.opera) effect.element.setStyle({top: ''});
  742. effect.element.makeClipping().show();
  743. },
  744. afterUpdateInternal: function(effect) {
  745. effect.element.down().setStyle({bottom:
  746. (effect.dims[0] - effect.element.clientHeight) + 'px' });
  747. },
  748. afterFinishInternal: function(effect) {
  749. effect.element.hide().undoClipping().undoPositioned();
  750. effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
  751. }
  752. }, arguments[1] || { })
  753. );
  754. };
  755. // Bug in opera makes the TD containing this element expand for a instance after finish
  756. Effect.Squish = function(element) {
  757. return new Effect.Scale(element, window.opera ? 1 : 0, {
  758. restoreAfterFinish: true,
  759. beforeSetup: function(effect) {
  760. effect.element.makeClipping();
  761. },
  762. afterFinishInternal: function(effect) {
  763. effect.element.hide().undoClipping();
  764. }
  765. });
  766. };
  767. Effect.Grow = function(element) {
  768. element = $(element);
  769. var options = Object.extend({
  770. direction: 'center',
  771. moveTransition: Effect.Transitions.sinoidal,
  772. scaleTransition: Effect.Transitions.sinoidal,
  773. opacityTransition: Effect.Transitions.full
  774. }, arguments[1] || { });
  775. var oldStyle = {
  776. top: element.style.top,
  777. left: element.style.left,
  778. height: element.style.height,
  779. width: element.style.width,
  780. opacity: element.getInlineOpacity() };
  781. var dims = element.getDimensions();
  782. var initialMoveX, initialMoveY;
  783. var moveX, moveY;
  784. switch (options.direction) {
  785. case 'top-left':
  786. initialMoveX = initialMoveY = moveX = moveY = 0;
  787. break;
  788. case 'top-right':
  789. initialMoveX = dims.width;
  790. initialMoveY = moveY = 0;
  791. moveX = -dims.width;
  792. break;
  793. case 'bottom-left':
  794. initialMoveX = moveX = 0;
  795. initialMoveY = dims.height;
  796. moveY = -dims.height;
  797. break;
  798. case 'bottom-right':
  799. initialMoveX = dims.width;
  800. initialMoveY = dims.height;
  801. moveX = -dims.width;
  802. moveY = -dims.height;
  803. break;
  804. case 'center':
  805. initialMoveX = dims.width / 2;
  806. initialMoveY = dims.height / 2;
  807. moveX = -dims.width / 2;
  808. moveY = -dims.height / 2;
  809. break;
  810. }
  811. return new Effect.Move(element, {
  812. x: initialMoveX,
  813. y: initialMoveY,
  814. duration: 0.01,
  815. beforeSetup: function(effect) {
  816. effect.element.hide().makeClipping().makePositioned();
  817. },
  818. afterFinishInternal: function(effect) {
  819. new Effect.Parallel(
  820. [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
  821. new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
  822. new Effect.Scale(effect.element, 100, {
  823. scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
  824. sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
  825. ], Object.extend({
  826. beforeSetup: function(effect) {
  827. effect.effects[0].element.setStyle({height: '0px'}).show();
  828. },
  829. afterFinishInternal: function(effect) {
  830. effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
  831. }
  832. }, options)
  833. );
  834. }
  835. });
  836. };
  837. Effect.Shrink = function(element) {
  838. element = $(element);
  839. var options = Object.extend({
  840. direction: 'center',
  841. moveTransition: Effect.Transitions.sinoidal,
  842. scaleTransition: Effect.Transitions.sinoidal,
  843. opacityTransition: Effect.Transitions.none
  844. }, arguments[1] || { });
  845. var oldStyle = {
  846. top: element.style.top,
  847. left: element.style.left,
  848. height: element.style.height,
  849. width: element.style.width,
  850. opacity: element.getInlineOpacity() };
  851. var dims = element.getDimensions();
  852. var moveX, moveY;
  853. switch (options.direction) {
  854. case 'top-left':
  855. moveX = moveY = 0;
  856. break;
  857. case 'top-right':
  858. moveX = dims.width;
  859. moveY = 0;
  860. break;
  861. case 'bottom-left':
  862. moveX = 0;
  863. moveY = dims.height;
  864. break;
  865. case 'bottom-right':
  866. moveX = dims.width;
  867. moveY = dims.height;
  868. break;
  869. case 'center':
  870. moveX = dims.width / 2;
  871. moveY = dims.height / 2;
  872. break;
  873. }
  874. return new Effect.Parallel(
  875. [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
  876. new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
  877. new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
  878. ], Object.extend({
  879. beforeStartInternal: function(effect) {
  880. effect.effects[0].element.makePositioned().makeClipping();
  881. },
  882. afterFinishInternal: function(effect) {
  883. effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
  884. }, options)
  885. );
  886. };
  887. Effect.Pulsate = function(element) {
  888. element = $(element);
  889. var options = arguments[1] || { },
  890. oldOpacity = element.getInlineOpacity(),
  891. transition = options.transition || Effect.Transitions.linear,
  892. reverser = function(pos){
  893. return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
  894. };
  895. return new Effect.Opacity(element,
  896. Object.extend(Object.extend({ duration: 2.0, from: 0,
  897. afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
  898. }, options), {transition: reverser}));
  899. };
  900. Effect.Fold = function(element) {
  901. element = $(element);
  902. var oldStyle = {
  903. top: element.style.top,
  904. left: element.style.left,
  905. width: element.style.width,
  906. height: element.style.height };
  907. element.makeClipping();
  908. return new Effect.Scale(element, 5, Object.extend({
  909. scaleContent: false,
  910. scaleX: false,
  911. afterFinishInternal: function(effect) {
  912. new Effect.Scale(element, 1, {
  913. scaleContent: false,
  914. scaleY: false,
  915. afterFinishInternal: function(effect) {
  916. effect.element.hide().undoClipping().setStyle(oldStyle);
  917. } });
  918. }}, arguments[1] || { }));
  919. };
  920. Effect.Morph = Class.create(Effect.Base, {
  921. initialize: function(element) {
  922. this.element = $(element);
  923. if (!this.element) throw(Effect._elementDoesNotExistError);
  924. var options = Object.extend({
  925. style: { }
  926. }, arguments[1] || { });
  927. if (!Object.isString(options.style)) this.style = $H(options.style);
  928. else {
  929. if (options.style.include(':'))
  930. this.style = options.style.parseStyle();
  931. else {
  932. this.element.addClassName(options.style);
  933. this.style = $H(this.element.getStyles());
  934. this.element.removeClassName(options.style);
  935. var css = this.element.getStyles();
  936. this.style = this.style.reject(function(style) {
  937. return style.value == css[style.key];
  938. });
  939. options.afterFinishInternal = function(effect) {
  940. effect.element.addClassName(effect.options.style);
  941. effect.transforms.each(function(transform) {
  942. effect.element.style[transform.style] = '';
  943. });
  944. };
  945. }
  946. }
  947. this.start(options);
  948. },
  949. setup: function(){
  950. function parseColor(color){
  951. if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
  952. color = color.parseColor();
  953. return $R(0,2).map(function(i){
  954. return parseInt( color.slice(i*2+1,i*2+3), 16 );
  955. });
  956. }
  957. this.transforms = this.style.map(function(pair){
  958. var property = pair[0], value = pair[1], unit = null;
  959. if (value.parseColor('#zzzzzz') != '#zzzzzz') {
  960. value = value.parseColor();
  961. unit = 'color';
  962. } else if (property == 'opacity') {
  963. value = parseFloat(value);
  964. if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
  965. this.element.setStyle({zoom: 1});
  966. } else if (Element.CSS_LENGTH.test(value)) {
  967. var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
  968. value = parseFloat(components[1]);
  969. unit = (components.length == 3) ? components[2] : null;
  970. }
  971. var originalValue = this.element.getStyle(property);
  972. return {
  973. style: property.camelize(),
  974. originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
  975. targetValue: unit=='color' ? parseColor(value) : value,
  976. unit: unit
  977. };
  978. }.bind(this)).reject(function(transform){
  979. return (
  980. (transform.originalValue == transform.targetValue) ||
  981. (
  982. transform.unit != 'color' &&
  983. (isNaN(transform.originalValue) || isNaN(transform.targetValue))
  984. )
  985. );
  986. });
  987. },
  988. update: function(position) {
  989. var style = { }, transform, i = this.transforms.length;
  990. while(i--)
  991. style[(transform = this.transforms[i]).style] =
  992. transform.unit=='color' ? '#'+
  993. (Math.round(transform.originalValue[0]+
  994. (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
  995. (Math.round(transform.originalValue[1]+
  996. (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
  997. (Math.round(transform.originalValue[2]+
  998. (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
  999. (transform.originalValue +
  1000. (transform.targetValue - transform.originalValue) * position).toFixed(3) +
  1001. (transform.unit === null ? '' : transform.unit);
  1002. this.element.setStyle(style, true);
  1003. }
  1004. });
  1005. Effect.Transform = Class.create({
  1006. initialize: function(tracks){
  1007. this.tracks = [];
  1008. this.options = arguments[1] || { };
  1009. this.addTracks(tracks);
  1010. },
  1011. addTracks: function(tracks){
  1012. tracks.each(function(track){
  1013. track = $H(track);
  1014. var data = track.values().first();
  1015. this.tracks.push($H({
  1016. ids: track.keys().first(),
  1017. effect: Effect.Morph,
  1018. options: { style: data }
  1019. }));
  1020. }.bind(this));
  1021. return this;
  1022. },
  1023. play: function(){
  1024. return new Effect.Parallel(
  1025. this.tracks.map(function(track){
  1026. var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
  1027. var elements = [$(ids) || $$(ids)].flatten();
  1028. return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
  1029. }).flatten(),
  1030. this.options
  1031. );
  1032. }
  1033. });
  1034. Element.CSS_PROPERTIES = $w(
  1035. 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
  1036. 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  1037. 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  1038. 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  1039. 'fontSize fontWeight height left letterSpacing lineHeight ' +
  1040. 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  1041. 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  1042. 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  1043. 'right textIndent top width wordSpacing zIndex');
  1044. Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
  1045. String.__parseStyleElement = document.createElement('div');
  1046. String.prototype.parseStyle = function(){
  1047. var style, styleRules = $H();
  1048. if (Prototype.Browser.WebKit)
  1049. style = new Element('div',{style:this}).style;
  1050. else {
  1051. String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
  1052. style = String.__parseStyleElement.childNodes[0].style;
  1053. }
  1054. Element.CSS_PROPERTIES.each(function(property){
  1055. if (style[property]) styleRules.set(property, style[property]);
  1056. });
  1057. if (Prototype.Browser.IE && this.include('opacity'))
  1058. styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
  1059. return styleRules;
  1060. };
  1061. if (document.defaultView && document.defaultView.getComputedStyle) {
  1062. Element.getStyles = function(element) {
  1063. var css = document.defaultView.getComputedStyle($(element), null);
  1064. return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
  1065. styles[property] = css[property];
  1066. return styles;
  1067. });
  1068. };
  1069. } else {
  1070. Element.getStyles = function(element) {
  1071. element = $(element);
  1072. var css = element.currentStyle, styles;
  1073. styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
  1074. results[property] = css[property];
  1075. return results;
  1076. });
  1077. if (!styles.opacity) styles.opacity = element.getOpacity();
  1078. return styles;
  1079. };
  1080. }
  1081. Effect.Methods = {
  1082. morph: function(element, style) {
  1083. element = $(element);
  1084. new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
  1085. return element;
  1086. },
  1087. visualEffect: function(element, effect, options) {
  1088. element = $(element);
  1089. var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
  1090. new Effect[klass](element, options);
  1091. return element;
  1092. },
  1093. highlight: function(element, options) {
  1094. element = $(element);
  1095. new Effect.Highlight(element, options);
  1096. return element;
  1097. }
  1098. };
  1099. $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
  1100. 'pulsate shake puff squish switchOff dropOut').each(
  1101. function(effect) {
  1102. Effect.Methods[effect] = function(element, options){
  1103. element = $(element);
  1104. Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
  1105. return element;
  1106. };
  1107. }
  1108. );
  1109. $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
  1110. function(f) { Effect.Methods[f] = Element[f]; }
  1111. );
  1112. Element.addMethods(Effect.Methods);
  1113. // script.aculo.us dragdrop.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
  1114. // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  1115. // (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
  1116. //
  1117. // script.aculo.us is freely distributable under the terms of an MIT-style license.
  1118. // For details, see the script.aculo.us web site: http://script.aculo.us/
  1119. if(Object.isUndefined(Effect))
  1120. throw("dragdrop.js requires including script.aculo.us' effects.js library");
  1121. var Droppables = {
  1122. drops: [],
  1123. remove: function(element) {
  1124. this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  1125. },
  1126. add: function(element) {
  1127. element = $(element);
  1128. var options = Object.extend({
  1129. greedy: true,
  1130. hoverclass: null,
  1131. tree: false
  1132. }, arguments[1] || { });
  1133. // cache containers
  1134. if(options.containment) {
  1135. options._containers = [];
  1136. var containment = options.containment;
  1137. if(Object.isArray(containment)) {
  1138. containment.each( function(c) { options._containers.push($(c)) });
  1139. } else {
  1140. options._containers.push($(containment));
  1141. }
  1142. }
  1143. if(options.accept) options.accept = [options.accept].flatten();
  1144. Element.makePositioned(element); // fix IE
  1145. options.element = element;
  1146. this.drops.push(options);
  1147. },
  1148. findDeepestChild: function(drops) {
  1149. deepest = drops[0];
  1150. for (i = 1; i < drops.length; ++i)
  1151. if (Element.isParent(drops[i].element, deepest.element))
  1152. deepest = drops[i];
  1153. return deepest;
  1154. },
  1155. isContained: function(element, drop) {
  1156. var containmentNode;
  1157. if(drop.tree) {
  1158. containmentNode = element.treeNode;
  1159. } else {
  1160. containmentNode = element.parentNode;
  1161. }
  1162. return drop._containers.detect(function(c) { return containmentNode == c });
  1163. },
  1164. isAffected: function(point, element, drop) {
  1165. return (
  1166. (drop.element!=element) &&
  1167. ((!drop._containers) ||
  1168. this.isContained(element, drop)) &&
  1169. ((!drop.accept) ||
  1170. (Element.classNames(element).detect(
  1171. function(v) { return drop.accept.include(v) } ) )) &&
  1172. Position.within(drop.element, point[0], point[1]) );
  1173. },
  1174. deactivate: function(drop) {
  1175. if(drop.hoverclass)
  1176. Element.removeClassName(drop.element, drop.hoverclass);
  1177. this.last_active = null;
  1178. },
  1179. activate: function(drop) {
  1180. if(drop.hoverclass)
  1181. Element.addClassName(drop.element, drop.hoverclass);
  1182. this.last_active = drop;
  1183. },
  1184. show: function(point, element) {
  1185. if(!this.drops.length) return;
  1186. var drop, affected = [];
  1187. this.drops.each( function(drop) {
  1188. if(Droppables.isAffected(point, element, drop))
  1189. affected.push(drop);
  1190. });
  1191. if(affected.length>0)
  1192. drop = Droppables.findDeepestChild(affected);
  1193. if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
  1194. if (drop) {
  1195. Position.within(drop.element, point[0], point[1]);
  1196. if(drop.onHover)
  1197. drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
  1198. if (drop != this.last_active) Droppables.activate(drop);
  1199. }
  1200. },
  1201. fire: function(event, element) {
  1202. if(!this.last_active) return;
  1203. Position.prepare();
  1204. if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
  1205. if (this.last_active.onDrop) {
  1206. this.last_active.onDrop(element, this.last_active.element, event);
  1207. return true;
  1208. }
  1209. },
  1210. reset: function() {
  1211. if(this.last_active)
  1212. this.deactivate(this.last_active);
  1213. }
  1214. };
  1215. var Draggables = {
  1216. drags: [],
  1217. observers: [],
  1218. register: function(draggable) {
  1219. if(this.drags.length == 0) {
  1220. this.eventMouseUp = this.endDrag.bindAsEventListener(this);
  1221. this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
  1222. this.eventKeypress = this.keyPress.bindAsEventListener(this);
  1223. Event.observe(document, "mouseup", this.eventMouseUp);
  1224. Event.observe(document, "mousemove", this.eventMouseMove);
  1225. Event.observe(document, "keypress", this.eventKeypress);
  1226. }
  1227. this.drags.push(draggable);
  1228. },
  1229. unregister: function(draggable) {
  1230. this.drags = this.drags.reject(function(d) { return d==draggable });
  1231. if(this.drags.length == 0) {
  1232. Event.stopObserving(document, "mouseup", this.eventMouseUp);
  1233. Event.stopObserving(document, "mousemove", this.eventMouseMove);
  1234. Event.stopObserving(document, "keypress", this.eventKeypress);
  1235. }
  1236. },
  1237. activate: function(draggable) {
  1238. if(draggable.options.delay) {
  1239. this._timeout = setTimeout(function() {
  1240. Draggables._timeout = null;
  1241. window.focus();
  1242. Draggables.activeDraggable = draggable;
  1243. }.bind(this), draggable.options.delay);
  1244. } else {
  1245. window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
  1246. this.activeDraggable = draggable;
  1247. }
  1248. },
  1249. deactivate: function() {
  1250. this.activeDraggable = null;
  1251. },
  1252. updateDrag: function(event) {
  1253. if(!this.activeDraggable) return;
  1254. var pointer = [Event.pointerX(event), Event.pointerY(event)];
  1255. // Mozilla-based browsers fire successive mousemove events with
  1256. // the same coordinates, prevent needless redrawing (moz bug?)
  1257. if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
  1258. this._lastPointer = pointer;
  1259. this.activeDraggable.updateDrag(event, pointer);
  1260. },
  1261. endDrag: function(event) {
  1262. if(this._timeout) {
  1263. clearTimeout(this._timeout);
  1264. this._timeout = null;
  1265. }
  1266. if(!this.activeDraggable) return;
  1267. this._lastPointer = null;
  1268. this.activeDraggable.endDrag(event);
  1269. this.activeDraggable = null;
  1270. },
  1271. keyPress: function(event) {
  1272. if(this.activeDraggable)
  1273. this.activeDraggable.keyPress(event);
  1274. },
  1275. addObserver: function(observer) {
  1276. this.observers.push(observer);
  1277. this._cacheObserverCallbacks();
  1278. },
  1279. removeObserver: function(element) { // element instead of observer fixes mem leaks
  1280. this.observers = this.observers.reject( function(o) { return o.element==element });
  1281. this._cacheObserverCallbacks();
  1282. },
  1283. notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
  1284. if(this[eventName+'Count'] > 0)
  1285. this.observers.each( function(o) {
  1286. if(o[eventName]) o[eventName](eventName, draggable, event);
  1287. });
  1288. if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  1289. },
  1290. _cacheObserverCallbacks: function() {
  1291. ['onStart','onEnd','onDrag'].each( function(eventName) {
  1292. Draggables[eventName+'Count'] = Draggables.observers.select(
  1293. function(o) { return o[eventName]; }
  1294. ).length;
  1295. });
  1296. }
  1297. };
  1298. /*--------------------------------------------------------------------------*/
  1299. var Draggable = Class.create({
  1300. initialize: function(element) {
  1301. var defaults = {
  1302. handle: false,
  1303. reverteffect: function(element, top_offset, left_offset) {
  1304. var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
  1305. new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
  1306. queue: {scope:'_draggable', position:'end'}
  1307. });
  1308. },
  1309. endeffect: function(element) {
  1310. var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
  1311. new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
  1312. queue: {scope:'_draggable', position:'end'},
  1313. afterFinish: function(){
  1314. Draggable._dragging[element] = false
  1315. }
  1316. });
  1317. },
  1318. zindex: 1000,
  1319. revert: false,
  1320. quiet: false,
  1321. scroll: false,
  1322. scrollSensitivity: 20,
  1323. scrollSpeed: 15,
  1324. snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
  1325. delay: 0
  1326. };
  1327. if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
  1328. Object.extend(defaults, {
  1329. starteffect: function(element) {
  1330. element._opacity = Element.getOpacity(element);
  1331. Draggable._dragging[element] = true;
  1332. new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
  1333. }
  1334. });
  1335. var options = Object.extend(defaults, arguments[1] || { });
  1336. this.element = $(element);
  1337. if(options.handle && Object.isStri