Current section
Files
Jump to
Current section
Files
priv/static/js/ex_admin_common.js
(function() {
'use strict';
var globals = typeof window === 'undefined' ? global : window;
if (typeof globals.require === 'function') return;
var modules = {};
var cache = {};
var aliases = {};
var has = ({}).hasOwnProperty;
var endsWith = function(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
};
var _cmp = 'components/';
var unalias = function(alias, loaderPath) {
var start = 0;
if (loaderPath) {
if (loaderPath.indexOf(_cmp) === 0) {
start = _cmp.length;
}
if (loaderPath.indexOf('/', start) > 0) {
loaderPath = loaderPath.substring(start, loaderPath.indexOf('/', start));
}
}
var result = aliases[alias + '/index.js'] || aliases[loaderPath + '/deps/' + alias + '/index.js'];
if (result) {
return _cmp + result.substring(0, result.length - '.js'.length);
}
return alias;
};
var _reg = /^\.\.?(\/|$)/;
var expand = function(root, name) {
var results = [], part;
var parts = (_reg.test(name) ? root + '/' + name : name).split('/');
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part === '..') {
results.pop();
} else if (part !== '.' && part !== '') {
results.push(part);
}
}
return results.join('/');
};
var dirname = function(path) {
return path.split('/').slice(0, -1).join('/');
};
var localRequire = function(path) {
return function expanded(name) {
var absolute = expand(dirname(path), name);
return globals.require(absolute, path);
};
};
var initModule = function(name, definition) {
var module = {id: name, exports: {}};
cache[name] = module;
definition(module.exports, localRequire(name), module);
return module.exports;
};
var require = function(name, loaderPath) {
var path = expand(name, '.');
if (loaderPath == null) loaderPath = '/';
path = unalias(name, loaderPath);
if (has.call(cache, path)) return cache[path].exports;
if (has.call(modules, path)) return initModule(path, modules[path]);
var dirIndex = expand(path, './index');
if (has.call(cache, dirIndex)) return cache[dirIndex].exports;
if (has.call(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
throw new Error('Cannot find module "' + name + '" from '+ '"' + loaderPath + '"');
};
require.alias = function(from, to) {
aliases[to] = from;
};
require.register = require.define = function(bundle, fn) {
if (typeof bundle === 'object') {
for (var key in bundle) {
if (has.call(bundle, key)) {
modules[key] = bundle[key];
}
}
} else {
modules[bundle] = fn;
}
};
require.list = function() {
var result = [];
for (var item in modules) {
if (has.call(modules, item)) {
result.push(item);
}
}
return result;
};
require.brunch = true;
require._cache = cache;
globals.require = require;
})();
//= require active_admin/base
//= require jquery
//= require jquery-ui
//= require jquery-migrate-1.1.1
// TODO: move this to a file provided by ace_contacts plugin
function serializeCategories() {
var categoryIds = $.makeArray(
$("table.index_table .category").map(function() {
return $(this).data('id');
})
);
return {ids: categoryIds};
};
$(document).ready(function(){
// Activating Best In Place
jQuery(".best_in_place").best_in_place();
//$('table.index_table tbody').sortable();
$('#backup-now').click(function(){
$('#title_bar').after("<div class='flashes'><div class='flash flash_info'>Creating backup. This may take a while ...</div></div>");
return true;
});
$('.restore-link').click(function(e){
if (e.isPropagationStopped()) {
$('#title_bar').after("<div class='flashes'><div class='flash flash_info'>Restoring backup. This may take a while ...</div></div>");
}
return true;
});
$('body.admin_categories table.index_table tbody').sortable({
update: function(){
$.ajax({
url: '/admin/categories/sort',
type: 'post',
data: serializeCategories(),
complete: function(){
$('.paginated_collection').effect('highlight');
}
});
}
});
});
// File: application.js.js
// Generated by CoffeeScript 1.10.0
(function() {
$(document).ready(function() {
var batch_actions_selector;
$(document).on('focus', '.datepicker:not(.hasDatepicker)', function() {
var defaults, options;
defaults = {
dateFormat: 'yy-mm-dd'
};
options = $(this).data('datepicker-options');
return $(this).datepicker($.extend(defaults, options));
});
$('.clear_filters_btn').click(function() {
var params, regex;
params = window.location.search.split('&');
regex = /^(q\[|q%5B|q%5b|page|commit)/;
return window.location.search = "";
});
$('.filter_form').submit(function() {
return $(this).find(':input').filter(function() {
return this.value === '';
}).prop('disabled', true);
});
$('.filter_form_field.select_and_search select').change(function() {
return $(this).siblings('input').prop({
name: "q[" + this.value + "]"
});
});
if ((batch_actions_selector = $('.table_tools .batch_actions_selector')).length) {
return batch_actions_selector.next().css({
width: "calc(100% - 10px - " + (batch_actions_selector.outerWidth()) + "px)",
'float': 'right'
});
}
});
}).call(this);
// File: base.js.js
// Generated by CoffeeScript 1.10.0
(function() {
window.ActiveAdmin = {};
}).call(this);
// File: batch_actions.js.js
// Generated by CoffeeScript 1.10.0
(function() {
$(document).on('ready page:load', function() {
$('#batch_actions_selector li a').click(function(e) {
var message, r;
e.stopPropagation();
e.preventDefault();
console.log('clicked it');
if (message = $(this).data('confirm')) {
r = window.confirm(message);
if (r === true) {
return $(this).trigger('confirm:complete', $(this).data('inputs'));
}
} else {
return $(this).trigger('confirm:complete');
}
});
$('#batch_actions_selector li a').on('confirm:complete', function(e, inputs) {
var val;
if (val = JSON.stringify(inputs)) {
$('#batch_action_inputs').val(val);
} else {
$('#batch_action_inputs').attr('disabled', 'disabled');
}
$('#batch_action').val($(this).data('action'));
return $('#collection_selection').submit();
});
if ($("#batch_actions_selector").length && $(":checkbox.toggle_all").length) {
if ($(".paginated_collection").find("table.index_table").length) {
$(".paginated_collection table").tableCheckboxToggler();
} else {
$(".paginated_collection").checkboxToggler();
}
return $(".paginated_collection").find(":checkbox").bind("change", function() {
if ($(".paginated_collection").find(":checkbox").filter(":checked").length > 0) {
return $("#batch_actions_selector").aaDropdownMenu("enable");
} else {
return $("#batch_actions_selector").aaDropdownMenu("disable");
}
});
}
});
}).call(this);
// File: checkbox-toggler.js.js
// Generated by CoffeeScript 1.10.0
(function() {
ActiveAdmin.CheckboxToggler = (function() {
function CheckboxToggler(options, container) {
var defaults;
this.options = options;
this.container = container;
defaults = {};
this.options = $.extend(defaults, this.options);
this._init();
this._bind();
}
CheckboxToggler.prototype._init = function() {
if (!this.container) {
throw new Error('Container element not found');
} else {
this.$container = $(this.container);
}
if (!this.$container.find('.toggle_all').length) {
throw new Error('"toggle all" checkbox not found');
} else {
this.toggle_all_checkbox = this.$container.find('.toggle_all');
}
return this.checkboxes = this.$container.find(':checkbox').not(this.toggle_all_checkbox);
};
CheckboxToggler.prototype._bind = function() {
this.checkboxes.change((function(_this) {
return function(e) {
return _this._didChangeCheckbox(e.target);
};
})(this));
return this.toggle_all_checkbox.change((function(_this) {
return function() {
return _this._didChangeToggleAllCheckbox();
};
})(this));
};
CheckboxToggler.prototype._didChangeCheckbox = function(checkbox) {
switch (this.checkboxes.filter(':checked').length) {
case this.checkboxes.length - 1:
return this.toggle_all_checkbox.prop({
checked: null
});
case this.checkboxes.length:
return this.toggle_all_checkbox.prop({
checked: true
});
}
};
CheckboxToggler.prototype._didChangeToggleAllCheckbox = function() {
var setting;
setting = this.toggle_all_checkbox.prop('checked') ? true : null;
return this.checkboxes.each((function(_this) {
return function(index, el) {
$(el).prop({
checked: setting
});
return _this._didChangeCheckbox(el);
};
})(this));
};
return CheckboxToggler;
})();
$.widget.bridge('checkboxToggler', ActiveAdmin.CheckboxToggler);
}).call(this);
// File: dropdown-menu.js.js
// Generated by CoffeeScript 1.10.0
(function() {
ActiveAdmin.DropdownMenu = (function() {
function DropdownMenu(options, element) {
var defaults;
this.options = options;
this.element = element;
this.$element = $(this.element);
defaults = {
fadeInDuration: 20,
fadeOutDuration: 100,
onClickActionItemCallback: null
};
this.options = $.extend(defaults, this.options);
this.isOpen = false;
this.$menuButton = this.$element.find('.dropdown_menu_button');
this.$menuList = this.$element.find('.dropdown_menu_list_wrapper');
this._buildMenuList();
this._bind();
}
DropdownMenu.prototype.open = function() {
this.isOpen = true;
this.$menuList.fadeIn(this.options.fadeInDuration);
this._position();
return this;
};
DropdownMenu.prototype.close = function() {
this.isOpen = false;
this.$menuList.fadeOut(this.options.fadeOutDuration);
return this;
};
DropdownMenu.prototype.destroy = function() {
this.$element.unbind();
this.$element = null;
return this;
};
DropdownMenu.prototype.isDisabled = function() {
return this.$menuButton.hasClass('disabled');
};
DropdownMenu.prototype.disable = function() {
return this.$menuButton.addClass('disabled');
};
DropdownMenu.prototype.enable = function() {
return this.$menuButton.removeClass('disabled');
};
DropdownMenu.prototype.option = function(key, value) {
if ($.isPlainObject(key)) {
return this.options = $.extend(true, this.options, key);
} else if (key != null) {
return this.options[key];
} else {
return this.options[key] = value;
}
};
DropdownMenu.prototype._buildMenuList = function() {
this.$nipple = $('<div class="dropdown_menu_nipple"></div>');
this.$menuList.prepend(this.$nipple);
return this.$menuList.hide();
};
DropdownMenu.prototype._bind = function() {
$('body').click((function(_this) {
return function() {
if (_this.isOpen) {
return _this.close();
}
};
})(this));
return this.$menuButton.click((function(_this) {
return function() {
if (!_this.isDisabled()) {
if (_this.isOpen) {
_this.close();
} else {
_this.open();
}
}
return false;
};
})(this));
};
DropdownMenu.prototype._position = function() {
var button_center, button_left, button_right, centered_menu_left, centered_menu_right, menu_center, nipple_center, window_right;
this.$menuList.css('top', this.$menuButton.position().top + this.$menuButton.outerHeight() + 10);
button_left = this.$menuButton.position().left;
button_center = this.$menuButton.outerWidth() / 2;
button_right = button_left + button_center * 2;
menu_center = this.$menuList.outerWidth() / 2;
nipple_center = this.$nipple.outerWidth() / 2;
window_right = $(window).width();
centered_menu_left = button_left + button_center - menu_center;
centered_menu_right = button_left + button_center + menu_center;
if (centered_menu_left < 0) {
this.$menuList.css('left', button_left);
return this.$nipple.css('left', button_center - nipple_center);
} else if (centered_menu_right > window_right) {
this.$menuList.css('right', window_right - button_right);
return this.$nipple.css('right', button_center - nipple_center);
} else {
this.$menuList.css('left', centered_menu_left);
return this.$nipple.css('left', menu_center - nipple_center);
}
};
return DropdownMenu;
})();
$.widget.bridge('aaDropdownMenu', ActiveAdmin.DropdownMenu);
$(document).on('ready page:load', function() {
return $('.dropdown_menu').aaDropdownMenu();
});
}).call(this);
// File: flash.js.js
// Generated by CoffeeScript 1.10.0
(function() {
var Flash;
ActiveAdmin.flash = Flash = (function() {
Flash.error = function(message, close_after) {
return new this(message, "error", close_after);
};
Flash.notice = function(message, close_after) {
return new this(message, "notice", close_after);
};
Flash.prototype.reference = function() {
return this.reference;
};
function Flash(message1, type1, close_after) {
this.message = message1;
this.type = type1 != null ? type1 : "notice";
this.reference = jQuery("<div>").addClass("flash flash_" + type).text(message);
jQuery(".flashes").append(this.reference);
if (close_after != null) {
this.close_after(close_after);
}
}
Flash.prototype.close_after = function(close_after) {
return setTimeout((function(_this) {
return function() {
return _this.close();
};
})(this), close_after * 1000);
};
Flash.prototype.close = function() {
return this.reference.remove();
};
return Flash;
})();
}).call(this);
// File: has_many.js.js
// Generated by CoffeeScript 1.10.0
(function() {
var init_sortable, recompute_positions;
$(function() {
$(document).on('click', 'a.button.has_many_remove', function(e) {
var parent, to_remove;
e.preventDefault();
parent = $(this).closest('.has_many_container');
to_remove = $(this).closest('fieldset');
recompute_positions(parent);
parent.trigger('has_many_remove:before', [to_remove, parent]);
to_remove.remove();
return parent.trigger('has_many_remove:after', [to_remove, parent]);
});
$(document).on('click', 'a.button.has_many_add', function(e) {
var before_add, fieldset, html, index, parent, regex;
e.preventDefault();
parent = $(this).closest('.has_many_container');
parent.trigger(before_add = $.Event('has_many_add:before'), [parent]);
if (!before_add.isDefaultPrevented()) {
index = parent.data('has_many_index') || parent.children('fieldset').length - 1;
parent.data({
has_many_index: ++index
});
regex = new RegExp($(this).data('placeholder'), 'g');
html = $(this).data('html').replace(regex, index);
fieldset = $(html).insertBefore(this);
recompute_positions(parent);
return parent.trigger('has_many_add:after', [fieldset, parent]);
}
});
$(document).on('change', '.has_many_container[data-sortable] :input[name$="[_destroy]"]', function() {
return recompute_positions($(this).closest('.has_many'));
});
init_sortable();
return $(document).on('has_many_add:after', '.has_many_container', init_sortable);
});
init_sortable = function() {
var elems;
elems = $('.has_many_container[data-sortable]:not(.ui-sortable)');
elems.sortable({
items: '> fieldset',
handle: '> ol > .handle',
stop: recompute_positions
});
return elems.each(recompute_positions);
};
recompute_positions = function(parent) {
var input_name, position;
parent = parent instanceof jQuery ? parent : $(this);
input_name = parent.data('sortable');
position = parseInt(parent.data('sortable-start') || 0, 10);
return parent.children('fieldset').each(function() {
var destroy_input, sortable_input;
destroy_input = $(this).find("> ol > .input > :input[name$='[_destroy]']");
sortable_input = $(this).find("> ol > .input > :input[name$='[" + input_name + "]']");
if (sortable_input.length) {
return sortable_input.val(destroy_input.is(':checked') ? '' : position++);
}
});
};
}).call(this);
// File: modal_dialog.js.js
// Generated by CoffeeScript 1.10.0
(function() {
ActiveAdmin.modal_dialog = function(message, inputs, callback) {
var elem, html, klass, name, opts, ref, ref1, type, v, wrapper;
html = "<form id=\"dialog_confirm\" title=\"" + message + "\"><ul>";
for (name in inputs) {
type = inputs[name];
if (/^(datepicker|checkbox|text)$/.test(type)) {
wrapper = 'input';
} else if (type === 'textarea') {
wrapper = 'textarea';
} else if ($.isArray(type)) {
ref = ['select', 'option', type, ''], wrapper = ref[0], elem = ref[1], opts = ref[2], type = ref[3];
} else {
throw new Error("Unsupported input type: {" + name + ": " + type + "}");
}
klass = type === 'datepicker' ? type : '';
html += ("<li>\n<label>" + (name.charAt(0).toUpperCase() + name.slice(1)) + "</label>\n<" + wrapper + " name=\"" + name + "\" class=\"" + klass + "\" type=\"" + type + "\">") + (opts ? ((function() {
var i, len, results;
results = [];
for (i = 0, len = opts.length; i < len; i++) {
v = opts[i];
if ($.isArray(v)) {
results.push("<" + elem + " value=" + v[1] + ">" + v[0] + "</" + elem + ">");
} else {
results.push("<" + elem + ">" + v + "</" + elem + ">");
}
}
return results;
})()).join('') : '') + ("</" + wrapper + ">") + "</li>";
ref1 = [], wrapper = ref1[0], elem = ref1[1], opts = ref1[2], type = ref1[3], klass = ref1[4];
}
html += "</ul></form>";
return $(html).appendTo('body').dialog({
modal: true,
dialogClass: 'active_admin_dialog',
buttons: {
OK: function() {
callback($(this).serializeObject());
return $(this).dialog('close');
},
Cancel: function() {
return $(this).dialog('close').remove();
}
}
});
};
}).call(this);
// File: per_page.js.js
// Generated by CoffeeScript 1.10.0
(function() {
ActiveAdmin.PerPage = (function() {
function PerPage(options, element) {
this.options = options;
this.element = element;
this.$element = $(this.element);
this._init();
this._bind();
}
PerPage.prototype._init = function() {
return this.$params = this._queryParams();
};
PerPage.prototype._bind = function() {
return this.$element.change((function(_this) {
return function() {
_this.$params['per_page'] = _this.$element.val();
delete _this.$params['page'];
return location.search = $.param(_this.$params);
};
})(this));
};
PerPage.prototype._queryParams = function() {
var m, params, query, re;
query = window.location.search.substring(1);
params = {};
re = /([^&=]+)=([^&]*)/g;
while (m = re.exec(query)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
return params;
};
return PerPage;
})();
$.widget.bridge('perPage', ActiveAdmin.PerPage);
$(function() {
return $('.pagination_per_page select').perPage();
});
}).call(this);
// File: popover.js.js
// Generated by CoffeeScript 1.10.0
(function() {
ActiveAdmin.Popover = (function() {
function Popover(options1, element) {
var defaults;
this.options = options1;
this.element = element;
this.$element = $(this.element);
defaults = {
fadeInDuration: 20,
fadeOutDuration: 100,
autoOpen: true,
pageWrapperElement: "#wrapper",
onClickActionItemCallback: null
};
this.options = $.extend(defaults, options);
this.isOpen = false;
if (!(this.$popover = $(this.$element.attr('href'))).length) {
this.$popover = this.$element.next('.popover');
}
this._buildPopover();
this._bind();
}
Popover.prototype.open = function() {
this.isOpen = true;
this.$popover.fadeIn(this.options.fadeInDuration);
this._positionPopover();
this._positionNipple();
return this;
};
Popover.prototype.close = function() {
this.isOpen = false;
this.$popover.fadeOut(this.options.fadeOutDuration);
return this;
};
Popover.prototype.destroy = function() {
this.$element.removeData('popover');
this.$element.unbind();
this.$element = null;
return this;
};
Popover.prototype._buildPopover = function() {
this.$nipple = $('<div class="popover_nipple"></div>');
this.$popover.prepend(this.$nipple);
this.$popover.hide();
return this.$popover.addClass('popover');
};
Popover.prototype._bind = function() {
$(this.options.pageWrapperElement).click((function(_this) {
return function() {
if (_this.isOpen) {
return _this.close();
}
};
})(this));
if (this.options.autoOpen) {
return this.$element.click((function(_this) {
return function(e) {
e.stopPropagation();
if (_this.isOpen) {
return _this.close();
} else {
return _this.open();
}
};
})(this));
}
};
Popover.prototype._positionPopover = function() {
var button_center, popover_center;
button_center = this.$element.offset().left + this.$element.outerWidth() / 2;
popover_center = this.$popover.outerWidth() / 2;
return this.$popover.css('left', button_center - popover_center);
};
Popover.prototype._positionNipple = function() {
this.$popover.css('top', this.$element.offset().top + this.$element.outerHeight() + 10);
return this.$nipple.css('left', this.$popover.outerWidth() / 2 - this.$nipple.outerWidth() / 2);
};
return Popover;
})();
$.widget.bridge('popover', ActiveAdmin.Popover);
}).call(this);
// File: table-checkbox-toggler.js.js
// Generated by CoffeeScript 1.10.0
(function() {
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
ActiveAdmin.TableCheckboxToggler = (function(superClass) {
extend(TableCheckboxToggler, superClass);
function TableCheckboxToggler() {
return TableCheckboxToggler.__super__.constructor.apply(this, arguments);
}
TableCheckboxToggler.prototype._init = function() {
return TableCheckboxToggler.__super__._init.apply(this, arguments);
};
TableCheckboxToggler.prototype._bind = function() {
TableCheckboxToggler.__super__._bind.apply(this, arguments);
return this.$container.find('tbody td').click((function(_this) {
return function(e) {
if (e.target.type !== 'checkbox') {
return _this._didClickCell(e.target);
}
};
})(this));
};
TableCheckboxToggler.prototype._didChangeCheckbox = function(checkbox) {
var $row;
TableCheckboxToggler.__super__._didChangeCheckbox.apply(this, arguments);
$row = $(checkbox).parents('tr');
if (checkbox.checked) {
return $row.addClass('selected');
} else {
return $row.removeClass('selected');
}
};
TableCheckboxToggler.prototype._didClickCell = function(cell) {
return $(cell).parent('tr').find(':checkbox').click();
};
return TableCheckboxToggler;
})(ActiveAdmin.CheckboxToggler);
$.widget.bridge('tableCheckboxToggler', ActiveAdmin.TableCheckboxToggler);
}).call(this);
// File: sortable_associations.js
$(document).ready(function() {
// Fix sortable helper
var fixHelper = function(e, ui) {
ui.children().each(function() {
$(this).width($(this).width());
});
return ui;
};
$('table.sortable').ready(function(){
var td_count = $(this).find('tbody tr:first-child td').length
$('table.sortable tbody').sortable(
{
handle: '.handle',
helper: fixHelper,
placeholder: 'ui-sortable-placeholder',
update: function(event, ui) {
//$("#progress").show();
var positions = [];
$.each($('table.sortable tbody tr'), function(position, obj){
var reg = /(\w+_?)+_(\d+)/;
var parts = reg.exec($(obj).prop('id'));
if (parts) {
positions = positions.concat({'id': parts[2], 'position': position});
}
});
$.ajax({
url: $(ui.item).closest("table.sortable").data("sortable-link"),
type: 'POST',
beforeSend: function(xhr) {
var csrf_token = $('meta[name=csrf-token]').attr('content');
xhr.setRequestHeader('x-csrf-token', csrf_token);
},
dataType: 'script',
data: {positions: positions},
success: function(data){
//$("#progress").hide();
}
});
},
start: function (event, ui) {
// Set correct height for placehoder (from dragged tr)
ui.placeholder.height(ui.item.height());
// Fix placeholder content to make it correct width
ui.placeholder.html("<td colspan='"+(td_count)+"'></td>");
},
stop: function (event, ui) {
// Fix odd/even classes after reorder
$("table.sortable tr:even").removeClass("odd even").addClass("even");
$("table.sortable tr:odd").removeClass("odd even").addClass("odd");
}
});
});
});
/*
BestInPlace (for jQuery)
version: 0.1.0 (01/01/2011)
@requires jQuery >= v1.4
@requires jQuery.purr to display pop-up windows
By Bernat Farrero based on the work of Jan Varwig.
Examples at http://bernatfarrero.com
Licensed under the MIT:
http://www.opensource.org/licenses/mit-license.php
Usage:
Attention.
The format of the JSON object given to the select inputs is the following:
[["key", "value"],["key", "value"]]
The format of the JSON object given to the checkbox inputs is the following:
["falseValue", "trueValue"]
*/
function BestInPlaceEditor(e) {
this.element = e;
this.initOptions();
this.bindForm();
this.initNil();
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
}
BestInPlaceEditor.prototype = {
// Public Interface Functions //////////////////////////////////////////////
activate : function() {
var to_display = "";
if (this.isNil) {
to_display = "";
}
else if (this.original_content) {
to_display = this.original_content;
}
else {
if (this.sanitize) {
to_display = this.element.text();
} else {
to_display = this.element.html();
}
}
var elem = this.isNil ? "-" : this.sanitize ? this.element.text() : this.element.html();
this.oldValue = elem;
this.display_value = to_display;
jQuery(this.activator).unbind("click", this.clickHandler);
this.activateForm();
this.element.trigger(jQuery.Event("best_in_place:activate"));
},
abort : function() {
if (this.isNil) this.element.text(this.nil);
else this.element.text(this.oldValue);
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:abort"));
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
abortIfConfirm : function () {
if (!this.useConfirm) {
this.abort();
return;
}
if (confirm("Are you sure you want to discard your changes?")) {
this.abort();
}
},
update : function() {
var editor = this;
if (this.formType in {"input":1, "textarea":1} && this.getValue() == this.oldValue)
{ // Avoid request if no change is made
this.abort();
return true;
}
this.isNil = false;
editor.ajax({
"type" : "post",
"dataType" : "text",
"data" : editor.requestData(),
"success" : function(data){ editor.loadSuccessCallback(data); },
"error" : function(request, error){ editor.loadErrorCallback(request, error); }
});
if (this.formType == "select") {
var value = this.getValue();
this.previousCollectionValue = value;
jQuery.each(this.values, function(i, v) {
if (value == v[0]) {
editor.element.html(v[1]);
}
}
);
} else if (this.formType == "checkbox") {
editor.element.html(this.getValue() ? this.values[1] : this.values[0]);
} else {
editor.element.text(this.getValue() !== "" ? this.getValue() : this.nil);
}
editor.element.trigger(jQuery.Event("best_in_place:update"));
},
activateForm : function() {
alert("The form was not properly initialized. activateForm is unbound");
},
// Helper Functions ////////////////////////////////////////////////////////
initOptions : function() {
// Try parent supplied info
var self = this;
self.element.parents().each(function(){
$parent = jQuery(this);
self.url = self.url || $parent.attr("data-url");
self.collection = self.collection || $parent.attr("data-collection");
self.formType = self.formType || $parent.attr("data-type");
self.objectName = self.objectName || $parent.attr("data-object");
self.attributeName = self.attributeName || $parent.attr("data-attribute");
self.activator = self.activator || $parent.attr("data-activator");
self.okButton = self.okButton || $parent.attr("data-ok-button");
self.cancelButton = self.cancelButton || $parent.attr("data-cancel-button");
self.nil = self.nil || $parent.attr("data-nil");
self.inner_class = self.inner_class || $parent.attr("data-inner-class");
self.html_attrs = self.html_attrs || $parent.attr("data-html-attrs");
self.original_content = self.original_content || $parent.attr("data-original-content");
self.collectionValue = self.collectionValue || $parent.attr("data-value");
});
// Try Rails-id based if parents did not explicitly supply something
self.element.parents().each(function(){
var res = this.id.match(/^(\w+)_(\d+)$/i);
if (res) {
self.objectName = self.objectName || res[1];
}
});
// Load own attributes (overrides all others)
self.url = self.element.attr("data-url") || self.url || document.location.pathname;
self.collection = self.element.attr("data-collection") || self.collection;
self.formType = self.element.attr("data-type") || self.formtype || "input";
self.objectName = self.element.attr("data-object") || self.objectName;
self.attributeName = self.element.attr("data-attribute") || self.attributeName;
self.activator = self.element.attr("data-activator") || self.element;
self.okButton = self.element.attr("data-ok-button") || self.okButton;
self.cancelButton = self.element.attr("data-cancel-button") || self.cancelButton;
self.nil = self.element.attr("data-nil") || self.nil || "-";
self.inner_class = self.element.attr("data-inner-class") || self.inner_class || null;
self.html_attrs = self.element.attr("data-html-attrs") || self.html_attrs;
self.original_content = self.element.attr("data-original-content") || self.original_content;
self.collectionValue = self.element.attr("data-value") || self.collectionValue;
if (!self.element.attr("data-sanitize")) {
self.sanitize = true;
}
else {
self.sanitize = (self.element.attr("data-sanitize") == "true");
}
if (!self.element.attr("data-use-confirm")) {
self.useConfirm = true;
} else {
self.useConfirm = (self.element.attr("data-use-confirm") != "false");
}
if ((self.formType == "select" || self.formType == "checkbox") && self.collection !== null)
{
self.values = jQuery.parseJSON(self.collection);
}
},
bindForm : function() {
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
},
initNil: function() {
if (this.element.text() === "")
{
this.isNil = true;
this.element.text(this.nil);
}
},
getValue : function() {
alert("The form was not properly initialized. getValue is unbound");
},
// Trim and Strips HTML from text
sanitizeValue : function(s) {
return jQuery.trim(s);
},
/* Generate the data sent in the POST request */
requestData : function() {
// To prevent xss attacks, a csrf token must be defined as a meta attribute
csrf_token = jQuery('meta[name=csrf-token]').attr('content');
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
var data = "_method=put";
data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
if (csrf_param !== undefined && csrf_token !== undefined) {
data += "&" + csrf_param + "=" + encodeURIComponent(csrf_token);
}
return data;
},
ajax : function(options) {
options.url = this.url;
options.beforeSend = function(xhr){ xhr.setRequestHeader("Accept", "application/json"); };
return jQuery.ajax(options);
},
// Handlers ////////////////////////////////////////////////////////////////
loadSuccessCallback : function(data) {
try {
var response = jQuery.parseJSON(jQuery.trim(data));
if (response !== null && response.hasOwnProperty("display_as")) {
this.element.attr("data-original-content", this.element.text());
this.original_content = this.element.text();
this.element.text(response["display_as"]);
}
this.element.trigger(jQuery.Event("ajax:success"), data);
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
if (this.collectionValue !== null) {
this.collectionValue = this.previousCollectionValue;
this.previousCollectionValue = null;
}
}
catch(err) {}
},
loadErrorCallback : function(request, error) {
this.element.text(this.oldValue);
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error])
this.element.trigger(jQuery.Event("ajax:error"));
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
clickHandler : function(event) {
event.preventDefault();
event.data.editor.activate();
},
setHtmlAttributes : function() {
var formField = this.element.find(this.formType);
try {
var attrs = jQuery.parseJSON(this.html_attrs);
for(var key in attrs){
formField.attr(key, attrs[key]);
}
}
catch(err) {}
}
};
// Button cases:
// If no buttons, then blur saves, ESC cancels
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
BestInPlaceEditor.forms = {
"input" : {
activateForm : function() {
var output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline');
var input_elt = jQuery(document.createElement('input'))
.attr('type', 'text')
.attr('name', this.attributeName)
.val(this.display_value);
if(this.inner_class !== null) {
input_elt.addClass(this.inner_class);
}
output.append(input_elt);
if(this.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('value', this.okButton)
)
}
if(this.cancelButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'button')
.attr('value', this.cancelButton)
)
}
this.element.html(output);
this.setHtmlAttributes();
this.element.find("input[type='text']")[0].select();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
}
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue : function() {
return this.sanitizeValue(this.element.find("input").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
inputBlurHandler : function(event) {
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abort();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abort();
event.stopPropagation(); // Without this, click isn't handled
},
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abort();
}
}
},
"date" : {
activateForm : function() {
var that = this,
output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline'),
input_elt = jQuery(document.createElement('input'))
.attr('type', 'text')
.attr('name', this.attributeName)
.attr('value', this.sanitizeValue(this.display_value));
if(this.inner_class !== null) {
input_elt.addClass(this.inner_class);
}
output.append(input_elt)
this.element.html(output);
this.setHtmlAttributes();
this.element.find('input')[0].select();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
this.element.find('input')
.datepicker({
onClose: function() {
that.update();
}
})
.datepicker('show');
},
getValue : function() {
return this.sanitizeValue(this.element.find("input").val());
},
submitHandler : function(event) {
event.data.editor.update();
},
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abort();
}
}
},
"select" : {
activateForm : function() {
var output = jQuery(document.createElement('form'))
.attr('action', 'javascript:void(0)')
.attr('style', 'display:inline');
selected = '',
oldValue = this.oldValue,
select_elt = jQuery(document.createElement('select')),
currentCollectionValue = this.collectionValue;
jQuery.each(this.values, function (index, value) {
var option_elt = jQuery(document.createElement('option'))
// .attr('value', value[0])
.val(value[0])
.html(value[1]);
if(value[0] == currentCollectionValue) {
option_elt.attr('selected', 'selected');
}
select_elt.append(option_elt);
});
output.append(select_elt);
this.element.html(output);
this.setHtmlAttributes();
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
this.element.find("select")[0].focus();
},
getValue : function() {
return this.sanitizeValue(this.element.find("select").val());
// return this.element.find("select").val();
},
blurHandler : function(event) {
event.data.editor.update();
},
keyupHandler : function(event) {
if (event.keyCode == 27) event.data.editor.abort();
}
},
"checkbox" : {
activateForm : function() {
var newValue = Boolean(this.oldValue.toLowerCase() != this.values[1].toLowerCase());
var output = newValue ? this.values[1] : this.values[0];
this.element.html(output);
this.setHtmlAttributes();
this.update();
},
getValue : function() {
return Boolean(this.element.html().toLowerCase() == this.values[1].toLowerCase());
}
},
"textarea" : {
activateForm : function() {
// grab width and height of text
width = this.element.css('width');
height = this.element.css('height');
// construct form
var output = jQuery(document.createElement('form'))
.attr('action', 'javascript:void(0)')
.attr('style', 'display:inline')
.append(jQuery(document.createElement('textarea'))
.val(this.sanitizeValue(this.display_value)));
if(this.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('value', this.okButton)
);
}
if(this.cancelButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'button')
.attr('value', this.cancelButton)
)
}
this.element.html(output);
this.setHtmlAttributes();
// set width and height of textarea
jQuery(this.element.find("textarea")[0]).css({ 'min-width': width, 'min-height': height });
jQuery(this.element.find("textarea")[0]).elastic();
this.element.find("textarea")[0].focus();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
}
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue : function() {
return this.sanitizeValue(this.element.find("textarea").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
blurHandler : function(event) {
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abortIfConfirm();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abortIfConfirm();
event.stopPropagation(); // Without this, click isn't handled
},
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abortIfConfirm();
}
}
}
};
jQuery.fn.best_in_place = function() {
function setBestInPlace(element) {
if (!element.data('bestInPlaceEditor')) {
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
return true;
}
}
jQuery(this.context).delegate(this.selector, 'click', function () {
var el = jQuery(this);
if (setBestInPlace(el))
el.click();
});
this.each(function () {
setBestInPlace(jQuery(this));
});
return this;
};
/**
* @name Elastic
* @descripton Elastic is Jquery plugin that grow and shrink your textareas automaticliy
* @version 1.6.5
* @requires Jquery 1.2.6+
*
* @author Jan Jarfalk
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
*/
(function(jQuery){
jQuery.fn.extend({
elastic: function() {
// We will create a div clone of the textarea
// by copying these attributes from the textarea to the div.
var mimics = [
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontSize',
'lineHeight',
'fontFamily',
'width',
'fontWeight'];
return this.each( function() {
// Elastic only works on textareas
if ( this.type != 'textarea' ) {
return false;
}
var $textarea = jQuery(this),
$twin = jQuery('<div />').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
goalheight = 0,
i = 0;
// Opera returns max-height of -1 if not set
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
// Append the twin to the DOM
// We are going to meassure the height of this, not the textarea.
$twin.appendTo($textarea.parent());
// Copy the essential styles (mimics) from the textarea to the twin
i = mimics.length;
while(i--){
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() != curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
// This function will update the height of the textarea if necessary
function update() {
// Get curated content from the textarea.
var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ /g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
// Compare curated content with curated twin.
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
if(textareaContent+' ' != twinContent){
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+' ');
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
var goalheight = $twin.height()+lineHeight;
if(goalheight >= maxheight) {
setHeightAndOverflow(maxheight,'auto');
} else if(goalheight <= minheight) {
setHeightAndOverflow(minheight,'hidden');
} else {
setHeightAndOverflow(goalheight,'hidden');
}
}
}
}
// Hide scrollbars
$textarea.css({'overflow':'hidden'});
// Update textarea size on keyup, change, cut and paste
$textarea.bind('keyup change cut paste', function(){
update();
});
// Compact textarea on blur
// Lets animate this....
$textarea.bind('blur',function(){
if($twin.height() < maxheight){
if($twin.height() > minheight) {
$textarea.height($twin.height());
} else {
$textarea.height(minheight);
}
}
});
// And this line is to catch the browser paste event
$textarea.live('input paste',function(e){ setTimeout( update, 250); });
// Run update once when elastic is initialized
update();
});
}
});
})(jQuery);
//= require jquery.purr
jQuery(document).on('best_in_place:error', function(event, request, error) {
// Display all error messages from server side validation
jQuery.each(jQuery.parseJSON(request.responseText), function(index, value) {
if( typeof(value) == "object") {value = index + " " + value.toString(); }
var container = jQuery("<span class='flash-error'></span>").html(value);
container.purr();
});
});
(function($, undefined) {
/**
* Unobtrusive scripting adapter for jQuery
* https://github.com/rails/jquery-ujs
*
* Requires jQuery 1.8.0 or later.
*
* Released under the MIT license
*
*/
// Cut down on the number of issues from people inadvertently including jquery_ujs twice
// by detecting and raising an error when it happens.
'use strict';
if ( $.rails !== undefined ) {
$.error('jquery-ujs has already been loaded!');
}
// Shorthand to make it a little easier to call public rails functions from within rails.js
var rails;
var $document = $(document);
$.rails = rails = {
// Link elements bound by jquery-ujs
linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]',
// Button elements bound by jquery-ujs
buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)',
// Select elements bound by jquery-ujs
inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
// Form elements bound by jquery-ujs
formSubmitSelector: 'form',
// Form input elements bound by jquery-ujs
formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])',
// Form input elements disabled during form submission
disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled',
// Form input elements re-enabled after form submission
enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled',
// Form required input elements
requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])',
// Form file input elements
fileInputSelector: 'input[name][type=file]:not([disabled])',
// Link onClick disable selector with possible reenable after remote submission
linkDisableSelector: 'a[data-disable-with], a[data-disable]',
// Button onClick disable selector with possible reenable after remote submission
buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]',
// Up-to-date Cross-Site Request Forgery token
csrfToken: function() {
return $('meta[name=csrf-token]').attr('content');
},
// URL param that must contain the CSRF token
csrfParam: function() {
return $('meta[name=csrf-param]').attr('content');
},
// Make sure that every Ajax request sends the CSRF token
CSRFProtection: function(xhr) {
var token = rails.csrfToken();
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
},
// Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
refreshCSRFTokens: function(){
$('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken());
},
// Triggers an event on an element and returns false if the event result is false
fire: function(obj, name, data) {
var event = $.Event(name);
obj.trigger(event, data);
return event.result !== false;
},
// Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
confirm: function(message) {
return confirm(message);
},
// Default ajax function, may be overridden with custom function in $.rails.ajax
ajax: function(options) {
return $.ajax(options);
},
// Default way to get an element's href. May be overridden at $.rails.href.
href: function(element) {
return element[0].href;
},
// Checks "data-remote" if true to handle the request through a XHR request.
isRemote: function(element) {
return element.data('remote') !== undefined && element.data('remote') !== false;
},
// Submits "remote" forms and links with ajax
handleRemote: function(element) {
var method, url, data, withCredentials, dataType, options;
if (rails.fire(element, 'ajax:before')) {
withCredentials = element.data('with-credentials') || null;
dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
if (element.is('form')) {
method = element.data('ujs:submit-button-formmethod') || element.attr('method');
url = element.data('ujs:submit-button-formaction') || element.attr('action');
data = $(element[0]).serializeArray();
// memoized value from clicked submit button
var button = element.data('ujs:submit-button');
if (button) {
data.push(button);
element.data('ujs:submit-button', null);
}
element.data('ujs:submit-button-formmethod', null);
element.data('ujs:submit-button-formaction', null);
} else if (element.is(rails.inputChangeSelector)) {
method = element.data('method');
url = element.data('url');
data = element.serialize();
if (element.data('params')) data = data + '&' + element.data('params');
} else if (element.is(rails.buttonClickSelector)) {
method = element.data('method') || 'get';
url = element.data('url');
data = element.serialize();
if (element.data('params')) data = data + '&' + element.data('params');
} else {
method = element.data('method');
url = rails.href(element);
data = element.data('params') || null;
}
options = {
type: method || 'GET', data: data, dataType: dataType,
// stopping the "ajax:beforeSend" event will cancel the ajax request
beforeSend: function(xhr, settings) {
if (settings.dataType === undefined) {
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
}
if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
element.trigger('ajax:send', xhr);
} else {
return false;
}
},
success: function(data, status, xhr) {
element.trigger('ajax:success', [data, status, xhr]);
},
complete: function(xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
},
error: function(xhr, status, error) {
element.trigger('ajax:error', [xhr, status, error]);
},
crossDomain: rails.isCrossDomain(url)
};
// There is no withCredentials for IE6-8 when
// "Enable native XMLHTTP support" is disabled
if (withCredentials) {
options.xhrFields = {
withCredentials: withCredentials
};
}
// Only pass url to `ajax` options if not blank
if (url) { options.url = url; }
return rails.ajax(options);
} else {
return false;
}
},
// Determines if the request is a cross domain request.
isCrossDomain: function(url) {
var originAnchor = document.createElement('a');
originAnchor.href = location.href;
var urlAnchor = document.createElement('a');
try {
urlAnchor.href = url;
// This is a workaround to a IE bug.
urlAnchor.href = urlAnchor.href;
// If URL protocol is false or is a string containing a single colon
// *and* host are false, assume it is not a cross-domain request
// (should only be the case for IE7 and IE compatibility mode).
// Otherwise, evaluate protocol and host of the URL against the origin
// protocol and host.
return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) ||
(originAnchor.protocol + '//' + originAnchor.host ===
urlAnchor.protocol + '//' + urlAnchor.host));
} catch (e) {
// If there is an error parsing the URL, assume it is crossDomain.
return true;
}
},
// Handles "data-method" on links such as:
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
handleMethod: function(link) {
var href = rails.href(link),
method = link.data('method'),
target = link.attr('target'),
csrfToken = rails.csrfToken(),
csrfParam = rails.csrfParam(),
form = $('<form method="post" action="' + href + '"></form>'),
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) {
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
}
if (target) { form.attr('target', target); }
form.hide().append(metadataInput).appendTo('body');
form.submit();
},
// Helper function that returns form elements that match the specified CSS selector
// If form is actually a "form" element this will return associated elements outside the from that have
// the html form attribute set
formElements: function(form, selector) {
return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
},
/* Disables form elements:
- Caches element value in 'ujs:enable-with' data store
- Replaces element text with value of 'data-disable-with' attribute
- Sets disabled property to true
*/
disableFormElements: function(form) {
rails.formElements(form, rails.disableSelector).each(function() {
rails.disableFormElement($(this));
});
},
disableFormElement: function(element) {
var method, replacement;
method = element.is('button') ? 'html' : 'val';
replacement = element.data('disable-with');
if (replacement !== undefined) {
element.data('ujs:enable-with', element[method]());
element[method](replacement);
}
element.prop('disabled', true);
element.data('ujs:disabled', true);
},
/* Re-enables disabled form elements:
- Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
- Sets disabled property to false
*/
enableFormElements: function(form) {
rails.formElements(form, rails.enableSelector).each(function() {
rails.enableFormElement($(this));
});
},
enableFormElement: function(element) {
var method = element.is('button') ? 'html' : 'val';
if (element.data('ujs:enable-with') !== undefined) {
element[method](element.data('ujs:enable-with'));
element.removeData('ujs:enable-with'); // clean up cache
}
element.prop('disabled', false);
element.removeData('ujs:disabled');
},
/* For 'data-confirm' attribute:
- Fires `confirm` event
- Shows the confirmation dialog
- Fires the `confirm:complete` event
Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
*/
allowAction: function(element) {
var message = element.data('confirm'),
answer = false, callback;
if (!message) { return true; }
if (rails.fire(element, 'confirm')) {
try {
answer = rails.confirm(message);
} catch (e) {
(console.error || console.log).call(console, e.stack || e);
}
callback = rails.fire(element, 'confirm:complete', [answer]);
}
return answer && callback;
},
// Helper function which checks for blank inputs in a form that match the specified CSS selector
blankInputs: function(form, specifiedSelector, nonBlank) {
var foundInputs = $(),
input,
valueToCheck,
radiosForNameWithNoneSelected,
radioName,
selector = specifiedSelector || 'input,textarea',
requiredInputs = form.find(selector),
checkedRadioButtonNames = {};
requiredInputs.each(function() {
input = $(this);
if (input.is('input[type=radio]')) {
// Don't count unchecked required radio as blank if other radio with same name is checked,
// regardless of whether same-name radio input has required attribute or not. The spec
// states https://www.w3.org/TR/html5/forms.html#the-required-attribute
radioName = input.attr('name');
// Skip if we've already seen the radio with this name.
if (!checkedRadioButtonNames[radioName]) {
// If none checked
if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) {
radiosForNameWithNoneSelected = form.find(
'input[type=radio][name="' + radioName + '"]');
foundInputs = foundInputs.add(radiosForNameWithNoneSelected);
}
// We only need to check each name once.
checkedRadioButtonNames[radioName] = radioName;
}
} else {
valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val();
if (valueToCheck === nonBlank) {
foundInputs = foundInputs.add(input);
}
}
});
return foundInputs.length ? foundInputs : false;
},
// Helper function which checks for non-blank inputs in a form that match the specified CSS selector
nonBlankInputs: function(form, specifiedSelector) {
return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
},
// Helper function, needed to provide consistent behavior in IE
stopEverything: function(e) {
$(e.target).trigger('ujs:everythingStopped');
e.stopImmediatePropagation();
return false;
},
// Replace element's html with the 'data-disable-with' after storing original html
// and prevent clicking on it
disableElement: function(element) {
var replacement = element.data('disable-with');
if (replacement !== undefined) {
element.data('ujs:enable-with', element.html()); // store enabled state
element.html(replacement);
}
element.bind('click.railsDisable', function(e) { // prevent further clicking
return rails.stopEverything(e);
});
element.data('ujs:disabled', true);
},
// Restore element to its original state which was disabled by 'disableElement' above
enableElement: function(element) {
if (element.data('ujs:enable-with') !== undefined) {
element.html(element.data('ujs:enable-with')); // set to old enabled state
element.removeData('ujs:enable-with'); // clean up cache
}
element.unbind('click.railsDisable'); // enable element
element.removeData('ujs:disabled');
}
};
if (rails.fire($document, 'rails:attachBindings')) {
$.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
// This event works the same as the load event, except that it fires every
// time the page is loaded.
//
// See https://github.com/rails/jquery-ujs/issues/357
// See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
$(window).on('pageshow.rails', function () {
$($.rails.enableSelector).each(function () {
var element = $(this);
if (element.data('ujs:disabled')) {
$.rails.enableFormElement(element);
}
});
$($.rails.linkDisableSelector).each(function () {
var element = $(this);
if (element.data('ujs:disabled')) {
$.rails.enableElement(element);
}
});
});
$document.delegate(rails.linkDisableSelector, 'ajax:complete', function() {
rails.enableElement($(this));
});
$document.delegate(rails.buttonDisableSelector, 'ajax:complete', function() {
rails.enableFormElement($(this));
});
$document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
if (!rails.allowAction(link)) return rails.stopEverything(e);
if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
if (rails.isRemote(link)) {
if (metaClick && (!method || method === 'GET') && !data) { return true; }
var handleRemote = rails.handleRemote(link);
// Response from rails.handleRemote() will either be false or a deferred object promise.
if (handleRemote === false) {
rails.enableElement(link);
} else {
handleRemote.fail( function() { rails.enableElement(link); } );
}
return false;
} else if (method) {
rails.handleMethod(link);
return false;
}
});
$document.delegate(rails.buttonClickSelector, 'click.rails', function(e) {
var button = $(this);
if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e);
if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button);
var handleRemote = rails.handleRemote(button);
// Response from rails.handleRemote() will either be false or a deferred object promise.
if (handleRemote === false) {
rails.enableFormElement(button);
} else {
handleRemote.fail( function() { rails.enableFormElement(button); } );
}
return false;
});
$document.delegate(rails.inputChangeSelector, 'change.rails', function(e) {
var link = $(this);
if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e);
rails.handleRemote(link);
return false;
});
$document.delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
var form = $(this),
remote = rails.isRemote(form),
blankRequiredInputs,
nonBlankFileInputs;
if (!rails.allowAction(form)) return rails.stopEverything(e);
// Skip other logic when required values are missing or file upload is present
if (form.attr('novalidate') === undefined) {
if (form.data('ujs:formnovalidate-button') === undefined) {
blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false);
if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
return rails.stopEverything(e);
}
} else {
// Clear the formnovalidate in case the next button click is not on a formnovalidate button
// Not strictly necessary to do here, since it is also reset on each button click, but just to be certain
form.data('ujs:formnovalidate-button', undefined);
}
}
if (remote) {
nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
if (nonBlankFileInputs) {
// Slight timeout so that the submit button gets properly serialized
// (make it easy for event handler to serialize form without disabled values)
setTimeout(function(){ rails.disableFormElements(form); }, 13);
var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
// Re-enable form elements if event bindings return false (canceling normal form submission)
if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
return aborted;
}
rails.handleRemote(form);
return false;
} else {
// Slight timeout so that the submit button gets properly serialized
setTimeout(function(){ rails.disableFormElements(form); }, 13);
}
});
$document.delegate(rails.formInputClickSelector, 'click.rails', function(event) {
var button = $(this);
if (!rails.allowAction(button)) return rails.stopEverything(event);
// Register the pressed submit button
var name = button.attr('name'),
data = name ? {name:name, value:button.val()} : null;
var form = button.closest('form');
if (form.length === 0) {
form = $('#' + button.attr('form'));
}
form.data('ujs:submit-button', data);
// Save attributes from button
form.data('ujs:formnovalidate-button', button.attr('formnovalidate'));
form.data('ujs:submit-button-formaction', button.attr('formaction'));
form.data('ujs:submit-button-formmethod', button.attr('formmethod'));
});
$document.delegate(rails.formSubmitSelector, 'ajax:send.rails', function(event) {
if (this === event.target) rails.disableFormElements($(this));
});
$document.delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
if (this === event.target) rails.enableFormElements($(this));
});
$(function(){
rails.refreshCSRFTokens();
});
}
})( jQuery );
//# sourceMappingURL=ex_admin_common.js.map