card-mod-script 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/assets/script/decko/autosave.js.coffee +30 -0
  3. data/assets/script/decko/bridge.js.coffee +31 -0
  4. data/assets/script/decko/card_menu.js.coffee +26 -0
  5. data/assets/script/decko/components.js.coffee +46 -0
  6. data/assets/script/decko/decko.js.coffee +97 -0
  7. data/assets/script/decko/doubleclick.js.coffee +30 -0
  8. data/assets/script/decko/editor.js.coffee +55 -0
  9. data/assets/script/decko/filter.js.coffee +176 -0
  10. data/assets/script/decko/filter_items.js.coffee +128 -0
  11. data/assets/script/decko/filter_links.js.coffee +81 -0
  12. data/assets/script/decko/follow.js.coffee +22 -0
  13. data/assets/script/decko/layout.js.coffee +76 -0
  14. data/assets/script/decko/link_editor.js.coffee +61 -0
  15. data/assets/script/decko/mod.js.coffee +85 -0
  16. data/assets/script/decko/modal.js.coffee +113 -0
  17. data/assets/script/decko/name_editor.js.coffee +58 -0
  18. data/assets/script/decko/navbox.js.coffee +74 -0
  19. data/assets/script/decko/nest_editor.js.coffee +166 -0
  20. data/assets/script/decko/nest_editor_name.js.coffee +102 -0
  21. data/assets/script/decko/nest_editor_options.js.coffee +93 -0
  22. data/assets/script/decko/nest_editor_rules.js.coffee +3 -0
  23. data/assets/script/decko/overlay.js.coffee +57 -0
  24. data/assets/script/decko/recaptcha.js.coffee +19 -0
  25. data/assets/script/decko/selectable_filtered_content.js.coffee +12 -0
  26. data/assets/script/decko/slot.js.coffee +182 -0
  27. data/assets/script/decko/slot_ready.js.coffee +11 -0
  28. data/assets/script/decko/slotter.js.coffee +276 -0
  29. data/assets/script/decko/upload.js.coffee +57 -0
  30. data/assets/script/jquery-ui.js +10 -0
  31. data/assets/script/jquery.autosize.js +274 -0
  32. data/assets/script/manifest.yml +44 -0
  33. data/assets/script/script_pointer_config.js.coffee +80 -0
  34. data/assets/script/script_pointer_list_editor.js.coffee +67 -0
  35. metadata +42 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e39b0d3c7d2728686cf541e1177988024c9c79630c985959111f45ba3d808cbd
4
- data.tar.gz: 7ef0c675fe6036d2323a1d19159976a2852780fa59be1265ba0b981d54045c7d
3
+ metadata.gz: 740c8b43709f696ea82eb875a37d92dc4c29aaf193c35dd084472817574dcb24
4
+ data.tar.gz: cddc64356e56ede909a08cd2a6988e3f0b0f63c7e727de9bf123e2bedc5b1a25
5
5
  SHA512:
