From fd72ed7d1b0a4463a85cd1c520224207cc89266b Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Sun, 25 Sep 2016 11:03:33 -0400 Subject: [PATCH 1/4] Bump jasmine. Avoid https://github.com/ariya/phantomjs/issues/11289 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c5eed4ad0a8..3692c74fbfe 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "grunt-contrib-coffee": "~0.6.4", "grunt-contrib-concat": "~0.1.3", "grunt-contrib-cssmin": "~0.6.1", - "grunt-contrib-jasmine": "~0.5.1", + "grunt-contrib-jasmine": "~1.0.3", "grunt-contrib-uglify": "~0.2.0", "grunt-contrib-watch": "~0.3.1", "grunt-dom-munger": "~2.0.1", From 29792b4c8a16bd78c99291fc687d83da73924041 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 27 Sep 2016 12:46:56 -0400 Subject: [PATCH 2/4] Factorize 'change' event trigger --- coffee/chosen.jquery.coffee | 9 ++++++--- coffee/chosen.proto.coffee | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/coffee/chosen.jquery.coffee b/coffee/chosen.jquery.coffee index 23bcd278731..377e199ce84 100644 --- a/coffee/chosen.jquery.coffee +++ b/coffee/chosen.jquery.coffee @@ -324,7 +324,7 @@ class Chosen extends AbstractChosen this.single_set_selected_text() this.show_search_field_default() this.results_reset_cleanup() - @form_field_jq.trigger "change" + this.trigger_form_field_change() this.results_hide() if @active_field results_reset_cleanup: -> @@ -362,7 +362,7 @@ class Chosen extends AbstractChosen this.results_hide() unless @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) this.show_search_field_default() - @form_field_jq.trigger "change", {'selected': @form_field.options[item.options_index].value} if @is_multiple || @form_field.selectedIndex != @current_selectedIndex + this.trigger_form_field_change selected: @form_field.options[item.options_index].value if @is_multiple || @form_field.selectedIndex != @current_selectedIndex @current_selectedIndex = @form_field.selectedIndex evt.preventDefault() @@ -390,7 +390,7 @@ class Chosen extends AbstractChosen this.result_clear_highlight() this.winnow_results() if @results_showing - @form_field_jq.trigger "change", {deselected: @form_field.options[result_data.options_index].value} + this.trigger_form_field_change deselected: @form_field.options[result_data.options_index].value this.search_field_scale() return true @@ -510,3 +510,6 @@ class Chosen extends AbstractChosen w = f_width - 10 @search_field.css({'width': w + 'px'}) + + trigger_form_field_change: (extra) -> + @form_field_jq.trigger "change", extra diff --git a/coffee/chosen.proto.coffee b/coffee/chosen.proto.coffee index 3297311e4ac..e0da3cc6193 100644 --- a/coffee/chosen.proto.coffee +++ b/coffee/chosen.proto.coffee @@ -315,7 +315,7 @@ class @Chosen extends AbstractChosen this.single_set_selected_text() this.show_search_field_default() this.results_reset_cleanup() - @form_field.simulate("change") if typeof Event.simulate is 'function' + this.trigger_form_field_change() this.results_hide() if @active_field results_reset_cleanup: -> @@ -353,7 +353,7 @@ class @Chosen extends AbstractChosen this.results_hide() unless @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) this.show_search_field_default() - @form_field.simulate("change") if typeof Event.simulate is 'function' && (@is_multiple || @form_field.selectedIndex != @current_selectedIndex) + this.trigger_form_field_change() if @is_multiple || @form_field.selectedIndex != @current_selectedIndex @current_selectedIndex = @form_field.selectedIndex evt.preventDefault() @@ -381,7 +381,7 @@ class @Chosen extends AbstractChosen this.result_clear_highlight() this.winnow_results() if @results_showing - @form_field.simulate("change") if typeof Event.simulate is 'function' + this.trigger_form_field_change() this.search_field_scale() return true else @@ -504,3 +504,6 @@ class @Chosen extends AbstractChosen w = f_width - 10 @search_field.setStyle({'width': w + 'px'}) + + trigger_form_field_change: -> + @form_field.simulate("change") if typeof Event.simulate is 'function' From e1064ebb108d4fe1c034fa862142c7f3a9186271 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Sun, 25 Sep 2016 11:29:09 -0400 Subject: [PATCH 3/4] Don't depend on Simulate (prototype) Except for tests --- coffee/chosen.proto.coffee | 13 ++++++++++++- public/options.html | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/coffee/chosen.proto.coffee b/coffee/chosen.proto.coffee index e0da3cc6193..6eb2ca2c9a6 100644 --- a/coffee/chosen.proto.coffee +++ b/coffee/chosen.proto.coffee @@ -506,4 +506,15 @@ class @Chosen extends AbstractChosen @search_field.setStyle({'width': w + 'px'}) trigger_form_field_change: -> - @form_field.simulate("change") if typeof Event.simulate is 'function' + triggerHtmlEvent @form_field, 'change' + + triggerHtmlEvent = (element, eventType) -> + if element.dispatchEvent # Modern way: + try + evt = new Event(eventType, bubbles: true, cancelable: true) + catch + evt = document.createEvent('HTMLEvents') + evt.initEvent(eventType, true, true); + element.dispatchEvent(evt) + else # Old IE: + element.fireEvent("on#{eventType}", document.createEventObject()); diff --git a/public/options.html b/public/options.html index 412101d0f5c..16b726c1d67 100644 --- a/public/options.html +++ b/public/options.html @@ -229,7 +229,7 @@

