/**
* Ruby On Rails common Ajax operations conventional wrapper
* and underscored aliases for core methods
*
* http://github.com/MadRabbit/right-rails
*
* Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
/**
* RR is the common ajax operations wrapper for ruby on rails
*
* Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
var RR = {
/**
* Basic options
*
* NOTE: DO NOT CHANGE this hash right here
* Use your application.js file to alter the options
*/
Options: {
format: 'js', // the working format for remote requests over the application
flashId: 'flashes', // the flashes element id
flashHideFx: 'slide', // use null if you don't want any fx in here
flashHideDelay: 3200, // use -1 to disable the flash element hidding
highlightUpdates: true,
removeFx: 'fade',
linkToAjaxEdit: '.ajax_edit',
linkToAjaxDelete: '.ajax_delete',
rescanWithScopes: true // if it should rescan only updated elements
},
/**
* Updates the flashes block with the source
*
* @param String new content
* @return RR this
*/
update_flash: function(content) {
var element = $(this.Options.flashId);
if (element) {
this.replace(element, content).hide_flash();
}
return this;
},
/**
* Initializes the delayed flashes hide call
*
* @return RR this
*/
hide_flash: function() {
if (this.Options.flashHideDelay > -1) {
var element = $(this.Options.flashId);
if (element && element.visible()) {
element.hide.bind(element, this.Options.flashHideFx).delay(this.Options.flashHideDelay);
}
}
return this;
},
/**
* Highlights the element according to the options
*
* @param String element id
* @return RR this
*/
highlight: function(id) {
if (this.Options.highlightUpdates) {
$(id).highlight();
}
return this;
},
/**
* Inserts the content into the given element
*
* @param String destination id
* @param String content
* @return RR this
*/
insert: function(where, what) {
return this.highlight($(where).insert(what).lastChild).rescan(where);
},
/**
* Replaces the given element with a new content
*
* @param String destination id
* @param String content
* @return RR this
*/
replace: function(id, source) {
$(id).replace(source);
return this.highlight(id).rescan(id);
},
/**
* removes the element by id
*
* @param String element id
* @return RR this
*/
remove: function(id) {
var element = $(id);
if (element) {
var remove_element = element.remove.bind(element).chain(Lightbox.rescan);
if (this.Options.removeFx) {
element.hide(this.Options.removeFx, {onFinish: remove_element});
} else {
remove_element;
}
}
},
/**
* Makes a remote form out of the form
*
* @param String form id
* @return RR this
*/
remotize_form: function(id) {
var form = $(id);
if (form) {
form.remotize().enable().action += '.'+this.Options.format;
}
return this;
},
/**
* Replaces the form with new content and makes it remote
*
* @param String form id
* @param String content
* @return RR this
*/
replace_form: function(id, source) {
var form = $(id);
if (form) {
form.replace(source);
this.remotize_form(id);
}
return this.rescan(id);
},
/**
* Inserts the form source into the given element
*
* @param String target id
* @param String form source
* @return RR this
*/
show_form_for: function(id, source) {
$(id).select('form').each('remove'); // removing old forms
$(id).insert(source);
return this.remotize_form($(id).first('form')).rescan(id);
},
/**
* watches link clicks and processes the ajax edit/delete operations
*
* @param Event event
*/
process_click: function(event) {
var target = event.target, link = [target].concat(target.parents()).first('match', 'a');
if (link) {
if (link.match(this.Options.linkToAjaxEdit)) {
event.stop();
Xhr.load(link.href + '.' + this.Options.format);
} else if (link.match(this.Options.linkToAjaxDelete) && link.has('onclick')) {
event.stop();
eval('({f:'+ link.onclick.toString().replace('.submit', '.send')+'})').f.call(link);
}
}
},
/**
* Scans for updated elements
*
* @return RR this
*/
rescan: function(scope) {
$w('Draggable Droppable Tabs Slider Selectable').each(function(name) {
if (self[name]) self[name].rescan(this.Options.rescanWithScopes ? scope : null);
}, this);
return this;
}
};
/**
* Rails 3 UJS support module
*
* Copyright (C) 2010 Nikolay V. Nemshilov
*/
(function() {
// tries to cancel the event via confirmation
var user_cancels = function(event, element) {
var message = element.get('data-confirm');
if (message && !confirm(message)) {
event.stop();
return true;
}
};
// adds XHR events to the element
var add_xhr_events = function(element, options) {
return Object.merge({
onCreate: function() { element.fire('ajax:loading', this) },
onComplete: function() { element.fire('ajax:complete', this) },
onSuccess: function() { element.fire('ajax:success', this) },
onFailure: function() { element.fire('ajax:failure', this) }
}, options);
};
// processes link clicks
var try_link_submit = function(event, link) {
var method = link.get('data-method'), remote = link.get('data-remote');
if (user_cancels(event, link)) return;
if (method || remote) event.stop();
if (remote)
Xhr.load(link.href, add_xhr_events(link, {
method: method || 'get',
spinner: link.get('data-spinner')
}));
else if (method) {
var param = $$('meta[name=csrf-param]')[0],
token = $$('meta[name=csrf-token]')[0],
form = $E('form', {action: link.href, method: 'post'});
if (param && token)
form.insert('');
form.insert('')
.insertTo(document.body).submit();
}
};
// processes form submits
var try_form_submit = function(event, button) {
if (!user_cancels(event, button) && $(button.form).has('data-remote')) {
event.stop();
button.form.send(add_xhr_events(button.form));
}
};
// global events listeners
document.on({
click: function (event) {
var target = event.target, form = target.form,
link = [target].concat(target.parents()).first('match', 'a');
if (form && ['submit', 'image'].include(target.type))
try_form_submit(event, target);
else if (link)
try_link_submit(event, link);
},
keydown: function(event) {
var target = event.target, form = target.form;
if (form && target.tagName === 'INPUT' && event.keyCode == 13) {
try_form_submit(event, target);
}
}
});
})();
// the document onload hook
document.on({
ready: function() {
RR.hide_flash();
},
click: function(event) {
RR.process_click(event);
}
});
/**
* Underscored aliases for Ruby On Rails
*
* Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
// the language and window level aliases
[String.prototype, Array.prototype, Function.prototype, Object, Options, Observer, Observer.prototype, window, document].each(function(object) {
for (var key in object) {
try { // some keys are not accessable
if (/[A-Z]/.test(key) && typeof(object[key]) === 'function') {
var u_key = key.underscored();
if (object[u_key] === null || object[u_key] === undefined) {
object[u_key] = object[key];
}
}
} catch (e) {}
}
});
// DOM package aliases
[Element, Event, Form, Form.Element].each(function(object) {
var aliases = {}, methods = object.Methods;
for (var key in methods) {
if (/[A-Z]/.test(key) && typeof(methods[key]) === 'function') {
aliases[key.underscored()] = methods[key];
}
}
object.include(aliases);
});
// various ruby-like method aliases
$alias(String.prototype, {
index_of: 'indexOf',
last_index_of: 'lastIndexOf',
to_f: 'toFloat',
to_i: 'toInt',
gsub: 'replace',
downcase: 'toLowerCase',
upcase: 'toUpperCase',
index: 'indexOf',
rindex: 'lastIndexOf',
strip: 'trim'
});
$alias(Array.prototype, {
collect: 'map',
detect: 'filter',
index_of: 'indexOf',
last_index_of: 'lastIndexOf',
index: 'indexOf',
rindex: 'lastIndexOf'
});