Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added tags to views

  • Loading branch information...
commit 22a264ae63a651cf5e5fb37c8bc70cea37f24451 1 parent a976125
@cpursley authored
View
3  app/views/dreams/index.html.erb
@@ -2,9 +2,8 @@
<div class="entry"><% @dreams.each do |dream| %>
<div class="matter">
<h2><%= link_to dream.title, dream %></h2>
- <div class="meta"><i class="icon-calendar"></i> <%= dream.created_at.strftime("%B %d, %Y") %> - <i class="icon-folder-open"></i> tag, tag - <i class="icon-comment"></i><%= dream.comments.count %></div>
+ <div class="meta"><i class="icon-calendar"></i> <%= dream.created_at.strftime("%B %d, %Y") %> - <i class="icon-folder-open"></i> <%= raw dream.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %> - <i class="icon-comment"></i><%= dream.comments.count %></div>
<p><%= dream.teaser %></p>
- <p><%= raw dream.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %></p>
</br>
</div>
<% end %>
View
3  app/views/dreams/show.html.erb
@@ -2,11 +2,10 @@
<div class="entry">
<div class="matter">
- <div class="meta"><i class="icon-calendar"></i><%= @dream.created_at.strftime("%B %d, %Y") %> - <i class="icon-folder-open"></i> tag, tag - <i class="icon-comment"></i><%= @dream.comments.count %></div>
+ <div class="meta"><i class="icon-calendar"></i><%= @dream.created_at.strftime("%B %d, %Y") %> - <i class="icon-folder-open"></i> <%= raw @dream.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %> - <i class="icon-comment"></i><%= @dream.comments.count %></div>
<div class="comment-author"><strong>By <%=@dream.user.fullname %></strong></div><br>
<p><%= @dream.body %></p>
- <p><%= raw @dream.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %></p>
</div>
</div>
View
16 public/javascripts/autocomplete-rails.js
@@ -0,0 +1,16 @@
+/*
+* Unobtrusive autocomplete
+*
+* To use it, you just have to include the HTML attribute autocomplete
+* with the autocomplete URL as the value
+*
+* Example:
+* <input type="text" data-autocomplete="/url/to/autocomplete">
+*
+* Optionally, you can use a jQuery selector to specify a field that can
+* be updated with the element id whenever you find a matching value
+*
+* Example:
+* <input type="text" data-autocomplete="/url/to/autocomplete" data-id-element="#id_field">
+*/
+(function(e){var t=null;e.fn.railsAutocomplete=function(){return this.live("focus",function(){this.railsAutoCompleter||(this.railsAutoCompleter=new e.railsAutocomplete(this))})},e.railsAutocomplete=function(e){_e=e,this.init(_e)},e.railsAutocomplete.fn=e.railsAutocomplete.prototype={railsAutocomplete:"0.0.1"},e.railsAutocomplete.fn.extend=e.railsAutocomplete.extend=e.extend,e.railsAutocomplete.fn.extend({init:function(t){function n(e){return e.split(t.delimiter)}function r(e){return n(e).pop().replace(/^\s+/,"")}t.delimiter=e(t).attr("data-delimiter")||null,e(t).autocomplete({source:function(n,i){e.getJSON(e(t).attr("data-autocomplete"),{term:r(n.term)},function(){arguments[0].length==0&&(arguments[0]=[],arguments[0][0]={id:"",label:"no existing match"}),e(arguments[0]).each(function(n,r){var i={};i[r.id]=r,e(t).data(i)}),i.apply(null,arguments)})},change:function(t,n){if(e(e(this).attr("data-id-element")).val()=="")return;e(e(this).attr("data-id-element")).val(n.item?n.item.id:"");var r=e.parseJSON(e(this).attr("data-update-elements")),i=n.item?e(this).data(n.item.id.toString()):{};if(r&&e(r["id"]).val()=="")return;for(var s in r)e(r[s]).val(n.item?i[s]:"")},search:function(){var e=r(this.value);if(e.length<2)return!1},focus:function(){return!1},select:function(r,i){var s=n(this.value);s.pop(),s.push(i.item.value);if(t.delimiter!=null)s.push(""),this.value=s.join(t.delimiter);else{this.value=s.join(""),e(this).attr("data-id-element")&&e(e(this).attr("data-id-element")).val(i.item.id);if(e(this).attr("data-update-elements")){var o=e(this).data(i.item.id.toString()),u=e.parseJSON(e(this).attr("data-update-elements"));for(var a in u)e(u[a]).val(o[a])}}var f=this.value;return e(this).bind("keyup.clearId",function(){e(this).val().trim()!=f.trim()&&(e(e(this).attr("data-id-element")).val(""),e(this).unbind("keyup.clearId"))}),e(t).trigger("railsAutocomplete.select",i),!1}})}}),e(document).ready(function(){e("input[data-autocomplete]").railsAutocomplete()})})(jQuery);
View
860 vendor/assets/javascripts/jquery.tokeninput.js
@@ -0,0 +1,860 @@
+/*
+ * jQuery Plugin: Tokenizing Autocomplete Text Entry
+ * Version 1.6.0
+ *
+ * Copyright (c) 2009 James Smith (http://loopj.com)
+ * Licensed jointly under the GPL and MIT licenses,
+ * choose which one suits your project best!
+ *
+ */
+
+(function ($) {
+// Default settings
+var DEFAULT_SETTINGS = {
+ // Search settings
+ method: "GET",
+ contentType: "json",
+ queryParam: "q",
+ searchDelay: 300,
+ minChars: 1,
+ propertyToSearch: "name",
+ jsonContainer: null,
+
+ // Display settings
+ hintText: "Type in a search term",
+ noResultsText: "No results",
+ searchingText: "Searching...",
+ deleteText: "&times;",
+ animateDropdown: true,
+
+ // Tokenization settings
+ tokenLimit: null,
+ tokenDelimiter: ",",
+ preventDuplicates: false,
+
+ // Output settings
+ tokenValue: "id",
+
+ // Prepopulation settings
+ prePopulate: null,
+ processPrePopulate: false,
+
+ // Manipulation settings
+ idPrefix: "token-input-",
+
+ // Formatters
+ resultsFormatter: function(item){ return "<li>" + item[this.propertyToSearch]+ "</li>" },
+ tokenFormatter: function(item) { return "<li><p>" + item[this.propertyToSearch] + "</p></li>" },
+
+ // Callbacks
+ onResult: null,
+ onAdd: null,
+ onDelete: null,
+ onReady: null
+};
+
+// Default classes to use when theming
+var DEFAULT_CLASSES = {
+ tokenList: "token-input-list",
+ token: "token-input-token",
+ tokenDelete: "token-input-delete-token",
+ selectedToken: "token-input-selected-token",
+ highlightedToken: "token-input-highlighted-token",
+ dropdown: "token-input-dropdown",
+ dropdownItem: "token-input-dropdown-item",
+ dropdownItem2: "token-input-dropdown-item2",
+ selectedDropdownItem: "token-input-selected-dropdown-item",
+ inputToken: "token-input-input-token"
+};
+
+// Input box position "enum"
+var POSITION = {
+ BEFORE: 0,
+ AFTER: 1,
+ END: 2
+};
+
+// Keys "enum"
+var KEY = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ ESCAPE: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ NUMPAD_ENTER: 108,
+ COMMA: 188
+};
+
+// Additional public (exposed) methods
+var methods = {
+ init: function(url_or_data_or_function, options) {
+ var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
+
+ return this.each(function () {
+ $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
+ });
+ },
+ clear: function() {
+ this.data("tokenInputObject").clear();
+ return this;
+ },
+ add: function(item) {
+ this.data("tokenInputObject").add(item);
+ return this;
+ },
+ remove: function(item) {
+ this.data("tokenInputObject").remove(item);
+ return this;
+ },
+ get: function() {
+ return this.data("tokenInputObject").getTokens();
+ }
+}
+
+// Expose the .tokenInput function to jQuery as a plugin
+$.fn.tokenInput = function (method) {
+ // Method calling and initialization logic
+ if(methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else {
+ return methods.init.apply(this, arguments);
+ }
+};
+
+// TokenList class for each input
+$.TokenList = function (input, url_or_data, settings) {
+ //
+ // Initialization
+ //
+
+ // Configure the data source
+ if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") {
+ // Set the url to query against
+ settings.url = url_or_data;
+
+ // If the URL is a function, evaluate it here to do our initalization work
+ var url = computeURL();
+
+ // Make a smart guess about cross-domain if it wasn't explicitly specified
+ if(settings.crossDomain === undefined) {
+ if(url.indexOf("://") === -1) {
+ settings.crossDomain = false;
+ } else {
+ settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
+ }
+ }
+ } else if(typeof(url_or_data) === "object") {
+ // Set the local data to search through
+ settings.local_data = url_or_data;
+ }
+
+ // Build class names
+ if(settings.classes) {
+ // Use custom class names
+ settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
+ } else if(settings.theme) {
+ // Use theme-suffixed default class names
+ settings.classes = {};
+ $.each(DEFAULT_CLASSES, function(key, value) {
+ settings.classes[key] = value + "-" + settings.theme;
+ });
+ } else {
+ settings.classes = DEFAULT_CLASSES;
+ }
+
+
+ // Save the tokens
+ var saved_tokens = [];
+
+ // Keep track of the number of tokens in the list
+ var token_count = 0;
+
+ // Basic cache to save on db hits
+ var cache = new $.TokenList.Cache();
+
+ // Keep track of the timeout, old vals
+ var timeout;
+ var input_val;
+
+ // Create a new text input an attach keyup events
+ var input_box = $("<input type=\"text\" autocomplete=\"off\">")
+ .css({
+ outline: "none"
+ })
+ .attr("id", settings.idPrefix + input.id)
+ .focus(function () {
+ if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
+ show_dropdown_hint();
+ }
+ })
+ .blur(function () {
+ hide_dropdown();
+ $(this).val("");
+ })
+ .bind("keyup keydown blur update", resize_input)
+ .keydown(function (event) {
+ var previous_token;
+ var next_token;
+
+ switch(event.keyCode) {
+ case KEY.LEFT:
+ case KEY.RIGHT:
+ case KEY.UP:
+ case KEY.DOWN:
+ if(!$(this).val()) {
+ previous_token = input_token.prev();
+ next_token = input_token.next();
+
+ if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
+ // Check if there is a previous/next token and it is selected
+ if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
+ deselect_token($(selected_token), POSITION.BEFORE);
+ } else {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+ } else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
+ // We are moving left, select the previous token if it exists
+ select_token($(previous_token.get(0)));
+ } else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
+ // We are moving right, select the next token if it exists
+ select_token($(next_token.get(0)));
+ }
+ } else {
+ var dropdown_item = null;
+
+ if(event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) {
+ dropdown_item = $(selected_dropdown_item).next();
+ } else {
+ dropdown_item = $(selected_dropdown_item).prev();
+ }
+
+ if(dropdown_item.length) {
+ select_dropdown_item(dropdown_item);
+ }
+ return false;
+ }
+ break;
+
+ case KEY.BACKSPACE:
+ previous_token = input_token.prev();
+
+ if(!$(this).val().length) {
+ if(selected_token) {
+ delete_token($(selected_token));
+ hidden_input.change();
+ } else if(previous_token.length) {
+ select_token($(previous_token.get(0)));
+ }
+
+ return false;
+ } else if($(this).val().length === 1) {
+ hide_dropdown();
+ } else {
+ // set a timeout just long enough to let this function finish.
+ setTimeout(function(){do_search();}, 5);
+ }
+ break;
+
+ case KEY.TAB:
+ case KEY.ENTER:
+ case KEY.NUMPAD_ENTER:
+ case KEY.COMMA:
+ if(selected_dropdown_item) {
+ add_token($(selected_dropdown_item).data("tokeninput"));
+ hidden_input.change();
+ return false;
+ }
+ break;
+
+ case KEY.ESCAPE:
+ hide_dropdown();
+ return true;
+
+ default:
+ if(String.fromCharCode(event.which)) {
+ // set a timeout just long enough to let this function finish.
+ setTimeout(function(){do_search();}, 5);
+ }
+ break;
+ }
+ });
+
+ // Keep a reference to the original input box
+ var hidden_input = $(input)
+ .hide()
+ .val("")
+ .focus(function () {
+ input_box.focus();
+ })
+ .blur(function () {
+ input_box.blur();
+ });
+
+ // Keep a reference to the selected token and dropdown item
+ var selected_token = null;
+ var selected_token_index = 0;
+ var selected_dropdown_item = null;
+
+ // The list to store the token items in
+ var token_list = $("<ul />")
+ .addClass(settings.classes.tokenList)
+ .click(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
+ toggle_select_token(li);
+ } else {
+ // Deselect selected token
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+
+ // Focus input box
+ input_box.focus();
+ }
+ })
+ .mouseover(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && selected_token !== this) {
+ li.addClass(settings.classes.highlightedToken);
+ }
+ })
+ .mouseout(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && selected_token !== this) {
+ li.removeClass(settings.classes.highlightedToken);
+ }
+ })
+ .insertBefore(hidden_input);
+
+ // The token holding the input box
+ var input_token = $("<li />")
+ .addClass(settings.classes.inputToken)
+ .appendTo(token_list)
+ .append(input_box);
+
+ // The list to store the dropdown items in
+ var dropdown = $("<div>")
+ .addClass(settings.classes.dropdown)
+ .appendTo("body")
+ .hide();
+
+ // Magic element to help us resize the text input
+ var input_resizer = $("<tester/>")
+ .insertAfter(input_box)
+ .css({
+ position: "absolute",
+ top: -9999,
+ left: -9999,
+ width: "auto",
+ fontSize: input_box.css("fontSize"),
+ fontFamily: input_box.css("fontFamily"),
+ fontWeight: input_box.css("fontWeight"),
+ letterSpacing: input_box.css("letterSpacing"),
+ whiteSpace: "nowrap"
+ });
+
+ // Pre-populate list if items exist
+ hidden_input.val("");
+ var li_data = settings.prePopulate || hidden_input.data("pre");
+ if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
+ li_data = settings.onResult.call(hidden_input, li_data);
+ }
+ if(li_data && li_data.length) {
+ $.each(li_data, function (index, value) {
+ insert_token(value);
+ checkTokenLimit();
+ });
+ }
+
+ // Initialization is done
+ if($.isFunction(settings.onReady)) {
+ settings.onReady.call();
+ }
+
+ //
+ // Public functions
+ //
+
+ this.clear = function() {
+ token_list.children("li").each(function() {
+ if ($(this).children("input").length === 0) {
+ delete_token($(this));
+ }
+ });
+ }
+
+ this.add = function(item) {
+ add_token(item);
+ }
+
+ this.remove = function(item) {
+ token_list.children("li").each(function() {
+ if ($(this).children("input").length === 0) {
+ var currToken = $(this).data("tokeninput");
+ var match = true;
+ for (var prop in item) {
+ if (item[prop] !== currToken[prop]) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ delete_token($(this));
+ }
+ }
+ });
+ }
+
+ this.getTokens = function() {
+ return saved_tokens;
+ }
+
+ //
+ // Private functions
+ //
+
+ function checkTokenLimit() {
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
+ input_box.hide();
+ hide_dropdown();
+ return;
+ }
+ }
+
+ function resize_input() {
+ if(input_val === (input_val = input_box.val())) {return;}
+
+ // Enter new content into resizer and resize input accordingly
+ var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ input_resizer.html(escaped);
+ input_box.width(input_resizer.width() + 30);
+ }
+
+ function is_printable_character(keycode) {
+ return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
+ (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
+ (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
+ (keycode >= 219 && keycode <= 222)); // ( \ ) '
+ }
+
+ // Inner function to a token to the list
+ function insert_token(item) {
+ var this_token = settings.tokenFormatter(item);
+ this_token = $(this_token)
+ .addClass(settings.classes.token)
+ .insertBefore(input_token);
+
+ // The 'delete token' button
+ $("<span>" + settings.deleteText + "</span>")
+ .addClass(settings.classes.tokenDelete)
+ .appendTo(this_token)
+ .click(function () {
+ delete_token($(this).parent());
+ hidden_input.change();
+ return false;
+ });
+
+ // Store data on the token
+ var token_data = {"id": item.id};
+ token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
+ $.data(this_token.get(0), "tokeninput", item);
+
+ // Save this token for duplicate checking
+ saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
+ selected_token_index++;
+
+ // Update the hidden input
+ update_hidden_input(saved_tokens, hidden_input);
+
+ token_count += 1;
+
+ // Check the token limit
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
+ input_box.hide();
+ hide_dropdown();
+ }
+
+ return this_token;
+ }
+
+ // Add a token to the token list based on user input
+ function add_token (item) {
+ var callback = settings.onAdd;
+
+ // See if the token already exists and select it if we don't want duplicates
+ if(token_count > 0 && settings.preventDuplicates) {
+ var found_existing_token = null;
+ token_list.children().each(function () {
+ var existing_token = $(this);
+ var existing_data = $.data(existing_token.get(0), "tokeninput");
+ if(existing_data && existing_data.id === item.id) {
+ found_existing_token = existing_token;
+ return false;
+ }
+ });
+
+ if(found_existing_token) {
+ select_token(found_existing_token);
+ input_token.insertAfter(found_existing_token);
+ input_box.focus();
+ return;
+ }
+ }
+
+ // Insert the new tokens
+ if(settings.tokenLimit == null || token_count < settings.tokenLimit) {
+ insert_token(item);
+ checkTokenLimit();
+ }
+
+ // Clear input box
+ input_box.val("");
+
+ // Don't show the help dropdown, they've got the idea
+ hide_dropdown();
+
+ // Execute the onAdd callback if defined
+ if($.isFunction(callback)) {
+ callback.call(hidden_input,item);
+ }
+ }
+
+ // Select a token in the token list
+ function select_token (token) {
+ token.addClass(settings.classes.selectedToken);
+ selected_token = token.get(0);
+
+ // Hide input box
+ input_box.val("");
+
+ // Hide dropdown if it is visible (eg if we clicked to select token)
+ hide_dropdown();
+ }
+
+ // Deselect a token in the token list
+ function deselect_token (token, position) {
+ token.removeClass(settings.classes.selectedToken);
+ selected_token = null;
+
+ if(position === POSITION.BEFORE) {
+ input_token.insertBefore(token);
+ selected_token_index--;
+ } else if(position === POSITION.AFTER) {
+ input_token.insertAfter(token);
+ selected_token_index++;
+ } else {
+ input_token.appendTo(token_list);
+ selected_token_index = token_count;
+ }
+
+ // Show the input box and give it focus again
+ input_box.focus();
+ }
+
+ // Toggle selection of a token in the token list
+ function toggle_select_token(token) {
+ var previous_selected_token = selected_token;
+
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+
+ if(previous_selected_token === token.get(0)) {
+ deselect_token(token, POSITION.END);
+ } else {
+ select_token(token);
+ }
+ }
+
+ // Delete a token from the token list
+ function delete_token (token) {
+ // Remove the id from the saved list
+ var token_data = $.data(token.get(0), "tokeninput");
+ var callback = settings.onDelete;
+
+ var index = token.prevAll().length;
+ if(index > selected_token_index) index--;
+
+ // Delete the token
+ token.remove();
+ selected_token = null;
+
+ // Show the input box and give it focus again
+ input_box.focus();
+
+ // Remove this token from the saved list
+ saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
+ if(index < selected_token_index) selected_token_index--;
+
+ // Update the hidden input
+ update_hidden_input(saved_tokens, hidden_input);
+
+ token_count -= 1;
+
+ if(settings.tokenLimit !== null) {
+ input_box
+ .show()
+ .val("")
+ .focus();
+ }
+
+ // Execute the onDelete callback if defined
+ if($.isFunction(callback)) {
+ callback.call(hidden_input,token_data);
+ }
+ }
+
+ // Update the hidden input box value
+ function update_hidden_input(saved_tokens, hidden_input) {
+ var token_values = $.map(saved_tokens, function (el) {
+ return el[settings.tokenValue];
+ });
+ hidden_input.val(token_values.join(settings.tokenDelimiter));
+
+ }
+
+ // Hide and clear the results dropdown
+ function hide_dropdown () {
+ dropdown.hide().empty();
+ selected_dropdown_item = null;
+ }
+
+ function show_dropdown() {
+ dropdown
+ .css({
+ position: "absolute",
+ top: $(token_list).offset().top + $(token_list).outerHeight(),
+ left: $(token_list).offset().left,
+ zindex: 999
+ })
+ .show();
+ }
+
+ function show_dropdown_searching () {
+ if(settings.searchingText) {
+ dropdown.html("<p>"+settings.searchingText+"</p>");
+ show_dropdown();
+ }
+ }
+
+ function show_dropdown_hint () {
+ if(settings.hintText) {
+ dropdown.html("<p>"+settings.hintText+"</p>");
+ show_dropdown();
+ }
+ }
+
+ // Highlight the query part of the search term
+ function highlight_term(value, term) {
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
+ }
+
+ function find_value_and_highlight_term(template, value, term) {
+ return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term));
+ }
+
+ // Populate the results dropdown with some results
+ function populate_dropdown (query, results) {
+ if(results && results.length) {
+ dropdown.empty();
+ var dropdown_ul = $("<ul>")
+ .appendTo(dropdown)
+ .mouseover(function (event) {
+ select_dropdown_item($(event.target).closest("li"));
+ })
+ .mousedown(function (event) {
+ add_token($(event.target).closest("li").data("tokeninput"));
+ hidden_input.change();
+ return false;
+ })
+ .hide();
+
+ $.each(results, function(index, value) {
+ var this_li = settings.resultsFormatter(value);
+
+ this_li = find_value_and_highlight_term(this_li ,value[settings.propertyToSearch], query);
+
+ this_li = $(this_li).appendTo(dropdown_ul);
+
+ if(index % 2) {
+ this_li.addClass(settings.classes.dropdownItem);
+ } else {
+ this_li.addClass(settings.classes.dropdownItem2);
+ }
+
+ if(index === 0) {
+ select_dropdown_item(this_li);
+ }
+
+ $.data(this_li.get(0), "tokeninput", value);
+ });
+
+ show_dropdown();
+
+ if(settings.animateDropdown) {
+ dropdown_ul.slideDown("fast");
+ } else {
+ dropdown_ul.show();
+ }
+ } else {
+ if(settings.noResultsText) {
+ dropdown.html("<p>"+settings.noResultsText+"</p>");
+ show_dropdown();
+ }
+ }
+ }
+
+ // Highlight an item in the results dropdown
+ function select_dropdown_item (item) {
+ if(item) {
+ if(selected_dropdown_item) {
+ deselect_dropdown_item($(selected_dropdown_item));
+ }
+
+ item.addClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = item.get(0);
+ }
+ }
+
+ // Remove highlighting from an item in the results dropdown
+ function deselect_dropdown_item (item) {
+ item.removeClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = null;
+ }
+
+ // Do a search and show the "searching" dropdown if the input is longer
+ // than settings.minChars
+ function do_search() {
+ var query = input_box.val().toLowerCase();
+
+ if(query && query.length) {
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+
+ if(query.length >= settings.minChars) {
+ show_dropdown_searching();
+ clearTimeout(timeout);
+
+ timeout = setTimeout(function(){
+ run_search(query);
+ }, settings.searchDelay);
+ } else {
+ hide_dropdown();
+ }
+ }
+ }
+
+ // Do the actual search
+ function run_search(query) {
+ var cache_key = query + computeURL();
+ var cached_results = cache.get(cache_key);
+ if(cached_results) {
+ populate_dropdown(query, cached_results);
+ } else {
+ // Are we doing an ajax search or local data search?
+ if(settings.url) {
+ var url = computeURL();
+ // Extract exisiting get params
+ var ajax_params = {};
+ ajax_params.data = {};
+ if(url.indexOf("?") > -1) {
+ var parts = url.split("?");
+ ajax_params.url = parts[0];
+
+ var param_array = parts[1].split("&");
+ $.each(param_array, function (index, value) {
+ var kv = value.split("=");
+ ajax_params.data[kv[0]] = kv[1];
+ });
+ } else {
+ ajax_params.url = url;
+ }
+
+ // Prepare the request
+ ajax_params.data[settings.queryParam] = query;
+ ajax_params.type = settings.method;
+ ajax_params.dataType = settings.contentType;
+ if(settings.crossDomain) {
+ ajax_params.dataType = "jsonp";
+ }
+
+ // Attach the success callback
+ ajax_params.success = function(results) {
+ if($.isFunction(settings.onResult)) {
+ results = settings.onResult.call(hidden_input, results);
+ }
+ cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results);
+
+ // only populate the dropdown if the results are associated with the active search query
+ if(input_box.val().toLowerCase() === query) {
+ populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
+ }
+ };
+
+ // Make the request
+ $.ajax(ajax_params);
+ } else if(settings.local_data) {
+ // Do the search through local data
+ var results = $.grep(settings.local_data, function (row) {
+ return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
+ });
+
+ if($.isFunction(settings.onResult)) {
+ results = settings.onResult.call(hidden_input, results);
+ }
+ cache.add(cache_key, results);
+ populate_dropdown(query, results);
+ }
+ }
+ }
+
+ // compute the dynamic URL
+ function computeURL() {
+ var url = settings.url;
+ if(typeof settings.url == 'function') {
+ url = settings.url.call();
+ }
+ return url;
+ }
+};
+
+// Really basic cache for the results
+$.TokenList.Cache = function (options) {
+ var settings = $.extend({
+ max_size: 500
+ }, options);
+
+ var data = {};
+ var size = 0;
+
+ var flush = function () {
+ data = {};
+ size = 0;
+ };
+
+ this.add = function (query, results) {
+ if(size > settings.max_size) {
+ flush();
+ }
+
+ if(!data[query]) {
+ size += 1;
+ }
+
+ data[query] = results;
+ };
+
+ this.get = function (query) {
+ return data[query];
+ };
+};
+}(jQuery));
View
122 vendor/assets/stylesheets/token-input-facebook.css
@@ -0,0 +1,122 @@
+/* Example tokeninput style #2: Facebook style */
+ul.token-input-list-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ width: 400px;
+ border: 1px solid #8496ba;
+ cursor: text;
+ font-size: 12px;
+ font-family: Verdana;
+ min-height: 1px;
+ z-index: 999;
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+ list-style-type: none;
+ clear: left;
+}
+
+ul.token-input-list-facebook li input {
+ border: 0;
+ width: 100px;
+ padding: 3px 8px;
+ background-color: white;
+ margin: 2px 0;
+ -webkit-appearance: caret;
+}
+
+li.token-input-token-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 15px;
+ margin: 3px;
+ padding: 1px 3px;
+ background-color: #eff2f7;
+ color: #000;
+ cursor: default;
+ border: 1px solid #ccd5e4;
+ font-size: 11px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ float: left;
+ white-space: nowrap;
+}
+
+li.token-input-token-facebook p {
+ display: inline;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-token-facebook span {
+ color: #a6b3cf;
+ margin-left: 5px;
+ font-weight: bold;
+ cursor: pointer;
+}
+
+li.token-input-selected-token-facebook {
+ background-color: #5670a6;
+ border: 1px solid #3b5998;
+ color: #fff;
+}
+
+li.token-input-input-token-facebook {
+ float: left;
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+div.token-input-dropdown-facebook {
+ position: absolute;
+ width: 400px;
+ background-color: #fff;
+ overflow: hidden;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ cursor: default;
+ font-size: 11px;
+ font-family: Verdana;
+ z-index: 1;
+}
+
+div.token-input-dropdown-facebook p {
+ margin: 0;
+ padding: 5px;
+ font-weight: bold;
+ color: #777;
+}
+
+div.token-input-dropdown-facebook ul {
+ margin: 0;
+ padding: 0;
+}
+
+div.token-input-dropdown-facebook ul li {
+ background-color: #fff;
+ padding: 3px;
+ margin: 0;
+ list-style-type: none;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook {
+ background-color: #fff;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook {
+ background-color: #fff;
+}
+
+div.token-input-dropdown-facebook ul li em {
+ font-weight: bold;
+ font-style: normal;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook {
+ background-color: #3b5998;
+ color: #fff;
+}
View
204 vendor/assets/stylesheets/token-input-mac.css
@@ -0,0 +1,204 @@
+/* Example tokeninput style #2: Mac Style */
+fieldset.token-input-mac {
+ position: relative;
+ padding: 0;
+ margin: 5px 0;
+ background: #fff;
+ width: 400px;
+ border: 1px solid #A4BDEC;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+}
+
+fieldset.token-input-mac.token-input-dropdown-mac {
+ border-radius: 10px 10px 0 0;
+ -moz-border-radius: 10px 10px 0 0;
+ -webkit-border-radius: 10px 10px 0 0;
+ box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+ -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+ -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+}
+
+ul.token-input-list-mac {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ cursor: text;
+ font-size: 12px;
+ font-family: Verdana;
+ min-height: 1px;
+ z-index: 999;
+ margin: 0;
+ padding: 3px;
+ background: transparent;
+}
+
+ul.token-input-list-mac.error {
+ border: 1px solid #C52020;
+}
+
+ul.token-input-list-mac li {
+ list-style-type: none;
+}
+
+li.token-input-token-mac p {
+ display: inline;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-token-mac span {
+ color: #a6b3cf;
+ margin-left: 5px;
+ font-weight: bold;
+ cursor: pointer;
+}
+
+/* TOKENS */
+
+li.token-input-token-mac {
+ font-family: "Lucida Grande", Arial, serif;
+ font-size: 9pt;
+ line-height: 12pt;
+ overflow: hidden;
+ height: 16px;
+ margin: 3px;
+ padding: 0 10px;
+ background: none;
+ background-color: #dee7f8;
+ color: #000;
+ cursor: default;
+ border: 1px solid #a4bdec;
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+ float: left;
+}
+
+li.token-input-highlighted-token-mac {
+ background-color: #bbcef1;
+ border: 1px solid #598bec;
+ color: #000;
+}
+
+li.token-input-selected-token-mac {
+ background-color: #598bec;
+ border: 1px solid transparent;
+ color: #fff;
+}
+
+li.token-input-highlighted-token-mac span.token-input-delete-token-mac {
+ color: #000;
+}
+
+li.token-input-selected-token-mac span.token-input-delete-token-mac {
+ color: #fff;
+}
+
+li.token-input-input-token-mac {
+ border: none;
+ background: transparent;
+ float: left;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-input-token-mac input {
+ border: 0;
+ width: 100px;
+ padding: 3px;
+ background-color: transparent;
+ margin: 0;
+}
+
+div.token-input-dropdown-mac {
+ position: absolute;
+ border: 1px solid #A4BDEC;
+ border-top: none;
+ left: -1px;
+ right: -1px;
+ background-color: #fff;
+ overflow: hidden;
+ cursor: default;
+ font-size: 10pt;
+ font-family: "Lucida Grande", Arial, serif;
+ padding: 5px;
+ border-radius: 0 0 10px 10px;
+ -moz-border-radius: 0 0 10px 10px;
+ -webkit-border-radius: 0 0 10px 10px;
+ box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+ -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+ -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
+ clip:rect(0px, 1000px, 1000px, -10px);
+}
+
+div.token-input-dropdown-mac p {
+ font-size: 8pt;
+ margin: 0;
+ padding: 0 5px;
+ font-style: italic;
+ color: #aaa;
+}
+
+div.token-input-dropdown-mac h3.token-input-dropdown-category-mac {
+ font-family: "Lucida Grande", Arial, serif;
+ font-size: 10pt;
+ font-weight: bold;
+ border: none;
+ padding: 0 5px;
+ margin: 0;
+}
+
+div.token-input-dropdown-mac ul {
+ margin: 0;
+ padding: 0;
+}
+
+div.token-input-dropdown-mac ul li {
+ list-style-type: none;
+ cursor: pointer;
+ background: none;
+ background-color: #fff;
+ margin: 0;
+ padding: 0 0 0 25px;
+}
+
+div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac {
+ background-color: #fff;
+}
+
+div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac.odd {
+ background-color: #ECF4F9;
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+}
+
+div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac span.token-input-dropdown-item-description-mac {
+ float: right;
+ font-size: 8pt;
+ font-style: italic;
+ padding: 0 10px 0 0;
+ color: #999;
+}
+
+div.token-input-dropdown-mac ul li strong {
+ font-weight: bold;
+ text-decoration: underline;
+ font-style: none;
+}
+
+div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac,
+div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd {
+ background-color: #598bec;
+ color: #fff;
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+}
+
+div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac span.token-input-dropdown-item-description-mac,
+div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd span.token-input-dropdown-item-description-mac {
+ color: #fff;
+}
View
113 vendor/assets/stylesheets/token-input.css
@@ -0,0 +1,113 @@
+/* Example tokeninput style #1: Token vertical list*/
+ul.token-input-list {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ width: 400px;
+ border: 1px solid #999;
+ cursor: text;
+ font-size: 12px;
+ font-family: Verdana;
+ z-index: 999;
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+ list-style-type: none;
+ clear: left;
+}
+
+ul.token-input-list li {
+ list-style-type: none;
+}
+
+ul.token-input-list li input {
+ border: 0;
+ width: 350px;
+ padding: 3px 8px;
+ background-color: white;
+ -webkit-appearance: caret;
+}
+
+li.token-input-token {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ margin: 3px;
+ padding: 3px 5px;
+ background-color: #d0efa0;
+ color: #000;
+ font-weight: bold;
+ cursor: default;
+ display: block;
+}
+
+li.token-input-token p {
+ float: left;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-token span {
+ float: right;
+ color: #777;
+ cursor: pointer;
+}
+
+li.token-input-selected-token {
+ background-color: #08844e;
+ color: #fff;
+}
+
+li.token-input-selected-token span {
+ color: #bbb;
+}
+
+div.token-input-dropdown {
+ position: absolute;
+ width: 400px;
+ background-color: #fff;
+ overflow: hidden;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ cursor: default;
+ font-size: 12px;
+ font-family: Verdana;
+ z-index: 1;
+}
+
+div.token-input-dropdown p {
+ margin: 0;
+ padding: 5px;
+ font-weight: bold;
+ color: #777;
+}
+
+div.token-input-dropdown ul {
+ margin: 0;
+ padding: 0;
+}
+
+div.token-input-dropdown ul li {
+ background-color: #fff;
+ padding: 3px;
+ list-style-type: none;
+}
+
+div.token-input-dropdown ul li.token-input-dropdown-item {
+ background-color: #fafafa;
+}
+
+div.token-input-dropdown ul li.token-input-dropdown-item2 {
+ background-color: #fff;
+}
+
+div.token-input-dropdown ul li em {
+ font-weight: bold;
+ font-style: normal;
+}
+
+div.token-input-dropdown ul li.token-input-selected-dropdown-item {
+ background-color: #d0efa0;
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.