Created
February 27, 2010 01:25
-
-
Save ttilley/316376 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dojo.provide('rails._util.ujs'); | |
dojo.require('rails._util.xhrDomEvents'); | |
dojo.require('dojo.NodeList-traverse'); | |
// main handlers: | |
// form[data-remote] -> submit | |
// input[data-remote] -> click | |
// a[data-remote] -> click | |
// a[data-method]:not([data-remote]) -> click | |
// | |
// other important selectors: | |
// input[data-disable-with] | |
// form[data-remote]:has(input[data-disable-with]) | |
// | |
// HTML5 data attributes: | |
// data-remote -> ajax-enable this element | |
// data-method -> HTTP verb emulation | |
// data-confirm -> add a confirmation dialog | |
// data-disable-with -> disable inputs/forms with in-flight requests | |
// data-url (deprecated, use href) -> define endpoint for verb emulation | |
// | |
// Cross-Site tags: | |
// meta[name=csrf-token] | |
// meta[name=csrf-param] | |
// | |
// data-remote request lifecycle events: | |
// ajax:before | |
// ajax:loading | |
// ajax:loaded | |
// ajax:interactive | |
// ajax:complete | |
// ajax:success | |
// ajax:failure | |
// ajax:after | |
(function(){ | |
function ajaxEnable(el){ | |
var method, url, params, hasBody; | |
if (el.tagName.toLowerCase() == 'form') { | |
method = el.attr('method') || 'post'; | |
url = el.attr('action'); | |
params = dojo.formToObject(el); | |
hasBody = true; | |
} | |
else { | |
method = el.attr('data-method') || 'get'; | |
url = el.attr('data-url') || el.attr('href'); | |
params = {}; | |
hasBody = false; | |
} | |
dojo.xhr(method, { | |
url: url, | |
handleAs: 'javascript', | |
content: params, | |
domEvents: el | |
}, hasBody); | |
} | |
function emulateVerb(el){ | |
var action = dojo.attr(el, 'data-url') || dojo.attr(el, 'href'); | |
var emulatedVerb = dojo.attr(el, 'data-method'); | |
var form = dojo.create('form', { | |
method: 'post', | |
action: action, | |
styles: { | |
display: 'none' | |
} | |
}, el, 'after'); | |
if (emulatedVerb.toLowerCase() != 'post') { | |
dojo.create('input', { | |
type: 'hidden', | |
name: '_method', | |
value: emulatedVerb | |
}, form, 'last'); | |
} | |
var csrf_param = dojo.query('meta[name=csrf-param]').attr('content')[0] || false; | |
var csrf_token = dojo.query('meta[name=csrf-token]').attr('content')[0] || false; | |
if (csrf_param && csrf_token) { | |
dojo.create('input', { | |
type: 'hidden', | |
name: csrf_param, | |
value: csrf_token | |
}, form, 'last'); | |
} | |
form.submit(); | |
} | |
function seekDisableableElement(el){ | |
return dojo.hasAttr(el, 'data-disable-with') ? el : dojo.query('[data-disable-with]', el)[0]; | |
} | |
function disableInput(element){ | |
var el = seekDisableableElement(element); | |
if (!el) { | |
return true; | |
} | |
if (!dojo.hasAttr(el, 'data-enable-with')) { | |
dojo.attr(el, 'data-enable-with', dojo.attr(el, 'value')); | |
} | |
dojo.attr(el, { | |
value: dojo.attr(el, 'data-disable-with'), | |
disabled: true | |
}); | |
} | |
function enableInput(el){ | |
if (dojo.hasAttr(el, 'data-enable-with')) { | |
var value = dojo.attr(el, 'data-enable-with'); | |
dojo.attr(el, 'value', value); | |
} | |
dojo.attr(el, 'disabled', false); | |
} | |
dojo.connect(document.body, 'onclick', function(event){ | |
var message = dojo.attr(event.target, 'data-confirm'); | |
if (message && !confirm(message)) { | |
dojo.stopEvent(event); | |
return false; | |
} | |
var wrapper = new dojo.NodeList(event.target); | |
var usesAjax = wrapper.closest("a[data-remote]")[0]; | |
if (usesAjax) { | |
ajaxEnable(usesAjax); | |
dojo.stopEvent(event); | |
return true; | |
} | |
var usesVerbEmulation = wrapper.closest("a[data-method]")[0]; | |
if (usesVerbEmulation) { | |
emulateVerb(usesVerbEmulation); | |
dojo.stopEvent(event); | |
return true; | |
} | |
}); | |
dojo.connect(document.body, 'onsubmit', function(event){ | |
var message = dojo.attr(event.target, 'data-confirm'); | |
if (message && !confirm(message)) { | |
dojo.stopEvent(event); | |
return false; | |
} | |
var inputs = dojo.query("input[type=submit][data-disable-with]", event.target); | |
for (var input in inputs) { | |
disableInput(input); | |
} | |
var usesAjax = new dojo.NodeList(event.target).closest("form[data-remote]")[0]; | |
if (usesAjax) { | |
ajaxEnable(usesAjax); | |
dojo.stopEvent(event); | |
return true; | |
} | |
}); | |
dojo.connect(document.body, 'ajax:complete', function(event){ | |
if (event.target.tagName.toLowerCase() == 'form') { | |
var inputs = dojo.query("input[type=submit][disabled=true][data-disable-with]", event.target); | |
for (var input in inputs) { | |
enableInput(input); | |
} | |
} | |
}); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dojo.provide('rails._util.xhrDomEvents'); | |
dojo.require('rails._util.xhrReadyState'); | |
dojo.require('plugd.trigger'); | |
(function(){ | |
var _xhr = dojo.xhr; | |
var _xhrDomEventHandler = function(element, customEvent){ | |
var handler = dojo.hitch(element, dojo.trigger, element, customEvent); | |
return function(xhr){ | |
handler({ | |
request: xhr | |
}); | |
}; | |
}; | |
var _xhrDomEventsFor = function(element){ | |
return { | |
onLoading: _xhrDomEventHandler(element, 'ajax:loading'), | |
onLoaded: _xhrDomEventHandler(element, 'ajax:loaded'), | |
onInteractive: _xhrDomEventHandler(element, 'ajax:interactive'), | |
onComplete: _xhrDomEventHandler(element, 'ajax:complete') | |
}; | |
}; | |
dojo.xhr = function(method, args, hasBody){ | |
if (args && args.domEvents) { | |
var element = args.domEvents; | |
delete args.domEvents; | |
var dfd; | |
if (!dojo.trigger(element, 'ajax:before')) { | |
var emptyFunction = function(){ | |
}; | |
dfd = dojo._ioSetArgs(args, emptyFunction, emptyFunction, emptyFunction); | |
dfd.cancel(); | |
return dfd; | |
} | |
var readyStateCallbacks = _xhrDomEventsFor(element); | |
if (args.readyStateCallbacks) { | |
var overWrite = args.readyStateCallbacks; | |
dojo.mixin(readyStateCallbacks, overWrite); | |
} | |
args.readyStateCallbacks = readyStateCallbacks; | |
dfd = _xhr(method, args, hasBody); | |
dojo.trigger(element, 'ajax:after'); | |
var ajaxSuccess = _xhrDomEventHandler(element, 'ajax:success'); | |
var ajaxFailure = _xhrDomEventHandler(element, 'ajax:failure'); | |
dfd.addCallbacks(function(dfd){ | |
ajaxSuccess(dfd.ioArgs.xhr); | |
}, function(dfd){ | |
ajaxFailure(dfd.ioArgs.xhr); | |
}); | |
return dfd; | |
} | |
else { | |
return _xhr(method, args, hasBody); | |
} | |
}; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dojo.provide('rails._util.xhrReadyState'); | |
(function(){ | |
var _xhrObj = dojo._xhrObj; | |
var _readyStates = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; | |
var _readyStateHandler = function(callbacks, event){ | |
var xhr = event.target; | |
var readyState = xhr.readyState; | |
var state = String(_readyStates[readyState]); | |
var callback = callbacks['on' + state]; | |
if (callback && dojo.isFunction(callback)) { | |
callback(xhr); | |
} | |
}; | |
dojo._xhrObj = function(args){ | |
var http = _xhrObj(); | |
var callbacks = args.readyStateCallbacks; | |
if (callbacks) { | |
delete args.readyStateCallbacks; | |
try { | |
http.onreadystatechange = dojo.hitch(null, _readyStateHandler, callbacks); | |
} | |
catch (e) { | |
console.error("Unable to setup ready state handler:"); | |
console.error(e); | |
} | |
} | |
return http; | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment