From 4c6120910f2b3f20540a2b20d7b0aae71d96bb82 Mon Sep 17 00:00:00 2001 From: Felix Niklas Date: Tue, 9 Feb 2016 14:30:36 +0100 Subject: [PATCH] columnSelect widget --- .../_ui_element/column_select.coffee | 29 +++++++ .../app/controllers/layout_ref.coffee | 8 ++ .../app/lib/app_post/column_select.coffee | 86 +++++++++++++++++++ .../app/views/generic/column_select.jst.eco | 35 ++++++++ .../app/views/layout_ref/inputs.jst.eco | 6 ++ app/assets/stylesheets/zammad.scss | 84 +++++++++++++++++- 6 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/app/controllers/_ui_element/column_select.coffee create mode 100644 app/assets/javascripts/app/lib/app_post/column_select.coffee create mode 100644 app/assets/javascripts/app/views/generic/column_select.jst.eco diff --git a/app/assets/javascripts/app/controllers/_ui_element/column_select.coffee b/app/assets/javascripts/app/controllers/_ui_element/column_select.coffee new file mode 100644 index 000000000..d28855e4e --- /dev/null +++ b/app/assets/javascripts/app/controllers/_ui_element/column_select.coffee @@ -0,0 +1,29 @@ +# coffeelint: disable=camel_case_classes +class App.UiElement.column_select extends App.UiElement.ApplicationUiElement + @render: (attribute, params) -> + + # set multiple option + attribute.multiple = 'multiple' + + # build options list based on config + @getConfigOptionList( attribute, params ) + + # build options list based on relation + @getRelationOptionList( attribute, params ) + + # add null selection if needed + @addNullOption( attribute, params ) + + # sort attribute.options + @sortOptions( attribute, params ) + + # finde selected/checked item of list + @selectedOptions( attribute, params ) + + # disable item of list + @disabledOptions( attribute, params ) + + # filter attributes + @filterOption( attribute, params ) + + new App.ColumnSelect( attribute: attribute ).element() diff --git a/app/assets/javascripts/app/controllers/layout_ref.coffee b/app/assets/javascripts/app/controllers/layout_ref.coffee index c28b437e3..bf01f7693 100644 --- a/app/assets/javascripts/app/controllers/layout_ref.coffee +++ b/app/assets/javascripts/app/controllers/layout_ref.coffee @@ -1516,6 +1516,14 @@ class InputsRef extends App.ControllerContent ) @$('.js-timepicker4').timepicker() + # column select + columnSelectObject = new App.ColumnSelect + attribute: + name: 'company-name' + id: 'company-name-12345' + options: [{value:0,name:'Apple'},{value:1,name:'Microsoft',selected:true},{value:2,name:'Google'},{value:3,name:'Deutsche Bahn'},{value:4,name:'Sparkasse'},{value:5,name:'Deutsche Post'},{value:6,name:'Mitfahrzentrale'},{value:7,name:'Starbucks'},{value:8,name:'Mac Donalds'},{value:9,name:'Flixbus'},{value:10,name:'Betahaus'},{value:11,name:'Bruno Banani'},{value:12,name:'Alpina'},{value:13,name:'Samsung'},{value:14,name:'ChariTea'},{value:15,name:'fritz-kola'},{value:16,name:'Vitamin Water'},{value:17,name:'Znuny'},{value:18,name:'Max & Moritz'}] + @$('.columnSelectPlaceholder').replaceWith( columnSelectObject.element() ) + App.Config.set( 'layout_ref/inputs', InputsRef, 'Routes' ) diff --git a/app/assets/javascripts/app/lib/app_post/column_select.coffee b/app/assets/javascripts/app/lib/app_post/column_select.coffee new file mode 100644 index 000000000..d0be820fb --- /dev/null +++ b/app/assets/javascripts/app/lib/app_post/column_select.coffee @@ -0,0 +1,86 @@ +class App.ColumnSelect extends Spine.Controller + elements: + '.js-pool': 'pool' + '.js-selected': 'selected' + '.js-shadow': 'shadow' + '.js-placeholder': 'placeholder' + '.js-pool .js-option': 'poolOptions' + '.js-selected .js-option': 'selectedOptions' + '.js-search': 'search' + '.js-clear': 'clearButton' + + events: + 'click .js-select': 'onSelect' + 'click .js-remove': 'onRemove' + 'input .js-search': 'filter' + 'click .js-clear': 'clear' + 'keydown .js-search': 'onFilterKeydown' + + className: 'form-control columnSelect' + + element: => + @el + + constructor: -> + super + @values = [] + @render() + + render: -> + @html App.view('generic/column_select')( @options.attribute ) + + # keep height fixed + setTimeout => + @el.css 'height', @el.height() + , 0 + + onSelect: (event) -> + @select $(event.currentTarget).attr('data-value') + + select: (value) -> + @selected.find("[data-value='#{value}']").removeClass 'is-hidden' + @pool.find("[data-value='#{value}']").addClass 'is-hidden' + @values.push(value) + @shadow.val(@values) + + @placeholder.addClass 'is-hidden' + + if @search.val() and @poolOptions.not('.is-filtered').not('.is-hidden').size() is 0 + @clear() + + onRemove: (event) -> + @remove $(event.currentTarget).attr('data-value') + + remove: (value) -> + @pool.find("[data-value='#{value}']").removeClass 'is-hidden' + @selected.find("[data-value='#{value}']").addClass 'is-hidden' + @values.splice(@values.indexOf(value), 1) + @shadow.val(@values) + + if !@values.length + @placeholder.removeClass 'is-hidden' + + filter: (event) -> + filter = $(event.currentTarget).val() + + @poolOptions.each (i, el) -> + return if $(el).hasClass('is-hidden') + + if $(el).text().indexOf(filter) > -1 + $(el).removeClass 'is-filtered' + else + $(el).addClass 'is-filtered' + + @clearButton.toggleClass 'is-hidden', filter.length is 0 + + clear: -> + @search.val('') + @poolOptions.removeClass 'is-filtered' + @clearButton.addClass 'is-hidden' + + onFilterKeydown: (event) -> + return if event.keyCode != 13 + + firstVisibleOption = @poolOptions.not('.is-filtered').not('.is-hidden').first() + if firstVisibleOption + @select firstVisibleOption.attr('data-value') \ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/column_select.jst.eco b/app/assets/javascripts/app/views/generic/column_select.jst.eco new file mode 100644 index 000000000..c890bd2f5 --- /dev/null +++ b/app/assets/javascripts/app/views/generic/column_select.jst.eco @@ -0,0 +1,35 @@ + +
+
<%- @T('No value selected') %>
+ <% for option in @options: %> + + <% end %> +
+
+ <% if @options.length > 10: %> + + <% end %> +
+ <% for option in @options: %> +
<%= option.name %>
+ <% end %> +
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/layout_ref/inputs.jst.eco b/app/assets/javascripts/app/views/layout_ref/inputs.jst.eco index 8bf7edf4f..1baef73fe 100644 --- a/app/assets/javascripts/app/views/layout_ref/inputs.jst.eco +++ b/app/assets/javascripts/app/views/layout_ref/inputs.jst.eco @@ -119,6 +119,12 @@ +

