Merge "Magic Search enhancements"

This commit is contained in:
Jenkins 2015-04-23 14:57:42 +00:00 committed by Gerrit Code Review
commit bafcfb02de
4 changed files with 174 additions and 37 deletions

View File

@ -1,15 +1,19 @@
<!--! Magic Searchbar --> <!--! Magic Searchbar -->
<div class="magic-search" magic-overrides> <div class="magic-search" magic-overrides>
<div class="search-bar"> <div class="search-bar">
<i class="fi-filter fa fa-filter go"></i> <i class="fi-filter fa fa-search go"></i>
<div class="search-main-area"> <div class="search-main-area">
<span class="item-list"> <span class="item-list">
<span class="label radius secondary item" <span class="label radius secondary item"
ng-repeat="facet in currentSearch" ng-cloak="cloak"> ng-repeat="facet in currentSearch" ng-cloak="cloak" ng-class="{'server-side-item': facet.isServer}">
<i data-toggle="tooltip" title="{$ ::strings.serverFacet $}"
ng-class="{'fa fa-server': facet.isServer}"></i>
<i data-toggle="tooltip" title="{$ ::strings.clientFacet $}"
ng-class="{'fa fa-desktop': !facet.isServer}"></i>
<span> <span>
{$ facet.label[0] $}:<b>{$ facet.label[1] $}</b> {$ ::facet.label[0] $}:<b>{$ ::facet.label[1] $}</b>
</span> </span>
<a class="remove" ng-click="removeFacet($index, $event)" title="{$ strings.remove $}"> <a class="remove" ng-click="removeFacet($index, $event)" title="{$ ::strings.remove $}">
<i class="fi-x fa fa-times"></i> <i class="fi-x fa fa-times"></i>
</a> </a>
</span> </span>
@ -24,10 +28,10 @@
<ul id="facet-drop" class="f-dropdown dropdown-menu" data-dropdown-content=""> <ul id="facet-drop" class="f-dropdown dropdown-menu" data-dropdown-content="">
<li ng-repeat="facet in filteredObj" ng-show="!facetSelected"> <li ng-repeat="facet in filteredObj" ng-show="!facetSelected">
<a ng-click="facetClicked($index, $event, facet.name)" <a ng-click="facetClicked($index, $event, facet.name)"
ng-show="!isMatchLabel(facet.label)">{$ facet.label $}</a> ng-show="!isMatchLabel(facet.label)">{$ ::facet.label $}</a>
<a ng-click="facetClicked($index, $event, facet.name)" <a ng-click="facetClicked($index, $event, facet.name)"
ng-show="isMatchLabel(facet.label)"> ng-show="isMatchLabel(facet.label)">
{$ facet.label[0] $}<span class="match">{$ facet.label[1] $}</span>{$ facet.label[2] $} {$ ::facet.label[0] $}<span class="match">{$ ::facet.label[1] $}</span>{$ ::facet.label[2] $}
</a> </a>
</li> </li>
<li ng-repeat="option in filteredOptions" ng-show="facetSelected"> <li ng-repeat="option in filteredOptions" ng-show="facetSelected">
@ -37,13 +41,13 @@
</a> </a>
<a ng-click="optionClicked($index, $event, option.key)" <a ng-click="optionClicked($index, $event, option.key)"
ng-show="isMatchLabel(option.label)"> ng-show="isMatchLabel(option.label)">
{$ option.label[0] $}<span class="match">{$ option.label[1] $}</span>{$ option.label[2] $} {$ ::option.label[0] $}<span class="match">{$ ::option.label[1] $}</span>{$ ::option.label[2] $}
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<a ng-click="clearSearch()" ng-show="currentSearch.length &gt; 0" title="{$ strings.cancel $}"> <a ng-click="clearSearch()" ng-show="currentSearch.length &gt; 0" title="{$ ::strings.cancel $}">
<i class="fi-x fa fa-times cancel"></i> <i class="fi-x fa fa-times cancel"></i>
</a> </a>
</div> </div>

View File

