mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Script.aculo.us: latest rev, new autocompleter features, memory leaks fixed #1695 [Thomas Fuchs]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1810 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
1911f8eee9
commit
1666977490
9 changed files with 611 additions and 230 deletions
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
* Added :handle as an option to sortable_element to restrict the drag handle to a given class #1642 [thejohnny]
|
* Added :handle as an option to sortable_element to restrict the drag handle to a given class #1642 [thejohnny]
|
||||||
|
|
||||||
* Added a bunch of script.aculo.us features #1644, #1677 [Thomas Fuchs]
|
* Added a bunch of script.aculo.us features #1644, #1677, #1695 [Thomas Fuchs]
|
||||||
* Effect.ScrollTo, to smoothly scroll the page to an element
|
* Effect.ScrollTo, to smoothly scroll the page to an element
|
||||||
* Better Firefox flickering handling on SlideUp/SlideDown
|
* Better Firefox flickering handling on SlideUp/SlideDown
|
||||||
* Removed a possible memory leak in IE with draggables
|
* Removed a possible memory leak in IE with draggables
|
||||||
|
@ -22,7 +22,11 @@
|
||||||
* Removed circular references from element to prevent memory leaks (still not completely gone in IE)
|
* Removed circular references from element to prevent memory leaks (still not completely gone in IE)
|
||||||
* Changes to class extension in effects.js
|
* 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)
|
* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with CSS classes that set a background color)
|
||||||
|
* Fixed myriads of memory leaks in IE and Gecko-based browsers [David Zülke]
|
||||||
|
* Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
|
||||||
|
* Extended the auto_complete_field helper to accept tokens option
|
||||||
|
* Changed object extension mechanism to favor Object.extend to make script.aculo.us easily adaptable to support 3rd party libs like IE7.js [David Zülke]
|
||||||
|
|
||||||
* Fixed that named routes didn't use the default values for action and possible other parameters #1534 [Nicholas Seckar]
|
* Fixed that named routes didn't use the default values for action and possible other parameters #1534 [Nicholas Seckar]
|
||||||
|
|
||||||
* Fixed JavascriptHelper#visual_effect to use camelize such that :blind_up will work #1639 [pelletierm@eastmedia.net]
|
* Fixed JavascriptHelper#visual_effect to use camelize such that :blind_up will work #1639 [pelletierm@eastmedia.net]
|
||||||
|
|
|
@ -358,8 +358,13 @@ module ActionView
|
||||||
function << "'#{field_id}', "
|
function << "'#{field_id}', "
|
||||||
function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
|
function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
|
||||||
function << "'#{url_for(options[:url])}'"
|
function << "'#{url_for(options[:url])}'"
|
||||||
|
|
||||||
js_options = {}
|
js_options = {}
|
||||||
|
if options[:tokens] and options[:tokens].kind_of?(Array)
|
||||||
|
js_options[:tokens] = "['#{options[:tokens].join('\',\'')}']"
|
||||||
|
elsif options[:tokens]
|
||||||
|
js_options[:tokens] = "'#{options[:tokens]}'" if options[:tokens]
|
||||||
|
end
|
||||||
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
||||||
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
||||||
function << (', ' + options_for_javascript(js_options) + ')')
|
function << (', ' + options_for_javascript(js_options) + ')')
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||||
|
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
|
@ -19,7 +20,6 @@
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
||||||
var children = $(element).childNodes;
|
var children = $(element).childNodes;
|
||||||
var text = "";
|
var text = "";
|
||||||
|
@ -37,42 +37,70 @@ Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ajax.Autocompleter = Class.create();
|
// Autocompleter.Base handles all the autocompletion functionality
|
||||||
Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
// that's independent of the data source for autocompletion. This
|
||||||
initialize: function(element, update, url, options) {
|
// includes drawing the autocompletion menu, observing keyboard
|
||||||
|
// and mouse events, and similar.
|
||||||
|
//
|
||||||
|
// Specific autocompleters need to provide, at the very least,
|
||||||
|
// a getUpdatedChoices function that will be invoked every time
|
||||||
|
// the text inside the monitored textbox changes. This method
|
||||||
|
// should get the text for which to provide autocompletion by
|
||||||
|
// invoking this.getEntry(), NOT by directly accessing
|
||||||
|
// this.element.value. This is to allow incremental tokenized
|
||||||
|
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
||||||
|
// belongs in getUpdatedChoices.
|
||||||
|
//
|
||||||
|
// Tokenized incremental autocompletion is enabled automatically
|
||||||
|
// when an autocompleter is instantiated with the 'tokens' option
|
||||||
|
// in the options parameter, e.g.:
|
||||||
|
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
||||||
|
// will incrementally autocomplete with a comma as the token.
|
||||||
|
// Additionally, ',' in the above example can be replaced with
|
||||||
|
// a token array, e.g. { tokens: new Array (',', '\n') } which
|
||||||
|
// enables autocompletion on multiple tokens. This is most
|
||||||
|
// useful when one of the tokens is \n (a newline), as it
|
||||||
|
// allows smart autocompletion after linebreaks.
|
||||||
|
|
||||||
|
var Autocompleter = {}
|
||||||
|
Autocompleter.Base = function() {};
|
||||||
|
Autocompleter.Base.prototype = {
|
||||||
|
base_initialize: function(element, update, options) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
this.update = $(update);
|
this.update = $(update);
|
||||||
this.has_focus = false;
|
this.has_focus = false;
|
||||||
this.changed = false;
|
this.changed = false;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.entry_count = 0;
|
this.entry_count = 0;
|
||||||
this.url = url;
|
|
||||||
|
|
||||||
this.setOptions(options);
|
if (this.setOptions)
|
||||||
this.options.asynchronous = true;
|
this.setOptions(options);
|
||||||
this.options.onComplete = this.onComplete.bind(this)
|
else
|
||||||
|
this.options = {}
|
||||||
|
|
||||||
|
this.options.tokens = this.options.tokens || new Array();
|
||||||
this.options.frequency = this.options.frequency || 0.4;
|
this.options.frequency = this.options.frequency || 0.4;
|
||||||
this.options.min_chars = this.options.min_chars || 1;
|
this.options.min_chars = this.options.min_chars || 1;
|
||||||
this.options.method = 'post';
|
this.options.onShow = this.options.onShow ||
|
||||||
|
function(element, update){
|
||||||
this.options.onShow = this.options.onShow ||
|
if(!update.style.position || update.style.position=='absolute') {
|
||||||
function(element, update){
|
update.style.position = 'absolute';
|
||||||
if(!update.style.position || update.style.position=='absolute') {
|
|
||||||
update.style.position = 'absolute';
|
|
||||||
var offsets = Position.cumulativeOffset(element);
|
var offsets = Position.cumulativeOffset(element);
|
||||||
update.style.left = offsets[0] + 'px';
|
update.style.left = offsets[0] + 'px';
|
||||||
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
||||||
update.style.width = element.offsetWidth + 'px';
|
update.style.width = element.offsetWidth + 'px';
|
||||||
}
|
}
|
||||||
new Effect.Appear(update,{duration:0.3});
|
new Effect.Appear(update,{duration:0.15});
|
||||||
};
|
};
|
||||||
this.options.onHide = this.options.onHide ||
|
this.options.onHide = this.options.onHide ||
|
||||||
function(element, update){ new Effect.Fade(update,{duration:0.3}) };
|
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
||||||
|
|
||||||
|
|
||||||
if(this.options.indicator)
|
if(this.options.indicator)
|
||||||
this.indicator = $(this.options.indicator);
|
this.indicator = $(this.options.indicator);
|
||||||
|
|
||||||
|
if (typeof(this.options.tokens) == 'string')
|
||||||
|
this.options.tokens = new Array(this.options.tokens);
|
||||||
|
|
||||||
this.observer = null;
|
this.observer = null;
|
||||||
|
|
||||||
|
@ -81,14 +109,14 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
||||||
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
||||||
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
||||||
new Insertion.After(this.update,
|
new Insertion.After(this.update,
|
||||||
'<iframe id="' + this.update.id + '_iefix" '+
|
'<iframe id="' + this.update.id + '_iefix" '+
|
||||||
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(apacity=0);" ' +
|
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
||||||
'src="javascript:;" frameborder="0" scrolling="no"></iframe>');
|
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
||||||
this.iefix = $(this.update.id+'_iefix');
|
this.iefix = $(this.update.id+'_iefix');
|
||||||
}
|
}
|
||||||
if(this.iefix) {
|
if(this.iefix) {
|
||||||
|
@ -111,51 +139,7 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
stopIndicator: function() {
|
stopIndicator: function() {
|
||||||
if(this.indicator) Element.hide(this.indicator);
|
if(this.indicator) Element.hide(this.indicator);
|
||||||
},
|
},
|
||||||
|
|
||||||
onObserverEvent: function() {
|
|
||||||
this.changed = false;
|
|
||||||
if(this.element.value.length>=this.options.min_chars) {
|
|
||||||
this.startIndicator();
|
|
||||||
this.options.parameters = this.options.callback ?
|
|
||||||
this.options.callback(this.element, Form.Element.getValue(this.element)) :
|
|
||||||
Form.Element.serialize(this.element);
|
|
||||||
new Ajax.Request(this.url, this.options);
|
|
||||||
} else {
|
|
||||||
this.active = false;
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addObservers: function(element) {
|
|
||||||
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
|
||||||
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
onComplete: function(request) {
|
|
||||||
if(!this.changed && this.has_focus) {
|
|
||||||
this.update.innerHTML = request.responseText;
|
|
||||||
Element.cleanWhitespace(this.update);
|
|
||||||
Element.cleanWhitespace(this.update.firstChild);
|
|
||||||
|
|
||||||
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
|
||||||
this.entry_count =
|
|
||||||
this.update.firstChild.childNodes.length;
|
|
||||||
for (var i = 0; i < this.entry_count; i++) {
|
|
||||||
entry = this.get_entry(i);
|
|
||||||
entry.autocompleteIndex = i;
|
|
||||||
this.addObservers(entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.entry_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stopIndicator();
|
|
||||||
|
|
||||||
this.index = 0;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyPress: function(event) {
|
onKeyPress: function(event) {
|
||||||
if(this.active)
|
if(this.active)
|
||||||
switch(event.keyCode) {
|
switch(event.keyCode) {
|
||||||
|
@ -255,7 +239,208 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
select_entry: function() {
|
select_entry: function() {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
||||||
this.element.value = value;
|
this.updateElement(value);
|
||||||
this.element.focus();
|
this.element.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateElement: function(value) {
|
||||||
|
var last_token_pos = this.findLastToken();
|
||||||
|
if (last_token_pos != -1) {
|
||||||
|
var new_value = this.element.value.substr(0, last_token_pos + 1);
|
||||||
|
var whitespace = this.element.value.substr(last_token_pos + 1).match(/^\s+/);
|
||||||
|
if (whitespace)
|
||||||
|
new_value += whitespace[0];
|
||||||
|
this.element.value = new_value + value;
|
||||||
|
} else {
|
||||||
|
this.element.value = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateChoices: function(choices) {
|
||||||
|
if(!this.changed && this.has_focus) {
|
||||||
|
this.update.innerHTML = choices;
|
||||||
|
Element.cleanWhitespace(this.update);
|
||||||
|
Element.cleanWhitespace(this.update.firstChild);
|
||||||
|
|
||||||
|
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
||||||
|
this.entry_count =
|
||||||
|
this.update.firstChild.childNodes.length;
|
||||||
|
for (var i = 0; i < this.entry_count; i++) {
|
||||||
|
entry = this.get_entry(i);
|
||||||
|
entry.autocompleteIndex = i;
|
||||||
|
this.addObservers(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.entry_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopIndicator();
|
||||||
|
|
||||||
|
this.index = 0;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addObservers: function(element) {
|
||||||
|
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
||||||
|
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
onObserverEvent: function() {
|
||||||
|
this.changed = false;
|
||||||
|
if(this.getEntry().length>=this.options.min_chars) {
|
||||||
|
this.startIndicator();
|
||||||
|
this.getUpdatedChoices();
|
||||||
|
} else {
|
||||||
|
this.active = false;
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getEntry: function() {
|
||||||
|
var token_pos = this.findLastToken();
|
||||||
|
if (token_pos != -1)
|
||||||
|
var ret = this.element.value.substr(token_pos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
|
||||||
|
else
|
||||||
|
var ret = this.element.value;
|
||||||
|
|
||||||
|
return /\n/.test(ret) ? '' : ret;
|
||||||
|
},
|
||||||
|
|
||||||
|
findLastToken: function() {
|
||||||
|
var last_token_pos = -1;
|
||||||
|
|
||||||
|
for (var i=0; i<this.options.tokens.length; i++) {
|
||||||
|
var this_token_pos = this.element.value.lastIndexOf(this.options.tokens[i]);
|
||||||
|
if (this_token_pos > last_token_pos)
|
||||||
|
last_token_pos = this_token_pos;
|
||||||
|
}
|
||||||
|
return last_token_pos;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
Ajax.Autocompleter = Class.create();
|
||||||
|
Ajax.Autocompleter.prototype = Object.extend(new Autocompleter.Base(),
|
||||||
|
Object.extend(new Ajax.Base(), {
|
||||||
|
initialize: function(element, update, url, options) {
|
||||||
|
this.base_initialize(element, update, options);
|
||||||
|
this.options.asynchronous = true;
|
||||||
|
this.options.onComplete = this.onComplete.bind(this)
|
||||||
|
this.options.method = 'post';
|
||||||
|
this.options.defaultParams = this.options.parameters || null;
|
||||||
|
this.url = url;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUpdatedChoices: function() {
|
||||||
|
entry = encodeURIComponent(this.element.name) + '=' +
|
||||||
|
encodeURIComponent(this.getEntry());
|
||||||
|
|
||||||
|
this.options.parameters = this.options.callback ?
|
||||||
|
this.options.callback(this.element, entry) : entry;
|
||||||
|
|
||||||
|
if(this.options.defaultParams)
|
||||||
|
this.options.parameters += '&' + this.options.defaultParams;
|
||||||
|
|
||||||
|
new Ajax.Request(this.url, this.options);
|
||||||
|
},
|
||||||
|
|
||||||
|
onComplete: function(request) {
|
||||||
|
this.updateChoices(request.responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
// The local array autocompleter. Used when you'd prefer to
|
||||||
|
// inject an array of autocompletion options into the page, rather
|
||||||
|
// than sending out Ajax queries, which can be quite slow sometimes.
|
||||||
|
//
|
||||||
|
// The constructor takes four parameters. The first two are, as usual,
|
||||||
|
// the id of the monitored textbox, and id of the autocompletion menu.
|
||||||
|
// The third is the array you want to autocomplete from, and the fourth
|
||||||
|
// is the options block.
|
||||||
|
//
|
||||||
|
// Extra local autocompletion options:
|
||||||
|
// - choices - How many autocompletion choices to offer
|
||||||
|
//
|
||||||
|
// - partial_search - If false, the autocompleter will match entered
|
||||||
|
// text only at the beginning of strings in the
|
||||||
|
// autocomplete array. Defaults to true, which will
|
||||||
|
// match text at the beginning of any *word* in the
|
||||||
|
// strings in the autocomplete array. If you want to
|
||||||
|
// search anywhere in the string, additionally set
|
||||||
|
// the option full_search to true (default: off).
|
||||||
|
//
|
||||||
|
// - full_search - Search anywhere in autocomplete array strings.
|
||||||
|
//
|
||||||
|
// - partial_chars - How many characters to enter before triggering
|
||||||
|
// a partial match (unlike min_chars, which defines
|
||||||
|
// how many characters are required to do any match
|
||||||
|
// at all). Defaults to 2.
|
||||||
|
//
|
||||||
|
// - ignore_case - Whether to ignore case when autocompleting.
|
||||||
|
// Defaults to true.
|
||||||
|
//
|
||||||
|
// It's possible to pass in a custom function as the 'selector'
|
||||||
|
// option, if you prefer to write your own autocompletion logic.
|
||||||
|
// In that case, the other options above will not apply unless
|
||||||
|
// you support them.
|
||||||
|
|
||||||
|
Autocompleter.Local = Class.create();
|
||||||
|
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
||||||
|
initialize: function(element, update, array, options) {
|
||||||
|
this.base_initialize(element, update, options);
|
||||||
|
this.options.array = array;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUpdatedChoices: function() {
|
||||||
|
this.updateChoices(this.options.selector(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
setOptions: function(options) {
|
||||||
|
this.options = Object.extend({
|
||||||
|
choices: 10,
|
||||||
|
partial_search: true,
|
||||||
|
partial_chars: 2,
|
||||||
|
ignore_case: true,
|
||||||
|
full_search: false,
|
||||||
|
selector: function(instance) {
|
||||||
|
var ret = new Array(); // Beginning matches
|
||||||
|
var partial = new Array(); // Inside matches
|
||||||
|
var entry = instance.getEntry();
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < instance.options.array.length &&
|
||||||
|
ret.length < instance.options.choices ; i++) {
|
||||||
|
var elem = instance.options.array[i];
|
||||||
|
var found_pos = instance.options.ignore_case ?
|
||||||
|
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
||||||
|
elem.indexOf(entry);
|
||||||
|
|
||||||
|
while (found_pos != -1) {
|
||||||
|
if (found_pos == 0 && elem.length != entry.length) {
|
||||||
|
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
||||||
|
elem.substr(entry.length) + "</li>");
|
||||||
|
break;
|
||||||
|
} else if (entry.length >= instance.options.partial_chars &&
|
||||||
|
instance.options.partial_search && found_pos != -1) {
|
||||||
|
if (instance.options.full_search || /\s/.test(elem.substr(found_pos-1,1))) {
|
||||||
|
partial.push("<li>" + elem.substr(0, found_pos) + "<strong>" +
|
||||||
|
elem.substr(found_pos, entry.length) + "</strong>" + elem.substr(
|
||||||
|
found_pos + entry.length) + "</li>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found_pos = instance.options.ignore_case ?
|
||||||
|
elem.toLowerCase().indexOf(entry.toLowerCase(), found_pos + 1) :
|
||||||
|
elem.indexOf(entry, found_pos + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (partial.length)
|
||||||
|
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
||||||
|
return "<ul>" + ret.join('') + "</ul>";
|
||||||
|
}
|
||||||
|
}, options || {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -120,10 +120,10 @@ var Droppables = {
|
||||||
|
|
||||||
add: function(element) {
|
add: function(element) {
|
||||||
var element = $(element);
|
var element = $(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
greedy: true,
|
greedy: true,
|
||||||
hoverclass: null
|
hoverclass: null
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// cache containers
|
// cache containers
|
||||||
if(options.containment) {
|
if(options.containment) {
|
||||||
|
@ -220,9 +220,9 @@ Draggables = {
|
||||||
addObserver: function(observer) {
|
addObserver: function(observer) {
|
||||||
this.observers.push(observer);
|
this.observers.push(observer);
|
||||||
},
|
},
|
||||||
removeObserver: function(observer) {
|
removeObserver: function(element) { // element instead of obsever fixes mem leaks
|
||||||
for(var i = 0; i < this.observers.length; i++)
|
for(var i = 0; i < this.observers.length; i++)
|
||||||
if(this.observers[i] = observer)
|
if(this.observers[i].element && (this.observers[i].element == element))
|
||||||
this.observers.splice(i,1);
|
this.observers.splice(i,1);
|
||||||
},
|
},
|
||||||
notify: function(eventName, draggable) { // 'onStart', 'onEnd'
|
notify: function(eventName, draggable) { // 'onStart', 'onEnd'
|
||||||
|
@ -236,7 +236,7 @@ Draggables = {
|
||||||
Draggable = Class.create();
|
Draggable = Class.create();
|
||||||
Draggable.prototype = {
|
Draggable.prototype = {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
handle: false,
|
handle: false,
|
||||||
starteffect: function(element) {
|
starteffect: function(element) {
|
||||||
new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
|
new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
|
||||||
|
@ -249,7 +249,7 @@ Draggable.prototype = {
|
||||||
},
|
},
|
||||||
zindex: 1000,
|
zindex: 1000,
|
||||||
revert: false
|
revert: false
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
this.handle = options.handle ? $(options.handle) : this.element;
|
this.handle = options.handle ? $(options.handle) : this.element;
|
||||||
|
@ -411,7 +411,7 @@ Sortable = {
|
||||||
for(var i=0;i<this.sortables.length;i++) {
|
for(var i=0;i<this.sortables.length;i++) {
|
||||||
if(this.sortables[i].element == element) {
|
if(this.sortables[i].element == element) {
|
||||||
var s = this.sortables[i];
|
var s = this.sortables[i];
|
||||||
Draggables.removeObserver(s.observer);
|
Draggables.removeObserver(s.element);
|
||||||
for(var j=0;j<s.droppables.length;j++)
|
for(var j=0;j<s.droppables.length;j++)
|
||||||
Droppables.remove(s.droppables[j]);
|
Droppables.remove(s.droppables[j]);
|
||||||
for(var j=0;j<s.draggables.length;j++)
|
for(var j=0;j<s.draggables.length;j++)
|
||||||
|
@ -422,7 +422,7 @@ Sortable = {
|
||||||
},
|
},
|
||||||
create: function(element) {
|
create: function(element) {
|
||||||
var element = $(element);
|
var element = $(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
element: element,
|
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'
|
||||||
|
@ -433,7 +433,7 @@ Sortable = {
|
||||||
hoverclass: null,
|
hoverclass: null,
|
||||||
onChange: function() {},
|
onChange: function() {},
|
||||||
onUpdate: function() {}
|
onUpdate: function() {}
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// clear any old sortable with same element
|
// clear any old sortable with same element
|
||||||
this.destroy(element);
|
this.destroy(element);
|
||||||
|
@ -499,7 +499,7 @@ 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];
|
||||||
|
|
||||||
options.draggables.push(new Draggable(elements[i], options_for_draggable.extend({ handle: handle })));
|
options.draggables.push(new Draggable(elements[i], Object.extend(options_for_draggable, { handle: handle })));
|
||||||
|
|
||||||
Droppables.add(elements[i], options_for_droppable);
|
Droppables.add(elements[i], options_for_droppable);
|
||||||
options.droppables.push(elements[i]);
|
options.droppables.push(elements[i]);
|
||||||
|
@ -510,18 +510,17 @@ Sortable = {
|
||||||
this.sortables.push(options);
|
this.sortables.push(options);
|
||||||
|
|
||||||
// for onupdate
|
// for onupdate
|
||||||
options.observer = new SortableObserver(element, options.onUpdate);
|
Draggables.addObserver(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 sortableOptions = this.options(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
tag: sortableOptions.tag,
|
tag: sortableOptions.tag,
|
||||||
only: sortableOptions.only,
|
only: sortableOptions.only,
|
||||||
name: element.id
|
name: element.id
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
var items = $(element).childNodes;
|
var items = $(element).childNodes;
|
||||||
var queryComponents = new Array();
|
var queryComponents = new Array();
|
||||||
|
|
|
@ -80,14 +80,14 @@ Element.undoClipping = function(element) {
|
||||||
Effect.Base = function() {};
|
Effect.Base = function() {};
|
||||||
Effect.Base.prototype = {
|
Effect.Base.prototype = {
|
||||||
setOptions: function(options) {
|
setOptions: function(options) {
|
||||||
this.options = {
|
this.options = Object.extend({
|
||||||
transition: Effect.Transitions.sinoidal,
|
transition: Effect.Transitions.sinoidal,
|
||||||
duration: 1.0, // seconds
|
duration: 1.0, // seconds
|
||||||
fps: 25.0, // max. 100fps
|
fps: 25.0, // max. 100fps
|
||||||
sync: false, // true for combining
|
sync: false, // true for combining
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0
|
to: 1.0
|
||||||
}.extend(options || {});
|
}, options || {});
|
||||||
},
|
},
|
||||||
start: function(options) {
|
start: function(options) {
|
||||||
this.setOptions(options || {});
|
this.setOptions(options || {});
|
||||||
|
@ -127,7 +127,7 @@ Effect.Base.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Parallel = Class.create();
|
Effect.Parallel = Class.create();
|
||||||
Effect.Parallel.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(effects) {
|
initialize: function(effects) {
|
||||||
this.effects = effects || [];
|
this.effects = effects || [];
|
||||||
this.start(arguments[1]);
|
this.start(arguments[1]);
|
||||||
|
@ -146,13 +146,13 @@ Effect.Parallel.prototype.extend(Effect.Base.prototype).extend({
|
||||||
// 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.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0
|
to: 1.0
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
this.start(options);
|
this.start(options);
|
||||||
},
|
},
|
||||||
update: function(position) {
|
update: function(position) {
|
||||||
|
@ -166,7 +166,7 @@ Effect.Opacity.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.MoveBy = Class.create();
|
Effect.MoveBy = Class.create();
|
||||||
Effect.MoveBy.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
|
||||||
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');
|
||||||
|
@ -188,17 +188,17 @@ Effect.MoveBy.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.Scale = Class.create();
|
Effect.Scale = Class.create();
|
||||||
Effect.Scale.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element, percent) {
|
initialize: function(element, percent) {
|
||||||
this.element = $(element)
|
this.element = $(element)
|
||||||
options = {
|
options = Object.extend({
|
||||||
scaleX: true,
|
scaleX: true,
|
||||||
scaleY: true,
|
scaleY: true,
|
||||||
scaleContent: true,
|
scaleContent: true,
|
||||||
scaleFromCenter: false,
|
scaleFromCenter: false,
|
||||||
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
||||||
scaleFrom: 100.0
|
scaleFrom: 100.0
|
||||||
}.extend(arguments[2] || {});
|
}, arguments[2] || {});
|
||||||
this.originalTop = this.element.offsetTop;
|
this.originalTop = this.element.offsetTop;
|
||||||
this.originalLeft = this.element.offsetLeft;
|
this.originalLeft = this.element.offsetLeft;
|
||||||
if(this.element.style.fontSize=="") this.sizeEm = 1.0;
|
if(this.element.style.fontSize=="") this.sizeEm = 1.0;
|
||||||
|
@ -246,7 +246,7 @@ Effect.Scale.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.Highlight = Class.create();
|
Effect.Highlight = Class.create();
|
||||||
Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
|
|
||||||
|
@ -259,11 +259,11 @@ Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
||||||
var cols = current.slice(4,current.length-1).split(',');
|
var cols = current.slice(4,current.length-1).split(',');
|
||||||
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 = Object.extend({
|
||||||
startcolor: "#ffff99",
|
startcolor: "#ffff99",
|
||||||
endcolor: endcolor,
|
endcolor: endcolor,
|
||||||
restorecolor: current
|
restorecolor: current
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// init color calculations
|
// init color calculations
|
||||||
this.colors_base = [
|
this.colors_base = [
|
||||||
|
@ -291,7 +291,7 @@ Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.ScrollTo = Class.create();
|
Effect.ScrollTo = Class.create();
|
||||||
Effect.ScrollTo.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
Position.prepare();
|
Position.prepare();
|
||||||
|
@ -315,18 +315,18 @@ Effect.ScrollTo.prototype.extend(Effect.Base.prototype).extend({
|
||||||
/* ------------- prepackaged effects ------------- */
|
/* ------------- prepackaged effects ------------- */
|
||||||
|
|
||||||
Effect.Fade = function(element) {
|
Effect.Fade = function(element) {
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 1.0,
|
from: 1.0,
|
||||||
to: 0.0,
|
to: 0.0,
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{ Element.hide(effect.element);
|
{ Element.hide(effect.element);
|
||||||
effect.setOpacity(1); }
|
effect.setOpacity(1); }
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
new Effect.Opacity(element,options);
|
new Effect.Opacity(element,options);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Appear = function(element) {
|
Effect.Appear = function(element) {
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0,
|
to: 1.0,
|
||||||
beforeStart: function(effect)
|
beforeStart: function(effect)
|
||||||
|
@ -334,7 +334,7 @@ Effect.Appear = function(element) {
|
||||||
Element.show(effect.element); },
|
Element.show(effect.element); },
|
||||||
afterUpdate: function(effect)
|
afterUpdate: function(effect)
|
||||||
{ Element.show(effect.element); }
|
{ Element.show(effect.element); }
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
new Effect.Opacity(element,options);
|
new Effect.Opacity(element,options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,14 +354,14 @@ Effect.Puff = function(element) {
|
||||||
Effect.BlindUp = function(element) {
|
Effect.BlindUp = function(element) {
|
||||||
Element.makeClipping(element);
|
Element.makeClipping(element);
|
||||||
new Effect.Scale(element, 0,
|
new Effect.Scale(element, 0,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{
|
{
|
||||||
Element.hide(effect.element);
|
Element.hide(effect.element);
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,14 +370,14 @@ Effect.BlindDown = function(element) {
|
||||||
Element.makeClipping(element);
|
Element.makeClipping(element);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 100,
|
new Effect.Scale(element, 100,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
scaleMode: 'contents',
|
scaleMode: 'contents',
|
||||||
scaleFrom: 0,
|
scaleFrom: 0,
|
||||||
afterFinish: function(effect) {
|
afterFinish: function(effect) {
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ Effect.SlideDown = function(element) {
|
||||||
Element.makePositioned(element.firstChild);
|
Element.makePositioned(element.firstChild);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 100,
|
new Effect.Scale(element, 100,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
scaleMode: 'contents',
|
scaleMode: 'contents',
|
||||||
scaleFrom: 0,
|
scaleFrom: 0,
|
||||||
|
@ -442,7 +442,7 @@ Effect.SlideDown = function(element) {
|
||||||
(effect.originalHeight - effect.element.clientHeight) + 'px'; },
|
(effect.originalHeight - effect.element.clientHeight) + 'px'; },
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{ Element.undoClipping(effect.element); }
|
{ Element.undoClipping(effect.element); }
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ Effect.SlideUp = function(element) {
|
||||||
Element.makePositioned(element.firstChild);
|
Element.makePositioned(element.firstChild);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 0,
|
new Effect.Scale(element, 0,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
afterUpdate: function(effect)
|
afterUpdate: function(effect)
|
||||||
{ effect.element.firstChild.style.bottom =
|
{ effect.element.firstChild.style.bottom =
|
||||||
|
@ -463,7 +463,7 @@ Effect.SlideUp = function(element) {
|
||||||
Element.hide(effect.element);
|
Element.hide(effect.element);
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,14 +582,14 @@ Effect.Pulsate = function(element) {
|
||||||
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
|
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
|
||||||
reverser.bind(transition);
|
reverser.bind(transition);
|
||||||
new Effect.Opacity(element,
|
new Effect.Opacity(element,
|
||||||
{ duration: 3.0,
|
Object.extend(Object.extend({ duration: 3.0,
|
||||||
afterFinish: function(effect) { Element.show(effect.element); }
|
afterFinish: function(effect) { Element.show(effect.element); }
|
||||||
}.extend(options).extend({transition: reverser}));
|
}, options), {transition: reverser}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Fold = function(element) {
|
Effect.Fold = function(element) {
|
||||||
$(element).style.overflow = 'hidden';
|
$(element).style.overflow = 'hidden';
|
||||||
new Effect.Scale(element, 5, {
|
new Effect.Scale(element, 5, Object.extend({
|
||||||
scaleContent: false,
|
scaleContent: false,
|
||||||
scaleTo: 100,
|
scaleTo: 100,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
|
@ -599,7 +599,7 @@ Effect.Fold = function(element) {
|
||||||
scaleTo: 0,
|
scaleTo: 0,
|
||||||
scaleY: false,
|
scaleY: false,
|
||||||
afterFinish: function(effect) { Element.hide(effect.element) } });
|
afterFinish: function(effect) { Element.hide(effect.element) } });
|
||||||
}}.extend(arguments[1] || {}));
|
}}, arguments[1] || {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// old: new Effect.ContentZoom(element, percent)
|
// old: new Effect.ContentZoom(element, percent)
|
||||||
|
|
|
@ -74,7 +74,11 @@ class JavaScriptHelperTest < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_auto_complete_field
|
def test_auto_complete_field
|
||||||
assert_equal %(<script type=\"text/javascript\">new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {})</script>),
|
assert_equal %(<script type=\"text/javascript\">new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {})</script>),
|
||||||
auto_complete_field("some_input", :url => { :action => "autocomplete" });
|
auto_complete_field("some_input", :url => { :action => "autocomplete" });
|
||||||
|
assert_equal %(<script type=\"text/javascript\">new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:','})</script>),
|
||||||
|
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => ',');
|
||||||
|
assert_equal %(<script type=\"text/javascript\">new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:[',']})</script>),
|
||||||
|
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => [',']);
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_auto_complete_result
|
def test_auto_complete_result
|
||||||
|
|
323
railties/html/javascripts/controls.js
vendored
323
railties/html/javascripts/controls.js
vendored
|
@ -1,4 +1,5 @@
|
||||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||||
|
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
|
@ -19,7 +20,6 @@
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
||||||
var children = $(element).childNodes;
|
var children = $(element).childNodes;
|
||||||
var text = "";
|
var text = "";
|
||||||
|
@ -37,42 +37,70 @@ Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ajax.Autocompleter = Class.create();
|
// Autocompleter.Base handles all the autocompletion functionality
|
||||||
Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
// that's independent of the data source for autocompletion. This
|
||||||
initialize: function(element, update, url, options) {
|
// includes drawing the autocompletion menu, observing keyboard
|
||||||
|
// and mouse events, and similar.
|
||||||
|
//
|
||||||
|
// Specific autocompleters need to provide, at the very least,
|
||||||
|
// a getUpdatedChoices function that will be invoked every time
|
||||||
|
// the text inside the monitored textbox changes. This method
|
||||||
|
// should get the text for which to provide autocompletion by
|
||||||
|
// invoking this.getEntry(), NOT by directly accessing
|
||||||
|
// this.element.value. This is to allow incremental tokenized
|
||||||
|
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
||||||
|
// belongs in getUpdatedChoices.
|
||||||
|
//
|
||||||
|
// Tokenized incremental autocompletion is enabled automatically
|
||||||
|
// when an autocompleter is instantiated with the 'tokens' option
|
||||||
|
// in the options parameter, e.g.:
|
||||||
|
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
||||||
|
// will incrementally autocomplete with a comma as the token.
|
||||||
|
// Additionally, ',' in the above example can be replaced with
|
||||||
|
// a token array, e.g. { tokens: new Array (',', '\n') } which
|
||||||
|
// enables autocompletion on multiple tokens. This is most
|
||||||
|
// useful when one of the tokens is \n (a newline), as it
|
||||||
|
// allows smart autocompletion after linebreaks.
|
||||||
|
|
||||||
|
var Autocompleter = {}
|
||||||
|
Autocompleter.Base = function() {};
|
||||||
|
Autocompleter.Base.prototype = {
|
||||||
|
base_initialize: function(element, update, options) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
this.update = $(update);
|
this.update = $(update);
|
||||||
this.has_focus = false;
|
this.has_focus = false;
|
||||||
this.changed = false;
|
this.changed = false;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.entry_count = 0;
|
this.entry_count = 0;
|
||||||
this.url = url;
|
|
||||||
|
|
||||||
this.setOptions(options);
|
if (this.setOptions)
|
||||||
this.options.asynchronous = true;
|
this.setOptions(options);
|
||||||
this.options.onComplete = this.onComplete.bind(this)
|
else
|
||||||
|
this.options = {}
|
||||||
|
|
||||||
|
this.options.tokens = this.options.tokens || new Array();
|
||||||
this.options.frequency = this.options.frequency || 0.4;
|
this.options.frequency = this.options.frequency || 0.4;
|
||||||
this.options.min_chars = this.options.min_chars || 1;
|
this.options.min_chars = this.options.min_chars || 1;
|
||||||
this.options.method = 'post';
|
this.options.onShow = this.options.onShow ||
|
||||||
|
function(element, update){
|
||||||
this.options.onShow = this.options.onShow ||
|
if(!update.style.position || update.style.position=='absolute') {
|
||||||
function(element, update){
|
update.style.position = 'absolute';
|
||||||
if(!update.style.position || update.style.position=='absolute') {
|
|
||||||
update.style.position = 'absolute';
|
|
||||||
var offsets = Position.cumulativeOffset(element);
|
var offsets = Position.cumulativeOffset(element);
|
||||||
update.style.left = offsets[0] + 'px';
|
update.style.left = offsets[0] + 'px';
|
||||||
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
||||||
update.style.width = element.offsetWidth + 'px';
|
update.style.width = element.offsetWidth + 'px';
|
||||||
}
|
}
|
||||||
new Effect.Appear(update,{duration:0.3});
|
new Effect.Appear(update,{duration:0.15});
|
||||||
};
|
};
|
||||||
this.options.onHide = this.options.onHide ||
|
this.options.onHide = this.options.onHide ||
|
||||||
function(element, update){ new Effect.Fade(update,{duration:0.3}) };
|
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
||||||
|
|
||||||
|
|
||||||
if(this.options.indicator)
|
if(this.options.indicator)
|
||||||
this.indicator = $(this.options.indicator);
|
this.indicator = $(this.options.indicator);
|
||||||
|
|
||||||
|
if (typeof(this.options.tokens) == 'string')
|
||||||
|
this.options.tokens = new Array(this.options.tokens);
|
||||||
|
|
||||||
this.observer = null;
|
this.observer = null;
|
||||||
|
|
||||||
|
@ -81,14 +109,14 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
||||||
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
||||||
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
||||||
new Insertion.After(this.update,
|
new Insertion.After(this.update,
|
||||||
'<iframe id="' + this.update.id + '_iefix" '+
|
'<iframe id="' + this.update.id + '_iefix" '+
|
||||||
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(apacity=0);" ' +
|
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
||||||
'src="javascript:;" frameborder="0" scrolling="no"></iframe>');
|
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
||||||
this.iefix = $(this.update.id+'_iefix');
|
this.iefix = $(this.update.id+'_iefix');
|
||||||
}
|
}
|
||||||
if(this.iefix) {
|
if(this.iefix) {
|
||||||
|
@ -111,51 +139,7 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
stopIndicator: function() {
|
stopIndicator: function() {
|
||||||
if(this.indicator) Element.hide(this.indicator);
|
if(this.indicator) Element.hide(this.indicator);
|
||||||
},
|
},
|
||||||
|
|
||||||
onObserverEvent: function() {
|
|
||||||
this.changed = false;
|
|
||||||
if(this.element.value.length>=this.options.min_chars) {
|
|
||||||
this.startIndicator();
|
|
||||||
this.options.parameters = this.options.callback ?
|
|
||||||
this.options.callback(this.element, Form.Element.getValue(this.element)) :
|
|
||||||
Form.Element.serialize(this.element);
|
|
||||||
new Ajax.Request(this.url, this.options);
|
|
||||||
} else {
|
|
||||||
this.active = false;
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addObservers: function(element) {
|
|
||||||
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
|
||||||
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
onComplete: function(request) {
|
|
||||||
if(!this.changed && this.has_focus) {
|
|
||||||
this.update.innerHTML = request.responseText;
|
|
||||||
Element.cleanWhitespace(this.update);
|
|
||||||
Element.cleanWhitespace(this.update.firstChild);
|
|
||||||
|
|
||||||
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
|
||||||
this.entry_count =
|
|
||||||
this.update.firstChild.childNodes.length;
|
|
||||||
for (var i = 0; i < this.entry_count; i++) {
|
|
||||||
entry = this.get_entry(i);
|
|
||||||
entry.autocompleteIndex = i;
|
|
||||||
this.addObservers(entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.entry_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stopIndicator();
|
|
||||||
|
|
||||||
this.index = 0;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyPress: function(event) {
|
onKeyPress: function(event) {
|
||||||
if(this.active)
|
if(this.active)
|
||||||
switch(event.keyCode) {
|
switch(event.keyCode) {
|
||||||
|
@ -255,7 +239,208 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
||||||
select_entry: function() {
|
select_entry: function() {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
||||||
this.element.value = value;
|
this.updateElement(value);
|
||||||
this.element.focus();
|
this.element.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateElement: function(value) {
|
||||||
|
var last_token_pos = this.findLastToken();
|
||||||
|
if (last_token_pos != -1) {
|
||||||
|
var new_value = this.element.value.substr(0, last_token_pos + 1);
|
||||||
|
var whitespace = this.element.value.substr(last_token_pos + 1).match(/^\s+/);
|
||||||
|
if (whitespace)
|
||||||
|
new_value += whitespace[0];
|
||||||
|
this.element.value = new_value + value;
|
||||||
|
} else {
|
||||||
|
this.element.value = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateChoices: function(choices) {
|
||||||
|
if(!this.changed && this.has_focus) {
|
||||||
|
this.update.innerHTML = choices;
|
||||||
|
Element.cleanWhitespace(this.update);
|
||||||
|
Element.cleanWhitespace(this.update.firstChild);
|
||||||
|
|
||||||
|
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
||||||
|
this.entry_count =
|
||||||
|
this.update.firstChild.childNodes.length;
|
||||||
|
for (var i = 0; i < this.entry_count; i++) {
|
||||||
|
entry = this.get_entry(i);
|
||||||
|
entry.autocompleteIndex = i;
|
||||||
|
this.addObservers(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.entry_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopIndicator();
|
||||||
|
|
||||||
|
this.index = 0;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addObservers: function(element) {
|
||||||
|
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
||||||
|
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
onObserverEvent: function() {
|
||||||
|
this.changed = false;
|
||||||
|
if(this.getEntry().length>=this.options.min_chars) {
|
||||||
|
this.startIndicator();
|
||||||
|
this.getUpdatedChoices();
|
||||||
|
} else {
|
||||||
|
this.active = false;
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getEntry: function() {
|
||||||
|
var token_pos = this.findLastToken();
|
||||||
|
if (token_pos != -1)
|
||||||
|
var ret = this.element.value.substr(token_pos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
|
||||||
|
else
|
||||||
|
var ret = this.element.value;
|
||||||
|
|
||||||
|
return /\n/.test(ret) ? '' : ret;
|
||||||
|
},
|
||||||
|
|
||||||
|
findLastToken: function() {
|
||||||
|
var last_token_pos = -1;
|
||||||
|
|
||||||
|
for (var i=0; i<this.options.tokens.length; i++) {
|
||||||
|
var this_token_pos = this.element.value.lastIndexOf(this.options.tokens[i]);
|
||||||
|
if (this_token_pos > last_token_pos)
|
||||||
|
last_token_pos = this_token_pos;
|
||||||
|
}
|
||||||
|
return last_token_pos;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
Ajax.Autocompleter = Class.create();
|
||||||
|
Ajax.Autocompleter.prototype = Object.extend(new Autocompleter.Base(),
|
||||||
|
Object.extend(new Ajax.Base(), {
|
||||||
|
initialize: function(element, update, url, options) {
|
||||||
|
this.base_initialize(element, update, options);
|
||||||
|
this.options.asynchronous = true;
|
||||||
|
this.options.onComplete = this.onComplete.bind(this)
|
||||||
|
this.options.method = 'post';
|
||||||
|
this.options.defaultParams = this.options.parameters || null;
|
||||||
|
this.url = url;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUpdatedChoices: function() {
|
||||||
|
entry = encodeURIComponent(this.element.name) + '=' +
|
||||||
|
encodeURIComponent(this.getEntry());
|
||||||
|
|
||||||
|
this.options.parameters = this.options.callback ?
|
||||||
|
this.options.callback(this.element, entry) : entry;
|
||||||
|
|
||||||
|
if(this.options.defaultParams)
|
||||||
|
this.options.parameters += '&' + this.options.defaultParams;
|
||||||
|
|
||||||
|
new Ajax.Request(this.url, this.options);
|
||||||
|
},
|
||||||
|
|
||||||
|
onComplete: function(request) {
|
||||||
|
this.updateChoices(request.responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
// The local array autocompleter. Used when you'd prefer to
|
||||||
|
// inject an array of autocompletion options into the page, rather
|
||||||
|
// than sending out Ajax queries, which can be quite slow sometimes.
|
||||||
|
//
|
||||||
|
// The constructor takes four parameters. The first two are, as usual,
|
||||||
|
// the id of the monitored textbox, and id of the autocompletion menu.
|
||||||
|
// The third is the array you want to autocomplete from, and the fourth
|
||||||
|
// is the options block.
|
||||||
|
//
|
||||||
|
// Extra local autocompletion options:
|
||||||
|
// - choices - How many autocompletion choices to offer
|
||||||
|
//
|
||||||
|
// - partial_search - If false, the autocompleter will match entered
|
||||||
|
// text only at the beginning of strings in the
|
||||||
|
// autocomplete array. Defaults to true, which will
|
||||||
|
// match text at the beginning of any *word* in the
|
||||||
|
// strings in the autocomplete array. If you want to
|
||||||
|
// search anywhere in the string, additionally set
|
||||||
|
// the option full_search to true (default: off).
|
||||||
|
//
|
||||||
|
// - full_search - Search anywhere in autocomplete array strings.
|
||||||
|
//
|
||||||
|
// - partial_chars - How many characters to enter before triggering
|
||||||
|
// a partial match (unlike min_chars, which defines
|
||||||
|
// how many characters are required to do any match
|
||||||
|
// at all). Defaults to 2.
|
||||||
|
//
|
||||||
|
// - ignore_case - Whether to ignore case when autocompleting.
|
||||||
|
// Defaults to true.
|
||||||
|
//
|
||||||
|
// It's possible to pass in a custom function as the 'selector'
|
||||||
|
// option, if you prefer to write your own autocompletion logic.
|
||||||
|
// In that case, the other options above will not apply unless
|
||||||
|
// you support them.
|
||||||
|
|
||||||
|
Autocompleter.Local = Class.create();
|
||||||
|
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
||||||
|
initialize: function(element, update, array, options) {
|
||||||
|
this.base_initialize(element, update, options);
|
||||||
|
this.options.array = array;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUpdatedChoices: function() {
|
||||||
|
this.updateChoices(this.options.selector(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
setOptions: function(options) {
|
||||||
|
this.options = Object.extend({
|
||||||
|
choices: 10,
|
||||||
|
partial_search: true,
|
||||||
|
partial_chars: 2,
|
||||||
|
ignore_case: true,
|
||||||
|
full_search: false,
|
||||||
|
selector: function(instance) {
|
||||||
|
var ret = new Array(); // Beginning matches
|
||||||
|
var partial = new Array(); // Inside matches
|
||||||
|
var entry = instance.getEntry();
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < instance.options.array.length &&
|
||||||
|
ret.length < instance.options.choices ; i++) {
|
||||||
|
var elem = instance.options.array[i];
|
||||||
|
var found_pos = instance.options.ignore_case ?
|
||||||
|
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
||||||
|
elem.indexOf(entry);
|
||||||
|
|
||||||
|
while (found_pos != -1) {
|
||||||
|
if (found_pos == 0 && elem.length != entry.length) {
|
||||||
|
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
||||||
|
elem.substr(entry.length) + "</li>");
|
||||||
|
break;
|
||||||
|
} else if (entry.length >= instance.options.partial_chars &&
|
||||||
|
instance.options.partial_search && found_pos != -1) {
|
||||||
|
if (instance.options.full_search || /\s/.test(elem.substr(found_pos-1,1))) {
|
||||||
|
partial.push("<li>" + elem.substr(0, found_pos) + "<strong>" +
|
||||||
|
elem.substr(found_pos, entry.length) + "</strong>" + elem.substr(
|
||||||
|
found_pos + entry.length) + "</li>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found_pos = instance.options.ignore_case ?
|
||||||
|
elem.toLowerCase().indexOf(entry.toLowerCase(), found_pos + 1) :
|
||||||
|
elem.indexOf(entry, found_pos + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (partial.length)
|
||||||
|
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
||||||
|
return "<ul>" + ret.join('') + "</ul>";
|
||||||
|
}
|
||||||
|
}, options || {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
27
railties/html/javascripts/dragdrop.js
vendored
27
railties/html/javascripts/dragdrop.js
vendored
|
@ -120,10 +120,10 @@ var Droppables = {
|
||||||
|
|
||||||
add: function(element) {
|
add: function(element) {
|
||||||
var element = $(element);
|
var element = $(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
greedy: true,
|
greedy: true,
|
||||||
hoverclass: null
|
hoverclass: null
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// cache containers
|
// cache containers
|
||||||
if(options.containment) {
|
if(options.containment) {
|
||||||
|
@ -220,9 +220,9 @@ Draggables = {
|
||||||
addObserver: function(observer) {
|
addObserver: function(observer) {
|
||||||
this.observers.push(observer);
|
this.observers.push(observer);
|
||||||
},
|
},
|
||||||
removeObserver: function(observer) {
|
removeObserver: function(element) { // element instead of obsever fixes mem leaks
|
||||||
for(var i = 0; i < this.observers.length; i++)
|
for(var i = 0; i < this.observers.length; i++)
|
||||||
if(this.observers[i] = observer)
|
if(this.observers[i].element && (this.observers[i].element == element))
|
||||||
this.observers.splice(i,1);
|
this.observers.splice(i,1);
|
||||||
},
|
},
|
||||||
notify: function(eventName, draggable) { // 'onStart', 'onEnd'
|
notify: function(eventName, draggable) { // 'onStart', 'onEnd'
|
||||||
|
@ -236,7 +236,7 @@ Draggables = {
|
||||||
Draggable = Class.create();
|
Draggable = Class.create();
|
||||||
Draggable.prototype = {
|
Draggable.prototype = {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
handle: false,
|
handle: false,
|
||||||
starteffect: function(element) {
|
starteffect: function(element) {
|
||||||
new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
|
new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
|
||||||
|
@ -249,7 +249,7 @@ Draggable.prototype = {
|
||||||
},
|
},
|
||||||
zindex: 1000,
|
zindex: 1000,
|
||||||
revert: false
|
revert: false
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
this.handle = options.handle ? $(options.handle) : this.element;
|
this.handle = options.handle ? $(options.handle) : this.element;
|
||||||
|
@ -411,7 +411,7 @@ Sortable = {
|
||||||
for(var i=0;i<this.sortables.length;i++) {
|
for(var i=0;i<this.sortables.length;i++) {
|
||||||
if(this.sortables[i].element == element) {
|
if(this.sortables[i].element == element) {
|
||||||
var s = this.sortables[i];
|
var s = this.sortables[i];
|
||||||
Draggables.removeObserver(s.observer);
|
Draggables.removeObserver(s.element);
|
||||||
for(var j=0;j<s.droppables.length;j++)
|
for(var j=0;j<s.droppables.length;j++)
|
||||||
Droppables.remove(s.droppables[j]);
|
Droppables.remove(s.droppables[j]);
|
||||||
for(var j=0;j<s.draggables.length;j++)
|
for(var j=0;j<s.draggables.length;j++)
|
||||||
|
@ -422,7 +422,7 @@ Sortable = {
|
||||||
},
|
},
|
||||||
create: function(element) {
|
create: function(element) {
|
||||||
var element = $(element);
|
var element = $(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
element: element,
|
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'
|
||||||
|
@ -433,7 +433,7 @@ Sortable = {
|
||||||
hoverclass: null,
|
hoverclass: null,
|
||||||
onChange: function() {},
|
onChange: function() {},
|
||||||
onUpdate: function() {}
|
onUpdate: function() {}
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// clear any old sortable with same element
|
// clear any old sortable with same element
|
||||||
this.destroy(element);
|
this.destroy(element);
|
||||||
|
@ -499,7 +499,7 @@ 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];
|
||||||
|
|
||||||
options.draggables.push(new Draggable(elements[i], options_for_draggable.extend({ handle: handle })));
|
options.draggables.push(new Draggable(elements[i], Object.extend(options_for_draggable, { handle: handle })));
|
||||||
|
|
||||||
Droppables.add(elements[i], options_for_droppable);
|
Droppables.add(elements[i], options_for_droppable);
|
||||||
options.droppables.push(elements[i]);
|
options.droppables.push(elements[i]);
|
||||||
|
@ -510,18 +510,17 @@ Sortable = {
|
||||||
this.sortables.push(options);
|
this.sortables.push(options);
|
||||||
|
|
||||||
// for onupdate
|
// for onupdate
|
||||||
options.observer = new SortableObserver(element, options.onUpdate);
|
Draggables.addObserver(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 sortableOptions = this.options(element);
|
||||||
var options = {
|
var options = Object.extend({
|
||||||
tag: sortableOptions.tag,
|
tag: sortableOptions.tag,
|
||||||
only: sortableOptions.only,
|
only: sortableOptions.only,
|
||||||
name: element.id
|
name: element.id
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
var items = $(element).childNodes;
|
var items = $(element).childNodes;
|
||||||
var queryComponents = new Array();
|
var queryComponents = new Array();
|
||||||
|
|
60
railties/html/javascripts/effects.js
vendored
60
railties/html/javascripts/effects.js
vendored
|
@ -80,14 +80,14 @@ Element.undoClipping = function(element) {
|
||||||
Effect.Base = function() {};
|
Effect.Base = function() {};
|
||||||
Effect.Base.prototype = {
|
Effect.Base.prototype = {
|
||||||
setOptions: function(options) {
|
setOptions: function(options) {
|
||||||
this.options = {
|
this.options = Object.extend({
|
||||||
transition: Effect.Transitions.sinoidal,
|
transition: Effect.Transitions.sinoidal,
|
||||||
duration: 1.0, // seconds
|
duration: 1.0, // seconds
|
||||||
fps: 25.0, // max. 100fps
|
fps: 25.0, // max. 100fps
|
||||||
sync: false, // true for combining
|
sync: false, // true for combining
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0
|
to: 1.0
|
||||||
}.extend(options || {});
|
}, options || {});
|
||||||
},
|
},
|
||||||
start: function(options) {
|
start: function(options) {
|
||||||
this.setOptions(options || {});
|
this.setOptions(options || {});
|
||||||
|
@ -127,7 +127,7 @@ Effect.Base.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Parallel = Class.create();
|
Effect.Parallel = Class.create();
|
||||||
Effect.Parallel.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(effects) {
|
initialize: function(effects) {
|
||||||
this.effects = effects || [];
|
this.effects = effects || [];
|
||||||
this.start(arguments[1]);
|
this.start(arguments[1]);
|
||||||
|
@ -146,13 +146,13 @@ Effect.Parallel.prototype.extend(Effect.Base.prototype).extend({
|
||||||
// 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.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0
|
to: 1.0
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
this.start(options);
|
this.start(options);
|
||||||
},
|
},
|
||||||
update: function(position) {
|
update: function(position) {
|
||||||
|
@ -166,7 +166,7 @@ Effect.Opacity.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.MoveBy = Class.create();
|
Effect.MoveBy = Class.create();
|
||||||
Effect.MoveBy.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
|
||||||
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');
|
||||||
|
@ -188,17 +188,17 @@ Effect.MoveBy.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.Scale = Class.create();
|
Effect.Scale = Class.create();
|
||||||
Effect.Scale.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element, percent) {
|
initialize: function(element, percent) {
|
||||||
this.element = $(element)
|
this.element = $(element)
|
||||||
options = {
|
options = Object.extend({
|
||||||
scaleX: true,
|
scaleX: true,
|
||||||
scaleY: true,
|
scaleY: true,
|
||||||
scaleContent: true,
|
scaleContent: true,
|
||||||
scaleFromCenter: false,
|
scaleFromCenter: false,
|
||||||
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
||||||
scaleFrom: 100.0
|
scaleFrom: 100.0
|
||||||
}.extend(arguments[2] || {});
|
}, arguments[2] || {});
|
||||||
this.originalTop = this.element.offsetTop;
|
this.originalTop = this.element.offsetTop;
|
||||||
this.originalLeft = this.element.offsetLeft;
|
this.originalLeft = this.element.offsetLeft;
|
||||||
if(this.element.style.fontSize=="") this.sizeEm = 1.0;
|
if(this.element.style.fontSize=="") this.sizeEm = 1.0;
|
||||||
|
@ -246,7 +246,7 @@ Effect.Scale.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.Highlight = Class.create();
|
Effect.Highlight = Class.create();
|
||||||
Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
|
|
||||||
|
@ -259,11 +259,11 @@ Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
||||||
var cols = current.slice(4,current.length-1).split(',');
|
var cols = current.slice(4,current.length-1).split(',');
|
||||||
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 = Object.extend({
|
||||||
startcolor: "#ffff99",
|
startcolor: "#ffff99",
|
||||||
endcolor: endcolor,
|
endcolor: endcolor,
|
||||||
restorecolor: current
|
restorecolor: current
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
|
|
||||||
// init color calculations
|
// init color calculations
|
||||||
this.colors_base = [
|
this.colors_base = [
|
||||||
|
@ -291,7 +291,7 @@ Effect.Highlight.prototype.extend(Effect.Base.prototype).extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Effect.ScrollTo = Class.create();
|
Effect.ScrollTo = Class.create();
|
||||||
Effect.ScrollTo.prototype.extend(Effect.Base.prototype).extend({
|
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
|
||||||
initialize: function(element) {
|
initialize: function(element) {
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
Position.prepare();
|
Position.prepare();
|
||||||
|
@ -315,18 +315,18 @@ Effect.ScrollTo.prototype.extend(Effect.Base.prototype).extend({
|
||||||
/* ------------- prepackaged effects ------------- */
|
/* ------------- prepackaged effects ------------- */
|
||||||
|
|
||||||
Effect.Fade = function(element) {
|
Effect.Fade = function(element) {
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 1.0,
|
from: 1.0,
|
||||||
to: 0.0,
|
to: 0.0,
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{ Element.hide(effect.element);
|
{ Element.hide(effect.element);
|
||||||
effect.setOpacity(1); }
|
effect.setOpacity(1); }
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
new Effect.Opacity(element,options);
|
new Effect.Opacity(element,options);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Appear = function(element) {
|
Effect.Appear = function(element) {
|
||||||
options = {
|
options = Object.extend({
|
||||||
from: 0.0,
|
from: 0.0,
|
||||||
to: 1.0,
|
to: 1.0,
|
||||||
beforeStart: function(effect)
|
beforeStart: function(effect)
|
||||||
|
@ -334,7 +334,7 @@ Effect.Appear = function(element) {
|
||||||
Element.show(effect.element); },
|
Element.show(effect.element); },
|
||||||
afterUpdate: function(effect)
|
afterUpdate: function(effect)
|
||||||
{ Element.show(effect.element); }
|
{ Element.show(effect.element); }
|
||||||
}.extend(arguments[1] || {});
|
}, arguments[1] || {});
|
||||||
new Effect.Opacity(element,options);
|
new Effect.Opacity(element,options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,14 +354,14 @@ Effect.Puff = function(element) {
|
||||||
Effect.BlindUp = function(element) {
|
Effect.BlindUp = function(element) {
|
||||||
Element.makeClipping(element);
|
Element.makeClipping(element);
|
||||||
new Effect.Scale(element, 0,
|
new Effect.Scale(element, 0,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{
|
{
|
||||||
Element.hide(effect.element);
|
Element.hide(effect.element);
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,14 +370,14 @@ Effect.BlindDown = function(element) {
|
||||||
Element.makeClipping(element);
|
Element.makeClipping(element);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 100,
|
new Effect.Scale(element, 100,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
scaleMode: 'contents',
|
scaleMode: 'contents',
|
||||||
scaleFrom: 0,
|
scaleFrom: 0,
|
||||||
afterFinish: function(effect) {
|
afterFinish: function(effect) {
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ Effect.SlideDown = function(element) {
|
||||||
Element.makePositioned(element.firstChild);
|
Element.makePositioned(element.firstChild);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 100,
|
new Effect.Scale(element, 100,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
scaleMode: 'contents',
|
scaleMode: 'contents',
|
||||||
scaleFrom: 0,
|
scaleFrom: 0,
|
||||||
|
@ -442,7 +442,7 @@ Effect.SlideDown = function(element) {
|
||||||
(effect.originalHeight - effect.element.clientHeight) + 'px'; },
|
(effect.originalHeight - effect.element.clientHeight) + 'px'; },
|
||||||
afterFinish: function(effect)
|
afterFinish: function(effect)
|
||||||
{ Element.undoClipping(effect.element); }
|
{ Element.undoClipping(effect.element); }
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ Effect.SlideUp = function(element) {
|
||||||
Element.makePositioned(element.firstChild);
|
Element.makePositioned(element.firstChild);
|
||||||
Element.show(element);
|
Element.show(element);
|
||||||
new Effect.Scale(element, 0,
|
new Effect.Scale(element, 0,
|
||||||
{ scaleContent: false,
|
Object.extend({ scaleContent: false,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
afterUpdate: function(effect)
|
afterUpdate: function(effect)
|
||||||
{ effect.element.firstChild.style.bottom =
|
{ effect.element.firstChild.style.bottom =
|
||||||
|
@ -463,7 +463,7 @@ Effect.SlideUp = function(element) {
|
||||||
Element.hide(effect.element);
|
Element.hide(effect.element);
|
||||||
Element.undoClipping(effect.element);
|
Element.undoClipping(effect.element);
|
||||||
}
|
}
|
||||||
}.extend(arguments[1] || {})
|
}, arguments[1] || {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,14 +582,14 @@ Effect.Pulsate = function(element) {
|
||||||
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
|
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
|
||||||
reverser.bind(transition);
|
reverser.bind(transition);
|
||||||
new Effect.Opacity(element,
|
new Effect.Opacity(element,
|
||||||
{ duration: 3.0,
|
Object.extend(Object.extend({ duration: 3.0,
|
||||||
afterFinish: function(effect) { Element.show(effect.element); }
|
afterFinish: function(effect) { Element.show(effect.element); }
|
||||||
}.extend(options).extend({transition: reverser}));
|
}, options), {transition: reverser}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect.Fold = function(element) {
|
Effect.Fold = function(element) {
|
||||||
$(element).style.overflow = 'hidden';
|
$(element).style.overflow = 'hidden';
|
||||||
new Effect.Scale(element, 5, {
|
new Effect.Scale(element, 5, Object.extend({
|
||||||
scaleContent: false,
|
scaleContent: false,
|
||||||
scaleTo: 100,
|
scaleTo: 100,
|
||||||
scaleX: false,
|
scaleX: false,
|
||||||
|
@ -599,7 +599,7 @@ Effect.Fold = function(element) {
|
||||||
scaleTo: 0,
|
scaleTo: 0,
|
||||||
scaleY: false,
|
scaleY: false,
|
||||||
afterFinish: function(effect) { Element.hide(effect.element) } });
|
afterFinish: function(effect) { Element.hide(effect.element) } });
|
||||||
}}.extend(arguments[1] || {}));
|
}}, arguments[1] || {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// old: new Effect.ContentZoom(element, percent)
|
// old: new Effect.ContentZoom(element, percent)
|
||||||
|
|
Loading…
Reference in a new issue