Changeset 28
- Timestamp:
- 04/17/06 10:29:54 (2 years ago)
- Files:
-
- trunk/demo/config/boot.rb (modified) (1 diff)
- trunk/demo/public/javascripts/application.js (added)
- trunk/demo/public/javascripts/controls.js (modified) (10 diffs)
- trunk/demo/public/javascripts/dragdrop.js (modified) (27 diffs)
- trunk/demo/public/javascripts/effects.js (modified) (42 diffs)
- trunk/demo/public/javascripts/prototype.js (modified) (29 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/demo/config/boot.rb
r5 r28 3 3 unless defined?(RAILS_ROOT) 4 4 root_path = File.join(File.dirname(__FILE__), '..') 5 5 6 unless RUBY_PLATFORM =~ /mswin32/ 6 7 require 'pathname' 7 8 root_path = Pathname.new(root_path).cleanpath(true).to_s 8 9 end 10 9 11 RAILS_ROOT = root_path 10 12 end 11 13 12 if File.directory?("#{RAILS_ROOT}/vendor/rails") 13 require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" 14 else 15 require 'rubygems' 16 require 'initializer' 14 unless defined?(Rails::Initializer) 15 if File.directory?("#{RAILS_ROOT}/vendor/rails") 16 require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" 17 else 18 require 'rubygems' 19 20 environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join 21 environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/ 22 rails_gem_version = $1 23 24 if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version 25 rails_gem = Gem.cache.search('rails', "=#{version}").first 26 27 if rails_gem 28 require_gem "rails", "=#{version}" 29 require rails_gem.full_gem_path + '/lib/initializer' 30 else 31 STDERR.puts %(Cannot find gem for Rails =#{version}: 32 Install the missing gem with 'gem install -v=#{version} rails', or 33 change environment.rb to define RAILS_GEM_VERSION with your desired version. 34 ) 35 exit 1 36 end 37 else 38 require_gem "rails" 39 require 'initializer' 40 end 41 end 42 43 Rails::Initializer.run(:set_load_path) 17 44 end 18 19 Rails::Initializer.run(:set_load_path)trunk/demo/public/javascripts/controls.js
r5 r28 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, trunk/demo/public/javascripts/dragdrop.js
r5 r28 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 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 46 63 isAffected: function(point, element, drop) { 47 64 return ( … … 69 86 show: function(point, element) { 70 87 if(!this.drops.length) return; 88 var affected = []; 71 89 72 90 if(this.last_active) this.deactivate(this.last_active); 73 91 this.drops.each( function(drop) { 74 if(Droppables.isAffected(point, element, drop)) { 75 if(drop.onHover) 76 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); 77 if(drop.greedy) { 78 Droppables.activate(drop); 79 throw $break; 80 } 81 } 92 if(Droppables.isAffected(point, element, drop)) 93 affected.push(drop); 82 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 } 83 104 }, 84 105 … … 129 150 }, 130 151 131 deactivate: function( draggbale) {152 deactivate: function() { 132 153 this.activeDraggable = null; 133 154 }, … … 147 168 this._lastPointer = null; 148 169 this.activeDraggable.endDrag(event); 170 this.activeDraggable = null; 149 171 }, 150 172 … … 192 214 reverteffect: function(element, top_offset, left_offset) { 193 215 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; 194 element._revert = new Effect.Move By(element, -top_offset, -left_offset, {duration:dur});216 element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur}); 195 217 }, 196 218 endeffect: function(element) { … … 199 221 zindex: 1000, 200 222 revert: false, 223 scroll: false, 224 scrollSensitivity: 20, 225 scrollSpeed: 15, 201 226 snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } 202 227 }, arguments[1] || {}); … … 204 229 this.element = $(element); 205 230 206 if(options.handle && (typeof options.handle == 'string')) 207 this.handle = Element.childrenWithClassName(this.element, options.handle)[0]; 231 if(options.handle && (typeof options.handle == 'string')) { 232 var h = Element.childrenWithClassName(this.element, options.handle, true); 233 if(h.length>0) this.handle = h[0]; 234 } 208 235 if(!this.handle) this.handle = $(options.handle); 209 236 if(!this.handle) this.handle = this.element; 237 238 if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) 239 options.scroll = $(options.scroll); 210 240 211 241 Element.makePositioned(this.element); // fix IE … … 228 258 currentDelta: function() { 229 259 return([ 230 parseInt( this.element.style.left|| '0'),231 parseInt( this.element.style.top|| '0')]);260 parseInt(Element.getStyle(this.element,'left') || '0'), 261 parseInt(Element.getStyle(this.element,'top') || '0')]); 232 262 }, 233 263 … … 239 269 src.tagName=='INPUT' || 240 270 src.tagName=='SELECT' || 271 src.tagName=='OPTION' || 241 272 src.tagName=='BUTTON' || 242 273 src.tagName=='TEXTAREA')) return; … … 268 299 Position.absolutize(this.element); 269 300 this.element.parentNode.insertBefore(this._clone, this.element); 301 } 302 303 if(this.options.scroll) { 304 if (this.options.scroll == window) { 305 var where = this._getWindowScroll(this.options.scroll); 306 this.originalScrollLeft = where.left; 307 this.originalScrollTop = where.top; 308 } else { 309 this.originalScrollLeft = this.options.scroll.scrollLeft; 310 this.originalScrollTop = this.options.scroll.scrollTop; 311 } 270 312 } 271 313 … … 282 324 if(this.options.change) this.options.change(this); 283 325 326 if(this.options.scroll) { 327 this.stopScrolling(); 328 329 var p; 330 if (this.options.scroll == window) { 331 with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } 332 } else { 333 p = Position.page(this.options.scroll); 334 p[0] += this.options.scroll.scrollLeft; 335 p[1] += this.options.scroll.scrollTop; 336 p.push(p[0]+this.options.scroll.offsetWidth); 337 p.push(p[1]+this.options.scroll.offsetHeight); 338 } 339 var speed = [0,0]; 340 if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); 341 if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); 342 if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); 343 if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); 344 this.startScrolling(speed); 345 } 346 284 347 // fix AppleWebKit rendering 285 348 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 349 286 350 Event.stop(event); 287 351 }, … … 321 385 322 386 keyPress: function(event) { 323 if( !event.keyCode==Event.KEY_ESC) return;387 if(event.keyCode!=Event.KEY_ESC) return; 324 388 this.finishDrag(event, false); 325 389 Event.stop(event); … … 328 392 endDrag: function(event) { 329 393 if(!this.dragging) return; 394 this.stopScrolling(); 330 395 this.finishDrag(event, true); 331 396 Event.stop(event); … … 337 402 pos[0] -= d[0]; pos[1] -= d[1]; 338 403 339 var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this)); 404 if(this.options.scroll && (this.options.scroll != window)) { 405 pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; 406 pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; 407 } 408 409 var p = [0,1].map(function(i){ 410 return (point[i]-pos[i]-this.offset[i]) 411 }.bind(this)); 340 412 341 413 if(this.options.snap) { … … 358 430 style.top = p[1] + "px"; 359 431 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering 432 }, 433 434 stopScrolling: function() { 435 if(this.scrollInterval) { 436 clearInterval(this.scrollInterval); 437 this.scrollInterval = null; 438 Draggables._lastScrollPointer = null; 439 } 440 }, 441 442 startScrolling: function(speed) { 443 this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; 444 this.lastScrolled = new Date(); 445 this.scrollInterval = setInterval(this.scroll.bind(this), 10); 446 }, 447 448 scroll: function() { 449 var current = new Date(); 450 var delta = current - this.lastScrolled; 451 this.lastScrolled = current; 452 if(this.options.scroll == window) { 453 with (this._getWindowScroll(this.options.scroll)) { 454 if (this.scrollSpeed[0] || this.scrollSpeed[1]) { 455 var d = delta / 1000; 456 this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); 457 } 458 } 459 } else { 460 this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; 461 this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; 462 } 463 464 Position.prepare(); 465 Droppables.show(Draggables._lastPointer, this.element); 466 Draggables.notify('onDrag', this); 467 Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); 468 Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; 469 Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; 470 if (Draggables._lastScrollPointer[0] < 0) 471 Draggables._lastScrollPointer[0] = 0; 472 if (Draggables._lastScrollPointer[1] < 0) 473 Draggables._lastScrollPointer[1] = 0; 474 this.draw(Draggables._lastScrollPointer); 475 476 if(this.options.change) this.options.change(this); 477 }, 478 479 _getWindowScroll: function(w) { 480 var T, L, W, H; 481 with (w.document) { 482 if (w.document.documentElement && documentElement.scrollTop) { 483 T = documentElement.scrollTop; 484 L = documentElement.scrollLeft; 485 } else if (w.document.body) { 486 T = body.scrollTop; 487 L = body.scrollLeft; 488 } 489 if (w.innerWidth) { 490 W = w.innerWidth; 491 H = w.innerHeight; 492 } else if (w.document.documentElement && documentElement.clientWidth) { 493 W = documentElement.clientWidth; 494 H = documentElement.clientHeight; 495 } else { 496 W = body.offsetWidth; 497 H = body.offsetHeight 498 } 499 } 500 return { top: T, left: L, width: W, height: H }; 360 501 } 361 502 } … … 383 524 384 525 var Sortable = { 385 sortables: new Array(), 386 387 options: function(element){ 388 element = $(element); 389 return this.sortables.detect(function(s) { return s.element == element }); 526 sortables: {}, 527 528 _findRootElement: function(element) { 529 while (element.tagName != "BODY") { 530 if(element.id && Sortable.sortables[element.id]) return element; 531 element = element.parentNode; 532 } 533 }, 534 535 options: function(element) { 536 element = Sortable._findRootElement($(element)); 537 if(!element) return; 538 return Sortable.sortables[element.id]; 390 539 }, 391 540 392 541 destroy: function(element){ 393 element = $(element); 394 this.sortables.findAll(function(s) { return s.element == element }).each(function(s){ 542 var s = Sortable.options(element); 543 544 if(s) { 395 545 Draggables.removeObserver(s.element); 396 546 s.droppables.each(function(d){ Droppables.remove(d) }); 397 547 s.draggables.invoke('destroy'); 398 }); 399 this.sortables = this.sortables.reject(function(s) { return s.element == element }); 400 }, 401 548 549 delete Sortable.sortables[s.element.id]; 550 } 551 }, 552 402 553 create: function(element) { 403 554 element = $(element); … … 406 557 tag: 'li', // assumes li children, override with tag: 'tagname' 407 558 dropOnEmpty: false, 408 tree: false, // fixme: unimplemented 559 tree: false, 560 treeTag: 'ul', 409 561 overlap: 'vertical', // one of 'vertical', 'horizontal' 410 562 constraint: 'vertical', // one of 'vertical', 'horizontal', false … … 414 566 hoverclass: null, 415 567 ghosting: false, 416 format: null, 568 scroll: false, 569 scrollSensitivity: 20, 570 scrollSpeed: 15, 571 format: /^[^_]*_(.*)$/, 417 572 onChange: Prototype.emptyFunction, 418 573 onUpdate: Prototype.emptyFunction … … 425 580 var options_for_draggable = { 426 581 revert: true, 582 scroll: options.scroll, 583 scrollSpeed: options.scrollSpeed, 584 scrollSensitivity: options.scrollSensitivity, 427 585 ghosting: options.ghosting, 428 586 constraint: options.constraint, … … 450 608 overlap: options.overlap, 451 609 containment: options.containment, 610 tree: options.tree, 452 611 hoverclass: options.hoverclass, 453 onHover: Sortable.onHover, 454 greedy: !options.dropOnEmpty 612 onHover: Sortable.onHover 613 //greedy: !options.dropOnEmpty 614 } 615 616 var options_for_tree = { 617 onHover: Sortable.onEmptyHover, 618 overlap: options.overlap, 619 containment: options.containment, 620 hoverclass: options.hoverclass 455 621 } 456 622 … … 461 627 options.droppables = []; 462 628 463 // make it so464 465 629 // drop on empty handling 466 if(options.dropOnEmpty) { 467 Droppables.add(element, 468 {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false}); 630 if(options.dropOnEmpty || options.tree) { 631 Droppables.add(element, options_for_tree); 469 632 options.droppables.push(element); 470 633 } … … 477 640 new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); 478 641 Droppables.add(e, options_for_droppable); 642 if(options.tree) e.treeNode = element; 479 643 options.droppables.push(e); 480 644 }); 645 646 if(options.tree) { 647 (Sortable.findTreeElements(element, options) || []).each( function(e) { 648 Droppables.add(e, options_for_tree); 649 e.treeNode = element; 650 options.droppables.push(e); 651 }); 652 } 481 653 482 654 // keep reference 483 this.sortables .push(options);655 this.sortables[element.id] = options; 484 656 485 657 // for onupdate … … 490 662 // return all suitable-for-sortable elements in a guaranteed order 491 663 findElements: function(element, options) { 492 if(!element.hasChildNodes()) return null; 493 var elements = []; 494 $A(element.childNodes).each( function(e) { 495 if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() && 496 (!options.only || (Element.hasClassName(e, options.only)))) 497 elements.push(e); 498 if(options.tree) { 499 var grandchildren = this.findElements(e, options); 500 if(grandchildren) elements.push(grandchildren); 501 } 502 }); 503 504 return (elements.length>0 ? elements.flatten() : null); 664 return Element.findChildren( 665 element, options.only, options.tree ? true : false, options.tag); 666 }, 667 668 findTreeElements: function(element, options) { 669 return Element.findChildren( 670 element, options.only, options.tree ? true : false, options.treeTag); 505 671 }, 506 672 507 673 onHover: function(element, dropon, overlap) { 508 if(overlap>0.5) { 674 if(Element.isParent(dropon, element)) return; 675 676 if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { 677 return; 678 } else if(overlap>0.5) { 509 679 Sortable.mark(dropon, 'before'); 510 680 if(dropon.previousSibling != element) { … … 529 699 } 530 700 }, 531 532 onEmptyHover: function(element, dropon) { 533 if(element.parentNode!=dropon) { 534 var oldParentNode = element.parentNode; 535 dropon.appendChild(element); 701 702 onEmptyHover: function(element, dropon, overlap) { 703 var oldParentNode = element.parentNode; 704 var droponOptions = Sortable.options(dropon); 705 706 if(!Element.isParent(dropon, element)) { 707 var index; 708 709 var children = Sortable.findElements(dropon, {tag: droponOptions.tag}); 710 var child = null; 711 712 if(children) { 713 var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); 714 715 for (index = 0; index < children.length; index += 1) { 716 if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { 717 offset -= Element.offsetSize (children[index], droponOptions.overlap); 718 } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { 719 child = index + 1 < children.length ? children[index + 1] : null; 720 break; 721 } else { 722 child = children[index]; 723 break; 724 } 725 } 726 } 727 728 dropon.insertBefore(element, child); 729 536 730 Sortable.options(oldParentNode).onChange(element); 537 Sortable.options(dropon).onChange(element);731 droponOptions.onChange(element); 538 732 } 539 733 }, … … 567 761 Element.show(Sortable._marker); 568 762 }, 569 570 serialize: function(element) { 763 764 _tree: function(element, options, parent) { 765 var children = Sortable.findElements(element, options) || []; 766 767 for (var i = 0; i < children.length; ++i) { 768 var match = children[i].id.match(options.format); 769 770 if (!match) continue; 771 772 var child = { 773 id: encodeURIComponent(match ? match[1] : null), 774 element: element, 775 parent: parent, 776 children: new Array, 777 position: parent.children.length, 778 container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) 779 } 780 781 /* Get the element containing the children and recurse over it */ 782 if (child.container) 783 this._tree(child.container, options, child) 784 785 parent.children.push (child); 786 } 787 788 return parent; 789 }, 790 791 /* Finds the first element of the given tag type within a parent element. 792 Used for finding the first LI[ST] within a L[IST]I[TEM].*/ 793 _findChildrenElement: function (element, containerTag) { 794 if (element && element.hasChildNodes) 795 for (var i = 0; i < element.childNodes.length; ++i) 796 if (element.childNodes[i].tagName == containerTag) 797 return element.childNodes[i]; 798 799 return null; 800 }, 801 802 tree: function(element) { 571 803 element = $(element); 572 804 var sortableOptions = this.options(element); 573 805 var options = Object.extend({ 574 tag: sortableOptions.tag, 806 tag: sortableOptions.tag, 807 treeTag: sortableOptions.treeTag, 575 808 only: sortableOptions.only, 576 809 name: element.id, 577 format: sortableOptions.format || /^[^_]*_(.*)$/810 format: sortableOptions.format 578 811 }, arguments[1] || {}); 812 813 var root = { 814 id: null, 815 parent: null, 816 children: new Array, 817 container: element, 818 position: 0 819 } 820 821 return Sortable._tree (element, options, root); 822 }, 823 824 /* Construct a [i] index for a particular node */ 825 _constructIndex: function(node) { 826 var index = ''; 827 do { 828 if (node.id) index = '[' + node.position + ']' + index; 829 } while ((node = node.parent) != null); 830 return index; 831 }, 832 833 sequence: function(element) { 834 element = $(element); 835 var options = Object.extend(this.options(element), arguments[1] || {}); 836 579 837 return $(this.findElements(element, options) || []).map( function(item) { 580 return (encodeURIComponent(options.name) + "[]=" + 581 encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : '')); 582 }).join("&"); 838 return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; 839 }); 840 }, 841 842 setSequence: function(element, new_sequence) { 843 element = $(element); 844 var options = Object.extend(this.options(element), arguments[2] || {}); 845 846 var nodeMap = {}; 847 this.findElements(element, options).each( function(n) { 848 if (n.id.match(options.format)) 849 nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; 850 n.parentNode.removeChild(n); 851 }); 852 853 new_sequence.each(function(ident) { 854 var n = nodeMap[ident]; 855 if (n) { 856 n[1].appendChild(n[0]); 857 delete nodeMap[ident]; 858 } 859 }); 860 }, 861 862 serialize: function(element) { 863 element = $(element); 864 var options = Object.extend(Sortable.options(element), arguments[1] || {}); 865 var name = encodeURIComponent( 866 (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); 867 868 if (options.tree) { 869 return Sortable.tree(element, arguments[1]).children.map( function (item) { 870 return [name + Sortable._constructIndex(item) + "=" + 871 encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); 872 }).flatten().join('&'); 873 } else { 874 return Sortable.sequence(element, arguments[1]).map( function(item) { 875 return name + "[]=" + encodeURIComponent(item); 876 }).join('&'); 877 } 583 878 } 584 879 } 880 881 /* Returns true if child is contained within element */ 882 Element.isParent = function(child, element) { 883 if (!child.parentNode || child == element) return false; 884 885 if (child.parentNode == element) return true; 886 887 return Element.isParent(child.parentNode, element); 888 } 889 890 Element.findChildren = function(element, only, recursive, tagName) { 891 if(!element.hasChildNodes()) return null; 892 tagName = tagName.toUpperCase(); 893 if(only) only = [only].flatten(); 894 var elements = []; 895 $A(element.childNodes).each( function(e) { 896 if(e.tagName && e.tagName.toUpperCase()==tagName && 897 (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) 898 elements.push(e); 899 if(recursive) { 900 var grandchildren = Element.findChildren(e, only, recursive, tagName); 901 if(grandchildren) elements.push(grandchildren); 902 } 903 }); 904 905 return (elements.length>0 ? elements.flatten() : []); 906 } 907 908 Element.offsetSize = function (element, type) { 909 if (type == 'vertical' || type == 'height') 910 return element.offsetHeight; 911 else 912 return element.offsetWidth; 913 } trunk/demo/public/javascripts/effects.js
r5 r28 7 7 // See scriptaculous.js for full license. 8 8 9 /* ------------- element ext -------------- */10 11 9 // converts rgb() and #xxx to #xxxxxx format, 12 10 // returns self (or first argument) if not convertable … … 23 21 } 24 22 return(color.length==7 ? color : (arguments[0] || this)); 25 } 26 27 Element.collectTextNodesIgnoreClass = function(element, ignoreclass) { 28 var children = $(element).childNodes; 29 var text = ''; 30 var classtest = new RegExp('^([^ ]+ )*' + ignoreclass+ '( [^ ]+)*$','i'); 31 32 for (var i = 0; i < children.length; i++) { 33 if(children[i].nodeType==3) { 34 text+=children[i].nodeValue; 35 } else { 36 if((!children[i].className.match(classtest)) && children[i].hasChildNodes()) 37 text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass); 38 } 39 } 40 41 return text; 42 } 43 44 Element.setStyle = function(element, style) { 45 element = $(element); 46 for(k in style) element.style[k.camelize()] = style[k]; 47 } 48 49 Element.setContentZoom = function(element, percent) { 23 } 24 25 /*--------------------------------------------------------------------------*/ 26 27 Element.collectTextNodes = function(element) { 28 return $A($(element).childNodes).collect( function(node) { 29 return (node.nodeType==3 ? node.nodeValue : 30 (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); 31 }).flatten().join(''); 32 } 33 34 Element.collectTextNodesIgnoreClass = function(element, className) { 35 return $A($(element).childNodes).collect( function(node) { 36 return (node.nodeType==3 ? node.nodeValue : 37 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 38 Element.collectTextNodesIgnoreClass(node, className) : '')); 39 }).flatten().join(''); 40 } 41 42 Element.setContentZoom = function(element, percent) { 43 element = $(element); 50 44 Element.setStyle(element, {fontSize: (percent/100) + 'em'}); 51 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 45 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 52 46 } 53 47 … … 76 70 { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 77 71 'alpha(opacity='+value*100+')' }); 78 } 72 } 79 73 } 80 74 … … 83 77 } 84 78 85 Element.childrenWithClassName = function(element, className) { 86 return $A($(element).getElementsByTagName('*')).select( 87 function(c) { return Element.hasClassName(c, className) }); 88 } 79 Element.childrenWithClassName = function(element, className, findFirst) { 80 var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)"); 81 var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { 82 return (c.className && c.className.match(classNameRegExp)); 83 }); 84 if(!results) results = []; 85 return results; 86 } 87 88 Element.forceRerendering = function(element) { 89 try { 90 element = $(element); 91 var n = document.createTextNode(' '); 92 element.appendChild(n); 93 element.removeChild(n); 94 } catch(e) { } 95 }; 96 97 /*--------------------------------------------------------------------------*/ 89 98 90 99 Array.prototype.call = function() { … … 130 139 new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); 131 140 }); 141 }, 142 PAIRS: { 143 'slide': ['SlideDown','SlideUp'], 144 'blind': ['BlindDown','BlindUp'], 145 'appear': ['Appear','Fade'] 146 }, 147 toggle: function(element, effect) { 148 element = $(element); 149 effect = (effect || 'appear').toLowerCase(); 150 var options = Object.extend({ 151 queue: { position:'end', scope:(element.id || 'global'), limit: 1 } 152 }, arguments[2] || {}); 153 Effect[element.visible() ? 154 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); 132 155 } 133 156 }; … … 167 190 /* ------------- core effects ------------- */ 168 191 169 Effect.Queue = { 170 effects: [], 192 Effect.ScopedQueue = Class.create(); 193 Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { 194 initialize: function() { 195 this.effects = []; 196 this.interval = null; 197 }, 171 198 _each: function(iterator) { 172 199 this.effects._each(iterator); 173 200 }, 174 interval: null,175 201 add: function(effect) { 176 202 var timestamp = new Date().getTime(); 177 203 178 switch(effect.options.queue) { 204 var position = (typeof effect.options.queue == 'string') ? 205 effect.options.queue : effect.options.queue.position; 206 207 switch(position) { 179 208 case 'front': 180 209 // move unstarted effects after this effect … … 192 221 effect.startOn += timestamp; 193 222 effect.finishOn += timestamp; 194 this.effects.push(effect); 223 224 if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) 225 this.effects.push(effect); 226 195 227 if(!this.interval) 196 228 this.interval = setInterval(this.loop.bind(this), 40); … … 207 239 this.effects.invoke('loop', timePos); 208 240 } 209 } 210 Object.extend(Effect.Queue, Enumerable); 241 }); 242 243 Effect.Queues = { 244 instances: $H(), 245 get: function(queueName) { 246 if(typeof queueName != 'string') return queueName; 247 248 if(!this.instances[queueName]) <
