Changeset 485
- Timestamp:
- 08/18/06 13:53:26
- Files:
-
- qPloneTabs/tags/0.2.1/__init__.py (modified) (1 diff)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/2.0.5/collapsible.css.dtml (deleted)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/2.0.5/collapsiblesections.js (deleted)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/2.0.5/cssQuery.js (deleted)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/2.0.5/nodeutilities.js (deleted)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/2.0.5/register_function.js (deleted)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/controls.js (modified) (10 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/dragdrop.js (modified) (24 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/qplonetabs.js (modified) (13 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/scriptaculous.js (modified) (2 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/slider.js (modified) (5 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/prefs_tabs_form.cpt (modified) (5 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qplonetabs.css.dtml (modified) (7 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qpt_add.py (modified) (3 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qpt_edit.py (modified) (1 diff)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qpt_getroottabs.pt (added)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qpt_gettabslist.pt (modified) (3 diffs)
- qPloneTabs/tags/0.2.1/skins/qPloneTabs/qpt_setvisibility.py (added)
- qPloneTabs/tags/0.2.1/utils.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
qPloneTabs/tags/0.2.1/__init__.py
r484 r485 8 8 9 9 from Products.qPloneTabs.utils import getPortalTabs 10 from Products.qPloneTabs.utils import getRootTabs qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/controls.js
r484 r485 142 142 } 143 143 else 144 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)145 return;144 if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 145 (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) 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(); 153 159 }, 154 160 … … 222 228 return; 223 229 } 224 225 var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); 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 226 237 var lastTokenPos = this.findLastToken(); 227 238 if (lastTokenPos != -1) { … … 306 317 Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { 307 318 initialize: function(element, update, url, options) { 308 this.baseInitialize(element, update, options);319 this.baseInitialize(element, update, options); 309 320 this.options.asynchronous = true; 310 321 this.options.onComplete = this.onComplete.bind(this); … … 449 460 450 461 this.options = Object.extend({ 462 okButton: true, 451 463 okText: "ok", 464 cancelLink: true, 452 465 cancelText: "cancel", 453 466 savingText: "Saving...", … … 471 484 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, 472 485 highlightendcolor: "#FFFFFF", 473 externalControl: null, 474 ajaxOptions: {} 486 externalControl: null, 487 submitOnBlur: false, 488 ajaxOptions: {}, 489 evalScripts: false 475 490 }, options || {}); 476 491 … … 537 552 } 538 553 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); 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 } 549 570 }, 550 571 hasHTMLLineBreaks: function(string) { … … 562 583 text = this.getText(); 563 584 } 585 586 var obj = this; 564 587 565 588 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { 566 589 this.options.textarea = false; 567 590 var textField = document.createElement("input"); 591 textField.obj = this; 568 592 textField.type = "text"; 569 593 textField.name = "value"; 570 594 textField.value = text; 571 595 textField.style.backgroundColor = this.options.highlightcolor; 596 textField.className = 'editor_field'; 572 597 var size = this.options.size || this.options.cols || 0; 573 598 if (size != 0) textField.size = size; 599 if (this.options.submitOnBlur) 600 textField.onblur = this.onSubmit.bind(this); 574 601 this.editField = textField; 575 602 } else { 576 603 this.options.textarea = true; 577 604 var textArea = document.createElement("textarea"); 605 textArea.obj = this; 578 606 textArea.name = "value"; 579 607 textArea.value = this.convertHTMLLineBreaks(text); 580 608 textArea.rows = this.options.rows; 581 609 textArea.cols = this.options.cols || 40; 610 textArea.className = 'editor_field'; 611 if (this.options.submitOnBlur) 612 textArea.onblur = this.onSubmit.bind(this); 582 613 this.editField = textArea; 583 614 } … … 630 661 this.onLoading(); 631 662 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 ); 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 } 645 683 // stop the event to avoid a page refresh in Safari 646 684 if (arguments.length > 1) { … … 723 761 } 724 762 }; 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 }); 725 790 726 791 // Delayed observer, like Form.Element.Observer, qPloneTabs/tags/0.2.1/skins/qPloneTabs/javascripts/dragdrop.js
r484 r485 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) 2 3 // 3 4 // See scriptaculous.js for full license. … … 16 17 var options = Object.extend({ 17 18 greedy: true, 18 hoverclass: null 19 hoverclass: null, 20 tree: false 19 21 }, arguments[1] || {}); 20 22 … … 38 40 this.drops.push(options); 39 41 }, 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 }, 40 52 41 53 isContained: function(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) { 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) { 47 64 return ( 48 65 (drop.element!=element) && … … 52 69 (Element.classNames(element).detect( 53 70 function(v) { return drop.accept.include(v) } ) )) && 54 Position.within(drop.element, p X, pY) );71 Position.within(drop.element, point[0], point[1]) ); 55 72 }, 56 73 … … 62 79 63 80 activate: function(drop) { 64 if(this.last_active) this.deactivate(this.last_active);65 81 if(drop.hoverclass) 66 82 Element.addClassName(drop.element, drop.hoverclass); … … 68 84 }, 69 85 70 show: function( event, element) {86 show: function(point, element) { 71 87 if(!this.drops.length) return; 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--); 88 var affected = []; 87 89 88 90 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 } 89 104 }, 90 105 … … 93 108 Position.prepare(); 94 109 95 if (this.isAffected( Event.pointerX(event), Event.pointerY(event), element, this.last_active))110 if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) 96 111 if (this.last_active.onDrop) 97 112 this.last_active.onDrop(element, this.last_active.element, event); … … 105 120 106 121 var Draggables = { 122 drags: [], 107 123 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 Safari 149 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 with 160 // 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 108 178 addObserver: function(observer) { 109 179 this.observers.push(observer); 110 180 this._cacheObserverCallbacks(); 111 181 }, 182 112 183 removeObserver: function(element) { // element instead of observer fixes mem leaks 113 184 this.observers = this.observers.reject( function(o) { return o.element==element }); 114 185 this._cacheObserverCallbacks(); 115 186 }, 187 116 188 notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' 117 189 if(this[eventName+'Count'] > 0) … … 120 192 }); 121 193 }, 194 122 195 _cacheObserverCallbacks: function() { 123 196 ['onStart','onEnd','onDrag'].each( function(eventName) { … … 136 209 var options = Object.extend({ 137 210 handle: false, 138 starteffect: function(element) { 139 new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7}); 211 starteffect: function(element) { 212 element._opacity = Element.getOpacity(element); 213 new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 140 214 }, 141 215 reverteffect: function(element, top_offset, left_offset) { 142 216 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; 143 new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});217 element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur}); 144 218 }, 145 endeffect: function(element) { 146 new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0}); 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}); 147 222 }, 148 223 zindex: 1000, 149 224 revert: false, 225 scroll: false, 226 scrollSensitivity: 20, 227 scrollSpeed: 15, 150 228 snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } 151 229 }, arguments[1] || {}); 152 230 153 this.element = $(element); 154 if(options.handle && (typeof options.handle == 'string')) 155 this.handle = Element.childrenWithClassName(this.element, options.handle)[0]; 156 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 } 157 237 if(!this.handle) this.handle = $(options.handle); 158 238 if(!this.handle) this.handle = this.element; 239 240 if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) 241 options.scroll = $(options.scroll); 159 242 160 243 Element.makePositioned(this.element); // fix IE 161 244 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 }, 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 181 255 destroy: function() { 182 256 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); 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 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)) { 206 268 // abort on form elements, fixes a Firefox issue 207 269 var src = Event.element(event); … … 209 271 src.tagName=='INPUT' || 210 272 src.tagName=='SELECT' || 273 src.tagName=='OPTION' || 211 274 src.tagName=='BUTTON' || 212 275 src.tagName=='TEXTAREA')) return; 213 214 // this.registerEvents(); 215 this.active = true; 276 277 if(this.element._revert) { 278 this.element._revert.cancel(); 279 this.element._revert = null; 280 } 281 216 282 var pointer = [Event.pointerX(event), Event.pointerY(event)]; 217 var offsets = Position.cumulativeOffset(this.element); 218 this.offsetX = (pointer[0] - offsets[0]); 219 this.offsetY = (pointer[1] - offsets[1]); 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); 220 287 Event.stop(event); 221 288 } 222 289 }, 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 rendering 350 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 351 352 Event.stop(event); 353 }, 354 223 355 finishDrag: function(event, success) { 224 // this.unregisterEvents();225 226 this.active = false;227 356 this.dragging = false; 228 357 … … 238 367 var revert = this.options.revert; 239 368 if(revert && typeof revert == 'function') revert = revert(this.element); 240 369 370 var d = this.currentDelta(); 241 371 if(revert && this.options.reverteffect) { 242 372 this.options.reverteffect(this.element, 243 this.currentTop()-this.originalTop, 244 this.currentLeft()-this.originalLeft); 373 d[1]-this.delta[1], d[0]-this.delta[0]); 245 374 } else { 246 this.originalLeft = this.currentLeft(); 247 this.originalTop = this.currentTop(); 375 this.delta = d; 248 376 } 249 377 … … 254 382 this.options.endeffect(this.element); 255 383 256 384 Draggables.deactivate(this); 257 385 Droppables.reset(); 258 386 }, 387 259 388 keyPress: function(event) { 260 if(this.active) { 261 if(event.keyCode==Event.KEY_ESC) { 262 this.finishDrag(event, false); 263 Event.stop(event); 264 } 265 } 266 }, 389 if(event.keyCode!=Event.KEY_ESC) return; 390 this.finishDrag(event, false); 391 Event.stop(event); 392 }, 393 267 394 endDrag: function(event) { 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)]; 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)); 285 414 286 415 if(this.options.snap) { 287 416 if(typeof this.options.snap == 'function') { 288 p os = this.options.snap(pos[0],pos[1]);417 p = this.options.snap(p[0],p[1],this); 289 418 } else { 290 var draggable = this;291 419 if(this.options.snap instanceof Array) { 292 p os = pos.collect( function(v, i) {293 return Math.round(v/ draggable.options.snap[i])*draggable.options.snap[i] })420 p = p.map( function(v, i) { 421 return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) 294 422 } else { 295 p os = pos.collect( function(v) {296 return Math.round(v/ draggable.options.snap)*draggable.options.snap })423 p = p.map( function(v) { 424 return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) 297 425 } 298 426 }} 299 427 428 var style = this.element.style; 300 429 if((!this.options.constraint) || (this.options.constraint=='horizontal')) 301 style.left = p os[0] + "px";430 style.left = p[0] + "px"; 302 431 if((!this.options.constraint) || (this.options.constraint=='vertical')) 303 style.top = p os[1] + "px";432 style.top = p[1] + "px"; 304 433 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering 305 434 }, 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; 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] ); 318 459 } 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 } 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 }; 340 503 } 341 504 } … … 350 513 this.lastValue = Sortable.serialize(this.element); 351 514 }, 515 352 516 onStart: function() { 353 517 this.lastValue = Sortable.serialize(this.element); 354 518 }, 519 355 520 onEnd: function() { 356 521 Sortable.unmark(); … … 361 526 362 527 var Sortable = { 363 sortables: new Array(), 364 options: function(element){ 365 element = $(element); 366 return this.sortables.detect(function(s) { return s.element == element }); 367 }, 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 368 543 destroy: function(element){ 369 element = $(element); 370 this.sortables.findAll(function(s) { return s.element == element }).each(function(s){ 544 var s = Sortable.options(element); 545 546 if(s) { 371 547 Draggables.removeObserver(s.element); 372 548 s.droppables.each(function(d){ Droppables.remove(d) }); 373 549 s.draggables.invoke('destroy'); 374 }); 375 this.sortables = this.sortables.reject(function(s) { return s.element == element }); 376 }, 550 551 delete Sortable.sortables[s.element.id]; 552 } 553 }, 554 377 555 create: function(element) { 378 556 element = $(element); … … 381 559 tag: 'li', // assumes li children, override with tag: 'tagname' 382 560 dropOnEmpty: false, 383 tree: false, // fixme: unimplemented 561 tree: false, 562 treeTag: 'ul', 384 563 overlap: 'vertical', // one of 'vertical', 'horizontal' 385 564 constraint: 'vertical', // one of 'vertical', 'horizontal', false … … 389 568 hoverclass: null, 390 569 ghosting: false, 391 format: null, 570 scroll: false, 571 scrollSensitivity: 20, 572 scrollSpeed: 15, 573 format: /^[^_]*_(.*)$/, 392 574 onChange: Prototype.emptyFunction, 393 575 onUpdate: Prototype.emptyFunction … … 400 582 var options_for_draggable = { 401 583 revert: true, 584 scroll: options.scroll, 585 scrollSpeed: options.scrollSpeed, 586 scrollSensitivity: options.scrollSensitivity, 402 587 ghosting: options.ghosting, 403 588 constraint: options.constraint, … … 425 610 overlap: options.overlap, 426 611 containment: options.containment, 612 tree: options.tree, 427 613 hoverclass: options.hoverclass, 428 onHover: Sortable.onHover, 429 greedy: !options.dropOnEmpty 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 430 623 } 431 624 … … 436 629 options.droppables = []; 437 630 438 // make it so439 440 631 // drop on empty handling 441 if(options.dropOnEmpty) { 442 Droppables.add(element, 443 {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false}); 632 if(options.dropOnEmpty || options.tree) { 633 Droppables.add(element, options_for_tree); 444 634 options.droppables.push(element); 445 635 } … … 452 642 new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); 453 643 Droppables.add(e, options_for_droppable); 644 if(options.tree) e.treeNode = element; 454 645 options.droppables.push(e); 455 646 }); 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 } 456 655 457 656 // keep reference 458 this.sortables .push(options);657 this.sortables[element.id] = options; 459 658 460 659 // for onupdate … … 465 664 // return all suitable-for-sortable elements in a guaranteed order 466 665 findElements: function(element, options) { 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); 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); 480 673 }, 481 674 482 675 onHover: function(element, dropon, overlap) { 483 if(overlap>0.5) { 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) { 484 681 Sortable.mark(dropon, 'before'); 485 682 if(dropon.previousSibling != element) { … … 504 701 } 505 702 }, 506 507 onEmptyHover: function(element, dropon) { 508 if(element.parentNode!=dropon) { 509 var oldParentNode = element.parentNode; 510 dropon.appendChild(element); 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 511 732 Sortable.options(oldParentNode).onChange(element); 512 Sortable.options(dropon)
