Changeset 491
- Timestamp:
- 08/22/06 07:37:33
- Files:
-
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/behaviour.js (modified) (previous)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/controls.js (modified) (10 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/dragdrop.js (modified) (24 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/effects.js (modified) (38 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/prototype.js (modified) (35 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/qplonetabs.js (modified) (9 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/scriptaculous.js (modified) (2 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/javascripts/slider.js (modified) (5 diffs)
- qPloneTabs/trunk/skins/qPloneTabs/qplonetabs.css.dtml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
qPloneTabs/trunk/skins/qPloneTabs/javascripts/controls.js
r490 r491 142 142 } 143 143 else 144 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||145 (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0))return;144 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN) 145 return; 146 146 147 147 this.changed = true; … … 151 151 this.observer = 152 152 setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); 153 },154 155 activate: function() {156 this.changed = false;157 this.hasFocus = true;158 this.getUpdatedChoices();159 153 }, 160 154 … … 228 222 return; 229 223 } 230 var value = ''; 231 if (this.options.select) { 232 var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; 233 if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); 234 } else 235 value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); 236 224 225 var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); 237 226 var lastTokenPos = this.findLastToken(); 238 227 if (lastTokenPos != -1) { … … 317 306 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { 318 307 initialize: function(element, update, url, options) { 319 this.baseInitialize(element, update, options);308 this.baseInitialize(element, update, options); 320 309 this.options.asynchronous = true; 321 310 this.options.onComplete = this.onComplete.bind(this); … … 460 449 461 450 this.options = Object.extend({ 462 okButton: true,463 451 okText: "ok", 464 cancelLink: true,465 452 cancelText: "cancel", 466 453 savingText: "Saving...", … … 484 471 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, 485 472 highlightendcolor: "#FFFFFF", 486 externalControl: null, 487 submitOnBlur: false, 488 ajaxOptions: {}, 489 evalScripts: false 473 externalControl: null, 474 ajaxOptions: {} 490 475 }, options || {}); 491 476 … … 552 537 } 553 538 554 if (this.options.okButton) { 555 okButton = document.createElement("input"); 556 okButton.type = "submit"; 557 okButton.value = this.options.okText; 558 okButton.className = 'editor_ok_button'; 559 this.form.appendChild(okButton); 560 } 561 562 if (this.options.cancelLink) { 563 cancelLink = document.createElement("a"); 564 cancelLink.href = "#"; 565 cancelLink.appendChild(document.createTextNode(this.options.cancelText)); 566 cancelLink.onclick = this.onclickCancel.bind(this); 567 cancelLink.className = 'editor_cancel'; 568 this.form.appendChild(cancelLink); 569 } 539 okButton = document.createElement("input"); 540 okButton.type = "submit"; 541 okButton.value = this.options.okText; 542 this.form.appendChild(okButton); 543 544 cancelLink = document.createElement("a"); 545 cancelLink.href = "#"; 546 cancelLink.appendChild(document.createTextNode(this.options.cancelText)); 547 cancelLink.onclick = this.onclickCancel.bind(this); 548 this.form.appendChild(cancelLink); 570 549 }, 571 550 hasHTMLLineBreaks: function(string) { … … 583 562 text = this.getText(); 584 563 } 585 586 var obj = this;587 564 588 565 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { 589 566 this.options.textarea = false; 590 567 var textField = document.createElement("input"); 591 textField.obj = this;592 568 textField.type = "text"; 593 569 textField.name = "value"; 594 570 textField.value = text; 595 571 textField.style.backgroundColor = this.options.highlightcolor; 596 textField.className = 'editor_field';597 572 var size = this.options.size || this.options.cols || 0; 598 573 if (size != 0) textField.size = size; 599 if (this.options.submitOnBlur)600 textField.onblur = this.onSubmit.bind(this);601 574 this.editField = textField; 602 575 } else { 603 576 this.options.textarea = true; 604 577 var textArea = document.createElement("textarea"); 605 textArea.obj = this;606 578 textArea.name = "value"; 607 579 textArea.value = this.convertHTMLLineBreaks(text); 608 580 textArea.rows = this.options.rows; 609 581 textArea.cols = this.options.cols || 40; 610 textArea.className = 'editor_field';611 if (this.options.submitOnBlur)612 textArea.onblur = this.onSubmit.bind(this);613 582 this.editField = textArea; 614 583 } … … 661 630 this.onLoading(); 662 631 663 if (this.options.evalScripts) { 664 new Ajax.Request( 665 this.url, Object.extend({ 666 parameters: this.options.callback(form, value), 667 onComplete: this.onComplete.bind(this), 668 onFailure: this.onFailure.bind(this), 669 asynchronous:true, 670 evalScripts:true 671 }, this.options.ajaxOptions)); 672 } else { 673 new Ajax.Updater( 674 { success: this.element, 675 // don't update on failure (this could be an option) 676 failure: null }, 677 this.url, Object.extend({ 678 parameters: this.options.callback(form, value), 679 onComplete: this.onComplete.bind(this), 680 onFailure: this.onFailure.bind(this) 681 }, this.options.ajaxOptions)); 682 } 632 new Ajax.Updater( 633 { 634 success: this.element, 635 // don't update on failure (this could be an option) 636 failure: null 637 }, 638 this.url, 639 Object.extend({ 640 parameters: this.options.callback(form, value), 641 onComplete: this.onComplete.bind(this), 642 onFailure: this.onFailure.bind(this) 643 }, this.options.ajaxOptions) 644 ); 683 645 // stop the event to avoid a page refresh in Safari 684 646 if (arguments.length > 1) { … … 761 723 } 762 724 }; 763 764 Ajax.InPlaceCollectionEditor = Class.create();765 Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);766 Object.extend(Ajax.InPlaceCollectionEditor.prototype, {767 createEditField: function() {768 if (!this.cached_selectTag) {769 var selectTag = document.createElement("select");770 var collection = this.options.collection || [];771 var optionTag;772 collection.each(function(e,i) {773 optionTag = document.createElement("option");774 optionTag.value = (e instanceof Array) ? e[0] : e;775 if(this.options.value==optionTag.value) optionTag.selected = true;776 optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));777 selectTag.appendChild(optionTag);778 }.bind(this));779 this.cached_selectTag = selectTag;780 }781 782 this.editField = this.cached_selectTag;783 if(this.options.loadTextURL) this.loadExternalText();784 this.form.appendChild(this.editField);785 this.options.callback = function(form, value) {786 return "value=" + encodeURIComponent(value);787 }788 }789 });790 725 791 726 // Delayed observer, like Form.Element.Observer, qPloneTabs/trunk/skins/qPloneTabs/javascripts/dragdrop.js
r490 r491 1 1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 2 // (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)3 2 // 4 3 // See scriptaculous.js for full license. … … 17 16 var options = Object.extend({ 18 17 greedy: true, 19 hoverclass: null, 20 tree: false 18 hoverclass: null 21 19 }, arguments[1] || {}); 22 20 … … 40 38 this.drops.push(options); 41 39 }, 42 43 findDeepestChild: function(drops) {44 deepest = drops[0];45 46 for (i = 1; i < drops.length; ++i)47 if (Element.isParent(drops[i].element, deepest.element))48 deepest = drops[i];49 50 return deepest;51 },52 40 53 41 isContained: function(element, drop) { 54 var containmentNode; 55 if(drop.tree) { 56 containmentNode = element.treeNode; 57 } else { 58 containmentNode = element.parentNode; 59 } 60 return drop._containers.detect(function(c) { return containmentNode == c }); 61 }, 62 63 isAffected: function(point, element, drop) { 42 var parentNode = element.parentNode; 43 return drop._containers.detect(function(c) { return parentNode == c }); 44 }, 45 46 isAffected: function(pX, pY, element, drop) { 64 47 return ( 65 48 (drop.element!=element) && … … 69 52 (Element.classNames(element).detect( 70 53 function(v) { return drop.accept.include(v) } ) )) && 71 Position.within(drop.element, p oint[0], point[1]) );54 Position.within(drop.element, pX, pY) ); 72 55 }, 73 56 … … 79 62 80 63 activate: function(drop) { 64 if(this.last_active) this.deactivate(this.last_active); 81 65 if(drop.hoverclass) 82 66 Element.addClassName(drop.element, drop.hoverclass); … … 84 68 }, 85 69 86 show: function( point, element) {70 show: function(event, element) { 87 71 if(!this.drops.length) return; 88 var affected = []; 72 var pX = Event.pointerX(event); 73 var pY = Event.pointerY(event); 74 Position.prepare(); 75 76 var i = this.drops.length-1; do { 77 var drop = this.drops[i]; 78 if(this.isAffected(pX, pY, element, drop)) { 79 if(drop.onHover) 80 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); 81 if(drop.greedy) { 82 this.activate(drop); 83 return; 84 } 85 } 86 } while (i--); 89 87 90 88 if(this.last_active) this.deactivate(this.last_active); 91 this.drops.each( function(drop) {92 if(Droppables.isAffected(point, element, drop))93 affected.push(drop);94 });95 96 if(affected.length>0) {97 drop = Droppables.findDeepestChild(affected);98 Position.within(drop.element, point[0], point[1]);99 if(drop.onHover)100 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));101 102 Droppables.activate(drop);103 }104 89 }, 105 90 … … 108 93 Position.prepare(); 109 94 110 if (this.isAffected( [Event.pointerX(event), Event.pointerY(event)], element, this.last_active))95 if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active)) 111 96 if (this.last_active.onDrop) 112 97 this.last_active.onDrop(element, this.last_active.element, event); … … 120 105 121 106 var Draggables = { 122 drags: [],123 107 observers: [], 124 125 register: function(draggable) {126 if(this.drags.length == 0) {127 this.eventMouseUp = this.endDrag.bindAsEventListener(this);128 this.eventMouseMove = this.updateDrag.bindAsEventListener(this);129 this.eventKeypress = this.keyPress.bindAsEventListener(this);130 131 Event.observe(document, "mouseup", this.eventMouseUp);132 Event.observe(document, "mousemove", this.eventMouseMove);133 Event.observe(document, "keypress", this.eventKeypress);134 }135 this.drags.push(draggable);136 },137 138 unregister: function(draggable) {139 this.drags = this.drags.reject(function(d) { return d==draggable });140 if(this.drags.length == 0) {141 Event.stopObserving(document, "mouseup", this.eventMouseUp);142 Event.stopObserving(document, "mousemove", this.eventMouseMove);143 Event.stopObserving(document, "keypress", this.eventKeypress);144 }145 },146 147 activate: function(draggable) {148 window.focus(); // allows keypress events if window isn't currently focused, fails for Safari149 this.activeDraggable = draggable;150 },151 152 deactivate: function() {153 this.activeDraggable = null;154 },155 156 updateDrag: function(event) {157 if(!this.activeDraggable) return;158 var pointer = [Event.pointerX(event), Event.pointerY(event)];159 // Mozilla-based browsers fire successive mousemove events with160 // the same coordinates, prevent needless redrawing (moz bug?)161 if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;162 this._lastPointer = pointer;163 this.activeDraggable.updateDrag(event, pointer);164 },165 166 endDrag: function(event) {167 if(!this.activeDraggable) return;168 this._lastPointer = null;169 this.activeDraggable.endDrag(event);170 this.activeDraggable = null;171 },172 173 keyPress: function(event) {174 if(this.activeDraggable)175 this.activeDraggable.keyPress(event);176 },177 178 108 addObserver: function(observer) { 179 109 this.observers.push(observer); 180 110 this._cacheObserverCallbacks(); 181 111 }, 182 183 112 removeObserver: function(element) { // element instead of observer fixes mem leaks 184 113 this.observers = this.observers.reject( function(o) { return o.element==element }); 185 114 this._cacheObserverCallbacks(); 186 115 }, 187 188 116 notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' 189 117 if(this[eventName+'Count'] > 0) … … 192 120 }); 193 121 }, 194 195 122 _cacheObserverCallbacks: function() { 196 123 ['onStart','onEnd','onDrag'].each( function(eventName) { … … 209 136 var options = Object.extend({ 210 137 handle: false, 211 starteffect: function(element) { 212 element._opacity = Element.getOpacity(element); 213 new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 138 starteffect: function(element) { 139 new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7}); 214 140 }, 215 141 reverteffect: function(element, top_offset, left_offset) { 216 142 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; 217 element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration:dur});143 new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur}); 218 144 }, 219 endeffect: function(element) { 220 var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0 221 new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity}); 145 endeffect: function(element) { 146 new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0}); 222 147 }, 223 148 zindex: 1000, 224 149 revert: false, 225 scroll: false,226 scrollSensitivity: 20,227 scrollSpeed: 15,228 150 snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } 229 151 }, arguments[1] || {}); 230 152 231 this.element = $(element); 232 233 if(options.handle && (typeof options.handle == 'string')) { 234 var h = Element.childrenWithClassName(this.element, options.handle, true); 235 if(h.length>0) this.handle = h[0]; 236 } 153 this.element = $(element); 154 if(options.handle && (typeof options.handle == 'string')) 155 this.handle = Element.childrenWithClassName(this.element, options.handle)[0]; 156 237 157 if(!this.handle) this.handle = $(options.handle); 238 158 if(!this.handle) this.handle = this.element; 239 240 if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)241 options.scroll = $(options.scroll);242 159 243 160 Element.makePositioned(this.element); // fix IE 244 161 245 this.delta = this.currentDelta(); 246 this.options = options; 247 this.dragging = false; 248 249 this.eventMouseDown = this.initDrag.bindAsEventListener(this); 250 Event.observe(this.handle, "mousedown", this.eventMouseDown); 251 252 Draggables.register(this); 253 }, 254 162 this.offsetX = 0; 163 this.offsetY = 0; 164 this.originalLeft = this.currentLeft(); 165 this.originalTop = this.currentTop(); 166 this.originalX = this.element.offsetLeft; 167 this.originalY = this.element.offsetTop; 168 169 this.options = options; 170 171 this.active = false; 172 this.dragging = false; 173 174 this.eventMouseDown = this.startDrag.bindAsEventListener(this); 175 this.eventMouseUp = this.endDrag.bindAsEventListener(this); 176 this.eventMouseMove = this.update.bindAsEventListener(this); 177 this.eventKeypress = this.keyPress.bindAsEventListener(this); 178 179 this.registerEvents(); 180 }, 255 181 destroy: function() { 256 182 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); 257 Draggables.unregister(this); 258 }, 259 260 currentDelta: function() { 261 return([ 262 parseInt(Element.getStyle(this.element,'left') || '0'), 263 parseInt(Element.getStyle(this.element,'top') || '0')]); 264 }, 265 266 initDrag: function(event) { 267 if(Event.isLeftClick(event)) { 183 this.unregisterEvents(); 184 }, 185 registerEvents: function() { 186 Event.observe(document, "mouseup", this.eventMouseUp); 187 Event.observe(document, "mousemove", this.eventMouseMove); 188 Event.observe(document, "keypress", this.eventKeypress); 189 Event.observe(this.handle, "mousedown", this.eventMouseDown); 190 }, 191 unregisterEvents: function() { 192 //if(!this.active) return; 193 //Event.stopObserving(document, "mouseup", this.eventMouseUp); 194 //Event.stopObserving(document, "mousemove", this.eventMouseMove); 195 //Event.stopObserving(document, "keypress", this.eventKeypress); 196 }, 197 currentLeft: function() { 198 return parseInt(this.element.style.left || '0'); 199 }, 200 currentTop: function() { 201 return parseInt(this.element.style.top || '0') 202 }, 203 startDrag: function(event) { 204 if(Event.isLeftClick(event)) { 205 268 206 // abort on form elements, fixes a Firefox issue 269 207 var src = Event.element(event); … … 271 209 src.tagName=='INPUT' || 272 210 src.tagName=='SELECT' || 273 src.tagName=='OPTION' ||274 211 src.tagName=='BUTTON' || 275 212 src.tagName=='TEXTAREA')) return; 276 277 if(this.element._revert) {278 this.element._revert.cancel();279 this.element._revert = null;280 }281 213 214 // this.registerEvents(); 215 this.active = true; 282 216 var pointer = [Event.pointerX(event), Event.pointerY(event)]; 283 var pos = Position.cumulativeOffset(this.element); 284 this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); 285 286 Draggables.activate(this); 217 var offsets = Position.cumulativeOffset(this.element); 218 this.offsetX = (pointer[0] - offsets[0]); 219 this.offsetY = (pointer[1] - offsets[1]); 287 220 Event.stop(event); 288 221 } 289 222 }, 290 291 startDrag: function(event) {292 this.dragging = true;293 294 if(this.options.zindex) {295 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);296 this.element.style.zIndex = this.options.zindex;297 }298 299 if(this.options.ghosting) {300 this._clone = this.element.cloneNode(true);301 Position.absolutize(this.element);302 this.element.parentNode.insertBefore(this._clone, this.element);303 }304 305 if(this.options.scroll) {306 if (this.options.scroll == window) {307 var where = this._getWindowScroll(this.options.scroll);308 this.originalScrollLeft = where.left;309 this.originalScrollTop = where.top;310 } else {311 this.originalScrollLeft = this.options.scroll.scrollLeft;312 this.originalScrollTop = this.options.scroll.scrollTop;313 }314 }315 316 Draggables.notify('onStart', this, event);317 if(this.options.starteffect) this.options.starteffect(this.element);318 },319 320 updateDrag: function(event, pointer) {321 if(!this.dragging) this.startDrag(event);322 Position.prepare();323 Droppables.show(pointer, this.element);324 Draggables.notify('onDrag', this, event);325 this.draw(pointer);326 if(this.options.change) this.options.change(this);327 328 if(this.options.scroll) {329 this.stopScrolling();330 331 var p;332 if (this.options.scroll == window) {333 with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }334 } else {335 p = Position.page(this.options.scroll);336 p[0] += this.options.scroll.scrollLeft;337 p[1] += this.options.scroll.scrollTop;338 p.push(p[0]+this.options.scroll.offsetWidth);339 p.push(p[1]+this.options.scroll.offsetHeight);340 }341 var speed = [0,0];342 if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);343 if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);344 if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);345 if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);346 this.startScrolling(speed);347 }348 349 // fix AppleWebKit rendering350 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);351 352 Event.stop(event);353 },354 355 223 finishDrag: function(event, success) { 224 // this.unregisterEvents(); 225 226 this.active = false; 356 227 this.dragging = false; 357 228 … … 367 238 var revert = this.options.revert; 368 239 if(revert && typeof revert == 'function') revert = revert(this.element); 369 370 var d = this.currentDelta(); 240 371 241 if(revert && this.options.reverteffect) { 372 242 this.options.reverteffect(this.element, 373 d[1]-this.delta[1], d[0]-this.delta[0]); 243 this.currentTop()-this.originalTop, 244 this.currentLeft()-this.originalLeft); 374 245 } else { 375 this.delta = d; 246 this.originalLeft = this.currentLeft(); 247 this.originalTop = this.currentTop(); 376 248 } 377 249 … … 382 254 this.options.endeffect(this.element); 383 255 384 Draggables.deactivate(this); 256 385 257 Droppables.reset(); 386 258 }, 387 388 259 keyPress: function(event) { 389 if(event.keyCode!=Event.KEY_ESC) return; 390 this.finishDrag(event, false); 391 Event.stop(event); 392 }, 393 260 if(this.active) { 261 if(event.keyCode==Event.KEY_ESC) { 262 this.finishDrag(event, false); 263 Event.stop(event); 264 } 265 } 266 }, 394 267 endDrag: function(event) { 395 if(!this.dragging) return; 396 this.stopScrolling(); 397 this.finishDrag(event, true); 398 Event.stop(event); 399 }, 400 401 draw: function(point) { 402 var pos = Position.cumulativeOffset(this.element); 403 var d = this.currentDelta(); 404 pos[0] -= d[0]; pos[1] -= d[1]; 405 406 if(this.options.scroll && (this.options.scroll != window)) { 407 pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; 408 pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; 409 } 410 411 var p = [0,1].map(function(i){ 412 return (point[i]-pos[i]-this.offset[i]) 413 }.bind(this)); 268 if(this.active && this.dragging) { 269 this.finishDrag(event, true); 270 Event.stop(event); 271 } 272 this.active = false; 273 this.dragging = false; 274 }, 275 draw: function(event) { 276 var pointer = [Event.pointerX(event), Event.pointerY(event)]; 277 var offsets = Position.cumulativeOffset(this.element); 278 offsets[0] -= this.currentLeft(); 279 offsets[1] -= this.currentTop(); 280 var style = this.element.style; 281 282 var pos = [ 283 (pointer[0] - offsets[0] - this.offsetX), 284 (pointer[1] - offsets[1] - this.offsetY)]; 414 285 415 286 if(this.options.snap) { 416 287 if(typeof this.options.snap == 'function') { 417 p = this.options.snap(p[0],p[1],this);288 pos = this.options.snap(pos[0],pos[1]); 418 289 } else { 290 var draggable = this; 419 291 if(this.options.snap instanceof Array) { 420 p = p.map( function(v, i) {421 return Math.round(v/ this.options.snap[i])*this.options.snap[i] }.bind(this))292 pos = pos.collect( function(v, i) { 293 return Math.round(v/draggable.options.snap[i])*draggable.options.snap[i] }) 422 294 } else { 423 p = p.map( function(v) {424 return Math.round(v/ this.options.snap)*this.options.snap }.bind(this))295 pos = pos.collect( function(v) { 296 return Math.round(v/draggable.options.snap)*draggable.options.snap }) 425 297 } 426 298 }} 427 299 428 var style = this.element.style;429 300 if((!this.options.constraint) || (this.options.constraint=='horizontal')) 430 style.left = p [0] + "px";301 style.left = pos[0] + "px"; 431 302 if((!this.options.constraint) || (this.options.constraint=='vertical')) 432 style.top = p [1] + "px";303 style.top = pos[1] + "px"; 433 304 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering 434 305 }, 435 436 stopScrolling: function() { 437 if(this.scrollInterval) { 438 clearInterval(this.scrollInterval); 439 this.scrollInterval = null; 440 Draggables._lastScrollPointer = null; 441 } 442 }, 443 444 startScrolling: function(speed) { 445 this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; 446 this.lastScrolled = new Date(); 447 this.scrollInterval = setInterval(this.scroll.bind(this), 10); 448 }, 449 450 scroll: function() { 451 var current = new Date(); 452 var delta = current - this.lastScrolled; 453 this.lastScrolled = current; 454 if(this.options.scroll == window) { 455 with (this._getWindowScroll(this.options.scroll)) { 456 if (this.scrollSpeed[0] || this.scrollSpeed[1]) { 457 var d = delta / 1000; 458 this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); 306 update: function(event) { 307 if(this.active) { 308 if(!this.dragging) { 309 var style = this.element.style; 310 this.dragging = true; 311 312 if(Element.getStyle(this.element,'position')=='') 313 style.position = "relative"; 314 315 if(this.options.zindex) { 316 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); 317 style.zIndex = this.options.zindex; 459 318 } 460 } 461 } else { 462 this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; 463 this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; 464 } 465 466 Position.prepare(); 467 Droppables.show(Draggables._lastPointer, this.element); 468 Draggables.notify('onDrag', this); 469 Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); 470 Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; 471 Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; 472 if (Draggables._lastScrollPointer[0] < 0) 473 Draggables._lastScrollPointer[0] = 0; 474 if (Draggables._lastScrollPointer[1] < 0) 475 Draggables._lastScrollPointer[1] = 0; 476 this.draw(Draggables._lastScrollPointer); 477 478 if(this.options.change) this.options.change(this); 479 }, 480 481 _getWindowScroll: function(w) { 482 var T, L, W, H; 483 with (w.document) { 484 if (w.document.documentElement && documentElement.scrollTop) { 485 T = documentElement.scrollTop; 486 L = documentElement.scrollLeft; 487 } else if (w.document.body) { 488 T = body.scrollTop; 489 L = body.scrollLeft; 490 } 491 if (w.innerWidth) { 492 W = w.innerWidth; 493 H = w.innerHeight; 494 } else if (w.document.documentElement && documentElement.clientWidth) { 495 W = documentElement.clientWidth; 496 H = documentElement.clientHeight; 497 } else { 498 W = body.offsetWidth; 499 H = body.offsetHeight 500 } 501 } 502 return { top: T, left: L, width: W, height: H }; 319 320 if(this.options.ghosting) { 321 this._clone = this.element.cloneNode(true); 322 Position.absolutize(this.element); 323 this.element.parentNode.insertBefore(this._clone, this.element); 324 } 325 326 Draggables.notify('onStart', this, event); 327 if(this.options.starteffect) this.options.starteffect(this.element); 328 } 329 330 Droppables.show(event, this.element); 331 Draggables.notify('onDrag', this, event); 332 this.draw(event); 333 if(this.options.change) this.options.change(this); 334 335 // fix AppleWebKit rendering 336 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 337 338 Event.stop(event); 339 } 503 340 } 504 341 } … … 513 350 this.lastValue = Sortable.serialize(this.element); 514 351 }, 515 516 352 onStart: function() { 517 353 this.lastValue = Sortable.serialize(this.element); 518 354 }, 519 520 355 onEnd: function() { 521 356 Sortable.unmark(); … … 526 361 527 362 var Sortable = { 528 sortables: {}, 529 530 _findRootElement: function(element) { 531 while (element.tagName != "BODY") { 532 if(element.id && Sortable.sortables[element.id]) return element; 533 element = element.parentNode; 534 } 535 }, 536 537 options: function(element) { 538 element = Sortable._findRootElement($(element)); 539 if(!element) return; 540 return Sortable.sortables[element.id]; 541 }, 542 363 sortables: new Array(), 364 options: function(element){ 365 element = $(element); 366 return this.sortables.detect(function(s) { return s.element == element }); 367 }, 543 368 destroy: function(element){ 544 var s = Sortable.options(element); 545 546 if(s) { 369 element = $(element); 370 this.sortables.findAll(function(s) { return s.element == element }).each(function(s){ 547 371 Draggables.removeObserver(s.element); 548 372 s.droppables.each(function(d){ Droppables.remove(d) }); 549 373 s.draggables.invoke('destroy'); 550 551 delete Sortable.sortables[s.element.id]; 552 } 553 }, 554 374 }); 375 this.sortables = this.sortables.reject(function(s) { return s.element == element }); 376 }, 555 377 create: function(element) { 556 378 element = $(element); … … 559 381 tag: 'li', // assumes li children, override with tag: 'tagname' 560 382 dropOnEmpty: false, 561 tree: false, 562 treeTag: 'ul', 383 tree: false, // fixme: unimplemented 563 384 overlap: 'vertical', // one of 'vertical', 'horizontal' 564 385 constraint: 'vertical', // one of 'vertical', 'horizontal', false … … 568 389 hoverclass: null, 569 390 ghosting: false, 570 scroll: false, 571 scrollSensitivity: 20, 572 scrollSpeed: 15, 573 format: /^[^_]*_(.*)$/, 391 format: null, 574 392 onChange: Prototype.emptyFunction, 575 393 onUpdate: Prototype.emptyFunction … … 582 400 var options_for_draggable = { 583 401 revert: true, 584 scroll: options.scroll,585 scrollSpeed: options.scrollSpeed,586 scrollSensitivity: options.scrollSensitivity,587 402 ghosting: options.ghosting, 588 403 constraint: options.constraint, … … 610 425 overlap: options.overlap, 611 426 containment: options.containment, 612 tree: options.tree,613 427 hoverclass: options.hoverclass, 614 onHover: Sortable.onHover 615 //greedy: !options.dropOnEmpty 616 } 617 618 var options_for_tree = { 619 onHover: Sortable.onEmptyHover, 620 overlap: options.overlap, 621 containment: options.containment, 622 hoverclass: options.hoverclass 428 onHover: Sortable.onHover, 429 greedy: !options.dropOnEmpty 623 430 } 624 431 … … 629 436 options.droppables = []; 630 437 438 // make it so 439 631 440 // drop on empty handling 632 if(options.dropOnEmpty || options.tree) { 633 Droppables.add(element, options_for_tree); 441 if(options.dropOnEmpty) { 442 Droppables.add(element, 443 {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false}); 634 444 options.droppables.push(element); 635 445 } … … 642 452 new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); 643 453 Droppables.add(e, options_for_droppable); 644 if(options.tree) e.treeNode = element;645 454 options.droppables.push(e); 646 455 }); 647 648 if(options.tree) {649 (Sortable.findTreeElements(element, options) || []).each( function(e) {650 Droppables.add(e, options_for_tree);651 e.treeNode = element;652 options.droppables.push(e);653 });654 }655 456 656 457 // keep reference 657 this.sortables [element.id] = options;458 this.sortables.push(options); 658 459 659 460 // for onupdate … … 664 465 // return all suitable-for-sortable elements in a guaranteed order 665 466 findElements: function(element, options) { 666 return Element.findChildren( 667 element, options.only, options.tree ? true : false, options.tag); 668 }, 669 670 findTreeElements: function(element, options) { 671 return Element.findChildren( 672 element, options.only, options.tree ? true : false, options.treeTag); 467 if(!element.hasChildNodes()) return null; 468 var elements = []; 469 $A(element.childNodes).each( function(e) { 470 if(e.tagName && e.tagName==options.tag.toUpperCase() && 471 (!options.only || (Element.hasClassName(e, options.only)))) 472 elements.push(e); 473 if(options.tree) { 474 var grandchildren = this.findElements(e, options); 475 if(grandchildren) elements.push(grandchildren); 476 } 477 }); 478 479 return (elements.length>0 ? elements.flatten() : null); 673 480 }, 674 481 675 482 onHover: function(element, dropon, overlap) { 676 if(Element.isParent(dropon, element)) return; 677 678 if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { 679 return; 680 } else if(overlap>0.5) { 483 if(overlap>0.5) { 681 484 Sortable.mark(dropon, 'before'); 682 485 if(dropon.previousSibling != element) { … … 701 504 } 702 505 }, 703 704 onEmptyHover: function(element, dropon, overlap) { 705 var oldParentNode = element.parentNode; 706 var droponOptions = Sortable.options(dropon); 707 708 if(!Element.isParent(dropon, element)) { 709 var index; 710 711 var children = Sortable.findElements(dropon, {tag: droponOptions.tag}); 712 var child = null; 713 714 if(children) { 715 var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); 716 717 for (index = 0; index < children.length; index += 1) { 718 if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { 719 offset -= Element.offsetSize (children[index], droponOptions.overlap); 720 } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { 721 child = index + 1 < children.length ? children[index + 1] : null; 722 break; 723 } else { 724 child = children[index]; 725 break; 726 } 727 } 728 } 729 730 dropon.insertBefore(element, child); 731 506 507 onEmptyHover: function(element, dropon) { 508 if(element.parentNode!=dropon) { 509 var oldParentNode = element.parentNode; 510 dropon.appendChild(element); 732 511 Sortable.options(oldParentNode).onChange(element); 733 droponOptions.onChange(element);512 Sortable.options(dropon).onChange(element); 734 513 } 735 514 }, … … 763 542 Element.show(Sortable._marker); 764 543 }, 765 766 _tree: function(element, options, parent) { 767 var children = Sortable.findElements(element, options) || []; 768 769 for (var i = 0; i < children.length; ++i) { 770 var match = children[i].id.match(options.format); 771 772 if (!match) continue; 773 774 var child = { 775 id: encodeURIComponent(match ? match[1] : null), 776 element: element, 777 parent: parent, 778 children: new Array, 779 position: parent.children.length, 780 container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) 781 } 782 783 /* Get the element containing the children and recurse over it */ 784 if (child.container) 785 this._tree(child.container, options, child) 786 787 parent.children.push (child); 788 } 789 790 return parent; 791 }, 792 793 /* Finds the first element of the given tag type within a parent element. 794 Used for finding the first LI[ST] within a L[IST]I[TEM].*/ 795 _findChildrenElement: function (element, containerTag) { 796 if (element && element.hasChildNodes) 797 &
