diff --git a/isteven-multi-select.css b/isteven-multi-select.css index ab2183c..d3eafe4 100644 --- a/isteven-multi-select.css +++ b/isteven-multi-select.css @@ -4,7 +4,7 @@ /* ! vertical layout */ .multiSelect .vertical { - float: none; + float: none; } /* ! horizontal layout */ @@ -15,14 +15,14 @@ /* ! create a "row" */ .multiSelect .line { padding: 2px 0px 4px 0px; - max-height: 30px; + max-height: 30px; overflow: hidden; box-sizing: content-box; } /* ! create a "column" */ .multiSelect .acol { - display: inline-block; + display: inline-block; min-width: 12px; } @@ -35,33 +35,33 @@ .multiSelect > button { display: inline-block; position: relative; - text-align: center; + text-align: center; cursor: pointer; - border: 1px solid #c6c6c6; - padding: 1px 8px 1px 8px; + border: 1px solid #c6c6c6; + padding: 1px 8px 1px 8px; font-size: 14px; min-height : 38px !important; border-radius: 4px; - color: #555; + color: #555; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; - user-select: none; + user-select: none; white-space:normal; background-color: #fff; - background-image: linear-gradient(#fff, #f7f7f7); + background-image: linear-gradient(#fff, #f7f7f7); } /* button: hover */ -.multiSelect > button:hover { - background-image: linear-gradient(#fff, #e9e9e9); +.multiSelect > button:hover { + background-image: linear-gradient(#fff, #e9e9e9); } /* button: disabled */ .multiSelect > button:disabled { - background-image: linear-gradient(#fff, #fff); - border: 1px solid #ddd; + background-image: linear-gradient(#fff, #fff); + border: 1px solid #ddd; color: #999; } @@ -73,7 +73,7 @@ /* labels on the button */ .multiSelect .buttonLabel { display: inline-block; - padding: 5px 0px 5px 0px; + padding: 5px 0px 5px 0px; } /* downward pointing arrow */ @@ -81,12 +81,12 @@ display: inline-block; width: 0; height: 0; - margin: 0px 0px 1px 12px !important; + margin: 0px 0px 1px 12px !important; vertical-align: middle; border-top: 4px solid #333; border-right: 4px solid transparent; border-left: 4px solid transparent; - border-bottom: 0 dotted; + border-bottom: 0 dotted; } /* the main checkboxes and helper layer */ @@ -97,15 +97,15 @@ border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); min-width:278px; - display: none !important; + display: none !important; } /* container of helper elements */ .multiSelect .helperContainer { border-bottom: 1px solid #ddd; - padding: 8px 8px 0px 8px; + padding: 8px 8px 0px 8px; } /* helper buttons (select all, none, reset); */ @@ -117,7 +117,7 @@ height: 26px; font-size: 13px; border-radius: 2px; - color: #666; + color: #666; background-color: #f1f1f1; line-height: 1.6; margin: 0px 0px 8px 0px; @@ -128,7 +128,7 @@ } .multiSelect .helperButton:not( .reset ) { - margin-right: 4px; + margin-right: 4px; } /* clear button */ @@ -142,7 +142,7 @@ width: 22px; font-size: 13px; border-radius: 2px; - color: #666; + color: #666; background-color: #f1f1f1; line-height: 1.4; right : 2px; @@ -151,30 +151,30 @@ /* filter */ .multiSelect .inputFilter { - border-radius: 2px; + border-radius: 2px; border: 1px solid #ccc; height: 26px; font-size: 14px; - width:100%; + width:100%; padding-left:7px; -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ -moz-box-sizing: border-box; /* Firefox, other Gecko */ - box-sizing: border-box; /* Opera/IE 8+ */ + box-sizing: border-box; /* Opera/IE 8+ */ color: #888; margin: 0px 0px 8px 0px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); } /* helper elements on hover & focus */ .multiSelect .clearButton:hover, .multiSelect .helperButton:hover { border: 1px solid #ccc; - color: #999; - background-color: #f4f4f4; + color: #999; + background-color: #f4f4f4; } .multiSelect .helperButton:disabled { - color: #ccc; + color: #ccc; border: 1px solid #ddd; } @@ -184,13 +184,13 @@ border: 1px solid #66AFE9 !important; outline: 0; -webkit-box-shadow: inset 0 0 1px rgba(0,0,0,.065), 0 0 5px rgba(102, 175, 233, .6) !important; - box-shadow: inset 0 0 1px rgba(0,0,0,.065), 0 0 5px rgba(102, 175, 233, .6) !important; + box-shadow: inset 0 0 1px rgba(0,0,0,.065), 0 0 5px rgba(102, 175, 233, .6) !important; } /* container of multi select items */ .multiSelect .checkBoxContainer { display: block; - padding: 8px; + padding: 8px; overflow: hidden; } @@ -203,87 +203,87 @@ .multiSelect .multiSelectItem { display: block; padding: 3px; - color: #444; + color: #444; white-space: nowrap; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; - user-select: none; + user-select: none; border: 1px solid transparent; position: relative; - min-width:278px; - min-height: 32px; + min-width:278px; + min-height: 32px; } /* Styling on selected items */ .multiSelect .multiSelectItem:not(.multiSelectGroup).selected { - background-image: linear-gradient( #e9e9e9, #f1f1f1 ); - color: #555; - cursor: pointer; + background-image: linear-gradient( #e9e9e9, #f1f1f1 ); + color: #555; + cursor: pointer; border-top: 1px solid #e4e4e4; - border-left: 1px solid #e4e4e4; - border-right: 1px solid #d9d9d9; + border-left: 1px solid #e4e4e4; + border-right: 1px solid #d9d9d9; } .multiSelect .multiSelectItem .acol label { display: inline-block; - padding-right: 30px; + padding-right: 30px; margin: 0px; - font-weight: normal; + font-weight: normal; line-height: normal; } /* item labels focus on mouse hover */ -.multiSelect .multiSelectItem:hover, +.multiSelect .multiSelectItem:hover, .multiSelect .multiSelectGroup:hover { - background-image: linear-gradient( #c1c1c1, #999 ) !important; - color: #fff !important; - cursor: pointer; + background-image: linear-gradient( #c1c1c1, #999 ) !important; + color: #fff !important; + cursor: pointer; border: 1px solid #ccc !important; } /* item labels focus using keyboard */ -.multiSelect .multiSelectFocus { - background-image: linear-gradient( #c1c1c1, #999 ) !important; - color: #fff !important; - cursor: pointer; +.multiSelect .multiSelectFocus { + background-image: linear-gradient( #c1c1c1, #999 ) !important; + color: #fff !important; + cursor: pointer; border: 1px solid #ccc !important; } /* change mouse pointer into the pointing finger */ -.multiSelect .multiSelectItem span:hover, +.multiSelect .multiSelectItem span:hover, .multiSelect .multiSelectGroup span:hover -{ - cursor: pointer; +{ + cursor: pointer; } /* ! group labels */ -.multiSelect .multiSelectGroup { +.multiSelect .multiSelectGroup { display: block; clear: both; } /* right-align the tick mark (✔) */ .multiSelect .tickMark { - display:inline-block; - position: absolute; - right: 10px; + display:inline-block; + position: absolute; + right: 10px; top: 7px; - font-size: 10px; + font-size: 10px; } /* hide the original HTML checkbox away */ -.multiSelect .checkbox { - color: #ddd !important; +.multiSelect .checkbox { + color: #ddd !important; position: absolute; left: -9999px; - cursor: pointer; + cursor: pointer; } /* checkboxes currently disabled */ -.multiSelect .disabled, +.multiSelect .disabled, .multiSelect .disabled:hover, .multiSelect .disabled label input:hover ~ span { color: #c4c4c4 !important; @@ -297,3 +297,11 @@ max-height: 22px; max-width:22px; } + +.multiSelect .load-more-events { + overflow: hidden; + height: 0px; +} +.multiSelect .load-more-events.in-progress { + height: auto; +} diff --git a/isteven-multi-select.js b/isteven-multi-select.js index bda643e..c6ca568 100644 --- a/isteven-multi-select.js +++ b/isteven-multi-select.js @@ -1,86 +1,87 @@ -/* +/* * Angular JS Multi Select - * Creates a dropdown-like button with checkboxes. + * Creates a dropdown-like button with checkboxes. * * Project started on: Tue, 14 Jan 2014 - 5:18:02 PM * Current version: 4.0.0 - * + * * Released under the MIT License * -------------------------------------------------------------------------------- * The MIT License (MIT) * * Copyright (c) 2014 Ignatius Steven (https://github.com/isteven) * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all + * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * -------------------------------------------------------------------------------- */ 'use strict' -angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' , [ '$sce', '$timeout', '$templateCache', function ( $sce, $timeout, $templateCache ) { +angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' , [ '$sce', '$timeout', '$templateCache', '$document', function ( $sce, $timeout, $templateCache, $document ) { return { - restrict: + restrict: 'AE', - scope: - { - // models - inputModel : '=', - outputModel : '=', - - // settings based on attribute - isDisabled : '=', - - // callbacks - onClear : '&', - onClose : '&', - onSearchChange : '&', - onItemClick : '&', - onOpen : '&', - onReset : '&', - onSelectAll : '&', - onSelectNone : '&', - - // i18n - translation : '=' - }, - - /* + scope: + { + // models + inputModel : '=', + outputModel : '=', + + // settings based on attribute + isDisabled : '=', + + // callbacks + onClear : '&', + onClose : '&', + onSearchChange : '&', + onItemClick : '&', + onOpen : '&', + onReset : '&', + onSelectAll : '&', + onSelectNone : '&', + + // i18n + translation : '=' + }, + + /* * The rest are attributes. They don't need to be parsed / binded, so we can safely access them by value. * - buttonLabel, directiveId, helperElements, itemLabel, maxLabels, orientation, selectionMode, minSearchLength, * tickProperty, disableProperty, groupProperty, searchProperty, maxHeight, outputProperties */ - - templateUrl: - 'isteven-multi-select.htm', - link: function ( $scope, element, attrs ) { + templateUrl: + 'isteven-multi-select.htm', + + link: function ( $scope, element, attrs ) { $scope.backUp = []; - $scope.varButtonLabel = ''; + $scope.varButtonLabel = ''; $scope.spacingProperty = ''; - $scope.indexProperty = ''; + $scope.indexProperty = ''; $scope.orientationH = false; $scope.orientationV = true; $scope.filteredModel = []; - $scope.inputLabel = { labelFilter: '' }; - $scope.tabIndex = 0; + $scope.renderedItems = []; + $scope.inputLabel = { labelFilter: '' }; + $scope.tabIndex = 0; $scope.lang = {}; $scope.helperStatus = { all : true, @@ -89,7 +90,7 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' filter : true }; - var + var prevTabIndex = 0, helperItems = [], helperItemsLength = 0, @@ -98,38 +99,37 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' selectedItems = [], formElements = [], vMinSearchLength = 0, - clickedItem = null + clickedItem = null; // v3.0.0 // clear button clicked - $scope.clearClicked = function( e ) { + $scope.clearClicked = function( e ) { $scope.inputLabel.labelFilter = ''; $scope.updateFilter(); - $scope.select( 'clear', e ); + $scope.select( 'clear', e ); } // A little hack so that AngularJS ng-repeat can loop using start and end index like a normal loop // http://stackoverflow.com/questions/16824853/way-to-ng-repeat-defined-number-of-times-instead-of-repeating-over-array $scope.numberToArray = function( num ) { - return new Array( num ); + return new Array( num ); } // Call this function when user type on the filter field - $scope.searchChanged = function() { + $scope.searchChanged = function() { if ( $scope.inputLabel.labelFilter.length < vMinSearchLength && $scope.inputLabel.labelFilter.length > 0 ) { return false; - } + } $scope.updateFilter(); } - $scope.updateFilter = function() - { + $scope.updateFilter = function() { // we check by looping from end of input-model $scope.filteredModel = []; var i = 0; if ( typeof $scope.inputModel === 'undefined' ) { - return false; + return false; } for( i = $scope.inputModel.length - 1; i >= 0; i-- ) { @@ -138,39 +138,39 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' if ( typeof $scope.inputModel[ i ][ attrs.groupProperty ] !== 'undefined' && $scope.inputModel[ i ][ attrs.groupProperty ] === false ) { $scope.filteredModel.push( $scope.inputModel[ i ] ); } - - // if it's data + + // if it's data var gotData = false; - if ( typeof $scope.inputModel[ i ][ attrs.groupProperty ] === 'undefined' ) { - - // If we set the search-key attribute, we use this loop. + if ( typeof $scope.inputModel[ i ][ attrs.groupProperty ] === 'undefined' ) { + + // If we set the search-key attribute, we use this loop. if ( typeof attrs.searchProperty !== 'undefined' && attrs.searchProperty !== '' ) { for (var key in $scope.inputModel[ i ] ) { - if ( + if ( typeof $scope.inputModel[ i ][ key ] !== 'boolean' - && String( $scope.inputModel[ i ][ key ] ).toUpperCase().indexOf( $scope.inputLabel.labelFilter.toUpperCase() ) >= 0 + && String( $scope.inputModel[ i ][ key ] ).toUpperCase().indexOf( $scope.inputLabel.labelFilter.toUpperCase() ) >= 0 && attrs.searchProperty.indexOf( key ) > -1 ) { gotData = true; break; } - } + } } // if there's no search-key attribute, we use this one. Much better on performance. else { for ( var key in $scope.inputModel[ i ] ) { - if ( + if ( typeof $scope.inputModel[ i ][ key ] !== 'boolean' - && String( $scope.inputModel[ i ][ key ] ).toUpperCase().indexOf( $scope.inputLabel.labelFilter.toUpperCase() ) >= 0 + && String( $scope.inputModel[ i ][ key ] ).toUpperCase().indexOf( $scope.inputLabel.labelFilter.toUpperCase() ) >= 0 ) { gotData = true; break; } - } + } } - if ( gotData === true ) { + if ( gotData === true ) { // push $scope.filteredModel.push( $scope.inputModel[ i ] ); } @@ -179,23 +179,25 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' // if it's group start if ( typeof $scope.inputModel[ i ][ attrs.groupProperty ] !== 'undefined' && $scope.inputModel[ i ][ attrs.groupProperty ] === true ) { - if ( typeof $scope.filteredModel[ $scope.filteredModel.length - 1 ][ attrs.groupProperty ] !== 'undefined' - && $scope.filteredModel[ $scope.filteredModel.length - 1 ][ attrs.groupProperty ] === false ) { + if ( typeof $scope.filteredModel[ $scope.filteredModel.length - 1 ][ attrs.groupProperty ] !== 'undefined' + && $scope.filteredModel[ $scope.filteredModel.length - 1 ][ attrs.groupProperty ] === false ) { $scope.filteredModel.pop(); } else { $scope.filteredModel.push( $scope.inputModel[ i ] ); } } - } + } + + $scope.filteredModel.reverse(); + + $scope.updateRenderItems(); + + $timeout( function() { - $scope.filteredModel.reverse(); - - $timeout( function() { + $scope.getFormElements(); - $scope.getFormElements(); - - // Callback: on filter change + // Callback: on filter change var filterValue = $scope.inputLabel.labelFilter; var prevFilterValue = $scope.prevInputLabelValue; if ( filterValue.length >= vMinSearchLength ) { @@ -228,35 +230,35 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' }; // List all the input elements. We need this for our keyboard navigation. - // This function will be called everytime the filter is updated. + // This function will be called everytime the filter is updated. // Depending on the size of filtered mode, might not good for performance, but oh well.. - $scope.getFormElements = function() { + $scope.getFormElements = function() { formElements = []; - var + var selectButtons = [], inputField = [], checkboxes = [], clearButton = []; - + // If available, then get select all, select none, and reset buttons - if ( $scope.helperStatus.all || $scope.helperStatus.none || $scope.helperStatus.reset ) { - selectButtons = element.children().children().next().children().children()[ 0 ].getElementsByTagName( 'button' ); + if ( $scope.helperStatus.all || $scope.helperStatus.none || $scope.helperStatus.reset ) { + selectButtons = element.children().children().next().children().children()[ 0 ].getElementsByTagName( 'button' ); // If available, then get the search box and the clear button - if ( $scope.helperStatus.filter ) { - // Get helper - search and clear button. - inputField = element.children().children().next().children().children().next()[ 0 ].getElementsByTagName( 'input' ); - clearButton = element.children().children().next().children().children().next()[ 0 ].getElementsByTagName( 'button' ); + if ( $scope.helperStatus.filter ) { + // Get helper - search and clear button. + inputField = element.children().children().next().children().children().next()[ 0 ].getElementsByTagName( 'input' ); + clearButton = element.children().children().next().children().children().next()[ 0 ].getElementsByTagName( 'button' ); } } else { - if ( $scope.helperStatus.filter ) { - // Get helper - search and clear button. - inputField = element.children().children().next().children().children()[ 0 ].getElementsByTagName( 'input' ); + if ( $scope.helperStatus.filter ) { + // Get helper - search and clear button. + inputField = element.children().children().next().children().children()[ 0 ].getElementsByTagName( 'input' ); clearButton = element.children().children().next().children().children()[ 0 ].getElementsByTagName( 'button' ); } } - + // Get checkboxes if ( !$scope.helperStatus.all && !$scope.helperStatus.none && !$scope.helperStatus.reset && !$scope.helperStatus.filter ) { checkboxes = element.children().children().next()[ 0 ].getElementsByTagName( 'input' ); @@ -265,58 +267,58 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' checkboxes = element.children().children().next().children().next()[ 0 ].getElementsByTagName( 'input' ); } - // Push them into global array formElements[] + // Push them into global array formElements[] for ( var i = 0; i < selectButtons.length ; i++ ) { formElements.push( selectButtons[ i ] ); } for ( var i = 0; i < inputField.length ; i++ ) { formElements.push( inputField[ i ] ); } for ( var i = 0; i < clearButton.length ; i++ ) { formElements.push( clearButton[ i ] ); } - for ( var i = 0; i < checkboxes.length ; i++ ) { formElements.push( checkboxes[ i ] ); } - } + for ( var i = 0; i < checkboxes.length ; i++ ) { formElements.push( checkboxes[ i ] ); } + } // check if an item has attrs.groupProperty (be it true or false) $scope.isGroupMarker = function( item , type ) { - if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === type ) return true; + if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === type ) return true; return false; } $scope.removeGroupEndMarker = function( item ) { - if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === false ) return false; + if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === false ) return false; return true; - } + } // call this function when an item is clicked - $scope.syncItems = function( item, e, ng_repeat_index ) { + $scope.syncItems = function( item, e, ng_repeat_index ) { e.preventDefault(); e.stopPropagation(); // if the directive is globaly disabled, do nothing - if ( typeof attrs.disableProperty !== 'undefined' && item[ attrs.disableProperty ] === true ) { + if ( typeof attrs.disableProperty !== 'undefined' && item[ attrs.disableProperty ] === true ) { return false; } // if item is disabled, do nothing - if ( typeof attrs.isDisabled !== 'undefined' && $scope.isDisabled === true ) { + if ( typeof attrs.isDisabled !== 'undefined' && $scope.isDisabled === true ) { return false; - } + } // if end group marker is clicked, do nothing if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === false ) { return false; - } + } - var index = $scope.filteredModel.indexOf( item ); + var index = $scope.filteredModel.indexOf( item ); // if the start of group marker is clicked ( only for multiple selection! ) // how it works: // - if, in a group, there are items which are not selected, then they all will be selected - // - if, in a group, all items are selected, then they all will be de-selected - if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === true ) { + // - if, in a group, all items are selected, then they all will be de-selected + if ( typeof item[ attrs.groupProperty ] !== 'undefined' && item[ attrs.groupProperty ] === true ) { // this is only for multiple selection, so if selection mode is single, do nothing if ( typeof attrs.selectionMode !== 'undefined' && attrs.selectionMode.toUpperCase() === 'SINGLE' ) { return false; } - + var i,j,k; var startIndex = 0; var endIndex = $scope.filteredModel.length - 1; @@ -325,44 +327,44 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' // nest level is to mark the depth of the group. // when you get into a group (start group marker), nestLevel++ // when you exit a group (end group marker), nextLevel-- - var nestLevel = 0; + var nestLevel = 0; // we loop throughout the filtered model (not whole model) - for( i = index ; i < $scope.filteredModel.length ; i++) { + for( i = index ; i < $scope.filteredModel.length ; i++) { // this break will be executed when we're done processing each group - if ( nestLevel === 0 && i > index ) + if ( nestLevel === 0 && i > index ) { break; } - + if ( typeof $scope.filteredModel[ i ][ attrs.groupProperty ] !== 'undefined' && $scope.filteredModel[ i ][ attrs.groupProperty ] === true ) { - + // To cater multi level grouping if ( tempArr.length === 0 ) { - startIndex = i + 1; - } + startIndex = i + 1; + } nestLevel = nestLevel + 1; - } + } // if group end else if ( typeof $scope.filteredModel[ i ][ attrs.groupProperty ] !== 'undefined' && $scope.filteredModel[ i ][ attrs.groupProperty ] === false ) { - nestLevel = nestLevel - 1; + nestLevel = nestLevel - 1; - // cek if all are ticked or not - if ( tempArr.length > 0 && nestLevel === 0 ) { + // cek if all are ticked or not + if ( tempArr.length > 0 && nestLevel === 0 ) { - var allTicked = true; + var allTicked = true; endIndex = i; - for ( j = 0; j < tempArr.length ; j++ ) { + for ( j = 0; j < tempArr.length ; j++ ) { if ( typeof tempArr[ j ][ $scope.tickProperty ] !== 'undefined' && tempArr[ j ][ $scope.tickProperty ] === false ) { allTicked = false; break; } - } + } if ( allTicked === true ) { for ( j = startIndex; j <= endIndex ; j++ ) { @@ -380,19 +382,19 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' $scope.inputModel[ inputModelIndex ][ $scope.tickProperty ] = false; } } - } + } } else { for ( j = startIndex; j <= endIndex ; j++ ) { if ( typeof $scope.filteredModel[ j ][ attrs.groupProperty ] === 'undefined' ) { if ( typeof attrs.disableProperty === 'undefined' ) { - $scope.filteredModel[ j ][ $scope.tickProperty ] = true; + $scope.filteredModel[ j ][ $scope.tickProperty ] = true; // we refresh input model as well inputModelIndex = $scope.filteredModel[ j ][ $scope.indexProperty ]; $scope.inputModel[ inputModelIndex ][ $scope.tickProperty ] = true; - } + } else if ( $scope.filteredModel[ j ][ attrs.disableProperty ] !== true ) { $scope.filteredModel[ j ][ $scope.tickProperty ] = true; // we refresh input model as well @@ -400,16 +402,16 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' $scope.inputModel[ inputModelIndex ][ $scope.tickProperty ] = true; } } - } - } + } + } } } - + // if data - else { - tempArr.push( $scope.filteredModel[ i ] ); + else { + tempArr.push( $scope.filteredModel[ i ] ); } - } + } } // if an item (not group marker) is clicked @@ -417,18 +419,18 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' // If it's single selection mode if ( typeof attrs.selectionMode !== 'undefined' && attrs.selectionMode.toUpperCase() === 'SINGLE' ) { - + // first, set everything to false - for( i=0 ; i < $scope.filteredModel.length ; i++) { - $scope.filteredModel[ i ][ $scope.tickProperty ] = false; - } - for( i=0 ; i < $scope.inputModel.length ; i++) { - $scope.inputModel[ i ][ $scope.tickProperty ] = false; - } - + for( i=0 ; i < $scope.filteredModel.length ; i++) { + $scope.filteredModel[ i ][ $scope.tickProperty ] = false; + } + for( i=0 ; i < $scope.inputModel.length ; i++) { + $scope.inputModel[ i ][ $scope.tickProperty ] = false; + } + // then set the clicked item to true - $scope.filteredModel[ index ][ $scope.tickProperty ] = true; - } + $scope.filteredModel[ index ][ $scope.tickProperty ] = true; + } // Multiple else { @@ -436,29 +438,29 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' } // we refresh input model as well - var inputModelIndex = $scope.filteredModel[ index ][ $scope.indexProperty ]; - $scope.inputModel[ inputModelIndex ][ $scope.tickProperty ] = $scope.filteredModel[ index ][ $scope.tickProperty ]; - } + var inputModelIndex = $scope.filteredModel[ index ][ $scope.indexProperty ]; + $scope.inputModel[ inputModelIndex ][ $scope.tickProperty ] = $scope.filteredModel[ index ][ $scope.tickProperty ]; + } // we execute the callback function here - clickedItem = angular.copy( item ); - if ( clickedItem !== null ) { + clickedItem = angular.copy( item ); + if ( clickedItem !== null ) { $timeout( function() { delete clickedItem[ $scope.indexProperty ]; - delete clickedItem[ $scope.spacingProperty ]; + delete clickedItem[ $scope.spacingProperty ]; $scope.onItemClick( { data: clickedItem } ); - clickedItem = null; - }, 0 ); - } - + clickedItem = null; + }, 0 ); + } + $scope.refreshOutputModel(); - $scope.refreshButton(); + $scope.refreshButton(); // We update the index here prevTabIndex = $scope.tabIndex; $scope.tabIndex = ng_repeat_index + helperItemsLength; - - // Set focus on the hidden checkbox + + // Set focus on the hidden checkbox e.target.focus(); // set & remove CSS style @@ -467,67 +469,67 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' if ( typeof attrs.selectionMode !== 'undefined' && attrs.selectionMode.toUpperCase() === 'SINGLE' ) { // on single selection mode, we then hide the checkbox layer - $scope.toggleCheckboxes( e ); + $scope.toggleCheckboxes( e ); } - } + } // update $scope.outputModel - $scope.refreshOutputModel = function() { - + $scope.refreshOutputModel = function() { + $scope.outputModel = []; - var + var outputProps = [], tempObj = {}; // v4.0.0 - if ( typeof attrs.outputProperties !== 'undefined' ) { - outputProps = attrs.outputProperties.split(' '); - angular.forEach( $scope.inputModel, function( value, key ) { - if ( - typeof value !== 'undefined' - && typeof value[ attrs.groupProperty ] === 'undefined' - && value[ $scope.tickProperty ] === true + if ( typeof attrs.outputProperties !== 'undefined' ) { + outputProps = attrs.outputProperties.split(' '); + angular.forEach( $scope.inputModel, function( value, key ) { + if ( + typeof value !== 'undefined' + && typeof value[ attrs.groupProperty ] === 'undefined' + && value[ $scope.tickProperty ] === true ) { tempObj = {}; - angular.forEach( value, function( value1, key1 ) { - if ( outputProps.indexOf( key1 ) > -1 ) { - tempObj[ key1 ] = value1; + angular.forEach( value, function( value1, key1 ) { + if ( outputProps.indexOf( key1 ) > -1 ) { + tempObj[ key1 ] = value1; } }); - var index = $scope.outputModel.push( tempObj ); + var index = $scope.outputModel.push( tempObj ); delete $scope.outputModel[ index - 1 ][ $scope.indexProperty ]; - delete $scope.outputModel[ index - 1 ][ $scope.spacingProperty ]; + delete $scope.outputModel[ index - 1 ][ $scope.spacingProperty ]; } - }); + }); } else { - angular.forEach( $scope.inputModel, function( value, key ) { - if ( - typeof value !== 'undefined' - && typeof value[ attrs.groupProperty ] === 'undefined' - && value[ $scope.tickProperty ] === true + angular.forEach( $scope.inputModel, function( value, key ) { + if ( + typeof value !== 'undefined' + && typeof value[ attrs.groupProperty ] === 'undefined' + && value[ $scope.tickProperty ] === true ) { var temp = angular.copy( value ); - var index = $scope.outputModel.push( temp ); + var index = $scope.outputModel.push( temp ); delete $scope.outputModel[ index - 1 ][ $scope.indexProperty ]; - delete $scope.outputModel[ index - 1 ][ $scope.spacingProperty ]; + delete $scope.outputModel[ index - 1 ][ $scope.spacingProperty ]; } - }); + }); } } // refresh button label $scope.refreshButton = function() { - $scope.varButtonLabel = ''; - var ctr = 0; + $scope.varButtonLabel = ''; + var ctr = 0; // refresh button label... if ( $scope.outputModel.length === 0 ) { - // https://github.com/isteven/angular-multi-select/pull/19 + // https://github.com/isteven/angular-multi-select/pull/19 $scope.varButtonLabel = $scope.lang.nothingSelected; } - else { + else { var tempMaxLabels = $scope.outputModel.length; if ( typeof attrs.maxLabels !== 'undefined' && attrs.maxLabels !== '' ) { tempMaxLabels = attrs.maxLabels; @@ -539,85 +541,85 @@ angular.module( 'isteven-multi-select', ['ng'] ).directive( 'istevenMultiSelect' } else { $scope.more = false; - } - + } + angular.forEach( $scope.inputModel, function( value, key ) { - if ( typeof value !== 'undefined' && value[ attrs.tickProperty ] === true ) { - if ( ctr < tempMaxLabels ) { + if ( typeof value !== 'undefined' && value[ attrs.tickProperty ] === true ) { + if ( ctr < tempMaxLabels ) { $scope.varButtonLabel += ( $scope.varButtonLabel.length > 0 ? ',