rich_table_component 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. data/README.md +156 -139
  2. data/app/helpers/component_helper.rb +176 -0
  3. data/app/helpers/documents_helper.rb +22 -0
  4. data/app/helpers/menus_helper.rb +182 -0
  5. data/app/helpers/paragraph_helper.rb +57 -0
  6. data/app/helpers/translations_helper.rb +9 -0
  7. data/app/views/application/_document_fields.html.haml +20 -0
  8. data/app/views/application/_edit.html.haml +11 -0
  9. data/app/views/application/_new.html.haml +11 -0
  10. data/app/views/application/access_denied.js.erb +5 -0
  11. data/app/views/application/create.js.erb +19 -0
  12. data/app/views/application/destroy.js.erb +9 -0
  13. data/app/views/application/destroy_fail.js.erb +2 -0
  14. data/app/views/application/edit.html.haml +8 -0
  15. data/app/views/application/edit.js.erb +28 -0
  16. data/app/views/application/index.js.erb +7 -0
  17. data/app/views/application/index.pdf.haml +87 -0
  18. data/app/views/application/index.xls.haml +64 -0
  19. data/app/views/application/new.html.haml +7 -0
  20. data/app/views/application/new.js.erb +23 -0
  21. data/app/views/application/recapitulation.js.erb +12 -0
  22. data/app/views/application/recapitulation.pdf.haml +68 -0
  23. data/app/views/application/recapitulation.xls.haml +41 -0
  24. data/app/views/application/session_expired.js.erb +5 -0
  25. data/app/views/application/show.js.erb +29 -0
  26. data/app/views/application/update.js.erb +15 -0
  27. data/app/views/layouts/print/pdf.html.haml +8 -0
  28. data/app/views/layouts/print/recapitulation.html.haml +8 -0
  29. data/app/views/rich_table_component/_notification.html.haml +9 -0
  30. data/app/views/rich_table_component/_pagination.html.haml +11 -0
  31. data/app/views/rich_table_component/_recapitulation_matrix_groups.html.haml +42 -0
  32. data/app/views/rich_table_component/component/_ajax_upload.html.haml +6 -0
  33. data/app/views/rich_table_component/component/_ajax_upload_result.html.haml +2 -0
  34. data/app/views/rich_table_component/component/_breadcrumbs.html.haml +25 -0
  35. data/app/views/rich_table_component/component/_breadcrumbs_dropdown.html.haml +18 -0
  36. data/app/views/rich_table_component/component/_tabbed.html.haml +5 -0
  37. data/app/views/rich_table_component/rtc/_advanced_search.html.haml +95 -0
  38. data/app/views/rich_table_component/rtc/_advanced_search_recapitulation.html.haml +90 -0
  39. data/app/views/rich_table_component/rtc/_component.html.haml +62 -0
  40. data/app/views/rich_table_component/rtc/_component_actions.html.haml +69 -0
  41. data/app/views/rich_table_component/rtc/_component_content.html.haml +37 -0
  42. data/app/views/rich_table_component/rtc/_component_title.html.haml +37 -0
  43. data/app/views/rich_table_component/rtc/_content.html.haml +22 -0
  44. data/app/views/rich_table_component/rtc/_footer.html.haml +4 -0
  45. data/app/views/rich_table_component/rtc/_header.html.haml +56 -0
  46. data/app/views/rich_table_component/rtc/_recapitulation_matrix.html.haml +25 -0
  47. data/app/views/rich_table_component/rtc/_recapitulation_matrix_form.html.haml +47 -0
  48. data/app/views/rich_table_component/rtc/_table.html.haml +22 -0
  49. data/lib/pagination_list_link_renderer.rb +51 -0
  50. data/lib/rich_table_component/version.rb +1 -1
  51. data/lib/rich_table_component.rb +0 -8
  52. data/rich_table_component.gemspec +0 -1
  53. data/vendor/assets/images/icons/file_extension/file_extension_.png +0 -0
  54. data/vendor/assets/images/icons/file_extension/file_extension_3gp.png +0 -0
  55. data/vendor/assets/images/icons/file_extension/file_extension_7z.png +0 -0
  56. data/vendor/assets/images/icons/file_extension/file_extension_ace.png +0 -0
  57. data/vendor/assets/images/icons/file_extension/file_extension_ai.png +0 -0
  58. data/vendor/assets/images/icons/file_extension/file_extension_aif.png +0 -0
  59. data/vendor/assets/images/icons/file_extension/file_extension_aiff.png +0 -0
  60. data/vendor/assets/images/icons/file_extension/file_extension_amr.png +0 -0
  61. data/vendor/assets/images/icons/file_extension/file_extension_asf.png +0 -0
  62. data/vendor/assets/images/icons/file_extension/file_extension_asx.png +0 -0
  63. data/vendor/assets/images/icons/file_extension/file_extension_bat.png +0 -0
  64. data/vendor/assets/images/icons/file_extension/file_extension_bin.png +0 -0
  65. data/vendor/assets/images/icons/file_extension/file_extension_bmp.png +0 -0
  66. data/vendor/assets/images/icons/file_extension/file_extension_bup.png +0 -0
  67. data/vendor/assets/images/icons/file_extension/file_extension_cab.png +0 -0
  68. data/vendor/assets/images/icons/file_extension/file_extension_cbr.png +0 -0
  69. data/vendor/assets/images/icons/file_extension/file_extension_cda.png +0 -0
  70. data/vendor/assets/images/icons/file_extension/file_extension_cdl.png +0 -0
  71. data/vendor/assets/images/icons/file_extension/file_extension_cdr.png +0 -0
  72. data/vendor/assets/images/icons/file_extension/file_extension_chm.png +0 -0
  73. data/vendor/assets/images/icons/file_extension/file_extension_dat.png +0 -0
  74. data/vendor/assets/images/icons/file_extension/file_extension_divx.png +0 -0
  75. data/vendor/assets/images/icons/file_extension/file_extension_dll.png +0 -0
  76. data/vendor/assets/images/icons/file_extension/file_extension_dmg.png +0 -0
  77. data/vendor/assets/images/icons/file_extension/file_extension_doc.png +0 -0
  78. data/vendor/assets/images/icons/file_extension/file_extension_dss.png +0 -0
  79. data/vendor/assets/images/icons/file_extension/file_extension_dvf.png +0 -0
  80. data/vendor/assets/images/icons/file_extension/file_extension_dwg.png +0 -0
  81. data/vendor/assets/images/icons/file_extension/file_extension_eml.png +0 -0
  82. data/vendor/assets/images/icons/file_extension/file_extension_eps.png +0 -0
  83. data/vendor/assets/images/icons/file_extension/file_extension_exe.png +0 -0
  84. data/vendor/assets/images/icons/file_extension/file_extension_fla.png +0 -0
  85. data/vendor/assets/images/icons/file_extension/file_extension_flv.png +0 -0
  86. data/vendor/assets/images/icons/file_extension/file_extension_gif.png +0 -0
  87. data/vendor/assets/images/icons/file_extension/file_extension_gz.png +0 -0
  88. data/vendor/assets/images/icons/file_extension/file_extension_hqx.png +0 -0
  89. data/vendor/assets/images/icons/file_extension/file_extension_htm.png +0 -0
  90. data/vendor/assets/images/icons/file_extension/file_extension_html.png +0 -0
  91. data/vendor/assets/images/icons/file_extension/file_extension_ifo.png +0 -0
  92. data/vendor/assets/images/icons/file_extension/file_extension_indd.png +0 -0
  93. data/vendor/assets/images/icons/file_extension/file_extension_iso.png +0 -0
  94. data/vendor/assets/images/icons/file_extension/file_extension_jar.png +0 -0
  95. data/vendor/assets/images/icons/file_extension/file_extension_jpeg.png +0 -0
  96. data/vendor/assets/images/icons/file_extension/file_extension_jpg.png +0 -0
  97. data/vendor/assets/images/icons/file_extension/file_extension_lnk.png +0 -0
  98. data/vendor/assets/images/icons/file_extension/file_extension_log.png +0 -0
  99. data/vendor/assets/images/icons/file_extension/file_extension_m4a.png +0 -0
  100. data/vendor/assets/images/icons/file_extension/file_extension_m4b.png +0 -0
  101. data/vendor/assets/images/icons/file_extension/file_extension_m4p.png +0 -0
  102. data/vendor/assets/images/icons/file_extension/file_extension_m4v.png +0 -0
  103. data/vendor/assets/images/icons/file_extension/file_extension_mcd.png +0 -0
  104. data/vendor/assets/images/icons/file_extension/file_extension_mdb.png +0 -0
  105. data/vendor/assets/images/icons/file_extension/file_extension_mid.png +0 -0
  106. data/vendor/assets/images/icons/file_extension/file_extension_mov.png +0 -0
  107. data/vendor/assets/images/icons/file_extension/file_extension_mp2.png +0 -0
  108. data/vendor/assets/images/icons/file_extension/file_extension_mp4.png +0 -0
  109. data/vendor/assets/images/icons/file_extension/file_extension_mpeg.png +0 -0
  110. data/vendor/assets/images/icons/file_extension/file_extension_mpg.png +0 -0
  111. data/vendor/assets/images/icons/file_extension/file_extension_msi.png +0 -0
  112. data/vendor/assets/images/icons/file_extension/file_extension_mswmm.png +0 -0
  113. data/vendor/assets/images/icons/file_extension/file_extension_ogg.png +0 -0
  114. data/vendor/assets/images/icons/file_extension/file_extension_pdf.png +0 -0
  115. data/vendor/assets/images/icons/file_extension/file_extension_png.png +0 -0
  116. data/vendor/assets/images/icons/file_extension/file_extension_pps.png +0 -0
  117. data/vendor/assets/images/icons/file_extension/file_extension_ppt.png +0 -0
  118. data/vendor/assets/images/icons/file_extension/file_extension_ps.png +0 -0
  119. data/vendor/assets/images/icons/file_extension/file_extension_psd.png +0 -0
  120. data/vendor/assets/images/icons/file_extension/file_extension_pst.png +0 -0
  121. data/vendor/assets/images/icons/file_extension/file_extension_ptb.png +0 -0
  122. data/vendor/assets/images/icons/file_extension/file_extension_pub.png +0 -0
  123. data/vendor/assets/images/icons/file_extension/file_extension_qbb.png +0 -0
  124. data/vendor/assets/images/icons/file_extension/file_extension_qbw.png +0 -0
  125. data/vendor/assets/images/icons/file_extension/file_extension_qxd.png +0 -0
  126. data/vendor/assets/images/icons/file_extension/file_extension_ram.png +0 -0
  127. data/vendor/assets/images/icons/file_extension/file_extension_rar.png +0 -0
  128. data/vendor/assets/images/icons/file_extension/file_extension_rm.png +0 -0
  129. data/vendor/assets/images/icons/file_extension/file_extension_rmvb.png +0 -0
  130. data/vendor/assets/images/icons/file_extension/file_extension_rtf.png +0 -0
  131. data/vendor/assets/images/icons/file_extension/file_extension_sea.png +0 -0
  132. data/vendor/assets/images/icons/file_extension/file_extension_ses.png +0 -0
  133. data/vendor/assets/images/icons/file_extension/file_extension_sit.png +0 -0
  134. data/vendor/assets/images/icons/file_extension/file_extension_sitx.png +0 -0
  135. data/vendor/assets/images/icons/file_extension/file_extension_ss.png +0 -0
  136. data/vendor/assets/images/icons/file_extension/file_extension_swf.png +0 -0
  137. data/vendor/assets/images/icons/file_extension/file_extension_tgz.png +0 -0
  138. data/vendor/assets/images/icons/file_extension/file_extension_thm.png +0 -0
  139. data/vendor/assets/images/icons/file_extension/file_extension_tif.png +0 -0
  140. data/vendor/assets/images/icons/file_extension/file_extension_tmp.png +0 -0
  141. data/vendor/assets/images/icons/file_extension/file_extension_torrent.png +0 -0
  142. data/vendor/assets/images/icons/file_extension/file_extension_ttf.png +0 -0
  143. data/vendor/assets/images/icons/file_extension/file_extension_txt.png +0 -0
  144. data/vendor/assets/images/icons/file_extension/file_extension_vcd.png +0 -0
  145. data/vendor/assets/images/icons/file_extension/file_extension_vob.png +0 -0
  146. data/vendor/assets/images/icons/file_extension/file_extension_wav.png +0 -0
  147. data/vendor/assets/images/icons/file_extension/file_extension_wma.png +0 -0
  148. data/vendor/assets/images/icons/file_extension/file_extension_wmv.png +0 -0
  149. data/vendor/assets/images/icons/file_extension/file_extension_wps.png +0 -0
  150. data/vendor/assets/images/icons/file_extension/file_extension_xls.png +0 -0
  151. data/vendor/assets/images/icons/file_extension/file_extension_xpi.png +0 -0
  152. data/vendor/assets/images/icons/file_extension/file_extension_zip.png +0 -0
  153. data/vendor/assets/images/loading_image.gif +0 -0
  154. data/vendor/assets/images/pbar-ani.gif +0 -0
  155. data/vendor/assets/javascripts/admin/starqle.grid.js +708 -0
  156. data/vendor/assets/javascripts/admin/starqle.ui.jquery.js +927 -0
  157. data/vendor/assets/javascripts/ckeditor/config.js +112 -0
  158. data/vendor/assets/javascripts/jquery-ui-1.8.13.custom.min.js +445 -0
  159. data/vendor/assets/javascripts/jquery.fileupload-ui.js +533 -0
  160. data/vendor/assets/javascripts/jquery.fileupload.js +975 -0
  161. data/vendor/assets/javascripts/jquery.tmpl.min.js +1 -0
  162. data/vendor/assets/javascripts/jquery.tokeninput.js +860 -0
  163. data/vendor/assets/javascripts/nested_attribute_action.js +19 -0
  164. data/vendor/assets/javascripts/rich_table_component.js +51 -0
  165. data/vendor/assets/stylesheets/fontfaces/england_hand_db/Freeware License.txt +5 -0
  166. data/vendor/assets/stylesheets/fontfaces/england_hand_db/england-webfont.eot +0 -0
  167. data/vendor/assets/stylesheets/fontfaces/england_hand_db/england-webfont.svg +146 -0
  168. data/vendor/assets/stylesheets/fontfaces/england_hand_db/england-webfont.ttf +0 -0
  169. data/vendor/assets/stylesheets/fontfaces/england_hand_db/england-webfont.woff +0 -0
  170. data/vendor/assets/stylesheets/fontfaces/england_hand_db/stylesheet.css +16 -0
  171. data/vendor/assets/stylesheets/fontfaces/museo300-regular-webfont.eot +0 -0
  172. data/vendor/assets/stylesheets/fontfaces/museo300-regular-webfont.svg +249 -0
  173. data/vendor/assets/stylesheets/fontfaces/museo300-regular-webfont.ttf +0 -0
  174. data/vendor/assets/stylesheets/fontfaces/museo300-regular-webfont.woff +0 -0
  175. data/vendor/assets/stylesheets/fontfaces/museo500-regular-webfont.eot +0 -0
  176. data/vendor/assets/stylesheets/fontfaces/museo500-regular-webfont.svg +249 -0
  177. data/vendor/assets/stylesheets/fontfaces/museo500-regular-webfont.ttf +0 -0
  178. data/vendor/assets/stylesheets/fontfaces/museo500-regular-webfont.woff +0 -0
  179. data/vendor/assets/stylesheets/fontfaces/museo700-regular-webfont.eot +0 -0
  180. data/vendor/assets/stylesheets/fontfaces/museo700-regular-webfont.svg +249 -0
  181. data/vendor/assets/stylesheets/fontfaces/museo700-regular-webfont.ttf +0 -0
  182. data/vendor/assets/stylesheets/fontfaces/museo700-regular-webfont.woff +0 -0
  183. data/vendor/assets/stylesheets/partial/_base_functions.sass +101 -0
  184. data/vendor/assets/stylesheets/partial/_base_variables.sass +76 -0
  185. data/vendor/assets/stylesheets/partial/_form.sass +57 -0
  186. data/vendor/assets/stylesheets/partial/_grid.css +374 -0
  187. data/vendor/assets/stylesheets/partial/_notification.sass +33 -0
  188. data/vendor/assets/stylesheets/partial/_position.sass +122 -0
  189. data/vendor/assets/stylesheets/partial/_starqle.ui.grid.sass +495 -0
  190. data/vendor/assets/stylesheets/partial/_style.sass +674 -0
  191. data/vendor/assets/stylesheets/partial/_tabbed.sass +33 -0
  192. data/vendor/assets/stylesheets/partial/_user_component.sass +2 -0
  193. data/vendor/assets/stylesheets/rich_table_component/_custom.sass +0 -0
  194. data/vendor/assets/stylesheets/rich_table_component.css +18 -0
  195. data/vendor/assets/stylesheets/rtc_bootstrap_and_overrides.css.less +315 -0
  196. data/vendor/assets/stylesheets/rtc_config.sass +31 -0
  197. data/vendor/assets/stylesheets/rtc_jquery.fileupload-ui.css +155 -0
  198. data/vendor/assets/stylesheets/smoothness/images/Thumbs.db +0 -0
  199. data/vendor/assets/stylesheets/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  200. data/vendor/assets/stylesheets/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  201. data/vendor/assets/stylesheets/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  202. data/vendor/assets/stylesheets/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  203. data/vendor/assets/stylesheets/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  204. data/vendor/assets/stylesheets/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  205. data/vendor/assets/stylesheets/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  206. data/vendor/assets/stylesheets/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  207. data/vendor/assets/stylesheets/smoothness/images/ui-icons_222222_256x240.png +0 -0
  208. data/vendor/assets/stylesheets/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  209. data/vendor/assets/stylesheets/smoothness/images/ui-icons_454545_256x240.png +0 -0
  210. data/vendor/assets/stylesheets/smoothness/images/ui-icons_888888_256x240.png +0 -0
  211. data/vendor/assets/stylesheets/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  212. data/vendor/assets/stylesheets/smoothness/jquery-ui-1.8.11.custom.css +573 -0
  213. metadata +209 -17
