blob: 61912c33a49bffb9ce06f9aba595d488d2875f7e [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Wrapper View for all filter components. Layout template and common actions are located inside of it.
* Logic specific for data component(input, select, or custom multi select, which fire any changes on interface) are
* located in inner view - <code>filterView</code>.
*
* If we want to have input filter, put <code>textFieldView</code> to it.
* All inner views implemented below this view.
* @type {*}
*/
var wrapperView = Ember.View.extend({
classNames: ['view-wrapper'],
layout: Ember.Handlebars.compile('<a href="#" {{action "clearFilter" target="view"}} class="ui-icon ui-icon-circle-close"></a> {{yield}}'),
template: Ember.Handlebars.compile('{{#if view.fieldId}}<input type="hidden" id="{{unbound view.fieldId}}" value="" />{{/if}} {{view view.filterView}}'),
value: null,
/**
* If this field is exists we dynamically create hidden input element and set value there.
* Used for some cases, where this values will be used outside of component
*/
fieldId: null,
clearFilter: function(){
this.set('value', this.get('emptyValue'));
return false;
},
/**
* Use to determine whether filter is clear or not. Also when we want to set empty value
*/
emptyValue: '',
/**
* Whether our <code>value</code> is empty or not
* @return {Boolean}
*/
isEmpty: function(){
if(this.get('value') === null){
return true;
}
return this.get('value').toString() === this.get('emptyValue').toString();
},
/**
* Show/Hide <code>Clear filter</code> button.
* Also this method updates computed field related to <code>fieldId</code> if it exists.
* Call <code>onChangeValue</code> callback when everything is done.
*/
showClearFilter: function(){
if(!this.get('parentNode')){
return;
}
if(this.isEmpty()){
this.get('parentNode').addClass('notActive');
} else {
this.get('parentNode').removeClass('notActive');
}
if(this.get('fieldId')){
this.$('> input').eq(0).val(this.get('value'));
}
this.onChangeValue();
}.observes('value'),
/**
* Callback for value changes
*/
onChangeValue: function(){
},
/**
* Filter components is located here. Should be redefined
*/
filterView: Em.View,
/**
* Update class of parentNode(hide clear filter button) on page load
*/
didInsertElement: function(){
var parent = this.$().parent();
this.set('parentNode', parent);
parent.addClass('notActive');
}
});
/**
* Simple input control for wrapperView
*/
var textFieldView = Ember.TextField.extend({
type:'text',
placeholder: 'Any',
valueBinding: "parentView.value"
});
/**
* Simple multiselect control for wrapperView.
* Used to render blue button and popup, which opens on button click.
* All content related logic should be implemented manually outside of it
*/
var componentFieldView = Ember.View.extend({
classNames: ['btn-group'],
classNameBindings: ['isFilterOpen:open:'],
/**
* Whether popup is shown or not
*/
isFilterOpen: false,
/**
* We have <code>value</code> property similar to inputs <code>value</code> property
*/
valueBinding: 'parentView.value',
/**
* Clear filter to initial state
*/
clearFilter: function(){
this.set('value', '');
},
/**
* Onclick handler for <code>cancel filter</code> button
*/
closeFilter:function () {
$(document).unbind('click');
this.set('isFilterOpen', false);
},
/**
* Onclick handler for <code>apply filter</code> button
*/
applyFilter:function() {
this.closeFilter();
},
/**
* Onclick handler for <code>show component filter</code> button.
* Also this function is used in some other places
*/
clickFilterButton:function () {
var self = this;
this.set('isFilterOpen', !this.get('isFilterOpen'));
if (this.get('isFilterOpen')) {
var dropDown = this.$('.filter-components');
var firstClick = true;
$(document).bind('click', function (e) {
if (!firstClick && $(e.target).closest(dropDown).length == 0) {
self.set('isFilterOpen', false);
$(document).unbind('click');
}
firstClick = false;
});
}
}
});
/**
* Simple select control for wrapperView
*/
var selectFieldView = Ember.Select.extend({
selectionBinding: 'parentView.value',
contentBinding: 'parentView.content'
});
/**
* Result object, which will be accessible outside
* @type {Object}
*/
module.exports = {
/**
* You can access wrapperView outside
*/
wrapperView : wrapperView,
/**
* And also controls views if need it
*/
textFieldView : textFieldView,
selectFieldView: selectFieldView,
componentFieldView: componentFieldView,
/**
* Quick create input filters
* @param config parameters of <code>wrapperView</code>
*/
createTextView : function(config){
config.fieldType = config.fieldType || 'input-medium';
config.filterView = textFieldView.extend({
classNames : [ config.fieldType ]
});
return wrapperView.extend(config);
},
/**
* Quick create multiSelect filters
* @param config parameters of <code>wrapperView</code>
*/
createComponentView : function(config){
config.clearFilter = function(){
this.forEachChildView(function(item){
if(item.clearFilter){
item.clearFilter();
}
});
return false;
};
return wrapperView.extend(config);
},
/**
* Quick create select filters
* @param config parameters of <code>wrapperView</code>
*/
createSelectView: function(config){
config.fieldType = config.fieldType || 'input-medium';
config.filterView = selectFieldView.extend({
classNames : [ config.fieldType ]
});
config.emptyValue = 'Any';
return wrapperView.extend(config);
},
/**
* returns the filter function, which depends on the type of property
* @param type
* @param isGlobal check is search global
* @return {Function}
*/
getFilterByType: function(type, isGlobal){
switch (type){
case 'ambari-bandwidth':
return function(rowValue, rangeExp){
var compareChar = isNaN(rangeExp.charAt(0)) ? rangeExp.charAt(0) : false;
var compareScale = rangeExp.charAt(rangeExp.length - 1);
var compareValue = compareChar ? parseFloat(rangeExp.substr(1, rangeExp.length)) : parseFloat(rangeExp.substr(0, rangeExp.length));
var match = false;
if (rangeExp.length == 1 && compareChar !== false) {
// User types only '=' or '>' or '<', so don't filter column values
match = true;
return match;
}
switch (compareScale) {
case 'g':
compareValue *= 1073741824;
break;
case 'm':
compareValue *= 1048576;
break;
case 'k':
compareValue *= 1024;
break;
default:
//default value in GB
compareValue *= 1073741824;
}
rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue;
var convertedRowValue;
if (rowValue === '<1KB') {
convertedRowValue = 1;
} else {
var rowValueScale = rowValue.substr(rowValue.length - 2, 2);
switch (rowValueScale) {
case 'KB':
convertedRowValue = parseFloat(rowValue)*1024;
break;
case 'MB':
convertedRowValue = parseFloat(rowValue)*1048576;
break;
case 'GB':
convertedRowValue = parseFloat(rowValue)*1073741824;
break;
}
}
switch (compareChar) {
case '<':
if (compareValue > convertedRowValue) match = true;
break;
case '>':
if (compareValue < convertedRowValue) match = true;
break;
case false:
case '=':
if (compareValue == convertedRowValue) match = true;
break;
}
return match;
}
break;
case 'number':
return function(rowValue, rangeExp){
var compareChar = rangeExp.charAt(0);
var compareValue;
var match = false;
if (rangeExp.length == 1) {
if (isNaN(parseInt(compareChar))) {
// User types only '=' or '>' or '<', so don't filter column values
match = true;
return match;
}
else {
compareValue = parseFloat(parseFloat(rangeExp).toFixed(2));
}
}
else {
if (isNaN(parseInt(compareChar))) {
compareValue = parseFloat(parseFloat(rangeExp.substr(1, rangeExp.length)).toFixed(2));
}
else {
compareValue = parseFloat(parseFloat(rangeExp.substr(0, rangeExp.length)).toFixed(2));
}
}
rowValue = parseFloat((jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue);
match = false;
switch (compareChar) {
case '<':
if (compareValue > rowValue) match = true;
break;
case '>':
if (compareValue < rowValue) match = true;
break;
case '=':
if (compareValue == rowValue) match = true;
break;
default:
if (rangeExp == rowValue) match = true;
}
return match;
}
break;
case 'multiple':
return function(origin, compareValue){
var options = compareValue.split(',');
var rowValue = origin.mapProperty('componentName').join(" ");
var str = new RegExp(compareValue, "i");
for (var i = 0; i < options.length; i++) {
if(!isGlobal) {
str = new RegExp('(\\W|^)' + options[i] + '(\\W|$)');
}
if (rowValue.search(str) !== -1) {
return true;
}
}
return false;
}
break;
case 'string':
default:
return function(origin, compareValue){
var regex = new RegExp(compareValue,"i");
return regex.test(origin);
}
}
}
};