card-mod-script 0.13.1 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
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