Example:

change

Chosen triggers the standard DOM event whenever a selection is made (it also sends a selected or deselected parameter that tells you which option was changed).

-

Note: in order to use change in the Prototype version, you have to include the Event.simulate class. The selected and deselected parameters are not available for Prototype.

+

Note: The selected and deselected parameters are not available for Prototype.

From 80a5d63c8582f812cf6ba64238371a43dc5401a7 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 27 Sep 2016 13:58:26 -0400 Subject: [PATCH 4/4] Trigger 'input' events before 'change' events --- coffee/chosen.jquery.coffee | 1 + coffee/chosen.proto.coffee | 1 + spec/jquery/events.spec.coffee | 30 ++++++++++++++++++++++++++++++ spec/proto/events.spec.coffee | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 spec/jquery/events.spec.coffee create mode 100644 spec/proto/events.spec.coffee diff --git a/coffee/chosen.jquery.coffee b/coffee/chosen.jquery.coffee index 377e199ce84..004e0441d6d 100644 --- a/coffee/chosen.jquery.coffee +++ b/coffee/chosen.jquery.coffee @@ -512,4 +512,5 @@ class Chosen extends AbstractChosen @search_field.css({'width': w + 'px'}) trigger_form_field_change: (extra) -> + @form_field_jq.trigger "input", extra @form_field_jq.trigger "change", extra diff --git a/coffee/chosen.proto.coffee b/coffee/chosen.proto.coffee index 6eb2ca2c9a6..e5b1185d674 100644 --- a/coffee/chosen.proto.coffee +++ b/coffee/chosen.proto.coffee @@ -506,6 +506,7 @@ class @Chosen extends AbstractChosen @search_field.setStyle({'width': w + 'px'}) trigger_form_field_change: -> + triggerHtmlEvent @form_field, 'input' triggerHtmlEvent @form_field, 'change' triggerHtmlEvent = (element, eventType) -> diff --git a/spec/jquery/events.spec.coffee b/spec/jquery/events.spec.coffee new file mode 100644 index 00000000000..b6756048e85 --- /dev/null +++ b/spec/jquery/events.spec.coffee @@ -0,0 +1,30 @@ +describe "Events", -> + it "chosen should fire the right events", -> + tmpl = " + + " + div = $("
").html(tmpl) + select = div.find("select") + expect(select.size()).toBe(1) + select.chosen() + # very simple check that the necessary elements have been created + ["container", "container-single", "single", "default"].forEach (clazz)-> + el = div.find(".chosen-#{clazz}") + expect(el.size()).toBe(1) + + # test a few interactions + event_sequence = [] + div.on 'input change', (evt) -> event_sequence.push evt.type + + container = div.find(".chosen-container") + container.trigger("mousedown") # open the drop + expect(container.hasClass("chosen-container-active")).toBe true + #select an item + container.find(".active-result").last().trigger("mouseup") + + expect(event_sequence).toEqual ['input', 'change'] diff --git a/spec/proto/events.spec.coffee b/spec/proto/events.spec.coffee new file mode 100644 index 00000000000..8cffca2d8e4 --- /dev/null +++ b/spec/proto/events.spec.coffee @@ -0,0 +1,32 @@ +describe "Events", -> + it "chosen should fire the right events", -> + tmpl = " + + " + + div = new Element("div") + document.body.insert(div) + + div.update(tmpl) + select = div.down("select") + expect(select).toBeDefined() + new Chosen(select) + + event_sequence = [] + document.addEventListener 'input', -> event_sequence.push 'input' + document.addEventListener 'change', -> event_sequence.push 'change' + + container = div.down(".chosen-container") + container.simulate("mousedown") # open the drop + expect(container.hasClassName("chosen-container-active")).toBe true + + #select an item + container.select(".active-result").last().simulate("mouseup") + + expect(event_sequence).toEqual ['input', 'change'] + div.remove()