@@ -0,0 +1,860 @@
1
+ /*
2
+ * jQuery Plugin: Tokenizing Autocomplete Text Entry
3
+ * Version 1.6.0
4
+ *
5
+ * Copyright (c) 2009 James Smith (http://loopj.com)
6
+ * Licensed jointly under the GPL and MIT licenses,
7
+ * choose which one suits your project best!
8
+ *
9
+ */
10
+
11
+ (function ($) {
12
+ // Default settings
13
+ var DEFAULT_SETTINGS = {
14
+ // Search settings
15
+ method: "GET",
16
+ contentType: "json",
17
+ queryParam: "q",
18
+ searchDelay: 300,
19
+ minChars: 1,
20
+ propertyToSearch: "name",
21
+ jsonContainer: null,
22
+
23
+ // Display settings
24
+ hintText: "Type in a search term",
25
+ noResultsText: "No results",
26
+ searchingText: "Searching...",
27
+ deleteText: "×",
28
+ animateDropdown: true,
29
+
30
+ // Tokenization settings
31
+ tokenLimit: null,
32
+ tokenDelimiter: ",",
33
+ preventDuplicates: false,
34
+
35
+ // Output settings
36
+ tokenValue: "id",
37
+
38
+ // Prepopulation settings
39
+ prePopulate: null,
40
+ processPrePopulate: false,
41
+
42
+ // Manipulation settings
43
+ idPrefix: "token-input-",
44
+
45
+ // Formatters
46
+ resultsFormatter: function(item){ return "<li>" + item[this.propertyToSearch]+ "</li>" },
47
+ tokenFormatter: function(item) { return "<li><p>" + item[this.propertyToSearch] + "</p></li>" },
48
+
49
+ // Callbacks
50
+ onResult: null,
51
+ onAdd: null,
52
+ onDelete: null,
53
+ onReady: null
54
+ };
55
+
56
+ // Default classes to use when theming
57
+ var DEFAULT_CLASSES = {
58
+ tokenList: "token-input-list",
59
+ token: "token-input-token",
60
+ tokenDelete: "token-input-delete-token",
61
+ selectedToken: "token-input-selected-token",
62
+ highlightedToken: "token-input-highlighted-token",
63
+ dropdown: "token-input-dropdown",
64
+ dropdownItem: "token-input-dropdown-item",
65
+ dropdownItem2: "token-input-dropdown-item2",
66
+ selectedDropdownItem: "token-input-selected-dropdown-item",
67
+ inputToken: "token-input-input-token"
68
+ };
69
+
70
+ // Input box position "enum"
71
+ var POSITION = {
72
+ BEFORE: 0,
73
+ AFTER: 1,
74
+ END: 2
75
+ };
76
+
77
+ // Keys "enum"
78
+ var KEY = {
79
+ BACKSPACE: 8,
80
+ TAB: 9,
81
+ ENTER: 13,
82
+ ESCAPE: 27,
83
+ SPACE: 32,
84
+ PAGE_UP: 33,
85
+ PAGE_DOWN: 34,
86
+ END: 35,
87
+ HOME: 36,
88
+ LEFT: 37,
89
+ UP: 38,
90
+ RIGHT: 39,
91
+ DOWN: 40,
92
+ NUMPAD_ENTER: 108,
93
+ COMMA: 188
94
+ };
95
+
96
+ // Additional public (exposed) methods
97
+ var methods = {
98
+ init: function(url_or_data_or_function, options) {
99
+ var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
100
+
101
+ return this.each(function () {
102
+ $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
103
+ });
104
+ },
105
+ clear: function() {
106
+ this.data("tokenInputObject").clear();
107
+ return this;
108
+ },
109
+ add: function(item) {
110
+ this.data("tokenInputObject").add(item);
111
+ return this;
112
+ },
113
+ remove: function(item) {
114
+ this.data("tokenInputObject").remove(item);
115
+ return this;
116
+ },
117
+ get: function() {
118
+ return this.data("tokenInputObject").getTokens();
119
+ }
120
+ }
121
+
122
+ // Expose the .tokenInput function to jQuery as a plugin
123
+ $.fn.tokenInput = function (method) {
124
+ // Method calling and initialization logic
125
+ if(methods[method]) {
126
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
127
+ } else {
128
+ return methods.init.apply(this, arguments);
129
+ }
130
+ };
131
+
132
+ // TokenList class for each input
133
+ $.TokenList = function (input, url_or_data, settings) {
134
+ //
135
+ // Initialization
136
+ //
137
+
138
+ // Configure the data source
139
+ if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") {
140
+ // Set the url to query against
141
+ settings.url = url_or_data;
142
+
143
+ // If the URL is a function, evaluate it here to do our initalization work
144
+ var url = computeURL();
145
+
146
+ // Make a smart guess about cross-domain if it wasn't explicitly specified
147
+ if(settings.crossDomain === undefined) {
148
+ if(url.indexOf("://") === -1) {
149
+ settings.crossDomain = false;
150
+ } else {
151
+ settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
152
+ }
153
+ }
154
+ } else if(typeof(url_or_data) === "object") {
155
+ // Set the local data to search through
156
+ settings.local_data = url_or_data;
157
+ }
158
+
159
+ // Build class names
160
+ if(settings.classes) {
161
+ // Use custom class names
162
+ settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
163
+ } else if(settings.theme) {
164
+ // Use theme-suffixed default class names
165
+ settings.classes = {};
166
+ $.each(DEFAULT_CLASSES, function(key, value) {
167
+ settings.classes[key] = value + "-" + settings.theme;
168
+ });
169
+ } else {
170
+ settings.classes = DEFAULT_CLASSES;
171
+ }
172
+
173
+
174
+ // Save the tokens
175
+ var saved_tokens = [];
176
+
177
+ // Keep track of the number of tokens in the list
178
+ var token_count = 0;
179
+
180
+ // Basic cache to save on db hits
181
+ var cache = new $.TokenList.Cache();
182
+
183
+ // Keep track of the timeout, old vals
184
+ var timeout;
185
+ var input_val;
186
+
187
+ // Create a new text input an attach keyup events
188
+ var input_box = $("<input type=\"text\" autocomplete=\"off\">")
189
+ .css({
190
+ outline: "none"
191
+ })
192
+ .attr("id", settings.idPrefix + input.id)
193
+ .focus(function () {
194
+ if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
195
+ show_dropdown_hint();
196
+ }
197
+ })
198
+ .blur(function () {
199
+ hide_dropdown();
200
+ $(this).val("");
201
+ })
202
+ .bind("keyup keydown blur update", resize_input)
203
+ .keydown(function (event) {
204
+ var previous_token;
205
+ var next_token;
206
+
207
+ switch(event.keyCode) {
208
+ case KEY.LEFT:
209
+ case KEY.RIGHT:
210
+ case KEY.UP:
211
+ case KEY.DOWN:
212
+ if(!$(this).val()) {
213
+ previous_token = input_token.prev();
214
+ next_token = input_token.next();
215
+
216
+ if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
217
+ // Check if there is a previous/next token and it is selected
218
+ if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
219
+ deselect_token($(selected_token), POSITION.BEFORE);
220
+ } else {
221
+ deselect_token($(selected_token), POSITION.AFTER);
222
+ }
223
+ } else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
224
+ // We are moving left, select the previous token if it exists
225
+ select_token($(previous_token.get(0)));
226
+ } else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
227
+ // We are moving right, select the next token if it exists
228
+ select_token($(next_token.get(0)));
229
+ }
230
+ } else {
231
+ var dropdown_item = null;
232
+
233
+ if(event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) {
234
+ dropdown_item = $(selected_dropdown_item).next();
235
+ } else {
236
+ dropdown_item = $(selected_dropdown_item).prev();
237
+ }
238
+
239
+ if(dropdown_item.length) {
240
+ select_dropdown_item(dropdown_item);
241
+ }
242
+ return false;
243
+ }
244
+ break;
245
+
246
+ case KEY.BACKSPACE:
247
+ previous_token = input_token.prev();
248
+
249
+ if(!$(this).val().length) {
250
+ if(selected_token) {
251
+ delete_token($(selected_token));
252
+ hidden_input.change();
253
+ } else if(previous_token.length) {
254
+ select_token($(previous_token.get(0)));
255
+ }
256
+
257
+ return false;
258
+ } else if($(this).val().length === 1) {
259
+ hide_dropdown();
260
+ } else {
261
+ // set a timeout just long enough to let this function finish.
262
+ setTimeout(function(){do_search();}, 5);
263
+ }
264
+ break;
265
+
266
+ case KEY.TAB:
267
+ case KEY.ENTER:
268
+ case KEY.NUMPAD_ENTER:
269
+ case KEY.COMMA:
270
+ if(selected_dropdown_item) {
271
+ add_token($(selected_dropdown_item).data("tokeninput"));
272
+ hidden_input.change();
273
+ return false;
274
+ }
275
+ break;
276
+
277
+ case KEY.ESCAPE:
278
+ hide_dropdown();
279
+ return true;
280
+
281
+ default:
282
+ if(String.fromCharCode(event.which)) {
283
+ // set a timeout just long enough to let this function finish.
284
+ setTimeout(function(){do_search();}, 5);
285
+ }
286
+ break;
287
+ }
288
+ });
289
+
290
+ // Keep a reference to the original input box
291
+ var hidden_input = $(input)
292
+ .hide()
293
+ .val("")
294
+ .focus(function () {
295
+ input_box.focus();
296
+ })
297
+ .blur(function () {
298
+ input_box.blur();
299
+ });
300
+
301
+ // Keep a reference to the selected token and dropdown item
302
+ var selected_token = null;
303
+ var selected_token_index = 0;
304
+ var selected_dropdown_item = null;
305
+
306
+ // The list to store the token items in
307
+ var token_list = $("<ul />")
308
+ .addClass(settings.classes.tokenList)
309
+ .click(function (event) {
310
+ var li = $(event.target).closest("li");
311
+ if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
312
+ toggle_select_token(li);
313
+ } else {
314
+ // Deselect selected token
315
+ if(selected_token) {
316
+ deselect_token($(selected_token), POSITION.END);
317
+ }
318
+
319
+ // Focus input box
320
+ input_box.focus();
321
+ }
322
+ })
323
+ .mouseover(function (event) {
324
+ var li = $(event.target).closest("li");
325
+ if(li && selected_token !== this) {
326
+ li.addClass(settings.classes.highlightedToken);
327
+ }
328
+ })
329
+ .mouseout(function (event) {
330
+ var li = $(event.target).closest("li");
331
+ if(li && selected_token !== this) {
332
+ li.removeClass(settings.classes.highlightedToken);
333
+ }
334
+ })
335
+ .insertBefore(hidden_input);
336
+
337
+ // The token holding the input box
338
+ var input_token = $("<li />")
339
+ .addClass(settings.classes.inputToken)
340
+ .appendTo(token_list)
341
+ .append(input_box);
342
+
343
+ // The list to store the dropdown items in
344
+ var dropdown = $("<div>")
345
+ .addClass(settings.classes.dropdown)
346
+ .appendTo("body")
347
+ .hide();
348
+
349
+ // Magic element to help us resize the text input
350
+ var input_resizer = $("<tester/>")
351
+ .insertAfter(input_box)
352
+ .css({
353
+ position: "absolute",
354
+ top: -9999,
355
+ left: -9999,
356
+ width: "auto",
357
+ fontSize: input_box.css("fontSize"),
358
+ fontFamily: input_box.css("fontFamily"),
359
+ fontWeight: input_box.css("fontWeight"),
360
+ letterSpacing: input_box.css("letterSpacing"),
361
+ whiteSpace: "nowrap"
362
+ });
363
+
364
+ // Pre-populate list if items exist
365
+ hidden_input.val("");
366
+ var li_data = settings.prePopulate || hidden_input.data("pre");
367
+ if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
368
+ li_data = settings.onResult.call(hidden_input, li_data);
369
+ }
370
+ if(li_data && li_data.length) {
371
+ $.each(li_data, function (index, value) {
372
+ insert_token(value);
373
+ checkTokenLimit();
374
+ });
375
+ }
376
+
377
+ // Initialization is done
378
+ if($.isFunction(settings.onReady)) {
379
+ settings.onReady.call();
380
+ }
381
+
382
+ //
383
+ // Public functions
384
+ //
385
+
386
+ this.clear = function() {
387
+ token_list.children("li").each(function() {
388
+ if ($(this).children("input").length === 0) {
389
+ delete_token($(this));
390
+ }
391
+ });
392
+ }
393
+
394
+ this.add = function(item) {
395
+ add_token(item);
396
+ }
397
+
398
+ this.remove = function(item) {
399
+ token_list.children("li").each(function() {
400
+ if ($(this).children("input").length === 0) {
401
+ var currToken = $(this).data("tokeninput");
402
+ var match = true;
403
+ for (var prop in item) {
404
+ if (item[prop] !== currToken[prop]) {
405
+ match = false;
406
+ break;
407
+ }
408
+ }
409
+ if (match) {
410
+ delete_token($(this));
411
+ }
412
+ }
413
+ });
414
+ }
415
+
416
+ this.getTokens = function() {
417
+ return saved_tokens;
418
+ }
419
+
420
+ //
421
+ // Private functions
422
+ //
423
+
424
+ function checkTokenLimit() {
425
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
426
+ input_box.hide();
427
+ hide_dropdown();
428
+ return;
429
+ }
430
+ }
431
+
432
+ function resize_input() {
433
+ if(input_val === (input_val = input_box.val())) {return;}
434
+
435
+ // Enter new content into resizer and resize input accordingly
436
+ var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
437
+ input_resizer.html(escaped);
438
+ input_box.width(input_resizer.width() + 30);
439
+ }
440
+
441
+ function is_printable_character(keycode) {
442
+ return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
443
+ (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
444
+ (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
445
+ (keycode >= 219 && keycode <= 222)); // ( \ ) '
446
+ }
447
+
448
+ // Inner function to a token to the list
449
+ function insert_token(item) {
450
+ var this_token = settings.tokenFormatter(item);
451
+ this_token = $(this_token)
452
+ .addClass(settings.classes.token)
453
+ .insertBefore(input_token);
454
+
455
+ // The 'delete token' button
456
+ $("<span>" + settings.deleteText + "</span>")
457
+ .addClass(settings.classes.tokenDelete)
458
+ .appendTo(this_token)
459
+ .click(function () {
460
+ delete_token($(this).parent());
461
+ hidden_input.change();
462
+ return false;
463
+ });
464
+
465
+ // Store data on the token
466
+ var token_data = {"id": item.id};
467
+ token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
468
+ $.data(this_token.get(0), "tokeninput", item);
469
+
470
+ // Save this token for duplicate checking
471
+ saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
472
+ selected_token_index++;
473
+
474
+ // Update the hidden input
475
+ update_hidden_input(saved_tokens, hidden_input);
476
+
477
+ token_count += 1;
478
+
479
+ // Check the token limit
480
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
481
+ input_box.hide();
482
+ hide_dropdown();
483
+ }
484
+
485
+ return this_token;
486
+ }
487
+
488
+ // Add a token to the token list based on user input
489
+ function add_token (item) {
490
+ var callback = settings.onAdd;
491
+
492
+ // See if the token already exists and select it if we don't want duplicates
493
+ if(token_count > 0 && settings.preventDuplicates) {
494
+ var found_existing_token = null;
495
+ token_list.children().each(function () {
496
+ var existing_token = $(this);
497
+ var existing_data = $.data(existing_token.get(0), "tokeninput");
498
+ if(existing_data && existing_data.id === item.id) {
499
+ found_existing_token = existing_token;
500
+ return false;
501
+ }
502
+ });
503
+
504
+ if(found_existing_token) {
505
+ select_token(found_existing_token);
506
+ input_token.insertAfter(found_existing_token);
507
+ input_box.focus();
508
+ return;
509
+ }
510
+ }
511
+
512
+ // Insert the new tokens
513
+ if(settings.tokenLimit == null || token_count < settings.tokenLimit) {
514
+ insert_token(item);
515
+ checkTokenLimit();
516
+ }
517
+
518
+ // Clear input box
519
+ input_box.val("");
520
+
521
+ // Don't show the help dropdown, they've got the idea
522
+ hide_dropdown();
523
+
524
+ // Execute the onAdd callback if defined
525
+ if($.isFunction(callback)) {
526
+ callback.call(hidden_input,item);
527
+ }
528
+ }
529
+
530
+ // Select a token in the token list
531
+ function select_token (token) {
532
+ token.addClass(settings.classes.selectedToken);
533
+ selected_token = token.get(0);
534
+
535
+ // Hide input box
536
+ input_box.val("");
537
+
538
+ // Hide dropdown if it is visible (eg if we clicked to select token)
539
+ hide_dropdown();
540
+ }
541
+
542
+ // Deselect a token in the token list
543
+ function deselect_token (token, position) {
544
+ token.removeClass(settings.classes.selectedToken);
545
+ selected_token = null;
546
+
547
+ if(position === POSITION.BEFORE) {
548
+ input_token.insertBefore(token);
549
+ selected_token_index--;
550
+ } else if(position === POSITION.AFTER) {
551
+ input_token.insertAfter(token);
552
+ selected_token_index++;
553
+ } else {
554
+ input_token.appendTo(token_list);
555
+ selected_token_index = token_count;
556
+ }
557
+
558
+ // Show the input box and give it focus again
559
+ input_box.focus();
560
+ }
561
+
562
+ // Toggle selection of a token in the token list
563
+ function toggle_select_token(token) {
564
+ var previous_selected_token = selected_token;
565
+
566
+ if(selected_token) {
567
+ deselect_token($(selected_token), POSITION.END);
568
+ }
569
+
570
+ if(previous_selected_token === token.get(0)) {
571
+ deselect_token(token, POSITION.END);
572
+ } else {
573
+ select_token(token);
574
+ }
575
+ }
576
+
577
+ // Delete a token from the token list
578
+ function delete_token (token) {
579
+ // Remove the id from the saved list
580
+ var token_data = $.data(token.get(0), "tokeninput");
581
+ var callback = settings.onDelete;
582
+
583
+ var index = token.prevAll().length;
584
+ if(index > selected_token_index) index--;
585
+
586
+ // Delete the token
587
+ token.remove();
588
+ selected_token = null;
589
+
590
+ // Show the input box and give it focus again
591
+ input_box.focus();
592
+
593
+ // Remove this token from the saved list
594
+ saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
595
+ if(index < selected_token_index) selected_token_index--;
596
+
597
+ // Update the hidden input
598
+ update_hidden_input(saved_tokens, hidden_input);
599
+
600
+ token_count -= 1;
601
+
602
+ if(settings.tokenLimit !== null) {
603
+ input_box
604
+ .show()
605
+ .val("")
606
+ .focus();
607
+ }
608
+
609
+ // Execute the onDelete callback if defined
610
+ if($.isFunction(callback)) {
611
+ callback.call(hidden_input,token_data);
612
+ }
613
+ }
614
+
615
+ // Update the hidden input box value
616
+ function update_hidden_input(saved_tokens, hidden_input) {
617
+ var token_values = $.map(saved_tokens, function (el) {
618
+ return el[settings.tokenValue];
619
+ });
620
+ hidden_input.val(token_values.join(settings.tokenDelimiter));
621
+
622
+ }
623
+
624
+ // Hide and clear the results dropdown
625
+ function hide_dropdown () {
626
+ dropdown.hide().empty();
627
+ selected_dropdown_item = null;
628
+ }
629
+
630
+ function show_dropdown() {
631
+ dropdown
632
+ .css({
633
+ position: "absolute",
634
+ top: $(token_list).offset().top + $(token_list).outerHeight(),
635
+ left: $(token_list).offset().left,
636
+ zindex: 999
637
+ })
638
+ .show();
639
+ }
640
+
641
+ function show_dropdown_searching () {
642
+ if(settings.searchingText) {
643
+ dropdown.html("<p>"+settings.searchingText+"</p>");
644
+ show_dropdown();
645
+ }
646
+ }
647
+
648
+ function show_dropdown_hint () {
649
+ if(settings.hintText) {
650
+ dropdown.html("<p>"+settings.hintText+"</p>");
651
+ show_dropdown();
652
+ }
653
+ }
654
+
655
+ // Highlight the query part of the search term
656
+ function highlight_term(value, term) {
657
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
658
+ }
659
+
660
+ function find_value_and_highlight_term(template, value, term) {
661
+ return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term));
662
+ }
663
+
664
+ // Populate the results dropdown with some results
665
+ function populate_dropdown (query, results) {
666
+ if(results && results.length) {
667
+ dropdown.empty();
668
+ var dropdown_ul = $("<ul>")
669
+ .appendTo(dropdown)
670
+ .mouseover(function (event) {
671
+ select_dropdown_item($(event.target).closest("li"));
672
+ })
673
+ .mousedown(function (event) {
674
+ add_token($(event.target).closest("li").data("tokeninput"));
675
+ hidden_input.change();
676
+ return false;
677
+ })
678
+ .hide();
679
+
680
+ $.each(results, function(index, value) {
681
+ var this_li = settings.resultsFormatter(value);
682
+
683
+ this_li = find_value_and_highlight_term(this_li ,value[settings.propertyToSearch], query);
684
+
685
+ this_li = $(this_li).appendTo(dropdown_ul);
686
+
687
+ if(index % 2) {
688
+ this_li.addClass(settings.classes.dropdownItem);
689
+ } else {
690
+ this_li.addClass(settings.classes.dropdownItem2);
691
+ }
692
+
693
+ if(index === 0) {
694
+ select_dropdown_item(this_li);
695
+ }
696
+
697
+ $.data(this_li.get(0), "tokeninput", value);
698
+ });
699
+
700
+ show_dropdown();
701
+
702
+ if(settings.animateDropdown) {
703
+ dropdown_ul.slideDown("fast");
704
+ } else {
705
+ dropdown_ul.show();
706
+ }
707
+ } else {
708
+ if(settings.noResultsText) {
709
+ dropdown.html("<p>"+settings.noResultsText+"</p>");
710
+ show_dropdown();
711
+ }
712
+ }
713
+ }
714
+
715
+ // Highlight an item in the results dropdown
716
+ function select_dropdown_item (item) {
717
+ if(item) {
718
+ if(selected_dropdown_item) {
719
+ deselect_dropdown_item($(selected_dropdown_item));
720
+ }
721
+
722
+ item.addClass(settings.classes.selectedDropdownItem);
723
+ selected_dropdown_item = item.get(0);
724
+ }
725
+ }
726
+
727
+ // Remove highlighting from an item in the results dropdown
728
+ function deselect_dropdown_item (item) {
729
+ item.removeClass(settings.classes.selectedDropdownItem);
730
+ selected_dropdown_item = null;
731
+ }
732
+
733
+ // Do a search and show the "searching" dropdown if the input is longer
734
+ // than settings.minChars
735
+ function do_search() {
736
+ var query = input_box.val().toLowerCase();
737
+
738
+ if(query && query.length) {
739
+ if(selected_token) {
740
+ deselect_token($(selected_token), POSITION.AFTER);
741
+ }
742
+
743
+ if(query.length >= settings.minChars) {
744
+ show_dropdown_searching();
745
+ clearTimeout(timeout);
746
+
747
+ timeout = setTimeout(function(){
748
+ run_search(query);
749
+ }, settings.searchDelay);
750
+ } else {
751
+ hide_dropdown();
752
+ }
753
+ }
754
+ }
755
+
756
+ // Do the actual search
757
+ function run_search(query) {
758
+ var cache_key = query + computeURL();
759
+ var cached_results = cache.get(cache_key);
760
+ if(cached_results) {
761
+ populate_dropdown(query, cached_results);
762
+ } else {
763
+ // Are we doing an ajax search or local data search?
764
+ if(settings.url) {
765
+ var url = computeURL();
766
+ // Extract exisiting get params
767
+ var ajax_params = {};
768
+ ajax_params.data = {};
769
+ if(url.indexOf("?") > -1) {
770
+ var parts = url.split("?");
771
+ ajax_params.url = parts[0];
772
+
773
+ var param_array = parts[1].split("&");
774
+ $.each(param_array, function (index, value) {
775
+ var kv = value.split("=");
776
+ ajax_params.data[kv[0]] = kv[1];
777
+ });
778
+ } else {
779
+ ajax_params.url = url;
780
+ }
781
+
782
+ // Prepare the request
783
+ ajax_params.data[settings.queryParam] = query;
784
+ ajax_params.type = settings.method;
785
+ ajax_params.dataType = settings.contentType;
786
+ if(settings.crossDomain) {
787
+ ajax_params.dataType = "jsonp";
788
+ }
789
+
790
+ // Attach the success callback
791
+ ajax_params.success = function(results) {
792
+ if($.isFunction(settings.onResult)) {
793
+ results = settings.onResult.call(hidden_input, results);
794
+ }
795
+ cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results);
796
+
797
+ // only populate the dropdown if the results are associated with the active search query
798
+ if(input_box.val().toLowerCase() === query) {
799
+ populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
800
+ }
801
+ };
802
+
803
+ // Make the request
804
+ $.ajax(ajax_params);
805
+ } else if(settings.local_data) {
806
+ // Do the search through local data
807
+ var results = $.grep(settings.local_data, function (row) {
808
+ return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
809
+ });
810
+
811
+ if($.isFunction(settings.onResult)) {
812
+ results = settings.onResult.call(hidden_input, results);
813
+ }
814
+ cache.add(cache_key, results);
815
+ populate_dropdown(query, results);
816
+ }
817
+ }
818
+ }
819
+
820
+ // compute the dynamic URL
821
+ function computeURL() {
822
+ var url = settings.url;
823
+ if(typeof settings.url == 'function') {
824
+ url = settings.url.call();
825
+ }
826
+ return url;
827
+ }
828
+ };
829
+
830
+ // Really basic cache for the results
831
+ $.TokenList.Cache = function (options) {
832
+ var settings = $.extend({
833
+ max_size: 500
834
+ }, options);
835
+
836
+ var data = {};
837
+ var size = 0;
838
+
839
+ var flush = function () {
840
+ data = {};
841
+ size = 0;
842
+ };
843
+
844
+ this.add = function (query, results) {
845
+ if(size > settings.max_size) {
846
+ flush();
847
+ }
848
+
849
+ if(!data[query]) {
850
+ size += 1;
851
+ }
852
+
853
+ data[query] = results;
854
+ };
855
+
856
+ this.get = function (query) {
857
+ return data[query];
858
+ };
859
+ };
860
+ }(jQuery));