| <!-- The <query2-sk> custom element declaration. |
| |
| Starting from a serialized paramtools.ParamSet, this control allows the user |
| to build up a query, suitable for passing to query.New. |
| |
| Attributes: |
| current_query - The current query formatted as a URL formatted query string. |
| |
| Events: |
| 'query-change' |
| The 'query2-sk' element will produce 'query-change' events when the query |
| parameters chosen have changed. The event contains the current |
| selections formatted as a URL query, found in e.detail.q. |
| |
| Methods: |
| setCurrentQuery(s) - Sets the query selections of the control, where 's' |
| is a URL formatted query string, as returned from current_query. |
| |
| setParamset(p) - A serialized paramtools.ParamSet, that is the source |
| of the options for the query. |
| |
| setKeyOrder(s) - An array of strings, the keys in the order they should |
| appear. All keys not in the key order will be present after and in |
| alphabetical order. |
| --> |
| |
| <link rel="stylesheet" href="/res/common/css/md.css"> |
| <link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html"> |
| <dom-module id="query2-sk"> |
| <style include="iron-flex iron-flex-alignment iron-positioning"> |
| input, |
| select { |
| margin: 0 1em; |
| } |
| |
| paper-checkbox { |
| --paper-checkbox-checked-color: #1F78B4; |
| --paper-checkbox-checked-ink-color: #1F78B4; |
| --paper-checkbox-unchecked-color: #1F78B4; |
| --paper-checkbox-unchecked-ink-color: #1F78B4; |
| margin: 0 1em 0.5em 1em; |
| } |
| |
| .hidden { |
| display: none; |
| } |
| |
| </style> |
| <template> |
| <div class="horizontal layout"> |
| <div class="vertical layout"> |
| <div class="horizontal layout"> |
| <paper-input id="fast" label="Filter" on-input="_fastFilter"></paper-input> |
| <button on-tap="_clearFilter">Clear Filter</button> |
| </div> |
| <select id=keys size=12 on-change="_keyChange"> |
| <template is="dom-repeat" items="[[_keys]]"> |
| <option value="[[item]]">[[item]]</option> |
| </template> |
| </select> |
| <button on-tap="_clear">Clear Selections</button> |
| </div> |
| <div class="vertical layout"> |
| <paper-checkbox |
| disabled |
| id=invert |
| on-change="_valueChange" |
| title="Match items that aren't selected below.">Invert</paper-checkbox> |
| <paper-checkbox |
| disabled |
| id=regex |
| on-tap="_regexTap" |
| title="Match items via regular expression.">Regex</paper-checkbox> |
| <input |
| disabled |
| type="text" |
| id="regexValue" |
| value="[[_regexDisplayValue(_selectedValue)]]" |
| class=hidden |
| on-input="_valueChange" |
| /> |
| <select id=values size=10 on-change="_valueChange" multiple> |
| <template is="dom-repeat" items="[[_values]]"> |
| <option value="[[item]]" selected="[[_isSelected(item, _selectedValue)]]">[[item]]</option> |
| </template> |
| </select> |
| </div> |
| </div> |
| </template> |
| </dom-module> |
| |
| <script> |
| Polymer({ |
| is: "query2-sk", |
| |
| properties: { |
| // The serialized form of _query. |
| current_query: { |
| type: String, |
| value: "", |
| reflectToAttribute: true, |
| }, |
| // A serialized paramtools.ParamSet, which we are building a query around. |
| // |
| // Might contain a subset of _originalParamset if filtering has been applied. |
| _paramset: { |
| type: Object, |
| value: function() { return {}; }, |
| }, |
| |
| // A serialized paramtools.ParamSet, which we are building a query around. |
| _originalParamset: { |
| type: Object, |
| value: function() { return {}; }, |
| }, |
| |
| // The keys of paramset. |
| _keys: { |
| type: Array, |
| value: function() { return []; }, |
| }, |
| |
| // The currently selected key from _keys. |
| _selectedKey: { |
| type: String, |
| value: "", |
| }, |
| |
| // The currently selected value, i.e. _query[_selectedKey]. |
| _selectedValue: { |
| type: Array, |
| value: function() { return []; }, |
| }, |
| |
| // The values of paramset at _selectedKey. |
| _values: { |
| type: Array, |
| value: function() { return []; }, |
| }, |
| |
| // The current set of user selections. |
| _query: { |
| type: Object, |
| value: function() { return {}; }, |
| }, |
| // The order for some or all of the keys. An array of strings. |
| _key_order: { |
| type: Array, |
| value: [], |
| } |
| }, |
| |
| setCurrentQuery: function(s) { |
| this._query = sk.query.toParamSet(s); |
| this._queryChanged(); |
| }, |
| |
| setParamset: function(paramset) { |
| // Keep a backup, for when we do filtering. |
| this._originalParamset = paramset; |
| this._paramset = paramset; |
| this._recalcKeys(); |
| }, |
| |
| setKeyOrder: function(key_order) { |
| this._key_order = key_order; |
| }, |
| |
| _recalcKeys: function() { |
| var keys = Object.keys(this._paramset); |
| keys.sort(); |
| // Pull out all the keys that appear in _key_order to be pushed |
| // to the front of the list, store them in 'pre'. |
| var pre = []; |
| this._key_order.forEach(function(key) { |
| var index = keys.indexOf(key); |
| if (index != -1) { |
| pre.push(keys.splice(index, 1)[0]); |
| } |
| }.bind(this)); |
| keys = pre.concat(keys); |
| this.set("_keys", keys); |
| this.$.keys.selectedIndex = -1; |
| this.set("_values", []); |
| this.$.invert.disabled = true; |
| this.$.regex.disabled = true; |
| this.$.regexValue.disabled = true; |
| }, |
| |
| _fastFilter: function() { |
| var filters = this.$.fast.value.trim().toLowerCase().split(/\s+/); |
| |
| // Create a closure that returns true if the given label |
| // matches the filter. |
| var matches = function(s) { |
| s = s.toLowerCase(); |
| for (var i = 0; i < filters.length; i++) { |
| if (s.indexOf(filters[i]) >= 0) { |
| return true; |
| } |
| } |
| return false; |
| }; |
| |
| // Loop over this._originalParamset. |
| var filtered = {}; |
| Object.keys(this._originalParamset).forEach(function(paramkey) { |
| // If the param key matches, then all the values go over. |
| if (matches(paramkey)) { |
| filtered[paramkey] = this._originalParamset[paramkey]; |
| } else { |
| // Look for matches in the param values. |
| var valueMatches = []; |
| this._originalParamset[paramkey].forEach(function(paramvalue) { |
| if (matches(paramvalue)) { |
| valueMatches.push(paramvalue); |
| } |
| }.bind(this)); |
| if (valueMatches.length > 0) { |
| filtered[paramkey] = valueMatches; |
| } |
| } |
| }.bind(this)); |
| |
| this._paramset = filtered; |
| this._recalcKeys(); |
| }, |
| |
| _clearFilter: function() { |
| this._paramset = this._originalParamset; |
| this._recalcKeys(); |
| this.$.fast.value = ""; |
| }, |
| |
| // Returns the prefixed value, for example, "!" if it is an inverted search. |
| _prefixValue: function(v) { |
| return (this.$.invert.checked ? '!' : '') + v; |
| }, |
| |
| // Toggles between displaying the text box for a regular expression and |
| // the select box of the param values, depending on the regex checkbox |
| // being checked. |
| _toggleRegexDisplay: function() { |
| if (this.$.regex.checked) { |
| this.$.regexValue.classList.remove("hidden"); |
| this.$.values.classList.add("hidden"); |
| this.$.invert.disabled = true; |
| } else { |
| this.$.regexValue.classList.add("hidden"); |
| this.$.values.classList.remove("hidden"); |
| this.$.invert.disabled = false; |
| } |
| }, |
| |
| _regexTap: function() { |
| this._toggleRegexDisplay(); |
| this._valueChange(); |
| }, |
| |
| _keyChange: function() { |
| var key = this.$.keys.selectedOptions[0].value; |
| this.set("_values", this._paramset[key]); |
| this.set("_selectedValue", this._query[key] || []); |
| this.set("_selectedKey", key); |
| |
| this.$.invert.disabled = false; |
| this.$.regex.disabled = false; |
| this.$.regexValue.disabled = false; |
| |
| // Use !! to force a boolean value, to work around: https://github.com/PolymerElements/paper-checkbox/issues/140 |
| this.$.regex.checked = !!(this._query[key] && this._query[key].length == 1 && this._query[key][0][0] === "~"); |
| this.$.invert.checked = !!(this._query[key] && this._query[key].length >= 1 && this._query[key][0][0] === "!"); |
| this._toggleRegexDisplay(); |
| }, |
| |
| _valueChange: function(e) { |
| if (this.$.regex.checked) { |
| this._query[this._selectedKey] = ["~" + this.$.regexValue.value]; |
| } else { |
| var selectedValues = []; |
| $$("#values option", this).forEach(function(e){ |
| if (e.selected) { |
| selectedValues.push(this._prefixValue(e.value)); |
| } |
| }.bind(this)); |
| this._query[this._selectedKey] = selectedValues; |
| } |
| this._queryChanged(); |
| }, |
| |
| _queryChanged: function() { |
| this.current_query = sk.query.fromParamSet(this._query); |
| this.fire('query-change', {q: this.current_query}); |
| }, |
| |
| _clear: function() { |
| this._query = {}; |
| this._recalcKeys(); |
| this._queryChanged(); |
| }, |
| |
| _isSelected: function(paramValue, selectedValues) { |
| if (!selectedValues) { |
| return false; |
| } |
| return selectedValues.indexOf(this._prefixValue(paramValue)) !== -1; |
| }, |
| |
| _regexDisplayValue: function(arr) { |
| if (arr && arr.length > 0) { |
| return arr[0].slice(1); |
| } |
| return ""; |
| }, |
| |
| }); |
| </script> |