bootstrap-tag.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* ==========================================================
  2. * bootstrap-tag.js v2.2.2
  3. * https://github.com/fdeschenes/bootstrap-tag
  4. * ==========================================================
  5. * Copyright 2012 Francois Deschenes.
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * ========================================================== */
  19. // https://github.com/soliantconsulting/tagmanager/blob/master/tagmanager.js
  20. !function ( $ ) {
  21. 'use strict' // jshint ;_;
  22. var Tag = function ( element, options ) {
  23. this.element = $(element)
  24. this.options = $.extend(true, {}, $.fn.tag.defaults, options)
  25. this.values = $.grep($.map(this.element.val().split(','), $.trim), function ( value ) { return value.length > 0 })
  26. this.show()
  27. }
  28. Tag.prototype = {
  29. constructor: Tag
  30. , show: function () {
  31. var that = this
  32. that.element.parent().prepend(that.element.detach().attr('type', 'hidden'))
  33. that.element
  34. .wrap($('<div class="tags ' + (that.options.containerClasses ? that.options.containerClasses : '') + '">'))
  35. .parent()
  36. .on('click', function () {
  37. that.input.focus()
  38. })
  39. if (that.values.length) {
  40. $.each(that.values, function () {
  41. that.createBadge(this)
  42. })
  43. }
  44. that.input = $('<input type="text" class="' + (that.options.inputClasses ? that.options.inputClasses : '') + '">')
  45. .attr('placeholder', that.options.placeholder)
  46. .insertAfter(that.element)
  47. .on('focus', function () {
  48. that.element.parent().addClass('tags-hover')
  49. })
  50. .on('blur', function () {
  51. that.process()
  52. that.element.parent().removeClass('tags-hover')
  53. that.element.siblings('.tag').removeClass('tag-important')
  54. })
  55. .on('keydown', function ( event ) {
  56. if ( event.keyCode == 188 || event.keyCode == 13 || event.keyCode == 9 ) {
  57. if ( $.trim($(this).val()) && ( !that.element.siblings('.typeahead').length || that.element.siblings('.typeahead').is(':hidden') ) ) {
  58. if ( event.keyCode != 9 ) event.preventDefault()
  59. that.process()
  60. } else if ( event.keyCode == 188 ) {
  61. if ( !that.element.siblings('.typeahead').length || that.element.siblings('.typeahead').is(':hidden') ) {
  62. event.preventDefault()
  63. } else {
  64. that.input.data('typeahead').select()
  65. event.stopPropagation()
  66. event.preventDefault()
  67. }
  68. }
  69. } else if ( !$.trim($(this).val()) && event.keyCode == 8 ) {
  70. var count = that.element.siblings('.tag').length
  71. if (count) {
  72. var tag = that.element.siblings('.tag:eq(' + (count - 1) + ')')
  73. if (tag.hasClass('tag-important')) that.remove(count - 1)
  74. else tag.addClass('tag-important')
  75. }
  76. } else {
  77. that.element.siblings('.tag').removeClass('tag-important')
  78. }
  79. })
  80. .typeahead({
  81. source: that.options.source
  82. , matcher: function ( value ) {
  83. return ~value.toLowerCase().indexOf(this.query.toLowerCase()) && (that.inValues(value) == -1 || that.options.allowDuplicates)
  84. }
  85. , updater: $.proxy(that.add, that)
  86. });
  87. //auto resize input: this option added by keenthemes for inbos compose form needs. this will enable typing a tag in hirozontal position and input auto resizes while typing
  88. if (that.options.autosizedInput) {
  89. var input = that.input,
  90. minWidth = that.options.minWidth || input.width(),
  91. maxWidth = that.options.maxWidth || input.closest(".tags").width(),
  92. comfortZone = 10,
  93. val = '',
  94. testSubject = $('<tester/>').css({
  95. position: 'absolute',
  96. top: -9999,
  97. left: -9999,
  98. width: 'auto',
  99. paddingLeft: input.css('paddingLeft'),
  100. paddingRight: input.css('paddingRight'),
  101. fontSize: input.css('fontSize'),
  102. fontFamily: input.css('fontFamily'),
  103. fontWeight: input.css('fontWeight'),
  104. letterSpacing: input.css('letterSpacing'),
  105. whiteSpace: 'nowrap'
  106. }),
  107. check = function() {
  108. if (val === (val = input.val())) {return;}
  109. // Enter new content into testSubject
  110. var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  111. testSubject.html(escaped);
  112. // Calculate new width + whether to change
  113. var testerWidth = testSubject.width(),
  114. newWidth = (testerWidth + comfortZone) >= minWidth ? testerWidth + comfortZone : minWidth,
  115. currentWidth = input.width(),
  116. isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
  117. || (newWidth > minWidth && newWidth < maxWidth);
  118. // Animate width
  119. if (isValidWidthChange) {
  120. input.width(newWidth);
  121. }
  122. };
  123. testSubject.insertAfter(input);
  124. input.bind('keydown keyup blur update', check);
  125. }
  126. //auto resize input: added by keenthemes
  127. }
  128. , inValues: function ( value ) {
  129. if (this.options.caseInsensitive) {
  130. var index = -1
  131. $.each(this.values, function (indexInArray, valueOfElement) {
  132. if ( valueOfElement.toLowerCase() == value.toLowerCase() ) {
  133. index = indexInArray
  134. return false
  135. }
  136. })
  137. return index
  138. } else {
  139. return $.inArray(value, this.values)
  140. }
  141. }
  142. , createBadge: function ( value ) {
  143. var that = this
  144. $('<span class="tag">')
  145. .text(value)
  146. .append($('<button type="button" class="close"></button>') //modified by keenthemes sinse close class already defined in global style(style.css)
  147. .on('click', function () {
  148. that.remove(that.element.siblings('.tag').index($(this).closest('.tag')))
  149. })
  150. )
  151. .insertBefore(that.element)
  152. }
  153. , add: function ( value ) {
  154. var that = this
  155. if ( !that.options.allowDuplicates ) {
  156. var index = that.inValues(value)
  157. if ( index != -1 ) {
  158. var badge = that.element.siblings('.tag:eq(' + index + ')')
  159. badge.addClass('tag-warning')
  160. setTimeout(function () {
  161. $(badge).removeClass('tag-warning')
  162. }, 500)
  163. return
  164. }
  165. }
  166. this.values.push(value)
  167. this.createBadge(value)
  168. this.element.val(this.values.join(', '))
  169. }
  170. , remove: function ( index ) {
  171. if ( index >= 0 ) {
  172. this.values.splice(index, 1)
  173. this.element.siblings('.tag:eq(' + index + ')').remove()
  174. this.element.val(this.values.join(', '))
  175. }
  176. }
  177. , process: function () {
  178. var values = $.grep($.map(this.input.val().split(','), $.trim), function ( value ) { return value.length > 0 }),
  179. that = this
  180. $.each(values, function() {
  181. that.add(this)
  182. })
  183. this.input.val('')
  184. }
  185. }
  186. var old = $.fn.tag
  187. $.fn.tag = function ( option ) {
  188. return this.each(function () {
  189. var that = $(this)
  190. , data = that.data('tag')
  191. , options = typeof option == 'object' && option
  192. if (!data) that.data('tag', (data = new Tag(this, options)))
  193. if (typeof option == 'string') data[option]()
  194. })
  195. }
  196. $.fn.tag.defaults = {
  197. allowDuplicates: false
  198. , caseInsensitive: true
  199. , placeholder: ''
  200. , source: []
  201. }
  202. $.fn.tag.Constructor = Tag
  203. $.fn.tag.noConflict = function () {
  204. $.fn.tag = old
  205. return this
  206. }
  207. $(window).on('load', function () {
  208. $('[data-provide="tag"]').each(function () {
  209. var that = $(this)
  210. if (that.data('tag')) return
  211. that.tag(that.data())
  212. })
  213. })
  214. }(window.jQuery)