0
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
0
+// Element.Class part Copyright (c) 2005 by Rick Olson
0
+// Permission is hereby granted, free of charge, to any person obtaining
0
+// a copy of this software and associated documentation files (the
0
+// "Software"), to deal in the Software without restriction, including
0
+// without limitation the rights to use, copy, modify, merge, publish,
0
+// distribute, sublicense, and/or sell copies of the Software, and to
0
+// permit persons to whom the Software is furnished to do so, subject to
0
+// the following conditions:
0
+// The above copyright notice and this permission notice shall be
0
+// included in all copies or substantial portions of the Software.
0
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0
+ // Element.toggleClass(element, className) toggles the class being on/off
0
+ // Element.toggleClass(element, className1, className2) toggles between both classes,
0
+ // defaulting to className1 if neither exist
0
+ toggle: function(element, className) {
0
+ if(Element.Class.has(element, className)) {
0
+ Element.Class.remove(element, className);
0
+ if(arguments.length == 3) Element.Class.add(element, arguments[2]);
0
+ Element.Class.add(element, className);
0
+ if(arguments.length == 3) Element.Class.remove(element, arguments[2]);
0
+ // gets space-delimited classnames of an element as an array
0
+ get: function(element) {
0
+ return element.className.split(' ');
0
+ // functions adapted from original functions by Gavin Kistner
0
+ remove: function(element) {
0
+ for(var i = 1; i < arguments.length; i++) {
0
+ regEx = new RegExp("^" + arguments[i] + "\\b\\s*|\\s*\\b" + arguments[i] + "\\b", 'g');
0
+ element.className = element.className.replace(regEx, '')
0
+ add: function(element) {
0
+ for(var i = 1; i < arguments.length; i++) {
0
+ Element.Class.remove(element, arguments[i]);
0
+ element.className += (element.className.length > 0 ? ' ' : '') + arguments[i];
0
+ // returns true if all given classes exist in said element
0
+ has: function(element) {
0
+ if(!element || !element.className) return false;
0
+ for(var i = 1; i < arguments.length; i++) {
0
+ regEx = new RegExp("\\b" + arguments[i] + "\\b");
0
+ if(!regEx.test(element.className)) return false;
0
+ // expects arrays of strings and/or strings as optional paramters
0
+ // Element.Class.has_any(element, ['classA','classB','classC'], 'classD')
0
+ has_any: function(element) {
0
+ if(!element || !element.className) return false;
0
+ for(var i = 1; i < arguments.length; i++) {
0
+ if((typeof arguments[i] == 'object') &&
0
+ (arguments[i].constructor == Array)) {
0
+ for(var j = 0; j < arguments[i].length; j++) {
0
+ regEx = new RegExp("\\b" + arguments[i][j] + "\\b");
0
+ if(regEx.test(element.className)) return true;
0
+ regEx = new RegExp("\\b" + arguments[i] + "\\b");
0
+ if(regEx.test(element.className)) return true;
0
+ childrenWith: function(element, className) {
0
+ var children = $(element).getElementsByTagName('*');
0
+ var elements = new Array();
0
+ for (var i = 0; i < children.length; i++) {
0
+ if (Element.Class.has(children[i], className)) {
0
+ elements.push(children[i]);
0
+/*--------------------------------------------------------------------------*/
0
+ add: function(element) {
0
+ var element = $(element);
0
+ }.extend(arguments[1] || {});
0
+ if(options.containment) {
0
+ options._containers = new Array();
0
+ var containment = options.containment;
0
+ if((typeof containment == 'object') &&
0
+ (containment.constructor == Array)) {
0
+ for(var i=0; i<containment.length; i++)
0
+ options._containers.push($(containment[i]));
0
+ options._containers.push($(containment));
0
+ options._containers_length =
0
+ options._containers.length-1;
0
+ if(element.style.position=='') //fix IE
0
+ element.style.position = 'relative';
0
+ // activate the droppable
0
+ element.droppable = options;
0
+ if(!this.drops) this.drops = [];
0
+ this.drops.push(element);
0
+ is_contained: function(element, drop) {
0
+ var containers = drop.droppable._containers;
0
+ var parentNode = element.parentNode;
0
+ var i = drop.droppable._containers_length;
0
+ do { if(parentNode==containers[i]) return true; } while (i--);
0
+ is_affected: function(pX, pY, element, drop) {
0
+ ((!drop.droppable._containers) ||
0
+ this.is_contained(element, drop)) &&
0
+ ((!drop.droppable.accept) ||
0
+ (Element.Class.has_any(element, drop.droppable.accept))) &&
0
+ Position.within(drop, pX, pY) );
0
+ deactivate: function(drop) {
0
+ Element.Class.remove(drop, drop.droppable.hoverclass);
0
+ this.last_active = null;
0
+ activate: function(drop) {
0
+ if(this.last_active) this.deactivate(this.last_active);
0
+ if(drop.droppable.hoverclass) {
0
+ Element.Class.add(drop, drop.droppable.hoverclass);
0
+ this.last_active = drop;
0
+ show: function(event, element) {
0
+ if(!this.drops) return;
0
+ var pX = Event.pointerX(event);
0
+ var pY = Event.pointerY(event);
0
+ var i = this.drops.length-1; do {
0
+ var drop = this.drops[i];
0
+ if(this.is_affected(pX, pY, element, drop)) {
0
+ if(drop.droppable.onHover)
0
+ drop.droppable.onHover(
0
+ element, drop, Position.overlap(drop.droppable.overlap, drop));
0
+ if(drop.droppable.greedy) {
0
+ fire: function(event, element) {
0
+ if(!this.drops) return;
0
+ var pX = Event.pointerX(event);
0
+ var pY = Event.pointerY(event);
0
+ var i = this.drops.length-1; do {
0
+ var drop = this.drops[i];
0
+ if(this.is_affected(pX, pY, element, drop))
0
+ if(drop.droppable.onDrop)
0
+ drop.droppable.onDrop(element);
0
+ this.deactivate(this.last_active);
0
+ observers: new Array(),
0
+ addObserver: function(observer) {
0
+ this.observers.push(observer);
0
+ notify: function(eventName, draggable) { // 'onStart', 'onEnd'
0
+ for(var i = 0; i < this.observers.length; i++)
0
+ this.observers[i][eventName](draggable);
0
+/*--------------------------------------------------------------------------*/
0
+Draggable = Class.create();
0
+Draggable.prototype = {
0
+ initialize: function(element) {
0
+ starteffect: function(element) {
0
+ new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
0
+ reverteffect: function(element, top_offset, left_offset) {
0
+ new Effect.MoveBy(element, -top_offset, -left_offset, {duration:0.4});
0
+ endeffect: function(element) {
0
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
0
+ }.extend(arguments[1] || {});
0
+ this.element = $(element);
0
+ this.element.drag = this;
0
+ this.handle = options.handle ? $(options.handle) : this.element;
0
+ if(!this.element.style.position)
0
+ this.element.style.position = 'relative';
0
+ this.originalLeft = this.currentLeft();
0
+ this.originalTop = this.currentTop();
0
+ this.originalX = this.element.offsetLeft;
0
+ this.originalY = this.element.offsetTop;
0
+ this.originalZ = parseInt(this.element.style.zIndex || "0");
0
+ this.options = options;
0
+ this.dragging = false;
0
+ Event.observe(this.handle, "mousedown", this.startDrag.bindAsEventListener(this));
0
+ Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this));
0
+ Event.observe(document, "mousemove", this.update.bindAsEventListener(this));
0
+ currentLeft: function() {
0
+ return parseInt(this.element.style.left || '0');
0
+ currentTop: function() {
0
+ return parseInt(this.element.style.top || '0')
0
+ startDrag: function(event) {
0
+ if(Event.isLeftClick(event)) {
0
+ var style = this.element.style;
0
+ this.originalY = this.element.offsetTop - this.currentTop() - this.originalTop;
0
+ this.originalX = this.element.offsetLeft - this.currentLeft() - this.originalLeft;
0
+ this.offsetY = event.clientY - this.originalY - this.originalTop;
0
+ this.offsetX = event.clientX - this.originalX - this.originalLeft;
0
+ endDrag: function(event) {
0
+ if(this.active && this.dragging) {
0
+ this.dragging = false;
0
+ Droppables.fire(event, this.element);
0
+ Draggables.notify('onEnd', this);
0
+ var revert = this.options.revert;
0
+ if(revert && typeof revert == 'function') revert = revert(this.element);
0
+ if(revert && this.options.reverteffect) {
0
+ this.options.reverteffect(this.element,
0
+ this.currentTop()-this.originalTop,
0
+ this.currentLeft()-this.originalLeft);
0
+ this.originalLeft = this.currentLeft();
0
+ this.originalTop = this.currentTop();
0
+ this.element.style.zIndex = this.originalZ;
0
+ if(this.options.endeffect)
0
+ this.options.endeffect(this.element);
0
+ this.dragging = false;
0
+ draw: function(event) {
0
+ var style = this.element.style;
0
+ this.originalX = this.element.offsetLeft - this.currentLeft() - this.originalLeft;
0
+ this.originalY = this.element.offsetTop - this.currentTop() - this.originalTop;
0
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
0
+ style.left = ((event.clientX - this.originalX) - this.offsetX) + "px";
0
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
0
+ style.top = ((event.clientY - this.originalY) - this.offsetY) + "px";
0
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
0
+ update: function(event) {
0
+ var style = this.element.style;
0
+ if(style.position=="") style.position = "relative";
0
+ style.zIndex = this.options.zindex;
0
+ Draggables.notify('onStart', this);
0
+ if(this.options.starteffect) this.options.starteffect(this.element);
0
+ Droppables.show(event, this.element);
0
+ if(this.options.change) this.options.change(this);
0
+ // fix AppleWebKit rendering
0
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
0
+/*--------------------------------------------------------------------------*/
0
+SortableObserver = Class.create();
0
+SortableObserver.prototype = {
0
+ initialize: function(element, observer) {
0
+ this.element = $(element);
0
+ this.observer = observer;
0
+ this.lastValue = Sortable.serialize(this.element);
0
+ this.lastValue = Sortable.serialize(this.element);
0
+ if(this.lastValue != Sortable.serialize(this.element))
0
+ this.observer(this.element)
0
+ create: function(element) {
0
+ var element = $(element);
0
+ tag: 'li', // assumes li children, override with tag: 'tagname'
0
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
0
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
0
+ containment: element, // also takes array of elements (or id's); or false
0
+ handle: false, // or a CSS class
0
+ onChange: function() {},
0
+ onUpdate: function() {}
0
+ }.extend(arguments[1] || {});
0
+ element.sortable = options;