From fb4d4ef7cd79d3c28a100ed66c55d984e65c6e4f Mon Sep 17 00:00:00 2001 From: Victor Calvello Date: Wed, 9 Sep 2015 17:08:41 -0300 Subject: [PATCH] added opt to avoid input focus on show --- README.md | 33 +++++++++++++--------- dist/ionic.filter.bar.js | 11 +++++--- dist/ionic.filter.bar.min.js | 2 +- js/ionic.filter.bar.directive.js | 2 +- js/ionic.filter.bar.service.js | 9 ++++-- test/unit/ionic.filter.bar.service.unit.js | 5 +++- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index fa06c0f..3eb7e9a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Run the following ommands: npm install bower install gulp - + ## Setup #### Install @@ -49,7 +49,7 @@ Keyboard in your module's run section. #### JS/CSS Imports (index.html) Include the following JavaScript/CSS file imports in your index.html. Remember to import the ionic libraries first! The example below assumes your 3rd party bower dependencies are located in the default bower_components folder. - + @@ -155,7 +155,7 @@ A service you can inject in your controller to show the filter bar @param {object} options The options for the filterBar. Properties: - + - `[Object]` `items` The array of items to filter. When the filterBar is cancelled or removed, the original list of items will @@ -165,7 +165,7 @@ A service you can inject in your controller to show the filter bar - `{function=}` `update` Called after the items are filtered. The new filtered items will be passed to this function which can be used - to update the items on your controller's scope. The text string that was searched on will be passed as the + to update the items on your controller's scope. The text string that was searched on will be passed as the second argument. @@ -194,32 +194,32 @@ A service you can inject in your controller to show the filter bar - `{function=}` `expression` - The predicate to be used for selecting items from the `items` array. This is similar to the angular filter - `expression` function described [here](https://docs.angularjs.org/api/ng/filter/filter), except that the first + The predicate to be used for selecting items from the `items` array. This is similar to the angular filter + `expression` function described [here](https://docs.angularjs.org/api/ng/filter/filter), except that the first argument will be the filterText as shown below. Default value is `null`. NOTE: This property will take precedence over `filterProperties`. Only one can be defined. - + function (filterText, value, index, array) { return value.propertyName === filterText || value.anotherPropertyName === filterText; } - `{function,true,false,undefined=}` `comparator` - Determines if the expected value (from the filter expression) and actual value (from the object in the array) - should be considered a match. This is the same as the angular filter `comparator` argument described [here](https://docs.angularjs.org/api/ng/filter/filter). + Determines if the expected value (from the filter expression) and actual value (from the object in the array) + should be considered a match. This is the same as the angular filter `comparator` argument described [here](https://docs.angularjs.org/api/ng/filter/filter). Default value is `undefined`. - + - `[String]` `filterProperties` A string or string array of object properties that will be used to create a filterExpression object for - filtering items in the array. All properties will be matched against the input filter text. For example, given + filtering items in the array. All properties will be matched against the input filter text. For example, given the following object in an array of items , and assume the user searches for "fish" - + {name: 'fish', description: 'fish', color: 'blue'} - + filterProperties: ['name', 'description'] ... The object will be matched and passed to the array in `update` filterProperties: ['name', 'color'] ... The object will NOT be matched or passed to the array in `update` - + NOTE: If `expression` is defined, `filterProperties` will have no effect. Only one can be defined. Default value is null. @@ -252,6 +252,11 @@ A service you can inject in your controller to show the filter bar - `.modal` (Appends to a modal) - `.menu-content` (Appends to the content section of a side menu. Useful when the expose-aside-when attr is set.) + - `{boolean=}` `focusOnShow` + + Whether to focus the search input on filterBar show. If false, backdrop will be hidden. Default value is true. + + ## Screenshots diff --git a/dist/ionic.filter.bar.js b/dist/ionic.filter.bar.js index 9d39717..73fea4b 100644 --- a/dist/ionic.filter.bar.js +++ b/dist/ionic.filter.bar.js @@ -61,7 +61,7 @@ angular.module('jett.ionic.filter.bar', ['ionic']); cancelEl.bind('click', cancelFilterBar); // If backdrop is enabled, create and append it to filter, then add click/swipe listeners to cancel filter - if ($scope.config.backdrop) { + if ($scope.config.backdrop && $scope.focusOnShow) { backdrop = angular.element('
'); $element.append(backdrop); @@ -387,7 +387,8 @@ angular.module('jett.ionic.filter.bar', ['ionic']); delay: 300, cancelText: 'Cancel', cancelOnStateChange: true, - container: $body + container: $body, + focusOnShow: true, }, opts); //if no custom theme was configured, get theme of containers bar-header @@ -561,8 +562,10 @@ angular.module('jett.ionic.filter.bar', ['ionic']); $timeout(function () { filterWrapperEl.addClass('filter-bar-in'); - scope.focusInput(); - scope.showBackdrop(); + if (scope.focusOnShow) { + scope.focusInput(); + scope.showBackdrop(); + } (done || angular.noop)(); }, 20, false); }); diff --git a/dist/ionic.filter.bar.min.js b/dist/ionic.filter.bar.min.js index 35d79a7..1ef9a22 100644 --- a/dist/ionic.filter.bar.min.js +++ b/dist/ionic.filter.bar.min.js @@ -1 +1 @@ -angular.module("jett.ionic.filter.bar",["ionic"]),function(e){"use strict";e.module("jett.ionic.filter.bar").directive("ionFilterBar",["$document","$timeout","$ionicGesture","$ionicPlatform",function(t,n,r,i){var o;return o=i.is("android")?'
':'
',{restrict:"E",scope:!0,link:function(i,o){var a,c,l,s,f,u=e.element(o[0].querySelector(".filter-bar-clear")),d=e.element(o[0].querySelector(".filter-bar-cancel")),p=o.find("input");i.filterText="";var b=function(){i.cancelFilterBar()};d.bind("click",b),i.config.backdrop&&(l=e.element('
'),o.append(l),s=function(e){e.target==l[0]&&b()},l.bind("click",s),c=r.on("swipe",s,l));var m=function(){"none"===u.css("display")&&u.css("display","block")},h=function(){"block"===u.css("display")&&u.css("display","none")},g=function(){n(function(){i.filterText="",h(),ionic.requestAnimationFrame(function(){i.showBackdrop(),i.scrollItemsTop(),i.focusInput()})})};u.bind("touchstart mousedown",g),p.bind("touchstart mousedown",function(){i.scrollItemsTop(),i.focusInput()});var v=function(e){27==e.which?b():i.filterText&&i.filterText.length?(m(),i.hideBackdrop()):(h(),i.showBackdrop())};t.bind("keyup",v);var B=function(){i.filterItems(i.filterText)};i.$on("$destroy",function(){o.remove(),t.unbind("keyup",v),l&&r.off(c,"swipe",s),f()}),f=i.$watch("filterText",function(e,t){var r;a&&n.cancel(a),e!==t&&(r=e.length&&i.debounce?i.delay:0,a=n(B,r,!1))})},template:o}}])}(angular),function(e){"use strict";e.module("jett.ionic.filter.bar").provider("$ionicFilterBarConfig",function(){function t(e,t){c.platform[e]=t,o.platform[e]={},n(c,c.platform[e]),r(c.platform[e],o.platform[e],"")}function n(t,r){for(var i in t)i!=a&&t.hasOwnProperty(i)&&(e.isObject(t[i])?(e.isDefined(r[i])||(r[i]={}),n(t[i],r[i])):e.isDefined(r[i])||(r[i]=null))}function r(t,n,o){e.forEach(t,function(l,s){e.isObject(t[s])?(n[s]={},r(t[s],n[s],o+"."+s)):n[s]=function(e){if(arguments.length)return t[s]=e,n;if(t[s]==a){var r=i(c.platform,ionic.Platform.platform()+o+"."+s);return r||r===!1?r:i(c.platform,"default"+o+"."+s)}return t[s]}})}function i(t,n){n=n.split(".");for(var r=0;r')(s),g=h.children().eq(0),v=g.find("input")[0],B=h.children().eq(1),k=s.scrollDelegate.getScrollView(),$=!!k,y=$?e.element(k.__container):null,w=s.cancelOnStateChange?i.$on("$stateChangeSuccess",function(){s.cancelFilterBar()}):e.noop,T=function(){d||(d=!0,v&&v.focus())},F=function(){d&&(d=!1,v&&v.blur())},x=function(){k.__scrollTop>0&&F()};return s.scrollItemsTop=function(){$&&s.scrollDelegate.scrollTop&&s.scrollDelegate.scrollTop()},s.focusInput=function(){d=!1,T()},s.hideBackdrop=function(){B.length&&f&&(f=!1,B.removeClass("active").css("display","none"))},s.showBackdrop=function(){B.length&&!f&&(f=!0,B.css("display","block").addClass("active"))},s.filterItems=function(t){var n,r;t.length?(s.expression?n=e.bind(this,s.expression,t):e.isArray(s.filterProperties)?(n={},e.forEach(s.filterProperties,function(e){n[e]=t})):s.filterProperties?(n={},n[s.filterProperties]=t):n=t,r=s.filter(s.items,n,s.comparator)):r=s.items,a(function(){s.update(r,t),s.scrollItemsTop()})},s.$deregisterBackButton=l.registerBackButtonAction(function(){a(s.cancelFilterBar)},300),s.removeFilterBar=function(n){s.removed||(s.removed=!0,t.requestAnimationFrame(function(){g.removeClass("filter-bar-in"),F(),s.hideBackdrop(),a(function(){s.scrollItemsTop(),s.update(s.items),s.$destroy(),h.remove(),s.cancelFilterBar.$scope=y=k=g=B=v=null,p=!1,(n||e.noop)()},350)}),a(function(){s.container.removeClass("filter-bar-open")},400),s.$deregisterBackButton(),w(),y&&y.off("scroll",x))},s.showFilterBar=function(n){s.removed||(s.container.append(h).addClass("filter-bar-open"),s.scrollItemsTop(),t.requestAnimationFrame(function(){s.removed||a(function(){g.addClass("filter-bar-in"),s.focusInput(),s.showBackdrop(),(n||e.noop)()},20,!1)}),y&&y.on("scroll",x))},s.cancelFilterBar=function(){s.removeFilterBar(s.cancel)},s.showFilterBar(s.done),s.cancelFilterBar.$scope=s,s.cancelFilterBar}}var p=!1,b=e.element(r[0].body),m={theme:s.theme(),transition:s.transition(),back:f.backButton.icon(),clear:s.clear(),search:s.search(),backdrop:s.backdrop(),placeholder:s.placeholder()};return{show:d}}])}(angular,ionic); \ No newline at end of file +angular.module("jett.ionic.filter.bar",["ionic"]),function(e){"use strict";e.module("jett.ionic.filter.bar").directive("ionFilterBar",["$document","$timeout","$ionicGesture","$ionicPlatform",function(t,n,r,o){var i;return i=o.is("android")?'
':'
',{restrict:"E",scope:!0,link:function(o,i){var c,a,l,s,f,u=e.element(i[0].querySelector(".filter-bar-clear")),d=e.element(i[0].querySelector(".filter-bar-cancel")),p=i.find("input");o.filterText="";var b=function(){o.cancelFilterBar()};d.bind("click",b),o.config.backdrop&&o.focusOnShow&&(l=e.element('
'),i.append(l),s=function(e){e.target==l[0]&&b()},l.bind("click",s),a=r.on("swipe",s,l));var m=function(){"none"===u.css("display")&&u.css("display","block")},h=function(){"block"===u.css("display")&&u.css("display","none")},g=function(){n(function(){o.filterText="",h(),ionic.requestAnimationFrame(function(){o.showBackdrop(),o.scrollItemsTop(),o.focusInput()})})};u.bind("touchstart mousedown",g),p.bind("touchstart mousedown",function(){o.scrollItemsTop(),o.focusInput()});var v=function(e){27==e.which?b():o.filterText&&o.filterText.length?(m(),o.hideBackdrop()):(h(),o.showBackdrop())};t.bind("keyup",v);var B=function(){o.filterItems(o.filterText)};o.$on("$destroy",function(){i.remove(),t.unbind("keyup",v),l&&r.off(a,"swipe",s),f()}),f=o.$watch("filterText",function(e,t){var r;c&&n.cancel(c),e!==t&&(r=e.length&&o.debounce?o.delay:0,c=n(B,r,!1))})},template:i}}])}(angular),function(e){"use strict";e.module("jett.ionic.filter.bar").provider("$ionicFilterBarConfig",function(){function t(e,t){a.platform[e]=t,i.platform[e]={},n(a,a.platform[e]),r(a.platform[e],i.platform[e],"")}function n(t,r){for(var o in t)o!=c&&t.hasOwnProperty(o)&&(e.isObject(t[o])?(e.isDefined(r[o])||(r[o]={}),n(t[o],r[o])):e.isDefined(r[o])||(r[o]=null))}function r(t,n,i){e.forEach(t,function(l,s){e.isObject(t[s])?(n[s]={},r(t[s],n[s],i+"."+s)):n[s]=function(e){if(arguments.length)return t[s]=e,n;if(t[s]==c){var r=o(a.platform,ionic.Platform.platform()+i+"."+s);return r||r===!1?r:o(a.platform,"default"+i+"."+s)}return t[s]}})}function o(t,n){n=n.split(".");for(var r=0;r')(s),g=h.children().eq(0),v=g.find("input")[0],B=h.children().eq(1),k=s.scrollDelegate.getScrollView(),$=!!k,y=$?e.element(k.__container):null,w=s.cancelOnStateChange?o.$on("$stateChangeSuccess",function(){s.cancelFilterBar()}):e.noop,T=function(){d||(d=!0,v&&v.focus())},F=function(){d&&(d=!1,v&&v.blur())},x=function(){k.__scrollTop>0&&F()};return s.scrollItemsTop=function(){$&&s.scrollDelegate.scrollTop&&s.scrollDelegate.scrollTop()},s.focusInput=function(){d=!1,T()},s.hideBackdrop=function(){B.length&&f&&(f=!1,B.removeClass("active").css("display","none"))},s.showBackdrop=function(){B.length&&!f&&(f=!0,B.css("display","block").addClass("active"))},s.filterItems=function(t){var n,r;t.length?(s.expression?n=e.bind(this,s.expression,t):e.isArray(s.filterProperties)?(n={},e.forEach(s.filterProperties,function(e){n[e]=t})):s.filterProperties?(n={},n[s.filterProperties]=t):n=t,r=s.filter(s.items,n,s.comparator)):r=s.items,c(function(){s.update(r,t),s.scrollItemsTop()})},s.$deregisterBackButton=l.registerBackButtonAction(function(){c(s.cancelFilterBar)},300),s.removeFilterBar=function(n){s.removed||(s.removed=!0,t.requestAnimationFrame(function(){g.removeClass("filter-bar-in"),F(),s.hideBackdrop(),c(function(){s.scrollItemsTop(),s.update(s.items),s.$destroy(),h.remove(),s.cancelFilterBar.$scope=y=k=g=B=v=null,p=!1,(n||e.noop)()},350)}),c(function(){s.container.removeClass("filter-bar-open")},400),s.$deregisterBackButton(),w(),y&&y.off("scroll",x))},s.showFilterBar=function(n){s.removed||(s.container.append(h).addClass("filter-bar-open"),s.scrollItemsTop(),t.requestAnimationFrame(function(){s.removed||c(function(){g.addClass("filter-bar-in"),s.focusOnShow&&(s.focusInput(),s.showBackdrop()),(n||e.noop)()},20,!1)}),y&&y.on("scroll",x))},s.cancelFilterBar=function(){s.removeFilterBar(s.cancel)},s.showFilterBar(s.done),s.cancelFilterBar.$scope=s,s.cancelFilterBar}}var p=!1,b=e.element(r[0].body),m={theme:s.theme(),transition:s.transition(),back:f.backButton.icon(),clear:s.clear(),search:s.search(),backdrop:s.backdrop(),placeholder:s.placeholder()};return{show:d}}])}(angular,ionic); \ No newline at end of file diff --git a/js/ionic.filter.bar.directive.js b/js/ionic.filter.bar.directive.js index 16b905d..b229840 100644 --- a/js/ionic.filter.bar.directive.js +++ b/js/ionic.filter.bar.directive.js @@ -60,7 +60,7 @@ cancelEl.bind('click', cancelFilterBar); // If backdrop is enabled, create and append it to filter, then add click/swipe listeners to cancel filter - if ($scope.config.backdrop) { + if ($scope.config.backdrop && $scope.focusOnShow) { backdrop = angular.element('
'); $element.append(backdrop); diff --git a/js/ionic.filter.bar.service.js b/js/ionic.filter.bar.service.js index 3aa33ad..46b8ce7 100644 --- a/js/ionic.filter.bar.service.js +++ b/js/ionic.filter.bar.service.js @@ -92,7 +92,8 @@ delay: 300, cancelText: 'Cancel', cancelOnStateChange: true, - container: $body + container: $body, + focusOnShow: true, }, opts); //if no custom theme was configured, get theme of containers bar-header @@ -266,8 +267,10 @@ $timeout(function () { filterWrapperEl.addClass('filter-bar-in'); - scope.focusInput(); - scope.showBackdrop(); + if (scope.focusOnShow) { + scope.focusInput(); + scope.showBackdrop(); + } (done || angular.noop)(); }, 20, false); }); diff --git a/test/unit/ionic.filter.bar.service.unit.js b/test/unit/ionic.filter.bar.service.unit.js index 7dd7b86..7989b71 100644 --- a/test/unit/ionic.filter.bar.service.unit.js +++ b/test/unit/ionic.filter.bar.service.unit.js @@ -48,6 +48,7 @@ describe('Ionic FilterBar Service', function() { expect(scope.cancelText).toBe('Cancel'); expect(scope.cancelOnStateChange).toBe(true); expect(scope.container[0].nodeName).toBe('BODY'); + expect(scope.focusOnShow).toBe(true); })); it('show should add class on showing', inject(function($document) { @@ -174,7 +175,8 @@ describe('Ionic FilterBar Service', function() { filterProperties: ['propA', 'propB'], debounce: false, delay: 0, - cancelText: 'Done' + cancelText: 'Done', + focusOnShow: false }); expect(scope.config.theme).toBe('calm'); @@ -190,6 +192,7 @@ describe('Ionic FilterBar Service', function() { expect(scope.debounce).toBe(false); expect(scope.delay).toBe(0); expect(scope.cancelText).toBe('Done'); + expect(scope.focusOnShow).toBe(false); })); });