blob: 0b6b0d93c7ab754b6d51a1cb170567f2761e4b6a [file] [log] [blame]
<!-- 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.
'query-change-delayed'
The same exact event as query-change, but with a 500ms delay after
the query stops changing.
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-input/paper-input.html">
<link rel="import" href="/res/imp/bower_components/iron-selector/iron-selector.html">
<link rel="import" href="query2-values-sk.html">
<dom-module id="query2-sk">
<style include="iron-flex iron-flex-alignment iron-positioning">
input {
margin: 0 1em;
}
iron-selector {
cursor: pointer;
border: solid 1px #A6CEE3;
margin-top: 6px;
max-height: 600px;
overflow-y: auto;
}
iron-selector div {
padding: 0.4em 1.2em;
background-color: white;
border: none;
outline: none;
line-height: 20px;
vertical-align: middle;
}
iron-selector div:hover {
background-color: #A6CEE3;
}
iron-selector div.iron-selected {
background: #eee;
}
iron-selector div.iron-selected:hover {
background: #1F78B4;
color: white;
}
</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>
<iron-selector id=keys size=12
on-selected-items-changed="_keyChange"
attr-for-selected=value
>
<template is="dom-repeat" items="[[_keys]]">
<div value="[[item]]">[[item]]</div>
</template>
</iron-selector>
<button on-tap="_clear">Clear Selections</button>
</div>
<query2-values-sk id=values on-query2-values-changed="_valuesChanged"></query2-values-sk>
</div>
</template>
</dom-module>
<script>
Polymer({
is: "query2-sk",
properties: {
// The serialized form of _query.
current_query: {
type: String,
value: "",
reflectToAttribute: true,
notify: true,
observer: "_currentQueryChanged",
},
// 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 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: [],
},
_delayedTimeout: {
type: Number,
value: null,
},
},
setCurrentQuery: function(s) {
this._query = sk.query.toParamSet(s);
this._queryChanged();
},
_currentQueryChanged: function(s) {
this.setCurrentQuery(s)
},
setParamset: function(paramset) {
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);
var key = this.$.keys.selected;
this.set("_keys", keys);
this.$.keys.selectedIndex = -1;
this.$.keys.selected = key;
this._keyChange();
},
_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 = "";
},
_keyChange: function() {
var key = this.$.keys.selected;
this.$.values.setOptions(this._paramset[key], this._query[key]);
},
_valuesChanged: function(e) {
var key = this.$.keys.selected;
this._query[key] = e.detail;
this._queryChanged();
},
_queryChanged: function() {
var prev_query = this.current_query;
this.current_query = sk.query.fromParamSet(this._query);
if (prev_query !== this.current_query) {
this.dispatchEvent(new CustomEvent('query-change', {
detail: {q: this.current_query},
bubbles: true,
}));
clearTimeout(this._delayedTimeout);
this._delayedTimeout = setTimeout(function() {
this.dispatchEvent(new CustomEvent('query-change-delayed', {
detail: {q: this.current_query},
bubbles: true,
}));
}.bind(this), 500);
}
},
_clear: function() {
this._query = {};
this._recalcKeys();
this._queryChanged();
},
});
</script>