Skip to content

Commit

Permalink
Added even more goodies to script.aculo.us #1677 [Thomas Fuchs]
Browse files Browse the repository at this point in the history
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1783 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Jul 9, 2005
1 parent 14f06c2 commit 165f82d
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 150 deletions.
7 changes: 7 additions & 0 deletions actionpack/CHANGELOG
@@ -1,5 +1,12 @@
*SVN* *SVN*


* Added even more goodies to script.aculo.us #1677 [Thomas Fuchs]
* Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js (this makes it possible to call sortable_element on the same element more than once, e.g. in AJAX returns that modify the sortable element. all current sortable 'stuff' on the element will be discarded and the sortable will be rebuilt)
* Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
* Removed circular references from element to prevent memory leaks (still not completely gone in IE)
* Changes to class extension in effects.js
* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with CSS classes that set a background color)

* Improved error message for DoubleRenderError * Improved error message for DoubleRenderError


* Fixed routing to allow for testing of *path components #1650 [Nicholas Seckar] * Fixed routing to allow for testing of *path components #1650 [Nicholas Seckar]
Expand Down
122 changes: 88 additions & 34 deletions actionpack/lib/action_view/helpers/javascripts/dragdrop.js
Expand Up @@ -112,6 +112,12 @@ Element.Class = {
var Droppables = { var Droppables = {
drops: false, drops: false,


remove: function(element) {
for(var i = 0; i < this.drops.length; i++)
if(this.drops[i].element == element)
this.drops.splice(i,1);
},

add: function(element) { add: function(element) {
var element = $(element); var element = $(element);
var options = { var options = {
Expand All @@ -134,43 +140,42 @@ var Droppables = {
options._containers.length-1; options._containers.length-1;
} }


if(element.style.position=='') //fix IE Element.makePositioned(element); // fix IE
element.style.position = 'relative';


// activate the droppable options.element = element;
element.droppable = options;


// activate the droppable
if(!this.drops) this.drops = []; if(!this.drops) this.drops = [];
this.drops.push(element); this.drops.push(options);
}, },


is_contained: function(element, drop) { is_contained: function(element, drop) {
var containers = drop.droppable._containers; var containers = drop._containers;
var parentNode = element.parentNode; var parentNode = element.parentNode;
var i = drop.droppable._containers_length; var i = drop._containers_length;
do { if(parentNode==containers[i]) return true; } while (i--); do { if(parentNode==containers[i]) return true; } while (i--);
return false; return false;
}, },


is_affected: function(pX, pY, element, drop) { is_affected: function(pX, pY, element, drop) {
return ( return (
(drop!=element) && (drop.element!=element) &&
((!drop.droppable._containers) || ((!drop._containers) ||
this.is_contained(element, drop)) && this.is_contained(element, drop)) &&
((!drop.droppable.accept) || ((!drop.accept) ||
(Element.Class.has_any(element, drop.droppable.accept))) && (Element.Class.has_any(element, drop.accept))) &&
Position.within(drop, pX, pY) ); Position.within(drop.element, pX, pY) );
}, },


deactivate: function(drop) { deactivate: function(drop) {
Element.Class.remove(drop, drop.droppable.hoverclass); Element.Class.remove(drop.element, drop.hoverclass);
this.last_active = null; this.last_active = null;
}, },


activate: function(drop) { activate: function(drop) {
if(this.last_active) this.deactivate(this.last_active); if(this.last_active) this.deactivate(this.last_active);
if(drop.droppable.hoverclass) { if(drop.hoverclass) {
Element.Class.add(drop, drop.droppable.hoverclass); Element.Class.add(drop.element, drop.hoverclass);
this.last_active = drop; this.last_active = drop;
} }
}, },
Expand All @@ -184,10 +189,9 @@ var Droppables = {
var i = this.drops.length-1; do { var i = this.drops.length-1; do {
var drop = this.drops[i]; var drop = this.drops[i];
if(this.is_affected(pX, pY, element, drop)) { if(this.is_affected(pX, pY, element, drop)) {
if(drop.droppable.onHover) if(drop.onHover)
drop.droppable.onHover( drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
element, drop, Position.overlap(drop.droppable.overlap, drop)); if(drop.greedy) {
if(drop.droppable.greedy) {
this.activate(drop); this.activate(drop);
return; return;
} }
Expand All @@ -200,8 +204,8 @@ var Droppables = {
Position.prepare(); Position.prepare();


if (this.is_affected(Event.pointerX(event), Event.pointerY(event), element, this.last_active)) if (this.is_affected(Event.pointerX(event), Event.pointerY(event), element, this.last_active))
if (this.last_active.droppable.onDrop) if (this.last_active.onDrop)
this.last_active.droppable.onDrop(element, this.last_active); this.last_active.onDrop(element, this.last_active);


}, },


Expand All @@ -216,6 +220,11 @@ Draggables = {
addObserver: function(observer) { addObserver: function(observer) {
this.observers.push(observer); this.observers.push(observer);
}, },
removeObserver: function(observer) {
for(var i = 0; i < this.observers.length; i++)
if(this.observers[i] = observer)
this.observers.splice(i,1);
},
notify: function(eventName, draggable) { // 'onStart', 'onEnd' notify: function(eventName, draggable) { // 'onStart', 'onEnd'
for(var i = 0; i < this.observers.length; i++) for(var i = 0; i < this.observers.length; i++)
this.observers[i][eventName](draggable); this.observers[i][eventName](draggable);
Expand Down Expand Up @@ -245,9 +254,7 @@ Draggable.prototype = {
this.element = $(element); this.element = $(element);
this.handle = options.handle ? $(options.handle) : this.element; this.handle = options.handle ? $(options.handle) : this.element;


// fix IE Element.makePositioned(this.element); // fix IE
if(!this.element.style.position)
this.element.style.position = 'relative';


this.offsetX = 0; this.offsetX = 0;
this.offsetY = 0; this.offsetY = 0;
Expand All @@ -262,10 +269,21 @@ Draggable.prototype = {
this.active = false; this.active = false;
this.dragging = false; this.dragging = false;


Event.observe(this.handle, "mousedown", this.startDrag.bindAsEventListener(this)); this.eventMouseDown = this.startDrag.bindAsEventListener(this);
Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this)); this.eventMouseUp = this.endDrag.bindAsEventListener(this);
Event.observe(document, "mousemove", this.update.bindAsEventListener(this)); this.eventMouseMove = this.update.bindAsEventListener(this);
Event.observe(document, "keypress", this.keyPress.bindAsEventListener(this)); this.eventKeypress = this.keyPress.bindAsEventListener(this);

Event.observe(this.handle, "mousedown", this.eventMouseDown);
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
Event.observe(document, "keypress", this.eventKeypress);
},
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
Event.stopObserving(document, "mouseup", this.eventMouseUp);
Event.stopObserving(document, "mousemove", this.eventMouseMove);
Event.stopObserving(document, "keypress", this.eventKeypress);
}, },
currentLeft: function() { currentLeft: function() {
return parseInt(this.element.style.left || '0'); return parseInt(this.element.style.left || '0');
Expand Down Expand Up @@ -380,9 +398,32 @@ SortableObserver.prototype = {
} }


Sortable = { Sortable = {
sortables: new Array(),
options: function(element){
var element = $(element);
for(var i=0;i<this.sortables.length;i++)
if(this.sortables[i].element == element)
return this.sortables[i];
return null;
},
destroy: function(element){
var element = $(element);
for(var i=0;i<this.sortables.length;i++) {
if(this.sortables[i].element == element) {
var s = this.sortables[i];
Draggables.removeObserver(s.observer);
for(var j=0;j<s.droppables.length;j++)
Droppables.remove(s.droppables[j]);
for(var j=0;j<s.draggables.length;j++)
s.draggables[j].destroy();
this.sortables.splice(i,1);
}
}
},
create: function(element) { create: function(element) {
var element = $(element); var element = $(element);
var options = { var options = {
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname' tag: 'li', // assumes li children, override with tag: 'tagname'
overlap: 'vertical', // one of 'vertical', 'horizontal' overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false constraint: 'vertical', // one of 'vertical', 'horizontal', false
Expand All @@ -393,7 +434,9 @@ Sortable = {
onChange: function() {}, onChange: function() {},
onUpdate: function() {} onUpdate: function() {}
}.extend(arguments[1] || {}); }.extend(arguments[1] || {});
element.sortable = options;
// clear any old sortable with same element
this.destroy(element);


// build options for the draggables // build options for the draggables
var options_for_draggable = { var options_for_draggable = {
Expand Down Expand Up @@ -443,8 +486,8 @@ Sortable = {
// fix for gecko engine // fix for gecko engine
Element.cleanWhitespace(element); Element.cleanWhitespace(element);


// for onupdate options.draggables = [];
Draggables.addObserver(new SortableObserver(element, options.onUpdate)); options.droppables = [];


// make it so // make it so
var elements = element.childNodes; var elements = element.childNodes;
Expand All @@ -456,16 +499,27 @@ Sortable = {
var handle = options.handle ? var handle = options.handle ?
Element.Class.childrenWith(elements[i], options.handle)[0] : elements[i]; Element.Class.childrenWith(elements[i], options.handle)[0] : elements[i];


new Draggable(elements[i], options_for_draggable.extend({ handle: handle })); options.draggables.push(new Draggable(elements[i], options_for_draggable.extend({ handle: handle })));

Droppables.add(elements[i], options_for_droppable); Droppables.add(elements[i], options_for_droppable);
options.droppables.push(elements[i]);

} }


// keep reference
this.sortables.push(options);

// for onupdate
options.observer = new SortableObserver(element, options.onUpdate);
Draggables.addObserver(options.observer);

}, },
serialize: function(element) { serialize: function(element) {
var element = $(element); var element = $(element);
var sortableOptions = this.options(element);
var options = { var options = {
tag: element.sortable.tag, tag: sortableOptions.tag,
only: element.sortable.only, only: sortableOptions.only,
name: element.id name: element.id
}.extend(arguments[1] || {}); }.extend(arguments[1] || {});


Expand Down
86 changes: 45 additions & 41 deletions actionpack/lib/action_view/helpers/javascripts/effects.js
Expand Up @@ -127,26 +127,26 @@ Effect.Base.prototype = {
} }


Effect.Parallel = Class.create(); Effect.Parallel = Class.create();
Effect.Parallel.prototype = (new Effect.Base()).extend({ Effect.Parallel.prototype.extend(Effect.Base.prototype).extend({
initialize: function(effects) { initialize: function(effects) {
this.effects = effects || []; this.effects = effects || [];
this.start(arguments[1]); this.start(arguments[1]);
}, },
update: function(position) { update: function(position) {
for (var i = 0; i < this.effects.length; i++) for (var i = 0; i < this.effects.length; i++)
this.effects[i].render(position); this.effects[i].render(position);
}, },
finish: function(position) { finish: function(position) {
for (var i = 0; i < this.effects.length; i++) for (var i = 0; i < this.effects.length; i++)
if(this.effects[i].finish) this.effects[i].finish(position); if(this.effects[i].finish) this.effects[i].finish(position);
} }
}); });


// Internet Explorer caveat: works only on elements the have // Internet Explorer caveat: works only on elements the have
// a 'layout', meaning having a given width or height. // a 'layout', meaning having a given width or height.
// There is no way to safely set this automatically. // There is no way to safely set this automatically.
Effect.Opacity = Class.create(); Effect.Opacity = Class.create();
Effect.Opacity.prototype = (new Effect.Base()).extend({ Effect.Opacity.prototype.extend(Effect.Base.prototype).extend({
initialize: function(element) { initialize: function(element) {
this.element = $(element); this.element = $(element);
options = { options = {
Expand All @@ -166,29 +166,29 @@ Effect.Opacity.prototype = (new Effect.Base()).extend({
}); });


Effect.MoveBy = Class.create(); Effect.MoveBy = Class.create();
Effect.MoveBy.prototype = (new Effect.Base()).extend({ Effect.MoveBy.prototype.extend(Effect.Base.prototype).extend({
initialize: function(element, toTop, toLeft) { initialize: function(element, toTop, toLeft) {
this.element = $(element); this.element = $(element);
this.originalTop = parseFloat(this.element.style.top || '0'); this.originalTop = parseFloat(this.element.style.top || '0');
this.originalLeft = parseFloat(this.element.style.left || '0'); this.originalLeft = parseFloat(this.element.style.left || '0');
this.toTop = toTop; this.toTop = toTop;
this.toLeft = toLeft; this.toLeft = toLeft;
Element.makePositioned(this.element); Element.makePositioned(this.element);
this.start(arguments[3]); this.start(arguments[3]);
}, },
update: function(position) { update: function(position) {
topd = this.toTop * position + this.originalTop; topd = this.toTop * position + this.originalTop;
leftd = this.toLeft * position + this.originalLeft; leftd = this.toLeft * position + this.originalLeft;
this.setPosition(topd, leftd); this.setPosition(topd, leftd);
}, },
setPosition: function(topd, leftd) { setPosition: function(topd, leftd) {
this.element.style.top = topd + "px"; this.element.style.top = topd + "px";
this.element.style.left = leftd + "px"; this.element.style.left = leftd + "px";
} }
}); });


Effect.Scale = Class.create(); Effect.Scale = Class.create();
Effect.Scale.prototype = (new Effect.Base()).extend({ Effect.Scale.prototype.extend(Effect.Base.prototype).extend({
initialize: function(element, percent) { initialize: function(element, percent) {
this.element = $(element) this.element = $(element)
options = { options = {
Expand Down Expand Up @@ -246,7 +246,7 @@ Effect.Scale.prototype = (new Effect.Base()).extend({
}); });


Effect.Highlight = Class.create(); Effect.Highlight = Class.create();
Effect.Highlight.prototype = (new Effect.Base()).extend({ Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
initialize: function(element) { initialize: function(element) {
this.element = $(element); this.element = $(element);


Expand All @@ -260,8 +260,9 @@ Effect.Highlight.prototype = (new Effect.Base()).extend({
var i=0; do { endcolor += parseInt(cols[i]).toColorPart() } while (++i<3); } var i=0; do { endcolor += parseInt(cols[i]).toColorPart() } while (++i<3); }


var options = { var options = {
startcolor: "#ffff99", startcolor: "#ffff99",
endcolor: endcolor endcolor: endcolor,
restorecolor: current
}.extend(arguments[1] || {}); }.extend(arguments[1] || {});


// init color calculations // init color calculations
Expand All @@ -283,11 +284,14 @@ Effect.Highlight.prototype = (new Effect.Base()).extend({
Math.round(this.colors_base[2]+(this.colors_delta[2]*position)) ]; Math.round(this.colors_base[2]+(this.colors_delta[2]*position)) ];
this.element.style.backgroundColor = "#" + this.element.style.backgroundColor = "#" +
colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart(); colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart();
},
finish: function() {
this.element.style.backgroundColor = this.options.restorecolor;
} }
}); });


Effect.ScrollTo = Class.create(); Effect.ScrollTo = Class.create();
Effect.ScrollTo.prototype = (new Effect.Base()).extend({ Effect.ScrollTo.prototype.extend(Effect.Base.prototype).extend({
initialize: function(element) { initialize: function(element) {
this.element = $(element); this.element = $(element);
Position.prepare(); Position.prepare();
Expand All @@ -310,7 +314,7 @@ Effect.ScrollTo.prototype = (new Effect.Base()).extend({


/* ------------- prepackaged effects ------------- */ /* ------------- prepackaged effects ------------- */


Effect.Fade = function(element) { Effect.Fade = function(element) {
options = { options = {
from: 1.0, from: 1.0,
to: 0.0, to: 0.0,
Expand All @@ -321,7 +325,7 @@ Effect.Fade = function(element) {
new Effect.Opacity(element,options); new Effect.Opacity(element,options);
} }


Effect.Appear = function(element) { Effect.Appear = function(element) {
options = { options = {
from: 0.0, from: 0.0,
to: 1.0, to: 1.0,
Expand Down

0 comments on commit 165f82d

Please sign in to comment.