@ -1,35 +1,149 @@
(function() { (function() {
'use strict'; 'use strict';
angular.module('MagicSearch', ['ui.bootstrap']) angular.module('MagicSearch', ['ui.bootstrap'])
.directive('magicOverrides', function() { /**
return { * @ngdoc directive
restrict: 'A', * @name MagicSearch:magicOverrides
controller: ['$scope', '$timeout', * @description
function($scope, $timeout) { * A directive to modify / extend Magic Search functionality for use in
// showMenu and hideMenu depend on foundation's dropdown. They need * Horizon.
// to be modified to work with another dropdown implemenation. * 1. The base magic search uses Foundation, and in showMenu and
// For bootstrap, they are not needed at all. * hide menu makes a Foundation call, therefore we need to override.
$scope.showMenu = function() { *
$timeout(function() { * 2. Added 'facetsChanged' listener so we can notify base magic search
$scope.isMenuOpen = true; * widget that new facets are available so they will be picked up. (Use
}); * if your table has dynamic facets)
}; *
$scope.hideMenu = function() { * 3. To support the distinguishment between server & client side facets
$timeout(function() { * overrode methods removeFacet & initfacets to emit 'checkFacets' event
$scope.isMenuOpen = false; * so implementors can add propterty isServer to facets. (what keys the
}); * facet icon and color difference)
}; *
$scope.isMenuOpen = false; * 4. Overrode initfacets to fix refresh / bookmark issue where facets
* menu wasn't removing facets that were already on url.
*
* @restrict A
* @scope
*
* @example
* ```
* <div class="magic-search" magic-overrides>
* ```
*/
.directive('magicOverrides', function() {
return {
restrict: 'A',
controller: ['$scope', '$timeout',
function($scope, $timeout) {
// showMenu and hideMenu depend on foundation's dropdown. They need
// to be modified to work with another dropdown implementation.
// For bootstrap, they are not needed at all.
$scope.showMenu = function() {
$timeout(function() {
$scope.isMenuOpen = true;
});
};
$scope.hideMenu = function() {
$timeout(function() {
$scope.isMenuOpen = false;
});
};
$scope.isMenuOpen = false;
// magic_search.js should absorb this code? // Add ability to update facet
$scope.$on('facetsChanged', function() { // Broadcast event when fact options are returned via ajax.
// Should magic_search.js absorb this?
$scope.$on('facetsChanged', function() {
$timeout(function() {
$scope.currentSearch = [];
$scope.initSearch();
});
});
// Override magic_search.js initFacets to fix browswer refresh issue
// and to emit('checkFacets') to flag facets as isServer
$scope.initFacets = function() {
// set facets selected and remove them from facetsObj
var initialFacets = window.location.search;
if (initialFacets.indexOf('?') === 0) {
initialFacets = initialFacets.slice(1);
}
initialFacets = initialFacets.split('&');
if (initialFacets.length > 1 || initialFacets[0].length > 0) {
$timeout(function() { $timeout(function() {
$scope.currentSearch = []; $scope.strings.prompt = '';
$scope.initSearch(); });
}
angular.forEach(initialFacets, function(facet, idx) {
var facetParts = facet.split('=');
angular.forEach($scope.facetsObj, function(value, idx) {
if (value.name == facetParts[0]) {
if (value.options === undefined) {
$scope.currentSearch.push({
'name': facet,
'label': [value.label, facetParts[1]]
});
// for refresh case, need to remove facets that were bookmarked/
// current when broswer refresh was clicked
$scope.deleteFacetEntirely(facetParts);
} else {
angular.forEach(value.options, function(option, idx) {
if (option.key == facetParts[1]) {
$scope.currentSearch.push({
'name': facet,
'label': [value.label, option.label]
});
if (value.singleton === true) {
$scope.deleteFacetEntirely(facetParts);
} else {
$scope.deleteFacetSelection(facetParts);
}
}
});
}
}
}); });
}); });
} if ($scope.textSearch !== undefined) {
] $scope.currentSearch.push({
}; // end of return 'name': 'text=' + $scope.textSearch,
}); // end of directive 'label': [$scope.strings.text, $scope.textSearch]
});
}
$scope.filteredObj = $scope.facetsObj;
// broadcast to check facets for serverside
$scope.$emit('checkFacets', $scope.currentSearch);
};
// Override magic_search.js removeFacet to emit('checkFacets')
// to flag facets as isServer after removing facet and
// either update filter or search
$scope.removeFacet = function($index, $event) {
var removed = $scope.currentSearch[$index].name;
$scope.currentSearch.splice($index, 1);
if ($scope.facetSelected === undefined) {
$scope.emitQuery(removed);
} else {
$scope.resetState();
$('.search-input').val('');
}
if ($scope.currentSearch.length === 0) {
$scope.strings.prompt = $scope.promptString;
}
// re-init to restore facets cleanly
$scope.facetsObj = $scope.copyFacets($scope.facetsSave);
$scope.currentSearch = [];
$scope.initFacets();
// broadcast to check facets for serverside
$scope.$emit('checkFacets', $scope.currentSearch);
};
}
]
}; // end of return
}); // end of directive
})(); })();

View File

@ -1,25 +1,44 @@
// Augments magic_search.scss with styles for bootstrap/Horizon. // Augments magic_search.scss with styles for bootstrap/Horizon.
.search-bar { .search-bar {
min-width: 500px;
border-color: #ccc;
border-radius: 3px;
margin-bottom: 0;
.search-entry { .search-entry {
.search-input { .search-input {
padding: 1px 0px; padding: 1px 0px;
font: normal normal normal 12.6px/normal; font: normal normal normal 12.6px/normal;
outline: none; outline: none;
height: 24px; height: 24px;
width: 500px;
} }
height: 24px; height: 24px;
position: relative; position: relative;
} }
.item-list {
.item {
background-color: $gray-light;
a {
color: $brand-danger;
}
}
.server-side-item {
background-color: $gray-lighter;
}
}
.fa-filter { .fa-filter {
padding-left: 5px; padding-left: 5px;
font-size: larger; font-size: larger;
} }
.fa-times { .fa-times {
font-size: larger; font-size: larger;
cursor: pointer; cursor: pointer;
} }
.label { .label {
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;

View File

@ -14,6 +14,7 @@
// Vendor Components // Vendor Components
@import "/bootstrap/scss/bootstrap"; @import "/bootstrap/scss/bootstrap";
@import "/horizon/lib/font-awesome/scss/font-awesome.scss"; @import "/horizon/lib/font-awesome/scss/font-awesome.scss";
@import "/horizon/lib/magic_search/magic_search.scss";
// Dashboard Components // Dashboard Components
@import "splash"; @import "splash";
@ -26,7 +27,6 @@
@import "components/network_topology"; @import "components/network_topology";
@import "/angular/styles"; @import "/angular/styles";
@import "/horizon/lib/magic_search/magic_search.scss";
/* new clearfix */ /* new clearfix */
.clearfix:after { .clearfix:after {