assets
This commit is contained in:
parent
b455b93618
commit
98804be89d
2
Gemfile
2
Gemfile
@ -26,7 +26,7 @@ gem 'cocoon', :git => 'git://github.com/nathanvda/cocoon'
|
|||||||
gem 'zeroclipboard-rails'
|
gem 'zeroclipboard-rails'
|
||||||
gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git'
|
gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git'
|
||||||
gem 'asset_sync'
|
gem 'asset_sync'
|
||||||
|
gem 'angularjs-rails'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'foreman'
|
gem 'foreman'
|
||||||
|
@ -54,6 +54,7 @@ GEM
|
|||||||
airbrake (3.1.16)
|
airbrake (3.1.16)
|
||||||
builder
|
builder
|
||||||
multi_json
|
multi_json
|
||||||
|
angularjs-rails (1.2.16)
|
||||||
arel (5.0.1.20140414130214)
|
arel (5.0.1.20140414130214)
|
||||||
asset_sync (1.0.0)
|
asset_sync (1.0.0)
|
||||||
activemodel
|
activemodel
|
||||||
@ -275,6 +276,7 @@ PLATFORMS
|
|||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
airbrake
|
airbrake
|
||||||
|
angularjs-rails
|
||||||
annotate!
|
annotate!
|
||||||
asset_sync
|
asset_sync
|
||||||
awesome_print
|
awesome_print
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
//
|
//
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
|
//= require angular
|
||||||
//= require bootstrap-tagsinput.js
|
//= require bootstrap-tagsinput.js
|
||||||
//= require cocoon
|
//= require cocoon
|
||||||
//= require zeroclipboard
|
//= require zeroclipboard
|
||||||
|
@ -31,7 +31,7 @@ module Vidpush
|
|||||||
config.assets.enabled = true
|
config.assets.enabled = true
|
||||||
config.assets.compile = true
|
config.assets.compile = true
|
||||||
config.assets.digest = false
|
config.assets.digest = false
|
||||||
config.assets.precompile += %w( campaign.css bootstrap-tagsinput.css )
|
config.assets.precompile += %w( campaign.css bootstrap-tagsinput.css bootstrap-tagsinput.js )
|
||||||
|
|
||||||
# Settings in config/environments/* take precedence over those specified here.
|
# Settings in config/environments/* take precedence over those specified here.
|
||||||
# Application configuration should go into files in config/initializers
|
# Application configuration should go into files in config/initializers
|
||||||
|
File diff suppressed because one or more lines are too long
BIN
public/assets/application-7e306a179fde491fc797650e05356504.js.gz
Normal file
BIN
public/assets/application-7e306a179fde491fc797650e05356504.js.gz
Normal file
Binary file not shown.
33853
public/assets/application-8e6433a42738ebd38ce838a1f6a8b334.js
Normal file
33853
public/assets/application-8e6433a42738ebd38ce838a1f6a8b334.js
Normal file
File diff suppressed because one or more lines are too long
BIN
public/assets/application-8e6433a42738ebd38ce838a1f6a8b334.js.gz
Normal file
BIN
public/assets/application-8e6433a42738ebd38ce838a1f6a8b334.js.gz
Normal file
Binary file not shown.
405
public/assets/bootstrap-tagsinput-2be1f8ed64e954aea0c1219e9a6ba653.js
vendored
Normal file
405
public/assets/bootstrap-tagsinput-2be1f8ed64e954aea0c1219e9a6ba653.js
vendored
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
(function ($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var defaultOptions = {
|
||||||
|
tagClass: function(item) {
|
||||||
|
return 'label label-info';
|
||||||
|
},
|
||||||
|
itemValue: function(item) {
|
||||||
|
return item ? item.toString() : item;
|
||||||
|
},
|
||||||
|
itemText: function(item) {
|
||||||
|
return this.itemValue(item);
|
||||||
|
},
|
||||||
|
freeInput : true
|
||||||
|
};
|
||||||
|
|
||||||
|
function TagsInput(element, options) {
|
||||||
|
this.itemsArray = [];
|
||||||
|
|
||||||
|
this.$element = $(element);
|
||||||
|
this.$element.hide();
|
||||||
|
|
||||||
|
this.isSelect = (element.tagName === 'SELECT');
|
||||||
|
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
|
||||||
|
this.objectItems = options && options.itemValue;
|
||||||
|
|
||||||
|
this.$container = $('<div class="bootstrap-tagsinput"></div>');
|
||||||
|
this.$input = $('<input size="100" type="text" />').appendTo(this.$container);
|
||||||
|
|
||||||
|
this.$element.after(this.$container);
|
||||||
|
|
||||||
|
this.build(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagsInput.prototype = {
|
||||||
|
constructor: TagsInput,
|
||||||
|
|
||||||
|
add: function(item, dontPushVal) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Ignore falsey values, except false
|
||||||
|
if (item !== false && !item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Throw an error when trying to add an object while the itemValue option was not set
|
||||||
|
if (typeof item === "object" && !self.objectItems)
|
||||||
|
throw("Can't add objects when itemValue option is not set");
|
||||||
|
|
||||||
|
// Ignore strings only containg whitespace
|
||||||
|
if (item.toString().match(/^\s*$/))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If SELECT but not multiple, remove current tag
|
||||||
|
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
|
||||||
|
self.remove(self.itemsArray[0]);
|
||||||
|
|
||||||
|
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
|
||||||
|
var items = item.split(',');
|
||||||
|
if (items.length > 1) {
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
this.add(items[i], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dontPushVal)
|
||||||
|
self.pushVal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore items allready added
|
||||||
|
var itemValue = self.options.itemValue(item),
|
||||||
|
itemText = self.options.itemText(item),
|
||||||
|
tagClass = self.options.tagClass(item);
|
||||||
|
|
||||||
|
if ($.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0])
|
||||||
|
return;
|
||||||
|
|
||||||
|
// register item in internal array and map
|
||||||
|
self.itemsArray.push(item);
|
||||||
|
|
||||||
|
// add a tag element
|
||||||
|
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + '"><span class="tag-item">' + htmlEncode(itemText) + '</span><span class="remove" data-role="remove"></span></span>');
|
||||||
|
$tag.data('item', item);
|
||||||
|
self.$input.before($tag);
|
||||||
|
|
||||||
|
// add <option /> if item represents a value not present in one of the <select />'s options
|
||||||
|
if (self.isSelect && !$('option[value="' + escape(itemValue) + '"]')[0]) {
|
||||||
|
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
|
||||||
|
$option.data('item', item);
|
||||||
|
$option.attr('value', itemValue);
|
||||||
|
self.$element.append($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dontPushVal)
|
||||||
|
self.pushVal();
|
||||||
|
|
||||||
|
self.$element.trigger($.Event('itemAdded', { item: item }));
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(item, dontPushVal) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.objectItems) {
|
||||||
|
if (typeof item === "object")
|
||||||
|
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } )[0];
|
||||||
|
else
|
||||||
|
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } )[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
$('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
|
||||||
|
$('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
|
||||||
|
self.itemsArray.splice(self.itemsArray.indexOf(item), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dontPushVal)
|
||||||
|
self.pushVal();
|
||||||
|
|
||||||
|
self.$element.trigger($.Event('itemRemoved', { item: item }));
|
||||||
|
},
|
||||||
|
|
||||||
|
removeAll: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$('.tag', self.$container).remove();
|
||||||
|
$('option', self.$element).remove();
|
||||||
|
|
||||||
|
while(self.itemsArray.length > 0)
|
||||||
|
self.itemsArray.pop();
|
||||||
|
|
||||||
|
self.pushVal();
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
var self = this;
|
||||||
|
$('.tag', self.$container).each(function() {
|
||||||
|
var $tag = $(this),
|
||||||
|
item = $tag.data('item'),
|
||||||
|
itemValue = self.options.itemValue(item),
|
||||||
|
itemText = self.options.itemText(item),
|
||||||
|
tagClass = self.options.tagClass(item);
|
||||||
|
|
||||||
|
// Update tag's class and inner text
|
||||||
|
$tag.attr('class', null);
|
||||||
|
$tag.addClass('tag ' + htmlEncode(tagClass));
|
||||||
|
$tag.contents().filter(function() {
|
||||||
|
return this.nodeType == 3;
|
||||||
|
})[0].nodeValue = htmlEncode(itemText);
|
||||||
|
|
||||||
|
if (self.isSelect) {
|
||||||
|
var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
|
||||||
|
option.attr('value', itemValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Returns the items added as tags
|
||||||
|
items: function() {
|
||||||
|
return this.itemsArray;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Assembly value by retrieving the value of each item, and set it on the element.
|
||||||
|
pushVal: function() {
|
||||||
|
var self = this,
|
||||||
|
val = $.map(self.items(), function(item) {
|
||||||
|
return self.options.itemValue(item).toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.$element.val(val, true).trigger('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function(options) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.options = $.extend({}, defaultOptions, options);
|
||||||
|
var typeahead = self.options.typeahead || {};
|
||||||
|
|
||||||
|
// When itemValue is set, freeInput should always be false
|
||||||
|
if (self.objectItems)
|
||||||
|
self.options.freeInput = false;
|
||||||
|
|
||||||
|
makeOptionItemFunction(self.options, 'itemValue');
|
||||||
|
makeOptionItemFunction(self.options, 'itemText');
|
||||||
|
makeOptionItemFunction(self.options, 'tagClass');
|
||||||
|
|
||||||
|
// for backwards compatibility, self.options.source is deprecated
|
||||||
|
if (self.options.source)
|
||||||
|
typeahead.source = self.options.source;
|
||||||
|
|
||||||
|
if (typeahead.source && $.fn.typeahead) {
|
||||||
|
makeOptionFunction(typeahead, 'source');
|
||||||
|
|
||||||
|
self.$input.typeahead({
|
||||||
|
source: function (query, process) {
|
||||||
|
function processItems(items) {
|
||||||
|
var texts = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var text = self.options.itemText(items[i]);
|
||||||
|
map[text] = items[i];
|
||||||
|
texts.push(text);
|
||||||
|
}
|
||||||
|
process(texts);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map = {};
|
||||||
|
var map = this.map,
|
||||||
|
data = typeahead.source(query);
|
||||||
|
|
||||||
|
if ($.isFunction(data.success)) {
|
||||||
|
// support for Angular promises
|
||||||
|
data.success(processItems);
|
||||||
|
} else {
|
||||||
|
// support for functions and jquery promises
|
||||||
|
$.when(data)
|
||||||
|
.then(processItems);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updater: function (text) {
|
||||||
|
self.add(this.map[text]);
|
||||||
|
},
|
||||||
|
matcher: function (text) {
|
||||||
|
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
|
||||||
|
},
|
||||||
|
sorter: function (texts) {
|
||||||
|
return texts.sort();
|
||||||
|
},
|
||||||
|
highlighter: function (text) {
|
||||||
|
var regex = new RegExp( '(' + this.query + ')', 'gi' );
|
||||||
|
return text.replace( regex, "<strong>$1</strong>" );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.$container.on('click', $.proxy(function(event) {
|
||||||
|
self.$input.focus();
|
||||||
|
}, self));
|
||||||
|
|
||||||
|
self.$container.on('keydown', 'input', $.proxy(function(event) {
|
||||||
|
var $input = $(event.target);
|
||||||
|
switch (event.which) {
|
||||||
|
// BACKSPACE
|
||||||
|
case 8:
|
||||||
|
if (doGetCaretPosition($input[0]) === 0) {
|
||||||
|
var prev = $input.prev();
|
||||||
|
if (prev) {
|
||||||
|
self.remove(prev.data('item'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// DELETE
|
||||||
|
case 46:
|
||||||
|
if (doGetCaretPosition($input[0]) === 0) {
|
||||||
|
var next = $input.next();
|
||||||
|
if (next) {
|
||||||
|
self.remove(next.data('item'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// LEFT ARROW
|
||||||
|
case 37:
|
||||||
|
// Try to move the input before the previous tag
|
||||||
|
var $prevTag = $input.prev();
|
||||||
|
if ($input.val().length === 0 && $prevTag[0]) {
|
||||||
|
$prevTag.before($input);
|
||||||
|
$input.focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// LEFT ARROW
|
||||||
|
case 39:
|
||||||
|
// Try to move the input before the previous tag
|
||||||
|
var $nextTag = $input.next();
|
||||||
|
if ($input.val().length === 0 && $nextTag[0]) {
|
||||||
|
$nextTag.after($input);
|
||||||
|
$input.focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 188: // COMMA
|
||||||
|
case 13: // ENTER
|
||||||
|
if (self.options.freeInput) {
|
||||||
|
self.add($input.val());
|
||||||
|
$input.val('');
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.attr('size', Math.max(100, $input.val().length));
|
||||||
|
}, self));
|
||||||
|
|
||||||
|
// Remove icon clicked
|
||||||
|
self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
|
||||||
|
self.remove($(event.target).closest('.tag').data('item'));
|
||||||
|
}, self));
|
||||||
|
|
||||||
|
if (self.$element[0].tagName === 'INPUT') {
|
||||||
|
self.add(self.$element.val());
|
||||||
|
} else {
|
||||||
|
$('option', self.$element).each(function() {
|
||||||
|
self.add($(this).attr('value'), true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Unbind events
|
||||||
|
self.$container.off('keypress', 'input');
|
||||||
|
self.$container.off('click', '[50role=remove]');
|
||||||
|
|
||||||
|
self.$container.remove();
|
||||||
|
self.$element.removeData('tagsinput');
|
||||||
|
self.$element.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
focus: function() {
|
||||||
|
this.$input.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register JQuery plugin
|
||||||
|
$.fn.tagsinput = function(arg1, arg2) {
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
this.each(function() {
|
||||||
|
var tagsinput = $(this).data('tagsinput');
|
||||||
|
|
||||||
|
// Initialize a new tags input
|
||||||
|
if (!tagsinput) {
|
||||||
|
tagsinput = new TagsInput(this, arg1);
|
||||||
|
$(this).data('tagsinput', tagsinput);
|
||||||
|
results.push(tagsinput);
|
||||||
|
|
||||||
|
if (this.tagName === 'SELECT') {
|
||||||
|
$('option', $(this)).attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init tags from $(this).val()
|
||||||
|
$(this).val($(this).val());
|
||||||
|
} else {
|
||||||
|
// Invoke function on existing tags input
|
||||||
|
var retVal = tagsinput[arg1](arg2);
|
||||||
|
if (retVal !== undefined)
|
||||||
|
results.push(retVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( typeof arg1 == 'string') {
|
||||||
|
// Return the results from the invoked function calls
|
||||||
|
return results.length > 1 ? results : results[0];
|
||||||
|
} else {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.tagsinput.Constructor = TagsInput;
|
||||||
|
|
||||||
|
// Most options support both a string or number as well as a function as
|
||||||
|
// option value. This function makes sure that the option with the given
|
||||||
|
// key in the given options is wrapped in a function
|
||||||
|
function makeOptionItemFunction(options, key) {
|
||||||
|
if (typeof options[key] !== 'function') {
|
||||||
|
var value = options[key];
|
||||||
|
options[key] = function(item) { return item[value]; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function makeOptionFunction(options, key) {
|
||||||
|
if (typeof options[key] !== 'function') {
|
||||||
|
var value = options[key];
|
||||||
|
options[key] = function() { return value; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// HtmlEncodes the given value
|
||||||
|
var htmlEncodeContainer = $('<div />');
|
||||||
|
function htmlEncode(value) {
|
||||||
|
if (value) {
|
||||||
|
return htmlEncodeContainer.text(value).html();
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the position of the caret in the given input field
|
||||||
|
// http://flightschool.acylt.com/devnotes/caret-position-woes/
|
||||||
|
function doGetCaretPosition(oField) {
|
||||||
|
var iCaretPos = 0;
|
||||||
|
if (document.selection) {
|
||||||
|
oField.focus ();
|
||||||
|
var oSel = document.selection.createRange();
|
||||||
|
oSel.moveStart ('character', -oField.value.length);
|
||||||
|
iCaretPos = oSel.text.length;
|
||||||
|
} else if (oField.selectionStart || oField.selectionStart == '0') {
|
||||||
|
iCaretPos = oField.selectionStart;
|
||||||
|
}
|
||||||
|
return (iCaretPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
|
||||||
|
});
|
||||||
|
})(window.jQuery);
|
Binary file not shown.
1
public/assets/bootstrap-tagsinput-8ff2834030c2c89549dbca9dba968f6c.js
vendored
Normal file
1
public/assets/bootstrap-tagsinput-8ff2834030c2c89549dbca9dba968f6c.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user