handsontable-chosen-editor.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /// chosen plugin
  2. (function(Handsontable) {
  3. "use strict";
  4. var ChosenEditor = Handsontable.editors.TextEditor.prototype.extend();
  5. ChosenEditor.prototype.prepare = function(row, col, prop, td, originalValue, cellProperties) {
  6. Handsontable.editors.TextEditor.prototype.prepare.apply(this, arguments);
  7. this.options = {};
  8. if (this.cellProperties.chosenOptions) {
  9. this.options = $.extend(this.options, cellProperties.chosenOptions);
  10. }
  11. cellProperties.chosenOptions = $.extend({}, cellProperties.chosenOptions);
  12. };
  13. ChosenEditor.prototype.createElements = function() {
  14. this.$body = $(document.body);
  15. this.TEXTAREA = document.createElement('select');
  16. //this.TEXTAREA.setAttribute('type', 'text');
  17. this.$textarea = $(this.TEXTAREA);
  18. Handsontable.dom.addClass(this.TEXTAREA, 'handsontableInput');
  19. this.textareaStyle = this.TEXTAREA.style;
  20. this.textareaStyle.width = 0;
  21. this.textareaStyle.height = 0;
  22. this.TEXTAREA_PARENT = document.createElement('DIV');
  23. Handsontable.dom.addClass(this.TEXTAREA_PARENT, 'handsontableInputHolder');
  24. this.textareaParentStyle = this.TEXTAREA_PARENT.style;
  25. this.textareaParentStyle.top = 0;
  26. this.textareaParentStyle.left = 0;
  27. this.textareaParentStyle.display = 'none';
  28. this.textareaParentStyle.width = "200px";
  29. this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
  30. this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);
  31. var that = this;
  32. this.instance._registerTimeout(setTimeout(function() {
  33. that.refreshDimensions();
  34. }, 0));
  35. };
  36. var onChosenChanged = function() {
  37. var options = this.cellProperties.chosenOptions;
  38. if (!options.multiple) {
  39. this.close();
  40. this.finishEditing();
  41. }
  42. };
  43. var onChosenClosed = function() {
  44. var options = this.cellProperties.chosenOptions;
  45. if (!options.multiple) {
  46. this.close();
  47. this.finishEditing();
  48. } else {}
  49. };
  50. var onBeforeKeyDown = function(event) {
  51. var instance = this;
  52. var that = instance.getActiveEditor();
  53. var keyCodes = Handsontable.helper.KEY_CODES;
  54. var ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey; //catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)
  55. //Process only events that have been fired in the editor
  56. if (event.target.tagName !== "INPUT") {
  57. return;
  58. }
  59. if (event.keyCode === 17 || event.keyCode === 224 || event.keyCode === 91 || event.keyCode === 93) {
  60. //when CTRL or its equivalent is pressed and cell is edited, don't prepare selectable text in textarea
  61. event.stopImmediatePropagation();
  62. return;
  63. }
  64. var target = event.target;
  65. switch (event.keyCode) {
  66. case keyCodes.ARROW_RIGHT:
  67. if (Handsontable.dom.getCaretPosition(target) !== target.value.length) {
  68. event.stopImmediatePropagation();
  69. } else {
  70. that.$textarea.trigger("chosen:close");
  71. }
  72. break;
  73. case keyCodes.ARROW_LEFT:
  74. if (Handsontable.dom.getCaretPosition(target) !== 0) {
  75. event.stopImmediatePropagation();
  76. } else {
  77. that.$textarea.trigger("chosen:close");
  78. }
  79. break;
  80. case keyCodes.ENTER:
  81. if (that.cellProperties.chosenOptions.multiple) {
  82. event.stopImmediatePropagation();
  83. event.preventDefault();
  84. event.stopPropagation();
  85. }
  86. break;
  87. case keyCodes.A:
  88. case keyCodes.X:
  89. case keyCodes.C:
  90. case keyCodes.V:
  91. if (ctrlDown) {
  92. event.stopImmediatePropagation(); //CTRL+A, CTRL+C, CTRL+V, CTRL+X should only work locally when cell is edited (not in table context)
  93. }
  94. break;
  95. case keyCodes.BACKSPACE:
  96. var txt = $(that.TEXTAREA_PARENT).find("input").val();
  97. $(that.TEXTAREA_PARENT).find("input").val(txt.substr(0, txt.length - 1)).trigger("keyup.chosen");
  98. event.stopImmediatePropagation();
  99. break;
  100. case keyCodes.DELETE:
  101. case keyCodes.HOME:
  102. case keyCodes.END:
  103. event.stopImmediatePropagation(); //backspace, delete, home, end should only work locally when cell is edited (not in table context)
  104. break;
  105. }
  106. };
  107. ChosenEditor.prototype.open = function(keyboardEvent) {
  108. this.refreshDimensions();
  109. this.textareaParentStyle.display = 'block';
  110. this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
  111. this.$textarea.css({
  112. height: $(this.TD).height() + 4,
  113. 'min-width': $(this.TD).outerWidth() - 4
  114. });
  115. //display the list
  116. this.$textarea.hide();
  117. //make sure that list positions matches cell position
  118. //this.$textarea.offset($(this.TD).offset());
  119. var options = $.extend({}, this.options, {
  120. width: "100%",
  121. search_contains: true
  122. });
  123. if (options.multiple) {
  124. this.$textarea.attr("multiple", true);
  125. } else {
  126. this.$textarea.attr("multiple", false);
  127. }
  128. this.$textarea.empty();
  129. this.$textarea.append("<option value=''></option>");
  130. var el = null;
  131. var originalValue = (this.originalValue + "").split(",");
  132. if (options.data && options.data.length) {
  133. for (var i = 0; i < options.data.length; i++) {
  134. this.$textarea.append(el);
  135. if (options[i].content && options[i].content.length) {
  136. for (let k = 0; k < options[i].content.length; k++) {
  137. if (options[i].content[k] && options[i].content[k].length) {
  138. for (let j = 0; j < options[i].content[k].length; j++) {
  139. el = $("<option />");
  140. el.attr("value", options[i].content[k].content[j].code);
  141. el.html(options[i].content[k].content[j].name);
  142. if (originalValue.indexOf(options[i].content[k].content[j].code + "") > -1) {
  143. el.attr("selected", true);
  144. }
  145. }
  146. } else {
  147. el = $("<option />");
  148. el.attr("value", options[i].content[k].code);
  149. el.html(options[i].content[k].name);
  150. if (originalValue.indexOf(options[i].content[k].code + "") > -1) {
  151. el.attr("selected", true);
  152. }
  153. }
  154. }
  155. } else {
  156. el = $("<option />");
  157. el.attr("value", options[i].content[k].code);
  158. el.html(options[i].content[k].name);
  159. if (originalValue.indexOf(options[i].content[k].code + "") > -1) {
  160. el.attr("selected", true);
  161. }
  162. }
  163. }
  164. }
  165. }
  166. if ($(this.TEXTAREA_PARENT).find(".chosen-container").length) {
  167. this.$textarea.chosen("destroy");
  168. }
  169. this.$textarea.chosen(options);
  170. var self = this;
  171. setTimeout(function() {
  172. self.$textarea.on('change', onChosenChanged.bind(self));
  173. self.$textarea.on('chosen:hiding_dropdown', onChosenClosed.bind(self));
  174. self.$textarea.trigger("chosen:open");
  175. $(self.TEXTAREA_PARENT).find("input").on("keydown", function(e) {
  176. if (e.keyCode === Handsontable.helper.KEY_CODES.ENTER /*|| e.keyCode === Handsontable.helper.KEY_CODES.BACKSPACE*/ ) {
  177. if ($(this).val()) {
  178. e.preventDefault();
  179. e.stopPropagation();
  180. } else {
  181. e.preventDefault();
  182. e.stopPropagation();
  183. self.close();
  184. self.finishEditing();
  185. }
  186. }
  187. if (e.keyCode === Handsontable.helper.KEY_CODES.BACKSPACE) {
  188. var txt = $(self.TEXTAREA_PARENT).find("input").val();
  189. $(self.TEXTAREA_PARENT).find("input").val(txt.substr(0, txt.length - 1)).trigger("keyup.chosen");
  190. e.preventDefault();
  191. e.stopPropagation();
  192. }
  193. if (e.keyCode === Handsontable.helper.KEY_CODES.ARROW_DOWN || e.keyCode === Handsontable.helper.KEY_CODES.ARROW_UP) {
  194. e.preventDefault();
  195. e.stopPropagation();
  196. }
  197. });
  198. setTimeout(function() {
  199. self.$textarea.trigger("chosen:activate").focus();
  200. if (keyboardEvent && keyboardEvent.keyCode && keyboardEvent.keyCode != 113) {
  201. var key = keyboardEvent.keyCode;
  202. var keyText = (String.fromCharCode((96 <= key && key <= 105) ? key - 48 : key)).toLowerCase();
  203. $(self.TEXTAREA_PARENT).find("input").val(keyText).trigger("keyup.chosen");
  204. self.$textarea.trigger("chosen:activate");
  205. }
  206. }, 1);
  207. }, 1);
  208. };
  209. ChosenEditor.prototype.init = function() {
  210. Handsontable.editors.TextEditor.prototype.init.apply(this, arguments);
  211. };
  212. ChosenEditor.prototype.close = function() {
  213. this.instance.listen();
  214. this.instance.removeHook('beforeKeyDown', onBeforeKeyDown);
  215. this.$textarea.off();
  216. this.$textarea.hide();
  217. Handsontable.editors.TextEditor.prototype.close.apply(this, arguments);
  218. };
  219. ChosenEditor.prototype.getValue = function() {
  220. if (!this.$textarea.val()) {
  221. return "";
  222. }
  223. if (typeof this.$textarea.val() === "object") {
  224. return this.$textarea.val().join(",");
  225. }
  226. return this.$textarea.val();
  227. };
  228. ChosenEditor.prototype.focus = function() {
  229. this.instance.listen();
  230. // DO NOT CALL THE BASE TEXTEDITOR FOCUS METHOD HERE, IT CAN MAKE THIS EDITOR BEHAVE POORLY AND HAS NO PURPOSE WITHIN THE CONTEXT OF THIS EDITOR
  231. //Handsontable.editors.TextEditor.prototype.focus.apply(this, arguments);
  232. };
  233. ChosenEditor.prototype.beginEditing = function(initialValue) {
  234. var onBeginEditing = this.instance.getSettings().onBeginEditing;
  235. if (onBeginEditing && onBeginEditing() === false) {
  236. return;
  237. }
  238. Handsontable.editors.TextEditor.prototype.beginEditing.apply(this, arguments);
  239. };
  240. ChosenEditor.prototype.finishEditing = function(isCancelled, ctrlDown) {
  241. this.instance.listen();
  242. return Handsontable.editors.TextEditor.prototype.finishEditing.apply(this, arguments);
  243. };
  244. Handsontable.editors.ChosenEditor = ChosenEditor; Handsontable.editors.registerEditor('chosen', ChosenEditor);
  245. })(Handsontable);