PageRenderTime 56ms CodeModel.GetById 10ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/Resources/public/js/bootstrap-tagmanager.js

https://bitbucket.org/cmedia/cmediatagbundle
JavaScript | 460 lines | 331 code | 65 blank | 64 comment | 101 complexity | 982b87b55f274652b69be6fe1b7fd165 MD5 | raw file
  1/* ===================================================
  2 * bootstrap-tagmanager.js v2.2
  3 * http://welldonethings.com/tags/manager
  4 * ===================================================
  5 * Copyright 2012 Max Favilli
  6 *
  7 * Licensed under the Mozilla Public License, Version 2.0 You may not use this work except in compliance with the License.
  8 *
  9 * http://www.mozilla.org/MPL/2.0/
 10 *
 11 * Unless required by applicable law or agreed to in writing, software
 12 * distributed under the License is distributed on an "AS IS" BASIS,
 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14 * See the License for the specific language governing permissions and
 15 * limitations under the License.
 16 * ========================================================== */
 17
 18"use strict";
 19
 20(function (jQuery) {
 21  if (typeof console === "undefined" || typeof console.log === "undefined") {
 22    console = {};
 23    console.log = function () { };
 24  }
 25
 26  jQuery.fn.tagsManager = function (options,tagToManipulate) {
 27    var tagManagerOptions = {
 28      prefilled: null,
 29      CapitalizeFirstLetter: false,
 30      preventSubmitOnEnter: true,
 31      typeahead: false,
 32      typeaheadAjaxSource: null,
 33      typeaheadAjaxPolling: false,
 34      typeaheadSource: null,
 35      AjaxPush: null,
 36      delimeters: [44, 188, 13],
 37      backspace: [8],
 38      maxTags: 0,
 39      hiddenTagListName: null,
 40      hiddenTagListId: null,
 41      deleteTagsOnBackspace: true,
 42      tagsContainer: null,
 43      tagCloseIcon: 'x'
 44    };
 45
 46    jQuery.extend(tagManagerOptions, options);
 47
 48    if (tagManagerOptions.hiddenTagListName === null) {
 49      tagManagerOptions.hiddenTagListName = "hidden-" + this.attr('name');
 50    }
 51
 52    var obj = this;
 53    var objName = obj.attr('name').replace(/[^\w]/g, '_');
 54    var queuedTag = "";
 55    var delimeters = tagManagerOptions.delimeters;
 56    var backspace = tagManagerOptions.backspace;
 57
 58    var setupTypeahead = function () {
 59      if (!obj.typeahead) return;
 60
 61      if (tagManagerOptions.typeaheadSource != null && jQuery.isFunction(tagManagerOptions.typeaheadSource)) {
 62        obj.typeahead({ source: tagManagerOptions.typeaheadSource });
 63      } else if (tagManagerOptions.typeaheadSource != null) {
 64        obj.typeahead();
 65        obj.data('active', true);
 66        obj.data('typeahead').source = tagManagerOptions.typeaheadSource;
 67        obj.data('active', false);
 68      } else if (tagManagerOptions.typeaheadAjaxSource != null) {
 69        if (!tagManagerOptions.typeaheadAjaxPolling) {
 70          obj.typeahead();
 71          jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource+obj.attr('value'), function (data) {
 72            var sourceAjaxArray = [];
 73            if (data != undefined) {
 74              sourceAjaxArray.length = 0;
 75              jQuery.each(data, function (key, val) {
 76                // var a = 1;
 77                sourceAjaxArray.push(val);
 78                obj.data('active', true);
 79                obj.data('typeahead').source = sourceAjaxArray;
 80                obj.data('active', false);
 81              });
 82            }
 83          });
 84        } else if (tagManagerOptions.typeaheadAjaxPolling) {
 85          obj.typeahead({ source: ajaxPolling });
 86        }
 87      } else if (tagManagerOptions.typeaheadDelegate) {
 88        obj.typeahead(tagManagerOptions.typeaheadDelegate)
 89      }
 90    };
 91
 92    var ajaxPolling = function (query, process) {
 93      jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource, function (data) {
 94        var sourceAjaxArray = [];
 95        if (data != undefined && data.tags != undefined) {
 96          sourceAjaxArray.length = 0;
 97          jQuery.each(data.tags, function (key, val) {
 98            var a = 1;
 99            sourceAjaxArray.push(val.tag);
100          });
101          process(sourceAjaxArray);
102        }
103      });
104    };
105
106    var trimTag = function (tag) {
107      var txt = jQuery.trim(tag);
108
109      var l = txt.length;
110      var t = 0;
111
112      for (var i = l - 1; i >= 0; i--) {
113        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
114        t++;
115      }
116
117      txt = txt.substring(0, l - t);
118      l = txt.length;
119      t = 0;
120
121      //remove from head
122      for (var i = 0; i < l; i++) {
123        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
124        t++;
125      }
126
127      txt = txt.substring(t, l);
128      return txt;
129    };
130
131    //$(this).on('popTag', function (e){
132    //  var tlis = obj.data("tlis");
133    //  var tlid = obj.data("tlid");
134
135    //  if (tlid.length > 0) {
136    //    var tagId = tlid.pop();
137    //    tlis.pop();
138    //    // console.log("TagIdToRemove: " + tagId);
139    //    jQuery("#" + objName + "_" + tagId).remove();
140    //    refreshHiddenTagList();
141    //    // console.log(tlis);
142    //  }
143    //});
144
145    var popTag = function () {
146      var tlis = obj.data("tlis");
147      var tlid = obj.data("tlid");
148
149      if (tlid.length > 0) {
150        var tagId = tlid.pop();
151        tlis.pop();
152        // console.log("TagIdToRemove: " + tagId);
153        jQuery("#" + objName + "_" + tagId).remove();
154        refreshHiddenTagList();
155        // console.log(tlis);
156      }
157    };
158
159    var empty = function () {
160      var tlis = obj.data("tlis");
161      var tlid = obj.data("tlid");
162
163      while (tlid.length > 0) {
164        var tagId = tlid.pop();
165        tlis.pop();
166        // console.log("TagIdToRemove: " + tagId);
167        jQuery("#" + objName + "_" + tagId).remove();
168        refreshHiddenTagList();
169        // console.log(tlis);
170      }
171    };
172
173    var refreshHiddenTagList = function () {
174      var tlis = obj.data("tlis");
175      var lhiddenTagList = obj.data("lhiddenTagList");
176
177      if (lhiddenTagList == undefined)
178        return;
179      jQuery(lhiddenTagList).val(tlis.join(",")).change();
180    };
181
182    var spliceTag = function (tagId) {
183      var tlis = obj.data("tlis");
184      var tlid = obj.data("tlid");
185
186      var p = jQuery.inArray(tagId, tlid)
187
188      // console.log("TagIdToRemove: " + tagId);
189      // console.log("position: " + p);
190
191      if (-1 != p) {
192        jQuery("#" + objName + "_" + tagId).remove();
193        tlis.splice(p, 1);
194        tlid.splice(p, 1);
195        refreshHiddenTagList();
196        // console.log(tlis);
197      }
198
199      if (tagManagerOptions.maxTags > 0 && tlis.length < tagManagerOptions.maxTags) {
200        obj.show();
201      }
202    };
203
204    var pushTag = function (tag) {
205      if (!tag || tag.length <= 0) return;
206
207      if (tagManagerOptions.CapitalizeFirstLetter && tag.length > 1) {
208        tag = tag.charAt(0).toUpperCase() + tag.slice(1).toLowerCase();
209      }
210
211      // call the validator (if any) and do not let the tag pass if invalid
212      if (tagManagerOptions.validator !== undefined) {
213        if (tagManagerOptions.validator(tag) !== true) return;
214      }
215
216      var tlis = obj.data("tlis");
217      var tlid = obj.data("tlid");
218
219      // dont accept new tags beyond the defined maximum
220      if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) return;
221
222      var alreadyInList = false;
223      var p = jQuery.inArray(tag, tlis);
224      if (-1 != p) {
225        // console.log("tag:" + tag + " !!already in list!!");
226        alreadyInList = true;
227      }
228
229      if (alreadyInList) {
230        var pTagId = tlid[p];
231        jQuery("#" + objName + "_" + pTagId).stop()
232           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
233           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
234           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
235           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
236           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
237           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100);
238      } else {
239        var max = Math.max.apply(null, tlid);
240        max = max == -Infinity ? 0 : max;
241
242        var tagId = ++max;
243        tlis.push(tag);
244        tlid.push(tagId);
245
246        if (tagManagerOptions.AjaxPush != null) {
247          jQuery.post(tagManagerOptions.AjaxPush, { tag: tag });
248        }
249
250        // console.log("tagList: " + tlis);
251
252        var newTagId = objName + '_' + tagId;
253        var newTagRemoveId = objName + '_Remover_' + tagId;
254        var html = '';
255        html += '<span class="myTag" id="' + newTagId + '"><span>' + tag + '&nbsp;&nbsp;</span><a href="#" class="myTagRemover" id="' + newTagRemoveId + '" TagIdToRemove="' + tagId + '" title="Remove">' + tagManagerOptions.tagCloseIcon + '</a></span>';
256
257        if (tagManagerOptions.tagsContainer != null) {
258          jQuery(tagManagerOptions.tagsContainer).append(html)
259        } else {
260          obj.before(html);
261        }
262
263        jQuery("#" + newTagRemoveId).on("click", obj, function (e) {
264          e.preventDefault();
265          var TagIdToRemove = parseInt(jQuery(this).attr("TagIdToRemove"));
266          spliceTag(TagIdToRemove, e.data);
267        });
268
269        refreshHiddenTagList();
270
271        if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) {
272          obj.hide();
273        }
274      }
275      obj.val("");
276    };
277
278    return this.each(function () {
279
280      if (typeof options == 'string') {
281        switch (options) {
282          case "empty":
283            empty();
284            break;
285          case "popTag":
286            popTag();
287            break;
288          case "pushTag":
289            pushTag(tagToManipulate);
290            break;
291        }
292        return;
293      }
294
295      //let's store some instance specific data directly into the DOM object
296      var tlis = new Array();
297      var tlid = new Array();
298      obj.data("tlis", tlis); //list of string tags
299      obj.data("tlid", tlid); //list of ID of the string tags
300
301      if (tagManagerOptions.hiddenTagListId == null) { /* if hidden input not given default activity */
302        var html = "";
303        html += "<input name='" + tagManagerOptions.hiddenTagListName + "' type='hidden' value=''/>";
304        obj.after(html);
305        obj.data("lhiddenTagList", 
306           obj.siblings("input[name='" + tagManagerOptions.hiddenTagListName + "']")[0]
307        );
308      } else {
309        obj.data("lhiddenTagList", jQuery('#' + tagManagerOptions.hiddenTagListId))
310      }
311
312      if (tagManagerOptions.typeahead) {
313        setupTypeahead();
314        //obj.typeahead({ source: SourceArray })
315      }
316
317      obj.on("focus", function (e) {
318        if (jQuery(this).popover) {
319          jQuery(this).popover("hide");
320          //jQuery(this).popover = null;
321        }
322      });
323
324      // disable submit on enter for this input field
325      obj.on("keypress", function (e) {
326        if (jQuery(this).popover) {
327          jQuery(this).popover("hide");
328          //jQuery(this).popover = null;
329        }
330        if (tagManagerOptions.preventSubmitOnEnter) {
331          if (e.which == 13) {
332            e.cancelBubble = true;
333            e.returnValue = false;
334            e.stopPropagation();
335            e.preventDefault();
336            //e.keyCode = 9;
337          }
338        }
339        // console.log("keyup: " + e.keyCode);
340      });
341
342      obj.on("keyup", obj, function (e) {
343        var p = jQuery.inArray(e.which, delimeters);
344        if (-1 != p) {
345          //user just entered a valid delimeter
346          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
347          user_input = trimTag(user_input);
348          pushTag(user_input, e.data);
349          // console.log("pushTag: keyup");
350        }
351
352        // console.log("keyup: " + e.which);
353      });
354
355      if (tagManagerOptions.deleteTagsOnBackspace) {
356        obj.on("keydown", obj, function (e) {
357          var p = jQuery.inArray(e.which, backspace);
358          if (-1 != p) {
359            //user just entered backspace or equivalent
360            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
361            var i = user_input.length;
362            if (i <= 0) {
363              // console.log("backspace detected");
364              e.preventDefault();
365              popTag();
366            }
367          }
368        });
369      }
370
371      obj.change(function (e) {
372        e.cancelBubble = true;
373        e.returnValue = false;
374        e.stopPropagation();
375        e.preventDefault();
376
377        var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
378        var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
379        var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
380        var is_safari = navigator.userAgent.indexOf("Safari") > -1;
381
382        if (!is_chrome && !is_safari)
383          jQuery(this).focus();
384
385        // console.log('Handler for .change() called, value selected:' + obj.val());
386        var ao = jQuery(".typeahead:visible");
387        if (ao[0] != undefined) {
388          // console.log('change: typeaheadIsVisible is visible');
389          //when the user click with the mouse on the typeahead li element we get the change event fired twice, once when the input field loose focus and later with the input field value is replaced with li value
390          var user_input = $(this).data('typeahead').$menu.find('.active').attr('data-value');
391          user_input = trimTag(user_input);
392          if (queuedTag == obj.val() && queuedTag == user_input) {
393            queuedTag = "";
394            obj.val(queuedTag);
395          } else {
396            pushTag(user_input);
397            queuedTag = user_input;
398            // console.log('Handler for .change() called, typeahead value pushed:' + queuedTag);
399          }
400        } else {
401          // console.log('change: typeaheadIsVisible is NOT visible');
402          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
403          user_input = trimTag(user_input);
404          pushTag(user_input);
405          // console.log("pushTag: change ");
406        }
407
408      });
409
410      if (1 == 1 || !tagManagerOptions.typeahead) {
411        obj.on("blur", function (e) {
412          //lost focus
413          e.cancelBubble = true;
414          e.returnValue = false;
415          e.stopPropagation();
416          e.preventDefault();
417
418          var push = true;
419          if (tagManagerOptions.typeahead) {
420            var ao = jQuery(".typeahead:visible");
421            if (ao[0] != undefined) {
422              // console.log('blur: typeaheadIsVisible is visible');
423              push = false;
424            } else {
425              // console.log('blur: typeaheadIsVisible is NOT visible');
426              push = true;
427            }
428          }
429
430          if (push) {
431            // console.log('lost focus');
432            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
433            user_input = trimTag(user_input);
434            pushTag(user_input);
435            // console.log("pushTag: blur");
436          }
437        });
438      }
439
440      if (tagManagerOptions.prefilled != null) {
441        if (typeof (tagManagerOptions.prefilled) == "object") {
442          var pta = tagManagerOptions.prefilled;
443          jQuery.each(pta, function (key, val) {
444            var a = 1;
445            pushTag(val, obj);
446          });
447        } else if (typeof (tagManagerOptions.prefilled) == "string") {
448          var pta = tagManagerOptions.prefilled.split(',');
449
450          jQuery.each(pta, function (key, val) {
451            var a = 1;
452            pushTag(val, obj);
453          });
454
455        }
456      }
457    });
458
459  }
460})(jQuery);