diff options
author | Randy Bertram <rbertram@us.ibm.com> | 2015-03-03 01:40:24 -0500 |
---|---|---|
committer | Randy Bertram <rbertram@us.ibm.com> | 2015-03-03 01:40:24 -0500 |
commit | 60d6954a36e54afa1f925324e7b527d235bdb484 (patch) | |
tree | ecaf5d03a67de9a3653568495ee28f7843069842 | |
parent | 1e15e5bbb55b838bc4289ebc5c39d9c4dd9cb1e4 (diff) | |
download | xstatic-magic-search-60d6954a36e54afa1f925324e7b527d235bdb484.tar.gz |
Update Magic Search to 0.2.00.2.0.1
Update the XStatic Magic Search package, to take
advantage of Eucalyptus' new fixes and features.
This matches what is in PyPI now.
Change-Id: I44c91dd4afb4dd7043c9d0fe204f22feff50f6d5
Implements: blueprint filtered-client-side-table
-rwxr-xr-x | xstatic/pkg/magic_search/__init__.py | 4 | ||||
-rwxr-xr-x | xstatic/pkg/magic_search/data/magic_search.css | 85 | ||||
-rwxr-xr-x | xstatic/pkg/magic_search/data/magic_search.html | 19 | ||||
-rwxr-xr-x | xstatic/pkg/magic_search/data/magic_search.js | 154 | ||||
-rw-r--r--[-rwxr-xr-x] | xstatic/pkg/magic_search/data/magic_search.scss | 17 | ||||
-rwxr-xr-x | xstatic/pkg/magic_search/data/magic_search_bootstrap.html | 50 | ||||
-rwxr-xr-x | xstatic/pkg/magic_search/data/magic_search_bootstrap.js | 28 |
7 files changed, 127 insertions, 230 deletions
diff --git a/xstatic/pkg/magic_search/__init__.py b/xstatic/pkg/magic_search/__init__.py index 9d03d34..95f7fe5 100755 --- a/xstatic/pkg/magic_search/__init__.py +++ b/xstatic/pkg/magic_search/__init__.py @@ -11,9 +11,9 @@ NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar') # please use a all-lowercase valid python # package name -VERSION = '0.1.5' # version of the packaged files, please use the upstream +VERSION = '0.2.0' # version of the packaged files, please use the upstream # version number -BUILD = '9' # our package build number, so we can release new builds +BUILD = '1' # our package build number, so we can release new builds # with fixes for xstatic stuff. PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi diff --git a/xstatic/pkg/magic_search/data/magic_search.css b/xstatic/pkg/magic_search/data/magic_search.css deleted file mode 100755 index ef63fea..0000000 --- a/xstatic/pkg/magic_search/data/magic_search.css +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2014-2015 Eucalyptus Systems, Inc. */ -/*----------------------------------------- - Colors - ----------------------------------------- */ -/*----------------------------------------- - Item list - ----------------------------------------- */ -/*----------------------------------------- - Magic Search bar - ----------------------------------------- */ -/* line 30, ../src/magic_search.scss */ -.search-bar { - position: relative; - border: 1px solid black; - background-color: white; - margin-bottom: 0.5rem; - padding: 4px; - height: auto; -} -/* line 37, ../src/magic_search.scss */ -.search-bar i.fi-filter { - color: #444444; - position: absolute; - top: 0.5rem; - left: 0.65rem; -} -/* line 46, ../src/magic_search.scss */ -.search-bar #search-main-area { - position: relative; - margin-left: 1.65rem; - margin-right: 1.65rem; - cursor: text; -} -/* line 14, ../src/magic_search.scss */ -.search-bar .item-list { - margin-bottom: 6px; -} -/* line 16, ../src/magic_search.scss */ -.search-bar .item-list .item { - color: #333; - background-color: #e6e7e8; - margin-right: 8px; -} -/* line 20, ../src/magic_search.scss */ -.search-bar .item-list .item a { - color: white; -} -/* line 53, ../src/magic_search.scss */ -.search-bar .item-list { - margin-bottom: 2px; -} -/* line 56, ../src/magic_search.scss */ -.search-bar #search-selected { - background-color: white; - color: #444444; -} -/* line 60, ../src/magic_search.scss */ -.search-bar #search-entry { - display: inline-block; - height: 1.5rem; -} -/* line 64, ../src/magic_search.scss */ -.search-bar #search-input { - width: 220px; - border: 0; - box-shadow: none; - height: 1.5rem; - padding: 3px; - background-color: white; -} -/* line 75, ../src/magic_search.scss */ -.search-bar .match { - font-weight: bold; -} -/* line 78, ../src/magic_search.scss */ -.search-bar i.cancel { - color: #444444; - position: absolute; - top: 0.5rem; - right: 0.65rem; -} -/* line 80, ../src/magic_search.scss */ -.search-bar i.cancel:hover { - color: darkred; -} diff --git a/xstatic/pkg/magic_search/data/magic_search.html b/xstatic/pkg/magic_search/data/magic_search.html index e32e795..e005920 100755 --- a/xstatic/pkg/magic_search/data/magic_search.html +++ b/xstatic/pkg/magic_search/data/magic_search.html @@ -1,8 +1,8 @@ <!--! Magic Searchbar --> -<div id="magic-search" magic-overrides> +<div class="magic-search" magic-overrides> <div class="search-bar"> - <i class="fi-filter fa fa-filter go" ng-class="{'has-items': currentSearch.length > 0}"></i> - <div id="search-main-area"> + <i class="fi-filter go"></i> + <div class="search-main-area"> <span class="item-list"> <span class="label radius secondary item" ng-repeat="facet in currentSearch" ng-cloak="cloak"> @@ -10,17 +10,16 @@ {{ facet.label[0] }}:<b>{{ facet.label[1] }}</b> </span> <a class="remove" ng-click="removeFacet($index, $event)" title="{{ strings.remove }}"> - <i class="fi-x fa fa-times"></i> + <i class="fi-x"></i> </a> </span> </span> - <span id="search-selected" class="label" ng-cloak="" ng-show="facetSelected"> + <span class="search-selected label" ng-cloak="" ng-show="facetSelected"> {{ facetSelected.label[0] }}: </span> - <div id="search-entry" is-open="isMenuOpen"> - <input id="search-input" type="text" data-dropdown="facet-drop" dropdown-toggle - placeholder="{{ strings.prompt }}" autocomplete="off" - ng-class="{'has-items': currentSearch.length > 0}" /> + <div class="search-entry" is-open="isMenuOpen"> + <input class="search-input" type="text" data-dropdown="facet-drop" dropdown-toggle + placeholder="{{ strings.prompt }}" autocomplete="off" /> <ul id="facet-drop" class="f-dropdown dropdown-menu" data-dropdown-content=""> <li ng-repeat="facet in filteredObj" ng-show="!facetSelected"> <a ng-click="facetClicked($index, $event, facet.name)" @@ -43,7 +42,7 @@ </div> </div> <a ng-click="clearSearch()" ng-show="currentSearch.length > 0" title="{{ strings.cancel }}"> - <i class="fi-x fa fa-times cancel"></i> + <i class="fi-x cancel"></i> </a> </div> </div> diff --git a/xstatic/pkg/magic_search/data/magic_search.js b/xstatic/pkg/magic_search/data/magic_search.js index 943eda9..347bb33 100755 --- a/xstatic/pkg/magic_search/data/magic_search.js +++ b/xstatic/pkg/magic_search/data/magic_search.js @@ -16,7 +16,7 @@ angular.module('MagicSearch') return { restrict: 'E', scope: { - facets_json: '@facets', + facets_param: '@facets', filter_keys: '=filterKeys', strings: '=strings' }, @@ -24,11 +24,22 @@ angular.module('MagicSearch') return elem.template; }, controller: function ($scope, $timeout) { + $scope.promptString = $scope.strings['prompt']; $scope.currentSearch = []; $scope.initSearch = function() { - // Parse facets JSON and convert to a list of facets. - $scope.facetsJson = $scope.facets_json.replace(/__apos__/g, "\'").replace(/__dquote__/g, '\\"').replace(/__bslash__/g, "\\"); - $scope.facetsObj = JSON.parse($scope.facetsJson); + if (typeof $scope.facets_param === 'string') { + // Parse facets JSON and convert to a list of facets. + var tmp = $scope.facets_param.replace(/__apos__/g, "\'").replace(/__dquote__/g, '\\"').replace(/__bslash__/g, "\\"); + $scope.facetsObj = JSON.parse(tmp); + } + else { + // Assume this is a usable javascript object + $scope.facetsObj = $scope.facets_param; + } + $scope.facetsSave = $scope.copyFacets($scope.facetsObj); + $scope.initFacets(); + }; + $scope.initFacets = function() { // set facets selected and remove them from facetsObj var initialFacets = window.location.search; if (initialFacets.indexOf('?') === 0) { @@ -52,25 +63,47 @@ angular.module('MagicSearch') angular.forEach(value.options, function(option, idx) { if (option.key == facetParts[1]) { $scope.currentSearch.push({'name':facet, 'label':[value.label, option.label]}); - $scope.deleteFacetSelection(facetParts); + if (value.singleton === true) { + $scope.deleteFacetEntirely(facetParts); + } + else { + $scope.deleteFacetSelection(facetParts); + } } }); } } }); }); + if ($scope.textSearch !== undefined) { + $scope.currentSearch.push({'name':'text='+$scope.textSearch, 'label':[$scope.strings['text'], $scope.textSearch]}); + } $scope.filteredObj = $scope.facetsObj; }; + $scope.copyFacets = function(facets) { + var ret = [] + for (var i=0; i<facets.length; i++) { + var facet = Object.create(facets[i]); + if (facets[i].options !== undefined) { + facet.options = []; + for (var j=0; j<facets[i].options.length; j++) { + facet.options.push(Object.create(facets[i].options[j])); + } + } + ret.push(facet); + } + return ret; + } // removes a facet from the menu - $scope.deleteFacetSelection = function(facet_parts) { + $scope.deleteFacetSelection = function(facetParts) { angular.forEach($scope.facetsObj.slice(), function(facet, idx) { - if (facet.name == facet_parts[0]) { + if (facet.name == facetParts[0]) { if (facet.options === undefined) { return; // allow free-form facets to remain } for (var i=0; i<facet.options.length; i++) { var option = facet.options[i]; - if (option.key == facet_parts[1]) { + if (option.key == facetParts[1]) { $scope.facetsObj[idx].options.splice($scope.facetsObj[idx].options.indexOf(option), 1); } } @@ -80,17 +113,25 @@ angular.module('MagicSearch') } }); }; - $('#search-input').on('keydown', function($event) { // handle ctrl-char input + $scope.deleteFacetEntirely = function(facetParts) { + // remove entire facet + angular.forEach($scope.facetsObj.slice(), function(facet, idx) { + if (facet.name == facetParts[0]) { + $scope.facetsObj.splice($scope.facetsObj.indexOf(facet), 1); + } + }); + }; + $('.search-input').on('keydown', function($event) { // handle ctrl-char input var key = $event.keyCode || $event.charCode; if (key == 9) { // prevent default when we can. $event.preventDefault(); } }); - $('#search-input').on('keyup', function($event) { // handle ctrl-char input + $('.search-input').on('keyup', function($event) { // handle ctrl-char input if ($event.metaKey == true) { return; } - var search_val = $('#search-input').val(); + var searchVal = $('.search-input').val(); var key = $event.keyCode || $event.charCode; if (key == 9) { // tab, so select facet if narrowed down to 1 if ($scope.facetSelected === undefined) { @@ -98,30 +139,34 @@ angular.module('MagicSearch') $scope.facetClicked(0, '', $scope.filteredObj[0].name); } else { - if ($scope.filteredOptions.length != 1) return; + if ($scope.filteredOptions === undefined || $scope.filteredOptions.length != 1) return; $scope.optionClicked(0, '', $scope.filteredOptions[0].key); $scope.resetState(); } $timeout(function() { - $('#search-input').val(''); + $('.search-input').val(''); }); return; } if (key == 27) { // esc, so cancel and reset everthing $timeout(function() { $scope.hideMenu(); - $('#search-input').val(''); + $('.search-input').val(''); }); $scope.resetState(); - $scope.$emit('textSearch', '', $scope.filter_keys); + var textFilter = $scope.textSearch; + if (textFilter === undefined) { + textFilter = ''; + } + $scope.$emit('textSearch', textFilter, $scope.filter_keys); return; } if (key == 13) { // enter, so accept value // if tag search, treat as regular facet if ($scope.facetSelected && $scope.facetSelected.options === undefined) { var curr = $scope.facetSelected; - curr.name = curr.name + '=' + search_val; - curr.label[1] = search_val; + curr.name = curr.name + '=' + searchVal; + curr.label[1] = searchVal; $scope.currentSearch.push(curr); $scope.resetState(); $scope.emitQuery(); @@ -134,47 +179,48 @@ angular.module('MagicSearch') $scope.currentSearch.splice(i, 1); } } - $scope.currentSearch.push({'name':'text='+search_val, 'label':[$scope.strings['text'], search_val]}); + $scope.currentSearch.push({'name':'text='+searchVal, 'label':[$scope.strings['text'], searchVal]}); $scope.$apply(); $scope.hideMenu(); - $('#search-input').val(''); - $scope.$emit('textSearch', search_val, $scope.filter_keys); + $('.search-input').val(''); + $scope.$emit('textSearch', searchVal, $scope.filter_keys); + $scope.textSearch = searchVal; } $scope.filteredObj = $scope.facetsObj; } else { - if (search_val === '') { + if (searchVal === '') { $scope.filteredObj = $scope.facetsObj; $scope.$emit('textSearch', '', $scope.filter_keys); } else { - $scope.filterFacets(search_val); + $scope.filterFacets(searchVal); } } }); - $('#search-input').on('keypress', function($event) { // handle character input - var search_val = $('#search-input').val(); + $('.search-input').on('keypress', function($event) { // handle character input + var searchVal = $('.search-input').val(); var key = $event.which || $event.keyCode || $event.charCode; if (key != 8 && key != 46 && key != 13 && key != 9 && key != 27) { - search_val = search_val + String.fromCharCode(key).toLowerCase(); + searchVal = searchVal + String.fromCharCode(key).toLowerCase(); } - if (search_val == ' ') { // space and field is empty, show menu + if (searchVal == ' ') { // space and field is empty, show menu $scope.showMenu(); $timeout(function() { - $('#search-input').val(''); + $('.search-input').val(''); }); return; } - if (search_val === '') { + if (searchVal === '') { $scope.filteredObj = $scope.facetsObj; $scope.$emit('textSearch', '', $scope.filter_keys); return; } if (key != 8 && key != 46) { - $scope.filterFacets(search_val); + $scope.filterFacets(searchVal); } }); - $scope.filterFacets = function(search_val) { + $scope.filterFacets = function(searchVal) { // try filtering facets/options.. if no facets match, do text search var i, idx, label; var filtered = []; @@ -182,9 +228,9 @@ angular.module('MagicSearch') $scope.filteredObj = $scope.facetsObj; for (i=0; i<$scope.filteredObj.length; i++) { var facet = $scope.filteredObj[i]; - idx = facet.label.toLowerCase().indexOf(search_val); + idx = facet.label.toLowerCase().indexOf(searchVal); if (idx > -1) { - label = [facet.label.substring(0, idx), facet.label.substring(idx, idx + search_val.length), facet.label.substring(idx + search_val.length)]; + label = [facet.label.substring(0, idx), facet.label.substring(idx, idx + searchVal.length), facet.label.substring(idx + searchVal.length)]; filtered.push({'name':facet.name, 'label':label, 'options':facet.options}); } } @@ -195,7 +241,7 @@ angular.module('MagicSearch') }, 0.1); } else { - $scope.$emit('textSearch', search_val, $scope.filter_keys); + $scope.$emit('textSearch', searchVal, $scope.filter_keys); $scope.hideMenu(); } } @@ -206,9 +252,9 @@ angular.module('MagicSearch') } for (i=0; i<$scope.filteredOptions.length; i++) { var option = $scope.filteredOptions[i]; - idx = option.label.toLowerCase().indexOf(search_val); + idx = option.label.toLowerCase().indexOf(searchVal); if (idx > -1) { - label = [option.label.substring(0, idx), option.label.substring(idx, idx + search_val.length), option.label.substring(idx + search_val.length)]; + label = [option.label.substring(0, idx), option.label.substring(idx, idx + searchVal.length), option.label.substring(idx + searchVal.length)]; filtered.push({'key':option.key, 'label':label}); } } @@ -221,8 +267,8 @@ angular.module('MagicSearch') } }; // enable text entry when mouse clicked anywhere in search box - $('#search-main-area').on("click", function($event) { - $('#search-input').trigger("focus"); + $('.search-main-area').on("click", function($event) { + $('.search-input').trigger("focus"); if ($scope.facetSelected === undefined) { $scope.showMenu(); } @@ -241,11 +287,11 @@ angular.module('MagicSearch') $scope.showMenu(); } $timeout(function() { - $('#search-input').val(''); + $('.search-input').val(''); }); $scope.strings['prompt'] = ''; $timeout(function() { - $('#search-input').focus(); + $('.search-input').focus(); }); }; // when option clicked, complete facet and send event @@ -273,12 +319,23 @@ angular.module('MagicSearch') } if (removed !== undefined && removed.indexOf('text') === 0) { $scope.$emit('textSearch', '', $scope.filter_keys); + $scope.textSearch = undefined } else { $scope.$emit('searchUpdated', query); if ($scope.currentSearch.length > 0) { var newFacet = $scope.currentSearch[$scope.currentSearch.length-1].name; - $scope.deleteFacetSelection(newFacet.split('=')); + var facetParts = newFacet.split('='); + angular.forEach($scope.facetsSave, function(facet, idx) { + if (facet.name == facetParts[0]) { + if (facet.singleton === true) { + $scope.deleteFacetEntirely(facetParts); + } + else { + $scope.deleteFacetSelection(facetParts); + } + } + }); } } }; @@ -291,25 +348,32 @@ angular.module('MagicSearch') } else { $scope.resetState(); - $('#search-input').val(''); + $('.search-input').val(''); + } + if ($scope.currentSearch.length == 0) { + $scope.strings['prompt'] = $scope.promptString; } - // facet re-enabled by reload + // re-init to restore facets cleanly + $scope.facetsObj = $scope.copyFacets($scope.facetsSave); + $scope.currentSearch = []; + $scope.initFacets(); }; // clear entire searchbar $scope.clearSearch = function() { if ($scope.currentSearch.length > 0) { $scope.currentSearch = []; - $scope.facetsObj = JSON.parse($scope.facetsJson); + $scope.facetsObj = $scope.copyFacets($scope.facetsSave); $scope.resetState(); $scope.$emit('searchUpdated', ''); $scope.$emit('textSearch', '', $scope.filter_keys); + $scope.strings['prompt'] = $scope.promptString; } }; $scope.isMatchLabel = function(label) { return Array.isArray(label); }; $scope.resetState = function() { - $('#search-input').val(''); + $('.search-input').val(''); $scope.filteredObj = $scope.facetsObj; $scope.facetSelected = undefined; $scope.facetOptions = undefined; @@ -320,7 +384,7 @@ angular.module('MagicSearch') $scope.showMenu = function() { $timeout(function() { if ($('#facet-drop').hasClass('open') === false) { - $('#search-input').trigger('click'); + $('.search-input').trigger('click'); } }); }; diff --git a/xstatic/pkg/magic_search/data/magic_search.scss b/xstatic/pkg/magic_search/data/magic_search.scss index 4993fe3..b25cf3a 100755..100644 --- a/xstatic/pkg/magic_search/data/magic_search.scss +++ b/xstatic/pkg/magic_search/data/magic_search.scss @@ -39,11 +39,8 @@ $itembackground: #e6e7e8; position: absolute; top: 0.5rem; left: 0.65rem; - //&.has-items { - // margin-top: 6px; - //} } - #search-main-area { + .search-main-area { position: relative; margin-left: 1.65rem; margin-right: 1.65rem; @@ -53,24 +50,24 @@ $itembackground: #e6e7e8; .item-list { margin-bottom: 2px; } - #search-selected { + .search-selected { background-color: $background; color: $textcolor; } - #search-entry { + .search-entry { display: inline-block; height: 1.5rem; } - #search-input { + .search-input { width: 220px; border: 0; box-shadow: none; height: 1.5rem; padding: 3px; background-color: $background; - //&.has-items { - // margin-top: 6px; - //} + &:focus { + box-shadow: none; + } } .match { font-weight: bold; diff --git a/xstatic/pkg/magic_search/data/magic_search_bootstrap.html b/xstatic/pkg/magic_search/data/magic_search_bootstrap.html deleted file mode 100755 index b8639b0..0000000 --- a/xstatic/pkg/magic_search/data/magic_search_bootstrap.html +++ /dev/null @@ -1,50 +0,0 @@ -<!--! Magic Searchbar --> -<div id="magic-search" magic-overrides> - <div class="search-bar"> - <i class="fi-filter fa fa-filter go" ng-class="{'has-items': currentSearch.length > 0}"></i> - <div id="search-main-area"> - <span class="item-list"> - <span class="label radius secondary item" - ng-repeat="facet in currentSearch" ng-cloak="cloak"> - <span> - {{ facet.label[0] }}:<b>{{ facet.label[1] }}</b> - </span> - <a class="remove" ng-click="removeFacet($index, $event)" title="{{ strings.remove }}"> - <i class="fi-x fa fa-times"></i> - </a> - </span> - </span> - <span id="search-selected" class="label" ng-cloak="" ng-show="facetSelected"> - {{ facetSelected.label[0] }}: - </span> - <!-- For bootstrap, the dropdown attribute is moved from input up to div. --> - <div id="search-entry" dropdown is-open="isMenuOpen"> - <input id="search-input" type="text" dropdown-toggle - placeholder="{{ strings.prompt }}" autocomplete="off" - ng-class="{'has-items': currentSearch.length > 0}" /> - <ul id="facet-drop" class="f-dropdown dropdown-menu" data-dropdown-content=""> - <li ng-repeat="facet in filteredObj" ng-show="!facetSelected"> - <a ng-click="facetClicked($index, $event, facet.name)" - ng-show="!isMatchLabel(facet.label)">{{ facet.label }}</a> - <a ng-click="facetClicked($index, $event, facet.name)" - ng-show="isMatchLabel(facet.label)"> - {{ facet.label[0] }}<span class="match">{{ facet.label[1] }}</span>{{ facet.label[2] }} - </a> - </li> - <li ng-repeat="option in filteredOptions" ng-show="facetSelected"> - <a ng-click="optionClicked($index, $event, option.key)" - ng-show="!isMatchLabel(option.label)"> - {{ option.label }} - </a> - <a ng-click="optionClicked($index, $event, option.key)" - ng-show="isMatchLabel(option.label)"> - {{ option.label[0] }}<span class="match">{{ option.label[1] }}</span>{{ option.label[2] }} - </a> - </ul> - </div> - </div> - <a ng-click="clearSearch()" ng-show="currentSearch.length > 0" title="{{ strings.cancel }}"> - <i class="fi-x fa fa-times cancel"></i> - </a> - </div> -</div> diff --git a/xstatic/pkg/magic_search/data/magic_search_bootstrap.js b/xstatic/pkg/magic_search/data/magic_search_bootstrap.js deleted file mode 100755 index 69810fe..0000000 --- a/xstatic/pkg/magic_search/data/magic_search_bootstrap.js +++ /dev/null @@ -1,28 +0,0 @@ -angular.module('MagicSearch', ['ui.bootstrap']) - .directive('magicOverrides', function() { - return { - restrict: 'A', - controller: function($scope) { - // showMenu and hideMenu depend on foundation's dropdown. They need - // to be modified to work with another dropdown implemenation. - // For bootstrap, they are not needed at all. - $scope.showMenu = function() { - $scope.isMenuOpen = true; - }; - $scope.hideMenu = function() { - $scope.isMenuOpen = false; - }; - $scope.isMenuOpen = false; - - // remove the following when magic_search.js handles changing the facets/options - $scope.$watch('facets_json', function(newVal, oldVal) { - if (newVal === oldVal) { - return; - } - $scope.currentSearch = []; - $scope.initSearch(); - }); - - } - }; - });
\ No newline at end of file |