[ Index ] |
|
Code source de CMS made simple 1.0.5 |
1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 2 // 3 // Element.Class part Copyright (c) 2005 by Rick Olson 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining 6 // a copy of this software and associated documentation files (the 7 // "Software"), to deal in the Software without restriction, including 8 // without limitation the rights to use, copy, modify, merge, publish, 9 // distribute, sublicense, and/or sell copies of the Software, and to 10 // permit persons to whom the Software is furnished to do so, subject to 11 // the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 25 /*--------------------------------------------------------------------------*/ 26 27 var Droppables = { 28 drops: false, 29 30 remove: function(element) { 31 for(var i = 0; i < this.drops.length; i++) 32 if(this.drops[i].element == element) 33 this.drops.splice(i,1); 34 }, 35 36 add: function(element) { 37 var element = $(element); 38 var options = Object.extend({ 39 greedy: true, 40 hoverclass: null 41 }, arguments[1] || {}); 42 43 // cache containers 44 if(options.containment) { 45 options._containers = new Array(); 46 var containment = options.containment; 47 if((typeof containment == 'object') && 48 (containment.constructor == Array)) { 49 for(var i=0; i<containment.length; i++) 50 options._containers.push($(containment[i])); 51 } else { 52 options._containers.push($(containment)); 53 } 54 options._containers_length = 55 options._containers.length-1; 56 } 57 58 Element.makePositioned(element); // fix IE 59 60 options.element = element; 61 62 // activate the droppable 63 if(!this.drops) this.drops = []; 64 this.drops.push(options); 65 }, 66 67 isContained: function(element, drop) { 68 var containers = drop._containers; 69 var parentNode = element.parentNode; 70 var i = drop._containers_length; 71 do { if(parentNode==containers[i]) return true; } while (i--); 72 return false; 73 }, 74 75 isAffected: function(pX, pY, element, drop) { 76 return ( 77 (drop.element!=element) && 78 ((!drop._containers) || 79 this.isContained(element, drop)) && 80 ((!drop.accept) || 81 (Element.Class.has_any(element, drop.accept))) && 82 Position.within(drop.element, pX, pY) ); 83 }, 84 85 deactivate: function(drop) { 86 Element.Class.remove(drop.element, drop.hoverclass); 87 this.last_active = null; 88 }, 89 90 activate: function(drop) { 91 if(this.last_active) this.deactivate(this.last_active); 92 if(drop.hoverclass) 93 Element.Class.add(drop.element, drop.hoverclass); 94 this.last_active = drop; 95 }, 96 97 show: function(event, element) { 98 if(!this.drops) return; 99 var pX = Event.pointerX(event); 100 var pY = Event.pointerY(event); 101 Position.prepare(); 102 103 var i = this.drops.length-1; do { 104 var drop = this.drops[i]; 105 if(this.isAffected(pX, pY, element, drop)) { 106 if(drop.onHover) 107 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); 108 if(drop.greedy) { 109 this.activate(drop); 110 return; 111 } 112 } 113 } while (i--); 114 }, 115 116 fire: function(event, element) { 117 if(!this.last_active) return; 118 Position.prepare(); 119 120 if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active)) 121 if (this.last_active.onDrop) 122 this.last_active.onDrop(element, this.last_active); 123 124 }, 125 126 reset: function() { 127 if(this.last_active) 128 this.deactivate(this.last_active); 129 } 130 } 131 132 Draggables = { 133 observers: new Array(), 134 addObserver: function(observer) { 135 this.observers.push(observer); 136 }, 137 removeObserver: function(element) { // element instead of obsever fixes mem leaks 138 for(var i = 0; i < this.observers.length; i++) 139 if(this.observers[i].element && (this.observers[i].element == element)) 140 this.observers.splice(i,1); 141 }, 142 notify: function(eventName, draggable) { // 'onStart', 'onEnd' 143 for(var i = 0; i < this.observers.length; i++) 144 this.observers[i][eventName](draggable); 145 } 146 } 147 148 /*--------------------------------------------------------------------------*/ 149 150 Draggable = Class.create(); 151 Draggable.prototype = { 152 initialize: function(element) { 153 var options = Object.extend({ 154 handle: false, 155 starteffect: function(element) { 156 new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7}); 157 }, 158 reverteffect: function(element, top_offset, left_offset) { 159 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; 160 new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur}); 161 }, 162 endeffect: function(element) { 163 new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0}); 164 }, 165 zindex: 1000, 166 revert: false 167 }, arguments[1] || {}); 168 169 this.element = $(element); 170 this.handle = options.handle ? $(options.handle) : this.element; 171 172 Element.makePositioned(this.element); // fix IE 173 174 this.offsetX = 0; 175 this.offsetY = 0; 176 this.originalLeft = this.currentLeft(); 177 this.originalTop = this.currentTop(); 178 this.originalX = this.element.offsetLeft; 179 this.originalY = this.element.offsetTop; 180 this.originalZ = parseInt(this.element.style.zIndex || "0"); 181 182 this.options = options; 183 184 this.active = false; 185 this.dragging = false; 186 187 this.eventMouseDown = this.startDrag.bindAsEventListener(this); 188 this.eventMouseUp = this.endDrag.bindAsEventListener(this); 189 this.eventMouseMove = this.update.bindAsEventListener(this); 190 this.eventKeypress = this.keyPress.bindAsEventListener(this); 191 192 Event.observe(this.handle, "mousedown", this.eventMouseDown); 193 Event.observe(document, "mouseup", this.eventMouseUp); 194 Event.observe(document, "mousemove", this.eventMouseMove); 195 Event.observe(document, "keypress", this.eventKeypress); 196 }, 197 destroy: function() { 198 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); 199 Event.stopObserving(document, "mouseup", this.eventMouseUp); 200 Event.stopObserving(document, "mousemove", this.eventMouseMove); 201 Event.stopObserving(document, "keypress", this.eventKeypress); 202 }, 203 currentLeft: function() { 204 return parseInt(this.element.style.left || '0'); 205 }, 206 currentTop: function() { 207 return parseInt(this.element.style.top || '0') 208 }, 209 startDrag: function(event) { 210 if(Event.isLeftClick(event)) { 211 this.active = true; 212 var pointer = [Event.pointerX(event), Event.pointerY(event)]; 213 var offsets = Position.cumulativeOffset(this.element); 214 this.offsetX = (pointer[0] - offsets[0]); 215 this.offsetY = (pointer[1] - offsets[1]); 216 Event.stop(event); 217 } 218 }, 219 finishDrag: function(event, success) { 220 this.active = false; 221 this.dragging = false; 222 223 if(success) Droppables.fire(event, this.element); 224 Draggables.notify('onEnd', this); 225 226 var revert = this.options.revert; 227 if(revert && typeof revert == 'function') revert = revert(this.element); 228 229 if(this.options.ghosting) { 230 Position.relativize(this.element); 231 Element.remove(this._clone); 232 this._clone = null; 233 } 234 235 if(revert && this.options.reverteffect) { 236 this.options.reverteffect(this.element, 237 this.currentTop()-this.originalTop, 238 this.currentLeft()-this.originalLeft); 239 } else { 240 this.originalLeft = this.currentLeft(); 241 this.originalTop = this.currentTop(); 242 } 243 244 this.element.style.zIndex = this.originalZ; 245 246 if(this.options.endeffect) 247 this.options.endeffect(this.element); 248 249 250 Droppables.reset(); 251 }, 252 keyPress: function(event) { 253 if(this.active) { 254 if(event.keyCode==Event.KEY_ESC) { 255 this.finishDrag(event, false); 256 Event.stop(event); 257 } 258 } 259 }, 260 endDrag: function(event) { 261 if(this.active && this.dragging) { 262 this.finishDrag(event, true); 263 Event.stop(event); 264 } 265 this.active = false; 266 this.dragging = false; 267 }, 268 draw: function(event) { 269 var pointer = [Event.pointerX(event), Event.pointerY(event)]; 270 var offsets = Position.cumulativeOffset(this.element); 271 offsets[0] -= this.currentLeft(); 272 offsets[1] -= this.currentTop(); 273 var style = this.element.style; 274 if((!this.options.constraint) || (this.options.constraint=='horizontal')) 275 style.left = (pointer[0] - offsets[0] - this.offsetX) + "px"; 276 if((!this.options.constraint) || (this.options.constraint=='vertical')) 277 style.top = (pointer[1] - offsets[1] - this.offsetY) + "px"; 278 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering 279 }, 280 update: function(event) { 281 if(this.active) { 282 if(!this.dragging) { 283 var style = this.element.style; 284 this.dragging = true; 285 if(style.position=="") style.position = "relative"; 286 style.zIndex = this.options.zindex; 287 288 if(this.options.ghosting) { 289 this._clone = this.element.cloneNode(true); 290 Position.absolutize(this.element); 291 this.element.parentNode.insertBefore(this._clone, this.element); 292 } 293 294 Draggables.notify('onStart', this); 295 if(this.options.starteffect) this.options.starteffect(this.element); 296 } 297 298 Droppables.show(event, this.element); 299 this.draw(event); 300 if(this.options.change) this.options.change(this); 301 302 // fix AppleWebKit rendering 303 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 304 305 Event.stop(event); 306 } 307 } 308 } 309 310 /*--------------------------------------------------------------------------*/ 311 312 SortableObserver = Class.create(); 313 SortableObserver.prototype = { 314 initialize: function(element, observer) { 315 this.element = $(element); 316 this.observer = observer; 317 this.lastValue = Sortable.serialize(this.element); 318 }, 319 onStart: function() { 320 this.lastValue = Sortable.serialize(this.element); 321 }, 322 onEnd: function() { 323 Sortable.unmark(); 324 if(this.lastValue != Sortable.serialize(this.element)) 325 this.observer(this.element) 326 } 327 } 328 329 Sortable = { 330 sortables: new Array(), 331 options: function(element){ 332 var element = $(element); 333 for(var i=0;i<this.sortables.length;i++) 334 if(this.sortables[i].element == element) 335 return this.sortables[i]; 336 return null; 337 }, 338 destroy: function(element){ 339 var element = $(element); 340 for(var i=0;i<this.sortables.length;i++) { 341 if(this.sortables[i].element == element) { 342 var s = this.sortables[i]; 343 Draggables.removeObserver(s.element); 344 for(var j=0;j<s.droppables.length;j++) 345 Droppables.remove(s.droppables[j]); 346 for(var j=0;j<s.draggables.length;j++) 347 s.draggables[j].destroy(); 348 this.sortables.splice(i,1); 349 } 350 } 351 }, 352 create: function(element) { 353 var element = $(element); 354 var options = Object.extend({ 355 element: element, 356 tag: 'li', // assumes li children, override with tag: 'tagname' 357 dropOnEmpty: false, 358 tree: false, // fixme: unimplemented 359 overlap: 'vertical', // one of 'vertical', 'horizontal' 360 constraint: 'vertical', // one of 'vertical', 'horizontal', false 361 containment: element, // also takes array of elements (or id's); or false 362 handle: false, // or a CSS class 363 only: false, 364 hoverclass: null, 365 ghosting: false, 366 onChange: function() {}, 367 onUpdate: function() {} 368 }, arguments[1] || {}); 369 370 // clear any old sortable with same element 371 this.destroy(element); 372 373 // build options for the draggables 374 var options_for_draggable = { 375 revert: true, 376 ghosting: options.ghosting, 377 constraint: options.constraint, 378 handle: handle }; 379 380 if(options.starteffect) 381 options_for_draggable.starteffect = options.starteffect; 382 383 if(options.reverteffect) 384 options_for_draggable.reverteffect = options.reverteffect; 385 else 386 if(options.ghosting) options_for_draggable.reverteffect = function(element) { 387 element.style.top = 0; 388 element.style.left = 0; 389 }; 390 391 if(options.endeffect) 392 options_for_draggable.endeffect = options.endeffect; 393 394 if(options.zindex) 395 options_for_draggable.zindex = options.zindex; 396 397 // build options for the droppables 398 var options_for_droppable = { 399 overlap: options.overlap, 400 containment: options.containment, 401 hoverclass: options.hoverclass, 402 onHover: Sortable.onHover, 403 greedy: !options.dropOnEmpty 404 } 405 406 // fix for gecko engine 407 Element.cleanWhitespace(element); 408 409 options.draggables = []; 410 options.droppables = []; 411 412 // make it so 413 414 // drop on empty handling 415 if(options.dropOnEmpty) { 416 Droppables.add(element, 417 {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false}); 418 options.droppables.push(element); 419 } 420 421 var elements = this.findElements(element, options); 422 if(elements) { 423 for (var i = 0; i < elements.length; i++) { 424 // handles are per-draggable 425 var handle = options.handle ? 426 Element.Class.childrenWith(elements[i], options.handle)[0] : elements[i]; 427 options.draggables.push(new Draggable(elements[i], Object.extend(options_for_draggable, { handle: handle }))); 428 Droppables.add(elements[i], options_for_droppable); 429 430 options.droppables.push(elements[i]); 431 } 432 } 433 434 // keep reference 435 this.sortables.push(options); 436 437 // for onupdate 438 Draggables.addObserver(new SortableObserver(element, options.onUpdate)); 439 440 }, 441 442 // return all suitable-for-sortable elements in a guaranteed order 443 findElements: function(element, options) { 444 if(!element.hasChildNodes()) return null; 445 var elements = []; 446 var children = element.childNodes; 447 for(var i = 0; i<children.length; i++) { 448 if(children[i].tagName && children[i].tagName==options.tag.toUpperCase() && 449 (!options.only || (Element.Class.has(children[i], options.only)))) 450 elements.push(children[i]); 451 if(options.tree) { 452 var grandchildren = this.findElements(children[i], options); 453 if(grandchildren) elements.push(grandchildren); 454 } 455 } 456 457 return (elements.length>0 ? elements.flatten() : null); 458 }, 459 460 onHover: function(element, dropon, overlap) { 461 if(overlap>0.5) { 462 Sortable.mark(dropon, 'before'); 463 if(dropon.previousSibling != element) { 464 var oldParentNode = element.parentNode; 465 element.style.visibility = "hidden"; // fix gecko rendering 466 dropon.parentNode.insertBefore(element, dropon); 467 if(dropon.parentNode!=oldParentNode && oldParentNode.sortable) 468 oldParentNode.sortable.onChange(element); 469 if(dropon.parentNode.sortable) 470 dropon.parentNode.sortable.onChange(element); 471 } 472 } else { 473 Sortable.mark(dropon, 'after'); 474 var nextElement = dropon.nextSibling || null; 475 if(nextElement != element) { 476 var oldParentNode = element.parentNode; 477 element.style.visibility = "hidden"; // fix gecko rendering 478 dropon.parentNode.insertBefore(element, nextElement); 479 if(dropon.parentNode!=oldParentNode && oldParentNode.sortable) 480 oldParentNode.sortable.onChange(element); 481 if(dropon.parentNode.sortable) 482 dropon.parentNode.sortable.onChange(element); 483 } 484 } 485 }, 486 487 onEmptyHover: function(element, dropon) { 488 if(element.parentNode!=dropon) { 489 dropon.appendChild(element); 490 } 491 }, 492 493 unmark: function() { 494 if(Sortable._marker) Element.hide(Sortable._marker); 495 }, 496 497 mark: function(dropon, position) { 498 // mark on ghosting only 499 var sortable = Sortable.options(dropon.parentNode); 500 if(sortable && !sortable.ghosting) return; 501 502 if(!Sortable._marker) { 503 Sortable._marker = $('dropmarker') || document.createElement('DIV'); 504 Element.hide(Sortable._marker); 505 Element.Class.add(Sortable._marker, 'dropmarker'); 506 Sortable._marker.style.position = 'absolute'; 507 document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); 508 } 509 var offsets = Position.cumulativeOffset(dropon); 510 Sortable._marker.style.top = offsets[1] + 'px'; 511 if(position=='after') Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'; 512 Sortable._marker.style.left = offsets[0] + 'px'; 513 Element.show(Sortable._marker); 514 }, 515 516 serialize: function(element) { 517 var element = $(element); 518 var sortableOptions = this.options(element); 519 var options = Object.extend({ 520 tag: sortableOptions.tag, 521 only: sortableOptions.only, 522 name: element.id 523 }, arguments[1] || {}); 524 525 var items = $(element).childNodes; 526 var queryComponents = new Array(); 527 528 for(var i=0; i<items.length; i++) 529 if(items[i].tagName && items[i].tagName==options.tag.toUpperCase() && 530 (!options.only || (Element.Class.has(items[i], options.only)))) 531 queryComponents.push( 532 encodeURIComponent(options.name) + "[]=" + 533 encodeURIComponent(items[i].id.split("_")[1])); 534 535 return queryComponents.join("&"); 536 } 537 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Tue Apr 3 18:50:37 2007 | par Balluche grâce à PHPXref 0.7 |