1+ /**
2+ * click_to_edit plugin for Tomselect
3+ *
4+ * This plugin allows editing (and selecting text in) any selected item by clicking it.
5+ *
6+ * Usually, when the user typed some text and created an item in Tomselect that item cannot be edited anymore. To make
7+ * a change, the item has to be deleted and retyped completely. There is also generally no way to copy text out of a
8+ * tomselect item. The "restore_on_backspace" plugin improves that somewhat, by allowing the user to edit an item after
9+ * pressing backspace. However, it is somewhat confusing to first have to focus the field an then hit backspace in order
10+ * to copy a piece of text. It may also not be immediately obvious for editing.
11+ * This plugin transforms an item into editable text when it is clicked, e.g. when the user tries to place the caret
12+ * within an item or when they try to drag across the text to highlight it.
13+ * It also plays nice with the remove_button plugin which still removes (deselects) an option entirely.
14+ *
15+ * It is recommended to also enable the autoselect_typed plugin when using this plugin. Without it, the text in the
16+ * input field (i.e. the item that was just clicked) is lost when the user clicks outside the field. Also, when the user
17+ * clicks an option (making it text) and then tries to enter another one by entering the delimiter (e.g. space) nothing
18+ * happens until enter is pressed or the text is changed from what it was.
19+ */
20+
21+ /**
22+ * Return a dom element from either a dom query string, jQuery object, a dom element or html string
23+ * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
24+ *
25+ * param query should be {}
26+ */
27+ const getDom = query => {
28+ if ( query . jquery ) {
29+ return query [ 0 ] ;
30+ }
31+ if ( query instanceof HTMLElement ) {
32+ return query ;
33+ }
34+ if ( isHtmlString ( query ) ) {
35+ var tpl = document . createElement ( 'template' ) ;
36+ tpl . innerHTML = query . trim ( ) ; // Never return a text node of whitespace as the result
37+ return tpl . content . firstChild ;
38+ }
39+ return document . querySelector ( query ) ;
40+ } ;
41+ const isHtmlString = arg => {
42+ if ( typeof arg === 'string' && arg . indexOf ( '<' ) > - 1 ) {
43+ return true ;
44+ }
45+ return false ;
46+ } ;
47+
48+ function plugin ( plugin_options_ ) {
49+ const self = this
50+
51+ const plugin_options = Object . assign ( {
52+ //If there is unsubmitted text in the input field, should that text be automatically used to select a matching
53+ //element? If this is off, clicking on item1 and then clicking on item2 will result in item1 being deselected
54+ auto_select_before_edit : true ,
55+ //If there is unsubmitted text in the input field, should that text be automatically used to create a matching
56+ //element if no matching element was found or auto_select_before_edit is off?
57+ auto_create_before_edit : true ,
58+ //customize this function to change which text the item is replaced with when clicking on it
59+ text : option => {
60+ return option [ self . settings . labelField ] ;
61+ }
62+ } , plugin_options_ ) ;
63+
64+
65+ self . hook ( 'after' , 'setupTemplates' , ( ) => {
66+ const orig_render_item = self . settings . render . item ;
67+ self . settings . render . item = ( data , escape ) => {
68+ const item = getDom ( orig_render_item . call ( self , data , escape ) ) ;
69+
70+ item . addEventListener ( 'click' , evt => {
71+ if ( self . isLocked ) {
72+ return ;
73+ }
74+ const val = self . inputValue ( ) ;
75+
76+ if ( self . options [ val ] ) {
77+ self . addItem ( val )
78+ } else if ( self . settings . create ) {
79+ self . createItem ( ) ;
80+ }
81+ const option = self . options [ item . dataset . value ]
82+ self . setTextboxValue ( plugin_options . text . call ( self , option ) ) ;
83+ self . focus ( ) ;
84+ self . removeItem ( item ) ;
85+ }
86+ ) ;
87+
88+ return item ;
89+ }
90+ } ) ;
91+
92+ }
93+ export { plugin as default } ;
0 commit comments