Column Select

+
+ +
+
+

Switch

diff --git a/app/assets/stylesheets/zammad.scss b/app/assets/stylesheets/zammad.scss index 426a98ee7..b01a1e1a0 100644 --- a/app/assets/stylesheets/zammad.scss +++ b/app/assets/stylesheets/zammad.scss @@ -295,7 +295,8 @@ pre code.hljs { .textarea::placeholder, .form-control::placeholder, -.token-input::placeholder { +.token-input::placeholder, +.u-placeholder { color: hsl(0,0%,80%); } @@ -7771,6 +7772,87 @@ output { } } + +.columnSelect { + display: flex; + height: auto; + line-height: 25px; + max-height: 300px; + padding: 0; + line-height: 22px; + + .columnSelect-shadow { + display: none; + } + + .columnSelect-column--selected { + flex-basis: 66%; + flex-grow: 1; + overflow: auto; + padding: 7px 12px; + } + + .columnSelect-column--sidebar { + flex-basis: 33%; + flex-shrink: 1; + border-left: 1px dotted hsl(0,0%,90%); + display: flex; + flex-direction: column; + } + + .columnSelect-pool { + flex: 1; + overflow: auto; + padding: 7px 12px; + + .columnSelect-option { + padding-left: 18px; + } + } + + .columnSelect-option { + cursor: pointer; + user-select: none; + } + + .is-hidden, + .is-filtered { + display: none; + } +} + +.columnSelect-search { + position: relative; + + .icon { + fill: hsl(0,0%,90%); + } + + .icon-magnifier { + left: 7px; + top: 5px; + position: absolute; + } + + .columnSelect-search-clear { + position: absolute; + right: 0; + top: 0; + padding: 5px 7px; + cursor: pointer; + line-height: 1; + } + + input { + width: 100%; + padding: 2px 30px 1px; + border: none; + outline: none; + border-bottom: 1px dotted hsl(0,0%,90%); + background: none; + } +} + /* ----------------