6
- metadata.gz: 545e457a824be0d31dc0eb20b38c176da77a275edaa19d36ede9da1c750e91b56be212211597fdadb99fc040da84a7b3616663d2bf442d18e7a78ff4d91cf0a0
7
- data.tar.gz: 3b0fd23156411a1371dda1b8edd5a1c552eb07efb591fa3a88c49fc9e9da2ebc6810c4e464a7748afeb516427d927f1f01ad22522abb40efe2f8566c1ba4f71b
6
+ metadata.gz: 0b12a2aed352d954774cb731bf79ce89ae345962343762682246abd605a253d5e8556291c49790189a7975cd558e56626007ee7b2f6117191759e94d366fb436
7
+ data.tar.gz: 26181f4a51408bec334a90b4b782d68680903cb3ba68a81191d634411063747b82ab5788b4cb56980c24e5e080bbc1614223e7a7d305e8478c9ff6b24e9473bd
@@ -0,0 +1,30 @@
1
+ jQuery.fn.extend
2
+ autosave: ->
3
+ slot = @slot()
4
+ return if @attr 'no-autosave'
5
+ multi = @closest '.form-group'
6
+ if multi[0]
7
+ return unless id = multi.data 'cardId'
8
+ reportee = ': ' + multi.data 'cardName'
9
+ else
10
+ id = slot.data 'cardId'
11
+ reportee = ''
12
+
13
+ return unless id
14
+
15
+ # might be better to put this href base in the html
16
+ submit_url = decko.path 'update/~' + id
17
+ form_data = $('#edit_card_'+id).serializeArray().reduce( ((obj, item) ->
18
+ obj[item.name] = item.value
19
+ return obj
20
+ ), { 'draft' : 'true', 'success[view]' : 'blank'});
21
+ $.ajax submit_url, {
22
+ data : form_data,
23
+ type : 'POST'
24
+ }
25
+ ##{ 'card[content]' : @val() },
26
+
27
+ $(window).ready ->
28
+ $('body').on 'change', '.autosave .d0-card-content', ->
29
+ content_field = $(this)
30
+ setTimeout ( -> content_field.autosave() ), 500
@@ -0,0 +1,31 @@
1
+ decko.slotReady (slot, slotter) ->
2
+ slot.updateBridge(false, slotter)
3
+
4
+ links = slot.find('ul._auto-single-select > li.nav-item > a.nav-link')
5
+ if links.length == 1
6
+ $(links[0]).click()
7
+
8
+ jQuery.fn.extend
9
+ # overlayClosed=true means the bridge update was
10
+ # triggered by closing an overlay
11
+ updateBridge: (overlayClosed=false, slotter) ->
12
+ return unless @closest(".bridge").length > 0
13
+ if @data("breadcrumb")
14
+ @updateBreadcrumb()
15
+ else if slotter and $(slotter).data("breadcrumb")
16
+ $(slotter).updateBreadcrumb()
17
+
18
+ if overlayClosed
19
+ $(".bridge-pills > .nav-item > .nav-link.active").removeClass("active")
20
+
21
+ updateBreadcrumb: () ->
22
+ bc_item = $(".modal-header ._bridge-breadcrumb li:last-child")
23
+ bc_item.text(this.data("breadcrumb"))
24
+ bc_item.attr("class", "breadcrumb-item active #{this.data('breadcrumb-class')}")
25
+
26
+ $(window).ready ->
27
+ $('body').on "select2:select", "._close-rule-overlay-on-select", (event) ->
28
+ $(".overlay-container > ._overlay.card-slot.overlay_rule-view.RULE").removeOverlay()
29
+
30
+ $('body').on "click", "._update-history-pills", (event) ->
31
+ $(this).closest(".slotter").data("update-foreign-slot", ".card-slot.history_tab-view")
@@ -0,0 +1,26 @@
1
+ decko.isTouchDevice = ->
2
+ if 'ontouchstart' of window or window.DocumentTouch and
3
+ document instanceof DocumentTouch
4
+ return true
5
+ else
6
+ return detectMobileBrowser()
7
+
8
+ # source for this method: detectmobilebrowsers.com
9
+ detectMobileBrowser = (userAgent) ->
10
+ userAgent = navigator.userAgent or navigator.vendor or window.opera
11
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) or /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4))
12
+
13
+ decko.slotReady (slot) ->
14
+ if decko.isTouchDevice()
15
+ slot.find('._show-on-hover').removeClass('_show-on-hover')
16
+
17
+ $(window).ready ->
18
+ $('body').on 'show.bs.popover', '._card-menu-popover', () ->
19
+ $(this).closest(".card-menu._show-on-hover")
20
+ .removeClass("_show-on-hover")
21
+ .addClass("_show-on-hover-disabled")
22
+
23
+ $('body').on 'hide.bs.popover', '._card-menu-popover', () ->
24
+ $(this).closest(".card-menu._show-on-hover-disabled")
25
+ .removeClass("_show-on-hover-disabled")
26
+ .addClass("_show-on-hover")
@@ -0,0 +1,46 @@
1
+ submitAfterTyping = null
2
+
3
+ $(window).ready ->
4
+ $('body').on 'show.bs.tab', 'a.load[data-toggle="tab"][data-url]', (e) ->
5
+ tab_id = $(e.target).attr('href')
6
+ url = $(e.target).data('url')
7
+ $(e.target).removeClass('load')
8
+ $.ajax
9
+ url: url
10
+ type: 'GET'
11
+ success: (html) ->
12
+ $(tab_id).append(html)
13
+ decko.contentLoaded($(tab_id), $(this))
14
+
15
+ $('body').on "input", "._submit-after-typing", (event) ->
16
+ form = $(event.target).closest('form')
17
+ form.slot().find(".autosubmit-success-notification").remove()
18
+ clearTimeout(submitAfterTyping) if submitAfterTyping
19
+ submitAfterTyping = setTimeout ->
20
+ $(event.target).closest('form').submit()
21
+ submitAfterTyping = null
22
+ , 1000
23
+
24
+ $('body').on "keydown", "._submit-after-typing", (event) ->
25
+ if event.which == 13
26
+ clearTimeout(submitAfterTyping) if submitAfterTyping
27
+ submitAfterTyping = null
28
+ $(event.target).closest('form').submit()
29
+ false
30
+
31
+ $('body').on "change", "._submit-on-change", (event) ->
32
+ $(event.target).closest('form').submit()
33
+ false
34
+
35
+ $('body').on "change", "._edit-item", (event) ->
36
+ cb = $(event.target)
37
+ if cb.is(":checked")
38
+ cb.attr("name", "add_item")
39
+ else
40
+ cb.attr("name", "drop_item")
41
+
42
+ $(event.target).closest('form').submit()
43
+ false
44
+
45
+
46
+
@@ -0,0 +1,97 @@
1
+ $.extend decko,
2
+ # returns absolute path (starting with a slash)
3
+ # if rawPath is complete url, this returns the complete url
4
+ # if rawPath is relative (no slash), this adds relative root
5
+ path: (rawPath) ->
6
+ if rawPath.match /^\/|:\/\//
7
+ rawPath
8
+ else
9
+ decko.rootUrl + rawPath
10
+
11
+ pingName: (name, success)->
12
+ $.getJSON decko.path(''), format: 'json', view: 'status', 'card[name]': name, success
13
+
14
+ jQuery.fn.extend {
15
+ notify: (message, status) ->
16
+ slot = @slot(status)
17
+ notice = slot.find '.card-notice'
18
+ unless notice[0]
19
+ notice = $('<div class="card-notice"></div>')
20
+ form = slot.find('.card-form')
21
+ if form[0]
22
+ $(form[0]).append notice
23
+ else
24
+ slot.append notice
25
+ notice.html message
26
+ notice.show 'blind'
27
+
28
+ report: (message) ->
29
+ report = @slot().find '.card-report'
30
+ return false unless report[0]
31
+ report.hide()
32
+ report.html message
33
+ report.show 'drop', 750
34
+ setTimeout (->report.hide 'drop', 750), 3000
35
+ }
36
+
37
+ #~~~~~ ( EVENTS )
38
+
39
+ $(window).ready ->
40
+ $.ajaxSetup cache: false
41
+
42
+ $('body').on 'click', '.submitter', ->
43
+ $(this).closest('form').submit()
44
+
45
+ $('body').on 'click', 'button.redirecter', ->
46
+ window.location = $(this).attr('href')
47
+
48
+ $('body').on "change", '.live-type-field', ->
49
+ $this = $(this)
50
+
51
+ setSlotMode($this)
52
+ $this.data 'params', $(this).closest('form').serialize()
53
+ $this.data 'url', $(this).attr 'href'
54
+
55
+ $('body').on 'change', '.edit-type-field', ->
56
+ $(this).closest('form').submit()
57
+
58
+ $('body').on 'mouseenter', '[hover_content]', ->
59
+ $(this).attr 'hover_restore', $(this).html()
60
+ $(this).html $(this).attr( 'hover_content' )
61
+ $('body').on 'mouseleave', '[hover_content]', ->
62
+ $(this).html $(this).attr( 'hover_restore' )
63
+
64
+ $('body').on 'click', '.render-error-link', (event) ->
65
+ msg = $(this).closest('.render-error').find '.render-error-message'
66
+ msg.show()
67
+ # msg.dialog()
68
+ event.preventDefault()
69
+
70
+ decko.slotReady (slot) ->
71
+ slot.find('card-view-placeholder').each ->
72
+ $place = $(this)
73
+ return if $place.data("loading")
74
+
75
+ $place.data "loading", true
76
+ $.get $place.data("url"), (data, _status) ->
77
+ $place.replaceWith data
78
+
79
+ # important: this prevents jquery-mobile from taking over everything
80
+ # $( document ).on "mobileinit", ->
81
+ # $.extend $.mobile , {
82
+ # #autoInitializePage: false
83
+ # #ajaxEnabled: false
84
+ # }
85
+
86
+ setSlotMode = ($el, mode=null) ->
87
+ $slotter = $el.closest(".slotter")
88
+ if $slotter.length && $slotter.attr('data-slotter-mode')
89
+ $slotter.attr 'data-original-slotter-mode', $slotter.attr('slotter-mode')
90
+ $slotter.attr 'data-slotter-mode', mode
91
+
92
+
93
+ warn = (stuff) -> console.log stuff if console?
94
+
95
+
96
+
97
+
@@ -0,0 +1,30 @@
1
+ doubleClickActiveMap = { off: false, on: true, signed_in: decko.currentUserId }
2
+
3
+ doubleClickActive = () ->
4
+ doubleClickActiveMap[decko.doubleClick]
5
+ # else alert "illegal configuration: " + decko.doubleClick
6
+
7
+ doubleClickApplies = (el) ->
8
+ return false if ['.nodblclick', '.d0-card-header', '.card-editor'].some (klass) ->
9
+ el.closest(klass)[0]
10
+ # double click inactive inside header, editor, or tag with "nodblclick" class
11
+ !el.slot().find('.card-editor')[0]?
12
+
13
+
14
+ triggerDoubleClickEditingOn = (el)->
15
+ slot = el.slot()
16
+ edit_link = decko.slotEditLink(slot)
17
+
18
+ if edit_link
19
+ edit_link.click()
20
+ else
21
+ edit_view = decko.slotEditView(slot)
22
+ url = decko.path("~#{slot.data('cardId')}?view=#{edit_view}")
23
+ slot.reloadSlot url
24
+
25
+ $(window).ready ->
26
+ if doubleClickActive()
27
+ $('body').on 'dblclick', 'div', (_event) ->
28
+ if doubleClickApplies $(this)
29
+ triggerDoubleClickEditingOn $(this)
30
+ false # don't propagate up to next slot
@@ -0,0 +1,55 @@
1
+ $.extend decko,
2
+ initializeEditors: (range, map) ->
3
+ map = decko.editorInitFunctionMap unless map?
4
+ $.each map, (selector, fn) ->
5
+ $.each range.find(selector), ->
6
+ fn.call $(this)
7
+
8
+ editorContentFunctionMap: {}
9
+
10
+ editorInitFunctionMap:
11
+ 'textarea': -> $(this).autosize()
12
+ '.file-upload': -> decko.upload_file(this)
13
+ '.etherpad-textarea': ->
14
+ $(this).closest('form')
15
+ .find('.edit-submit-button')
16
+ .attr('class', 'etherpad-submit-button')
17
+
18
+ addEditor: (selector, init, get_content) ->
19
+ decko.editorContentFunctionMap[selector] = get_content
20
+ decko.editorInitFunctionMap[selector] = init
21
+
22
+ jQuery.fn.extend
23
+ setContentFieldsFromMap: (map) ->
24
+ map = decko.editorContentFunctionMap unless map?
25
+ this_form = $(this)
26
+ $.each map, (selector, fn) ->
27
+ this_form.setContentFields(selector, fn)
28
+ setContentFields: (selector, fn) ->
29
+ $.each @find(selector), ->
30
+ $(this).setContentField(fn)
31
+ setContentField: (fn) ->
32
+ field = @closest('.card-editor').find('.d0-card-content')
33
+ init_val = field.val() # tinymce-jquery overrides val();
34
+ # that's why we're not using it.
35
+ new_val = fn.call this
36
+ field.val new_val
37
+ field.change() if init_val != new_val
38
+
39
+ $(window).ready ->
40
+ # decko.initializeEditors $('body > :not(.modal)')
41
+ setTimeout (-> decko.initializeEditors $('body > :not(.modal)')), 10
42
+ # dislike the timeout, but without this forms with multiple TinyMCE editors
43
+ # were failing to load properly
44
+ # I couldn't reproduce that problem described above -pk
45
+
46
+ $('body').on 'submit', '.card-form', ->
47
+ $(this).setContentFieldsFromMap()
48
+ $(this).find('.d0-card-content').attr('no-autosave','true')
49
+ true
50
+
51
+ setInterval (-> $('.card-form').setContentFieldsFromMap()), 20000
52
+
53
+
54
+
55
+
@@ -0,0 +1,176 @@
1
+ # filter object that manages dynamic sorting and filtering
2
+
3
+ # el can be any element inside widget
4
+ decko.filter = (el) ->
5
+ closest_widget = $(el).closest "._filter-widget"
6
+ @widget =
7
+ if closest_widget.length
8
+ closest_widget
9
+ else
10
+ $(el).closest("._filtered-content").find "._filter-widget"
11
+
12
+ @activeContainer = @widget.find "._filter-container"
13
+ @dropdown = @widget.find "._add-filter-dropdown"
14
+ @dropdownItems = @widget.find "._filter-category-select"
15
+ @form = @widget.find "._filter-form"
16
+ @quickFilter = @widget.find "._quick-filter"
17
+
18
+ @showWithStatus = (status) ->
19
+ f = this
20
+ $.each (@dropdownItems), ->
21
+ item = $(this)
22
+ if item.data status
23
+ f.activate item.data("category")
24
+
25
+ @reset = () ->
26
+ # @clear()
27
+ @dropdownItems.show()
28
+ @restrict @form.find("._reset-filter").data("reset")
29
+
30
+ @clear = () ->
31
+ @activeContainer.find(".input-group").remove()
32
+
33
+ @activate = (category, value) ->
34
+ @activateField category, value
35
+ @hideOption category
36
+
37
+ @showOption = (category) ->
38
+ @dropdown.show()
39
+ @option(category).show()
40
+
41
+ @hideOption = (category) ->
42
+ @option(category).hide()
43
+ @dropdown.hide() if @dropdownItems.length <= @activeFields().length
44
+
45
+ @activeFields = () ->
46
+ @activeContainer.find "._filter-input"
47
+
48
+ @option = (category) ->
49
+ @dropdownItems.filter("[data-category='#{category}']")
50
+
51
+ @findPrototype = (category) ->
52
+ @widget.find "._filter-input-field-prototypes ._filter-input-#{category}"
53
+
54
+ @activateField = (category, value) ->
55
+ field = @findPrototype(category).clone()
56
+ @fieldValue field, value
57
+ @dropdown.before field
58
+ @initField field
59
+ field.find("input, select").first().focus()
60
+
61
+ @fieldValue = (field, value) ->
62
+ if typeof(value) == "object"
63
+ @compoundFieldValue field, value
64
+ else
65
+ @simpleFieldValue field, value
66
+
67
+ @simpleFieldValue = (field, value) ->
68
+ input = field.find("input, select")
69
+ input.val value if (typeof value != 'undefined')
70
+
71
+ @compoundFieldValue = (field, vals) ->
72
+ for key of vals
73
+ input = field.find "#filter_value_" + key
74
+ input.val vals[key]
75
+
76
+ @removeField = (category)->
77
+ @activeField(category).remove()
78
+ @showOption category
79
+
80
+ @initField = (field) ->
81
+ @initSelectField field
82
+ decko.initAutoCardPlete field.find("input")
83
+ # only has effect if there is a data-options-card value
84
+
85
+ @initSelectField = (field) ->
86
+ field.find("select").select2(
87
+ containerCssClass: ":all:"
88
+ width: "auto"
89
+ dropdownAutoWidth: "true"
90
+ )
91
+
92
+ @activeField = (category) ->
93
+ @activeContainer.find("._filter-input-#{category}")
94
+
95
+ @isActive = (category) ->
96
+ @activeField(category).length
97
+
98
+ @restrict = (data) ->
99
+ @clear()
100
+ for key of data
101
+ @activateField key, data[key]
102
+ @update()
103
+
104
+ @addRestrictions = (hash) ->
105
+ for category of hash
106
+ @removeField category
107
+ @activate category, hash[category]
108
+ @update()
109
+
110
+ @removeRestrictions = (hash) ->
111
+ for category of hash
112
+ @removeField category
113
+ @update()
114
+
115
+ # triggers update
116
+ @setInputVal = (field, value) ->
117
+ select = field.find "select"
118
+ if select.length
119
+ @setSelect2Val select, value
120
+ else
121
+ @setTextInputVal field.find("input"), value
122
+
123
+ # this triggers change, which updates form
124
+ # if we just use simple "val", the display doesn't update correctly
125
+ @setSelect2Val = (select, value) ->
126
+ value = [value] if select.attr("multiple") && !Array.isArray(value)
127
+ select.select2 "val", value
128
+
129
+ @setTextInputVal = (input, value) ->
130
+ input.val value
131
+ @update()
132
+
133
+ @updateLastVals = ()->
134
+ @activeFields().find("input, select").each ()->
135
+ $(this).data "lastVal", $(this).val()
136
+
137
+ @updateUrlBar = () ->
138
+ return if @widget.closest('._noFilterUrlUpdates')[0]
139
+ window.history.pushState "filter", "filter", '?' + @form.serialize()
140
+
141
+ @update = ()->
142
+ @updateLastVals()
143
+ @updateQuickLinks()
144
+ @form.submit()
145
+ @updateUrlBar()
146
+
147
+ @updateQuickLinks = ()->
148
+ widget = this
149
+ links = @quickFilter.find "._filter-link"
150
+ links.addClass "active"
151
+ links.each ->
152
+ link = $(this)
153
+ opts = link.data "filter"
154
+ for key of opts
155
+ widget.deactivateQuickLink link, key, opts[key]
156
+
157
+ @deactivateQuickLink = (link, key, value) ->
158
+ sel = "._filter-input-#{key}"
159
+ $.map [@form.find("#{sel} input, #{sel} select").val()], (arr) ->
160
+ arr = [arr].flat()
161
+ link.removeClass "active" if $.inArray(value, arr) > -1
162
+
163
+ @updateIfChanged = ()->
164
+ @update() if @changedSinceLastVal()
165
+
166
+ @updateIfPresent = (category)->
167
+ val = @activeField(category).find("input, select").val()
168
+ @update() if val && val.length > 0
169
+
170
+ @changedSinceLastVal = () ->
171
+ changed = false
172
+ @activeFields().find("input, select").each ()->
173
+ changed = true if $(this).val() != $(this).data("lastVal")
174
+ changed
175
+
176
+ this