(function ($, undefined) {
/** * Better Unobtrusive javascript request for Jquery * https://github.com/gagoar/SrBuj * * Requires jQuery 1.7.0 or later. * * Released under the MIT license * * JSHINT * jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, jquery:true, indent:4, maxerr:50 * global jQuery */ 'use strict'; $.fn.present = function () { return this.length === 1 && this; }; var SrBuj; $.SrBuj = SrBuj = { version: '0.10.0', selector: '[data-remote][data-target]', notifyHeaders: { message : 'X-SRBUJ-MSG', type : 'X-SRBUJ-TYPE', side : 'X-SRBUJ-SIDE', position : 'X-SRBUJ-POS', time : 'X-SRBUJ-TIME', remove : 'X-SRBUJ-REMOVE', raw : 'X-SRBUJ-RAW' }, defaults: { '$el': undefined, target: undefined, onError: undefined, wrapper: undefined, method: 'GET', modal: false, change: true, custom: false, replace: false, callback: false, remove: false, url: undefined, push: false, jqueryselector: false }, changeDom: function (method, $target, data) { switch (method) { case 'POST': $target.append(data); break; case 'PUT': case 'PATCH': $target.replaceWith(data); break; case 'DELETE': $target.remove(); break; default: $target.html(data); } }, kindOfCallback: function (callback) { if (typeof callback === 'function') { return callback; } else { if (window[callback]) { return window[callback]; } else { return new Function(callback); } } }, getUrl: function($el){ var url = $el.attr('href') || $el.attr('action'); if((/^[\/#](\w)/).test(url)){ return url } }, needToChangeUrl: function(url){ return !((window.document.location.origin + url) == window.document.location.href) }, browserSupportsPushState: function(){ return window.history && window.history.pushState && window.history.replaceState }, getVerb: function ($el) { var respond_as = $el.data('respond-as'), dataVerb = $el.data('method'), replace = $el.data('replace'), proto = $el.attr('method'); if (respond_as) { return respond_as.toUpperCase(); } else if (dataVerb) { return dataVerb.toUpperCase(); } else { if (proto) { return replace ? 'PUT' : proto.toUpperCase(); } } }, getOptions: function (el, user_options) { user_options = user_options || {}; var options = {}, $el = $(user_options.el || el).present(), el_options = { '$el': $el, 'target': $el.data('target'), 'method': $.SrBuj.getVerb($el), 'onError': $el.data('error'), 'callback': $el.data('callback'), 'change': !($el.data('nochange') || false), 'jqueryselector': $el.is('[data-jqueryselector]'), 'modal': $el.is('[data-modal]'), 'wrapper': $el.data('error'), 'custom': $el.is('[data-custom]'), 'replace': $el.data('replace'), 'url': $.SrBuj.getUrl($el), 'push': $el.is('[data-push]'), 'remove': $el.is('[data-srbuj]') }; user_options = user_options || {}; for ( var attr in this.defaults ) { if ( this.defaults.hasOwnProperty(attr) ) { options[attr] = user_options[attr] || el_options[attr] || this.defaults[attr]; } } return options; }, success: function (e, data, status, xhr, user_options) { if ( xhr ){ var notify = {}; for ( var attr in $.SrBuj.notifyHeaders ) if ( $.SrBuj.notifyHeaders.hasOwnProperty(attr) ) { notify[attr] = xhr.getResponseHeader($.SrBuj.notifyHeaders[attr]); } if (notify.message){ $.SrBuj.Util.notify(notify) } if (notify.remove){ $.SrBuj.Util.removeNotify() } if ( (/javascript/).test( xhr.getResponseHeader('Content-Type') )){ return true; } } var options = $.SrBuj.getOptions(e.target, user_options), $target = options.jqueryselector ? $(options.target).present() : $(document.getElementById(options.target)), $wrapper = options.jqueryselector ? $(options.wrapper) : $(document.getElementById(options.wrapper)); if ($target.present()) { e.stopPropagation(); if (!options.custom) { if (options.change) { $.SrBuj.changeDom(options.method, $target, data); } if (options.modal) { if (options.wrapper) { $wrapper.modal('toggle'); } else { $target.modal('toggle'); } } } if(options.url && options.push && $.SrBuj.needToChangeUrl(options.url) && $.SrBuj.browserSupportsPushState() ){ window.history.pushState({ SrBuj: true }, '', options.url) } if (options.callback) { var callback = $.SrBuj.kindOfCallback(options.callback); if (callback) { callback.apply(this, [e, data, status]); } } if (options.remove){ this.remove(); } }}, fail: function (e, data, status, error_code, user_options) { e.stopPropagation(); var $el = $(e.target).present(), error = $el.data('error'), jqueryselector = $el.data('jqueryselector'), $error = jqueryselector ? $(error) : $(document.getElementById(error)); if (error) { $.SrBuj.changeDom('ERROR', $error, data.responseText); var notify = {}; for (var attr in $.SrBuj.notifyHeaders) if ($.SrBuj.notifyHeaders.hasOwnProperty(attr)) { notify[attr] = data.getResponseHeader($.SrBuj.notifyHeaders[attr]); } if (notify.message){ $.SrBuj.Util.notify(notify) } }else { throw 'cant find data-error on element ' + e.target + ' maybe content_type missing on response?'; } }, bind: function (selector) { selector = selector || this.selector; $(document).on('ajax:success', selector, this.success); $(document).on('ajax:error', selector, this.fail); }, Util: { notify: function (options){ /* This function will show a growling element, with the message and attached class that was given. * will endure only a few seconds and its going to be removed from DOM afterwards. * use: $.SrBuj.Util.notify({message: 'This is Madness', type: 'info'}) this will produce * <s id=_growlingMsg class=info>This is Madness</s> */ var options = options || {}; if ($.SrBuj.gMsg_interval){ window.clearInterval($.SrBuj.gMsg_interval) } var gMsg = document.getElementById('_growlingMsg')|| document.createElement('s'); gMsg.id = '_growlingMsg'; if ( options.type ){ gMsg.className = (/^(info|warning|error)$/).test( options.type ) ? ['alert', '-' , options.type ].join('') : options.type; }else{ gMsg.className = 'alert-info'; } gMsg.innerHTML = options.raw ? options.message : $.SrBuj.Util.decodeUTF8(options.message); $('body').append(gMsg); gMsg.className += [' alert', options.side || 'right', options.position || 'bottom', 'srbuj-notify' ].join(' ').toLowerCase(); if (options.time != -1) { options.time = Number(options.time) > 0 ? options.time : 2000; $.SrBuj.gMsg_interval = window.setInterval( $.SrBuj.Util.removeNotify, options.time ); } }, removeNotify: function(){ $('#_growlingMsg').removeClass('srbuj-notify'); }, randomCode: function(size) { var size = !isNaN(size) && size < 12 ? size : 12 return Math.random().toString(36).substring(4).substring(0, size) }, decodeUTF8: function(message) { return decodeURIComponent(escape(message)) }, link: function (user_options){ /* This function will create a link with options, trigger it and remove the link afterwards * user_options must be a hash (Obj) with key: value without the data word * if the hash contain more keys, these will be integrated too as data-key form. Example: * { target: 'modal', error: 'modal', modal: true, href: '/admin/request'} * this will become: * <a href: '/admin/request' data-remote data-srbuj data-target= 'modal' data-modal data-error= 'modal' ></a> * note: we add an extra attribute, in order to debug ([data-srbuj]) and recover the link that has been made from the dom that * if the attribute [data-srbuj] its present in any element that is handled by SrBuj response it will be removed form dom after complete the process * the white spaces will be removed from keys. */ var user_options = user_options || {}; $.extend(user_options, {remote: true, srbuj: true}); if(user_options.target && user_options.href){ var _srbujLink = document.createElement('a'), randomKey = $.SrBuj.Util.randomCode(6); _srbujLink.id = ['_srbujLink', randomKey].join('_'); if (user_options.force_refresh) { var params = { key: randomKey } , urlParams = $.param(params) , splitedUrl = user_options.href.split(/\?.+/) , joinChar = (splitedUrl.length > 1) ? '&' : splitedUrl[0].match(/\?$/) ? '' : '?'; user_options.href += joinChar + urlParams; } _srbujLink.href = user_options.href; delete user_options.href; for (var attr in user_options) { if (user_options.hasOwnProperty(attr)) { var key = ['data', attr.replace(/\s/g, '')].join('-'), value = user_options[attr]; if( value === true ){ value = '' } _srbujLink.setAttribute(key, value); } } $('body').append(_srbujLink); $(_srbujLink).trigger('click'); }else{ throw 'not enough options given. Maybe target or href not present?' } } } }; $(function () { $.SrBuj.bind(); });
})(jQuery);