Repository: localytics/angular-chosen
Branch: master
Commit: 5675f52e9916
Files: 35
Total size: 48.9 KB
Directory structure:
gitextract_uvf_2ben/
├── .gitignore
├── .npmignore
├── .travis.yml
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── bower.json
├── chosen-spinner.css
├── chosen.js
├── dist/
│ └── angular-chosen.js
├── example/
│ ├── index.html
│ └── index.js
├── gulpfile.js
├── package.json
├── src/
│ ├── .editorconfig
│ ├── chosen.coffee
│ └── coffeelint.json
└── test/
├── base.spec.js
├── chosenAttrSpec.js
├── chosenOptions/
│ ├── allowSingleDeselected.spec.js
│ ├── disableSearch.spec.js
│ ├── disableSearchThreshold.spec.js
│ ├── inheritSelectClasses.spec.js
│ ├── maxShownResults.spec.js
│ ├── noResultsText.spec.js
│ ├── placeholderTextMultiple.spec.js
│ ├── placeholderTextSingle.spec.js
│ ├── searchContains.spec.js
│ └── width.spec.js
├── form.spec.js
├── issues/
│ └── 179-ng-if-breaks-inherit-select-classes.spec.js
└── support/
├── caseConvertFilter.js
├── chosenSelectHelper.js
├── karma.conf.js
└── specHelper.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
bower_components/
node_modules/
================================================
FILE: .npmignore
================================================
gulpfile.js
src
test
.gitignore
.travis.yml
================================================
FILE: .travis.yml
================================================
sudo: false
language: node_js
cache:
directories:
- node_modules
notifications:
email: false
node_js:
- '6'
before_install:
- npm i -g npm@^3.10.7
before_script:
- npm prune
script:
- npm run test
branches:
except:
- "/^v\\d+\\.\\d+\\.\\d+$/"
================================================
FILE: ISSUE_TEMPLATE.md
================================================
> If you are going to be lazy asking me properly, I'll be lazy answering to you (@leocaseiro)
### Please make sure you can mark all the options, before open this Issue. I'll prioritise the issues that are consistent and completed.
- [ ] I've read the documentation on http://leocaseiro.github.io/angular-chosen.
- [ ] I've searched on [github issues](https://github.com/leocaseiro/angular-chosen/issues?utf8=%E2%9C%93&q=is%3Aissue) and [stackoverflow](http://stackoverflow.com/questions/tagged/angular-chosen) before open this issue.
- [ ] I've tested with the [angular native select input](https://docs.angularjs.org/api/ng/directive/select) without the chosen directive
- [ ] I've tested with the oficial [jquery chosen](https://harvesthq.github.io/chosen/) without the angular chosen directive
## Please, post your plunker link here:
> (plunker link goes here)
If you need a starter plunker for a single select, use this one: https://plnkr.co/edit/Ec9l1C?p=preview
If you need a starter for a multiple select, use this one: https://plnkr.co/edit/vaRw1x?p=preview
## Write your issue:
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2013 Localytics http://www.localytics.com
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 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 SOFTWARE.
================================================
FILE: README.md
================================================
Angular Chosen Localytics [](https://github.com/leocaseiro/angular-chosen) [](https://www.npmjs.com/package/angular-chosen-localytics)
==============
AngularJS Chosen directive
This directive brings the [Chosen](http://harvesthq.github.com/chosen/) jQuery plugin
into AngularJS with ngModel and ngOptions integration.
To use, include `localytics.directives` as a dependency in your Angular module. You can now
use the `chosen` directive as an attribute on any select element. Angular version 1.3+ is required, but recommended 1.4.9+.
# [Full Documentation with Examples](http://leocaseiro.github.io/angular-chosen/)
* Documentation on [Github Page](http://leocaseiro.github.io/angular-chosen/)
* Examples on [example/index.html](http://htmlpreview.github.io/?https://github.com/leocaseiro/angular-chosen/blob/master/example/index.html)
## Installation (npm or bower)
Via bower
$ bower install angular-chosen-localytics --save
Via npm
$ npm install angular-chosen-localytics --save
Via [cdn](https://cdnjs.com/libraries/angular-chosen-localytics)
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-chosen-localytics/1.9.2/angular-chosen.min.js"></script>
```
Or download zip file
> [Download v1.9.2](https://github.com/leocaseiro/angular-chosen/archive/1.9.2.zip)
## Yeoman or Bower install
If you use Yeoman or Bower install, you need to rename the `chosen.jquery.js` or the `chosen.proto.js` to `chosen.js`. Otherwise Chosen won't be included in your `index.html`.
# Features
* Works with `ngModel` and `ngOptions`
* Supports usage of promises in `ngOptions`
* Provides a 'loading' animation when 'ngOptions' collection is a promise backed by a remote source
* Pass options to `Chosen` via attributes or by passing an object to the Chosen directive
* Provider with default values with `chosenProvider` ([read: Added config-provider](https://github.com/leocaseiro/angular-chosen/pull/231)) [since 1.6.0]
# Usage
### Simple example
Similar to `$("#states").chosen()`
```html
<select chosen multiple id="states">
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
</select>
```
### Pass any chosen options as attributes
```html
<select chosen
data-placeholder-text-single="'Pick one of these'"
disable-search="true"
allow-single-deselect="true">
<option value=""></option>
<option>This is fun</option>
<option>I like Chosen so much</option>
<option>I also like bunny rabbits</option>
</select>
```
> Note: the empty option element is mandatory when using `allow-single-deselect`
### Integration with `ngModel` and `ngOptions`
```html
<select multiple
chosen
ng-model="state"
ng-options="s for s in states">
</select>
```
> Note: don't try to use `ngModel` with `ngRepeat`. It won't work. Use `ngOptions`. It's better that way.
> Also important: if your `ngModel` is null or undefined, you must manually include an empty option inside your `<select>`, otherwise you'll encounter strange off-by-one errors:
```html
<select multiple
chosen
ng-model="state"
ng-options="s for s in states">
<option value=""></option>
</select>
```
> This annoying behavior is alluded to in the examples in the [documentation for ngOptions](http://docs.angularjs.org/api/ng.directive:select).
#### Works well with other AngularJS directives
```html
<select chosen
ng-model="state"
ng-options="s for s in states"
ng-disabled="editable">
<option value=""></option>
</select>
```
### Loading from a remote data source
Include `chosen-spinner.css` and `spinner.gif` to show an Ajax spinner icon while your data is loading. If the collection comes back empty, the directive will disable the element and show a default
"No values available" message. You can customize this message by passing in `noResultsText` in your options.
##### app.js
```js
angular.module('App', ['ngResource', 'localytics.directives'])
.controller('BeerCtrl', function($scope, $resource) {
$scope.beers = $resource('api/beers').query()
});
```
##### index.html
```html
<div ng-controller="BeerCtrl">
<select chosen
data-placeholder-text-single="'Choose a beer'"
no-results-text="'Could not find any beers :('"
ng-model="beer"
ng-options="b for b in beers">
<option value=""></option>
</select>
</div>
```
Image of select defined above in loading state:
`<img src="https://raw.github.com/localytics/angular-chosen/master/example/choose-a-beer.png">`
> Note: Assigning promises directly to scope is now deprecated in Angular 1.2+. Assign the results of the promise to scope
once the promise returns. The loader animation will still work as long as the collection expression
evaluates to `undefined` while your data is loading!
### Default values with chosenProvider (thanks @zlodes) [since 1.6.0]
```javascript
angular.module('chosenExampleApp', ['localytics.directives'])
.config(['chosenProvider', function (chosenProvider) {
chosenProvider.setOption({
no_results_text: 'There is no results!',
placeholder_text_multiple: 'Choose one or more!'
});
}]);
```
================================================
FILE: bower.json
================================================
{
"name": "angular-chosen-localytics",
"repository": {
"type": "git",
"url": "git://github.com/leocaseiro/angular-chosen.git"
},
"main": "dist/angular-chosen.js",
"ignore": [
"gulpfile.js",
"src",
"test"
],
"dependencies": {
"jquery": "^2.0.3",
"chosen": "^1.5.1",
"angular": "^1.4.9"
},
"license": "MIT"
}
================================================
FILE: chosen-spinner.css
================================================
/* Additional styles to display a spinner image while options are loading */
.localytics-chosen.loading+.chosen-container-multi .chosen-choices {
background-image: url('spinner.gif');
background-repeat: no-repeat;
background-position: 95%;
}
.localytics-chosen.loading+.chosen-container-single .chosen-single span {
background: url('spinner.gif') no-repeat right;
}
.localytics-chosen.loading+.chosen-container-single .chosen-single .search-choice-close {
display: none;
}
================================================
FILE: chosen.js
================================================
console.warn('the file ./chosen.js is deprecated, you must include ./dist/angular-chosen.js or ./dist/angular-chosen.min.js instead');
================================================
FILE: dist/angular-chosen.js
================================================
/**
* angular-chosen-localytics - Angular Chosen directive is an AngularJS Directive that brings the Chosen jQuery in a Angular way
* @version v1.9.2
* @link http://github.com/leocaseiro/angular-chosen
* @license MIT
*/
(function() {
var chosenModule,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
angular.module('localytics.directives', []);
chosenModule = angular.module('localytics.directives');
chosenModule.provider('chosen', function() {
var options;
options = {};
return {
setOption: function(newOpts) {
angular.extend(options, newOpts);
},
$get: function() {
return options;
}
};
});
chosenModule.directive('chosen', [
'chosen', '$timeout', '$parse', function(config, $timeout, $parse) {
var CHOSEN_OPTION_WHITELIST, NG_OPTIONS_REGEXP, isEmpty, snakeCase;
NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
CHOSEN_OPTION_WHITELIST = ['allowSingleDeselect', 'disableSearch', 'disableSearchThreshold', 'enableSplitWordSearch', 'inheritSelectClasses', 'maxSelectedOptions', 'noResultsText', 'placeholderTextMultiple', 'placeholderTextSingle', 'searchContains', 'groupSearch', 'singleBackstrokeDelete', 'width', 'displayDisabledOptions', 'displaySelectedOptions', 'includeGroupLabelInSelected', 'maxShownResults', 'caseSensitiveSearch', 'hideResultsOnSelect', 'rtl'];
snakeCase = function(input) {
return input.replace(/[A-Z]/g, function($1) {
return "_" + ($1.toLowerCase());
});
};
isEmpty = function(value) {
var key;
if (angular.isArray(value)) {
return value.length === 0;
} else if (angular.isObject(value)) {
for (key in value) {
if (value.hasOwnProperty(key)) {
return false;
}
}
}
return true;
};
return {
restrict: 'A',
require: ['select', '?ngModel'],
priority: 1,
link: function(scope, element, attr, ctrls) {
var $render, chosen, directiveOptions, disableIfEmpty, empty, initIfNotInitialized, match, ngModel, ngSelect, options, startLoading, stopLoading, timer, trackBy, valuesExpr, viewWatch;
scope.disabledValuesHistory = scope.disabledValuesHistory ? scope.disabledValuesHistory : [];
element = $(element);
element.addClass('localytics-chosen');
ngSelect = ctrls[0];
ngModel = ctrls[1];
match = attr.ngOptions && attr.ngOptions.match(NG_OPTIONS_REGEXP);
valuesExpr = match && $parse(match[7]);
trackBy = match && match[8];
directiveOptions = scope.$eval(attr.chosen) || {};
options = angular.copy(config);
angular.extend(options, directiveOptions);
angular.forEach(attr, function(value, key) {
if (indexOf.call(CHOSEN_OPTION_WHITELIST, key) >= 0) {
return attr.$observe(key, function(value) {
var prefix;
prefix = String(element.attr(attr.$attr[key])).slice(0, 2);
options[snakeCase(key)] = prefix === '{{' ? value : scope.$eval(value);
return disableIfEmpty();
});
}
});
startLoading = function() {
return element.addClass('loading').attr('disabled', true).trigger('chosen:updated');
};
stopLoading = function() {
element.removeClass('loading');
if (angular.isDefined(attr.disabled)) {
element.attr('disabled', attr.disabled);
} else {
element.attr('disabled', false);
}
return element.trigger('chosen:updated');
};
chosen = null;
empty = false;
initIfNotInitialized = function() {
if (!chosen) {
return scope.$evalAsync(function() {
if (!chosen) {
return chosen = element.chosen(options).data('chosen');
}
});
}
};
disableIfEmpty = function() {
if (chosen && empty) {
element.attr('disabled', true);
}
return element.trigger('chosen:updated');
};
if (ngModel) {
$render = ngModel.$render;
ngModel.$render = function() {
var isPrimitive, nextValue, previousValue, valueChanged;
initIfNotInitialized();
try {
previousValue = ngSelect.readValue();
} catch (error) {}
$render();
try {
nextValue = ngSelect.readValue();
} catch (error) {}
isPrimitive = !trackBy && !attr.multiple;
valueChanged = isPrimitive ? previousValue !== nextValue : !angular.equals(previousValue, nextValue);
if (valueChanged) {
return element.trigger('chosen:updated');
}
};
element.on('chosen:hiding_dropdown', function() {
return scope.$applyAsync(function() {
return ngModel.$setTouched();
});
});
if (attr.multiple) {
viewWatch = function() {
return ngModel.$viewValue;
};
scope.$watch(viewWatch, ngModel.$render, true);
}
} else {
initIfNotInitialized();
}
attr.$observe('disabled', function() {
return element.trigger('chosen:updated');
});
if (attr.ngOptions && ngModel) {
timer = null;
scope.$watchCollection(valuesExpr, function(newVal, oldVal) {
return timer = $timeout(function() {
if (angular.isUndefined(newVal)) {
return startLoading();
} else {
empty = isEmpty(newVal);
stopLoading();
return disableIfEmpty();
}
});
});
return scope.$on('$destroy', function(event) {
if (timer != null) {
return $timeout.cancel(timer);
}
});
}
}
};
}
]);
}).call(this);
================================================
FILE: example/index.html
================================================
<html ng-app="chosenExampleApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.jquery.min.js"></script>
<script src="../dist/angular-chosen.min.js"></script>
<script src="index.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.css" />
<link rel="stylesheet" type="text/css" href="../chosen-spinner.css" />
<style>
select.localytics-chosen {
display: block !important;
position:absolute;
clip:rect(0,0,0,0);
height: 29px;
}
.border-red {
border: 1px solid red;
}
</style>
</head>
<body ng-controller="IndexCtrl">
<h1>Chosen Directive Example Usage</h1>
<h2>Chosen with a promise: {{foo | json}}</h2>
<select
chosen
multiple
allow-single-deselect="true"
placeholder-text-multiple="'Choose Your Own Adventure'"
no-results-text="'Tough luck'"
ng-model="foo"
ng-options="value for value in optionsFromQuery"
style="width:200px;">
<option value=""></option>
</select>
<h2>Chosen with a promised hash: {{baz | json}}</h2>
<select
chosen
allow-single-deselect="true"
placeholder-text-single="'Choose Your Own Adventure'"
no-results-text="'Tough luck'"
ng-model="baz"
ng-options="value for (key,value) in optionsFromQueryAsHash"
style="width:200px;">
<option value=""></option>
</select>
<h2>Chosen with static options: {{ bar }}</h2>
<select chosen disable-search="true" ng-model="bar">
<option>Hi</option>
<option>This is fun</option>
<option>I like Chosen so much</option>
<option>I also like bunny rabbits</option>
<option value=""></option>
</select>
<h2>Passing options in as a hash: {{ woo }}</h2>
<select
ng-model="woo"
chosen="directiveOptions"
ng-options="value for value in optionsFromQuery"
style="width:200px;">
<option value=""></option>
</select>
<h2>Disabling the element with a message when the collection is empty: {{ whatever }}</h2>
<input type="checkbox" ng-model="emptyCollection" /> Empty?
<select
chosen
ng-model="whatever"
no-results-text="'Sorry no options for you'"
ng-options="value for value in emptyOptions"
style="width:200px;">
<option value=""></option>
</select>
<h2>Changing the ngModel externally: {{ myPets }}</h2>
<select
multiple
ng-model="myPets"
ng-options="value as label for (value, label) in pets"
chosen
style="width:200px;">
</select>
<h2>Disabling the selection:</h2>
<label for="disabled">Disabled</label>
<input id="disabled" type="checkbox" ng-model="disabled">
<br>
<select chosen disable-search="true" ng-model="somemodel" ng-disabled="disabled">
<option>Great</option>
<option>fun</option>
<option>Great fun .. indeed</option>
<option value=""></option>
</select>
<h2>Form validation</h2>
<p>Shows error after user selects nothing (works with Angular 1.3+, uses $touched + $invalid)</p>
<form name="form">
<select chosen disable-search="true" ng-model="somefun" name="fun" required>
<option></option>
<option>Great</option>
<option>fun</option>
<option>Great fun .. indeed</option>
</select>
<span ng-if="form.fun.$invalid && form.fun.$touched">
Error: {{form.fun.$error}}
</span>
<select disable-search="true" ng-model="somefun" name="fun" required>
<option></option>
<option>Great</option>
<option>fun</option>
<option>Great fun .. indeed</option>
</select>
<br>
<input type="submit" />
</form>
<h2>#179 - inherit-select-class inside ng-if:</h2>
<label for="ngIfInherit">Ng If {{ngIfInherit}}</label>
<input id="ngIfInherit" type="checkbox" value="1" ng-model="ngIfInherit">
<br>
<div>
<select ng-if="ngIfInherit" multiple inherit-select-classes="true" class="border-red" chosen ng-model="myPets"
ng-options="value as label for (value, label) in pets" style="width:200px;">
<option value=""></option>
</select>
</div>
<h2>#59 - Don't scroll to top when selecting multiple items with ctrl</h2>
<div>
<select multiple chosen ng-model="state" ng-options="s for s in states" style="width:200px;">
<option value=""></option>
</select>
</div>
</body>
</html>
================================================
FILE: example/index.js
================================================
// Generated by CoffeeScript 1.6.2
(function() {
angular.module('chosenExampleApp', ['localytics.directives'])
.config(['chosenProvider', function (chosenProvider) {
chosenProvider.setOption({
no_results_text: 'Haha! There is no results!',
placeholder_text_multiple: 'Choose a few!'
});
}])
.controller('IndexCtrl', [
'$scope', '$q', '$timeout', function($scope, $q, $timeout) {
var simulateAjax;
simulateAjax = function(result) {
var deferred, fn;
deferred = $q.defer();
fn = function() {
return deferred.resolve(result);
};
$timeout(fn, 3000);
return deferred.promise;
};
simulateAjax(['grooo', 'wowowowow', 'lakakalakakl', 'yadayada', 'insight', 'delve', 'synergy']).then(function(result) {
return $scope.optionsFromQuery = result;
});
$scope.optionsFromQueryAsHash = (function() {
var result;
result = {
win: "Brilliant Escape",
fail: "Untimely Demise"
};
return simulateAjax(result);
})();
$scope.$watch('emptyCollection', function(empty) {
return $scope.emptyOptions = simulateAjax(empty ? [] : ['look', 'i', 'have', 'data']);
});
$scope.directiveOptions = {
no_results_text: "SO SORRY"
};
$scope.ngIfInherit = true;
$scope.myPets = ['cat'];
$scope.pets = {
cat: 'Cat',
dog: 'Dog',
hamster: 'Hamster'
};
$scope.state = ['California', 'Arizona'];
$scope.states = {
"AL": "Alabama",
"AK": "Alaska",
"AS": "American Samoa",
"AZ": "Arizona",
"AR": "Arkansas",
"CA": "California",
"CO": "Colorado",
"CT": "Connecticut",
"DE": "Delaware",
"DC": "District Of Columbia",
"FM": "Federated States Of Micronesia",
"FL": "Florida",
"GA": "Georgia",
"GU": "Guam",
"HI": "Hawaii",
"ID": "Idaho",
"IL": "Illinois",
"IN": "Indiana",
"IA": "Iowa",
"KS": "Kansas",
"KY": "Kentucky",
"LA": "Louisiana",
"ME": "Maine",
"MH": "Marshall Islands",
"MD": "Maryland",
"MA": "Massachusetts",
"MI": "Michigan",
"MN": "Minnesota",
"MS": "Mississippi",
"MO": "Missouri",
"MT": "Montana",
"NE": "Nebraska",
"NV": "Nevada",
"NH": "New Hampshire",
"NJ": "New Jersey",
"NM": "New Mexico",
"NY": "New York",
"NC": "North Carolina",
"ND": "North Dakota",
"MP": "Northern Mariana Islands",
"OH": "Ohio",
"OK": "Oklahoma",
"OR": "Oregon",
"PW": "Palau",
"PA": "Pennsylvania",
"PR": "Puerto Rico",
"RI": "Rhode Island",
"SC": "South Carolina",
"SD": "South Dakota",
"TN": "Tennessee",
"TX": "Texas",
"UT": "Utah",
"VT": "Vermont",
"VI": "Virgin Islands",
"VA": "Virginia",
"WA": "Washington",
"WV": "West Virginia",
"WI": "Wisconsin",
"WY": "Wyoming"
};
$timeout(function() {
return $scope.$apply(function() {
return $scope.myPets.push('hamster');
});
}, 1000);
return $scope.disabled = true;
}
]);
}).call(this);
================================================
FILE: gulpfile.js
================================================
var config = {
test: './test',
src: './src/',
dist: './dist/',
file: 'angular-chosen'
};
var banner = ['/**',
' * <%= pkg.name %> - <%= pkg.description %>',
' * @version v<%= pkg.version %>',
' * @link <%= pkg.homepage %>',
' * @license <%= pkg.license %>',
' */',
''].join('\n');
var args = require('yargs').argv,
gulp = require('gulp'),
karma = require('karma'),
del = require('del'),
$ = require('gulp-load-plugins')({ lazy: true }),
pkg = require('./package.json');
// List Tasks by default
gulp.task('default', $.taskListing.withFilters(null, ['build-hint']));
gulp.task('build-hint', function() {
return gulp.src(config.src + '/*.coffee')
.pipe($.if(args.debug, $.debug()))
.pipe($.plumber())
.pipe($.coffeelint('./src/coffeelint.json'))
.pipe($.coffeelint.reporter());
});
/**
* Compile CoffeeScript into ./dist/angular-chose.js
*/
gulp.task('build-coffee-script', ['build-hint'], function() {
return gulp.src(config.src + '/*.coffee')
.pipe($.if(args.debug, $.debug()))
.pipe($.plumber())
.pipe($.coffee().on('error', $.util.log))
.pipe($.rename(config.file + '.js'))
.pipe($.header(banner, { pkg : pkg }))
.pipe(gulp.dest(config.dist));
});
/**
* Minify ./dist/angular-chose.js into ./dist/angular-chose.min.js
*/
gulp.task('build-minify', ['build-coffee-script'], function() {
return gulp.src(config.dist + '/angular-chosen.js')
.pipe($.if(args.debug, $.debug()))
.pipe($.plumber())
.pipe($.uglify({mangle: true}))
.pipe($.rename(config.file + '.min.js'))
.pipe($.header(banner, {pkg : pkg}))
.pipe(gulp.dest(config.dist));
});
/**
* Run Clean Javascripts, than minify(coffee-script)
*/
gulp.task('build', ['build-clean-javascripts'], function() {
gulp.start('build-minify');
});
/**
* Clean Javascripts from .dist/
*/
gulp.task('build-clean-javascripts', function() {
return del(config.dist);
});
/**
* Watch files and compile Coffee Script in real-time
*/
gulp.task('watcher', ['tests'], function() {
gulp.watch([config.src + '*.coffee', config.dist + '*.js'], ['tests']);
});
gulp.task('test', ['build'], function (done) {
new karma.Server({
configFile: __dirname + '/test/support/karma.conf.js',
singleRun: true
}, done).start();
});
gulp.task('tests', ['build'], function (done) {
new karma.Server({
configFile: __dirname + '/test/support/karma.conf.js',
singleRun: false
}, done).start();
});
================================================
FILE: package.json
================================================
{
"name": "angular-chosen-localytics",
"filename": "chosen.js",
"main": "dist/angular-chosen.js",
"version": "1.9.2",
"description": "Angular Chosen directive is an AngularJS Directive that brings the Chosen jQuery in a Angular way",
"homepage": "http://github.com/leocaseiro/angular-chosen",
"repository": {
"type": "git",
"url": "git://github.com/leocaseiro/angular-chosen"
},
"keywords": [
"angularjs",
"select",
"multiselect",
"dropdown",
"form",
"input",
"ui"
],
"license": "MIT",
"author": "jr314159",
"contributors": [
"abuggia",
"abyx",
"charandas",
"dariusriggins",
"darlanalves",
"dougludlow",
"failpunk",
"frnan",
"gaui",
"iamnewspecies",
"ilychkov",
"kfarst",
"leocaseiro",
"lpsBetty",
"lukeMason",
"nike-17",
"odi55555",
"paulpflug",
"simison",
"slobo",
"stefanvermaas",
"vantanev",
"vstene",
"zlodes"
],
"dependencies": {
"angular": "^1.5.7",
"chosen-js": "^1.6.1",
"jquery": "^3.0.0"
},
"bugs": {
"url": "https://github.com/leocaseiro/angular-chosen/issues"
},
"devDependencies": {
"angular-mocks": "^1.4.9",
"del": "^2.2.0",
"gulp": "^3.9.1",
"gulp-coffee": "^2.3.1",
"gulp-coffeelint": "^0.6.0",
"gulp-debug": "^2.1.2",
"gulp-header": "^1.7.1",
"gulp-if": "^2.0.0",
"gulp-load-plugins": "^1.2.0",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2",
"gulp-task-listing": "^1.0.1",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.7",
"jasmine-core": "^2.4.1",
"karma": "^0.13.22",
"karma-coffee-preprocessor": "^0.3.0",
"karma-jasmine": "^0.3.7",
"karma-jasmine-matchers": "^2.0.2",
"karma-mocha-reporter": "^2.0.0",
"karma-phantomjs-launcher": "^1.0.0",
"phantomjs-prebuilt": "^2.1.5",
"yargs": "^4.2.0"
},
"scripts": {
"test": "gulp test"
}
}
================================================
FILE: src/.editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = false
================================================
FILE: src/chosen.coffee
================================================
angular.module('localytics.directives', [])
chosenModule = angular.module('localytics.directives')
chosenModule.provider 'chosen', ->
options = {}
{
setOption: (newOpts) ->
angular.extend options, newOpts
return
$get: ->
options
}
chosenModule.directive 'chosen', ['chosen', '$timeout', '$parse', (config, $timeout, $parse) ->
# coffeelint: disable=max_line_length
# This is stolen from Angular...
NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/
# coffeelint: enable=max_line_length
# Whitelist of options that will be parsed from the element's attributes and passed into Chosen
#
# Can be updated by running the following script on the options page
# https://harvesthq.github.io/chosen/options.html
#
# Array.from(
# document.querySelectorAll('table:first-of-type tr td:first-of-type')
# )
# .map(node => node.textContent)
# .map(option => option.replace(/_(\w)/g, (_, letter) => letter.toUpperCase()))
#
CHOSEN_OPTION_WHITELIST = [
'allowSingleDeselect'
'disableSearch'
'disableSearchThreshold'
'enableSplitWordSearch'
'inheritSelectClasses'
'maxSelectedOptions'
'noResultsText'
'placeholderTextMultiple'
'placeholderTextSingle'
'searchContains'
'groupSearch'
'singleBackstrokeDelete'
'width'
'displayDisabledOptions'
'displaySelectedOptions'
'includeGroupLabelInSelected'
'maxShownResults'
'caseSensitiveSearch'
'hideResultsOnSelect'
'rtl'
]
snakeCase = (input) -> input.replace /[A-Z]/g, ($1) -> "_#{$1.toLowerCase()}"
isEmpty = (value) ->
if angular.isArray(value)
return value.length is 0
else if angular.isObject(value)
return false for key of value when value.hasOwnProperty(key)
true
restrict: 'A'
require: ['select', '?ngModel']
priority: 1
link: (scope, element, attr, ctrls) ->
scope.disabledValuesHistory = if scope.disabledValuesHistory then scope.disabledValuesHistory else []
element = $ element # Use real JQuery if it wasn't loaded before Angular.
element.addClass('localytics-chosen')
ngSelect = ctrls[0]
ngModel = ctrls[1]
match = attr.ngOptions && attr.ngOptions.match(NG_OPTIONS_REGEXP)
valuesExpr = match && $parse(match[7])
trackBy = match && match[8]
# Take a hash of options from the chosen directive
directiveOptions = scope.$eval(attr.chosen) or {}
# Clone options from configProvider
options = angular.copy(config)
# Merge options from directive with options from configProvider
angular.extend(options, directiveOptions)
# Options defined as attributes take precedence
angular.forEach attr, (value, key) ->
if key in CHOSEN_OPTION_WHITELIST
# Observe attributes
# Update the value in options. Set the default texts again. Update message.
attr.$observe key, (value) ->
prefix = String(element.attr(attr.$attr[key])).slice(0, 2)
options[snakeCase(key)] = if prefix is '{{' then value else scope.$eval(value)
disableIfEmpty()
startLoading = -> element.addClass('loading').attr('disabled', true).trigger('chosen:updated')
stopLoading = ->
element.removeClass('loading')
if angular.isDefined attr.disabled
element.attr 'disabled', attr.disabled
else
element.attr 'disabled', false
element.trigger('chosen:updated')
chosen = null
empty = false
# async initialize chosen if it's not initialized yet
initIfNotInitialized = ->
if !chosen
scope.$evalAsync ->
if !chosen then chosen = element.chosen(options).data('chosen')
# Use Chosen's placeholder or no results found text depending on whether there are options available
disableIfEmpty = ->
if chosen && empty
element.attr('disabled', true)
element.trigger('chosen:updated')
# Watch the underlying ngModel for updates and trigger an update when they occur.
if ngModel
$render = ngModel.$render
ngModel.$render = ->
initIfNotInitialized()
# We need to try and detect if the select value was changed from outside of chosen
try previousValue = ngSelect.readValue()
$render()
try nextValue = ngSelect.readValue()
isPrimitive = !trackBy && !attr.multiple
valueChanged = if isPrimitive
then previousValue != nextValue
else !angular.equals(previousValue, nextValue)
# If it was changed, then we trigger a chosen re-render
if (valueChanged)
element.trigger('chosen:updated')
element.on 'chosen:hiding_dropdown', ->
scope.$applyAsync -> ngModel.$setTouched()
# This is basically taken from angular ngOptions source. ngModel watches reference, not value,
# so when values are added or removed from array ngModels, $render won't be fired.
if attr.multiple
viewWatch = -> ngModel.$viewValue
scope.$watch viewWatch, ngModel.$render, true
else
initIfNotInitialized()
# Watch the disabled attribute (could be set by ngDisabled)
attr.$observe 'disabled', -> element.trigger('chosen:updated')
# Watch the collection in ngOptions and update chosen when it changes. This works with promises!
# ngOptions doesn't do anything unless there is an ngModel, so neither do we.
if attr.ngOptions and ngModel
timer = null
scope.$watchCollection valuesExpr, (newVal, oldVal) ->
# Defer execution until DOM is loaded
timer = $timeout(->
if angular.isUndefined(newVal)
startLoading()
else
empty = isEmpty(newVal)
stopLoading()
disableIfEmpty()
)
scope.$on '$destroy', (event) ->
$timeout.cancel timer if timer?
]
================================================
FILE: src/coffeelint.json
================================================
{
"coffeescript_error": {
"level": "error"
},
"arrow_spacing": {
"name": "arrow_spacing",
"level": "warn"
},
"no_tabs": {
"name": "no_tabs",
"level": "error"
},
"no_trailing_whitespace": {
"name": "no_trailing_whitespace",
"level": "warn",
"allowed_in_comments": false,
"allowed_in_empty_lines": false
},
"max_line_length": {
"name": "max_line_length",
"value": 120,
"level": "error",
"limitComments": true
},
"line_endings": {
"name": "line_endings",
"level": "ignore",
"value": "unix"
},
"no_trailing_semicolons": {
"name": "no_trailing_semicolons",
"level": "error"
},
"indentation": {
"name": "indentation",
"value": 2,
"level": "error"
},
"camel_case_classes": {
"name": "camel_case_classes",
"level": "error"
},
"colon_assignment_spacing": {
"name": "colon_assignment_spacing",
"level": "warn",
"spacing": {
"left": 0,
"right": 1
}
},
"no_implicit_braces": {
"name": "no_implicit_braces",
"level": "ignore",
"strict": true
},
"no_plusplus": {
"name": "no_plusplus",
"level": "ignore"
},
"no_throwing_strings": {
"name": "no_throwing_strings",
"level": "error"
},
"no_backticks": {
"name": "no_backticks",
"level": "error"
},
"no_implicit_parens": {
"name": "no_implicit_parens",
"level": "ignore"
},
"no_empty_param_list": {
"name": "no_empty_param_list",
"level": "warn"
},
"no_stand_alone_at": {
"name": "no_stand_alone_at",
"level": "ignore"
},
"space_operators": {
"name": "space_operators",
"level": "warn"
},
"duplicate_key": {
"name": "duplicate_key",
"level": "error"
},
"empty_constructor_needs_parens": {
"name": "empty_constructor_needs_parens",
"level": "ignore"
},
"cyclomatic_complexity": {
"name": "cyclomatic_complexity",
"value": 10,
"level": "ignore"
},
"newlines_after_classes": {
"name": "newlines_after_classes",
"value": 3,
"level": "ignore"
},
"no_unnecessary_fat_arrows": {
"name": "no_unnecessary_fat_arrows",
"level": "warn"
},
"missing_fat_arrows": {
"name": "missing_fat_arrows",
"level": "ignore"
},
"non_empty_constructor_needs_parens": {
"name": "non_empty_constructor_needs_parens",
"level": "ignore"
}
}
================================================
FILE: test/base.spec.js
================================================
describe('base functionality', function() {
var element;
it('should work without ngModel', function() {
element = $compile('<select chosen><option value="one">One</option></select>')($scope);
$scope.$apply();
var chosenSelected = element.next().find('.chosen-single span');
expect(chosenSelected.length).toBe(1)
})
beforeEach(function() {
$scope.currentLanguage = 'german';
$scope.languages = ['german', 'english'];
// Compile a piece of HTML containing the directive
element = $compile('<select chosen ng-options="lang for lang in languages" ng-model="currentLanguage"><option></option></select>')($scope);
$scope.$apply();
$timeout.flush();
element.trigger('chosen:open.chosen'); // fills dropdown (triggers chosen:showing_dropdown when finished)
element.trigger('chosen:close.chosen');
});
it('should add chosen dropdown', function() {
var chosenContainer = element.next();
var chosenSelected = chosenContainer.find('.chosen-single span');
var chosenList = chosenContainer.find('.chosen-drop ul li');
expect(chosenSelected.text()).toBe($scope.currentLanguage);
expect(chosenList.length).toBe(2);
expect(chosenList.first().text()).toBe($scope.languages[0]);
expect(chosenList.last().text()).toBe($scope.languages[1]);
});
it('should work when current model updates', function() {
var chosenContainer = element.next();
var chosenSelected = chosenContainer.find('.chosen-single span');
expect(chosenSelected.text()).toBe('german');
$scope.currentLanguage = 'english';
$scope.$apply();
expect(chosenSelected.text()).toBe('english');
});
it('should trigger ngChange function when selecting a chosen result', function() {
$scope.changed = false;
// Compile a piece of HTML containing the directive
element = $compile('<select chosen ng-options="lang for lang in languages" ng-model="currentLanguage" ng-change="changed=true"><option></option></select>')($scope);
$scope.$apply();
$timeout.flush();
element.trigger('chosen:open.chosen');
var chosenContainer = element.next();
var chosenSelected = chosenContainer.find('.chosen-single span');
var chosenList = chosenContainer.find('.chosen-drop ul li');
expect(chosenSelected.text()).toBe('german');
chosenList.last().trigger('mouseup'); // select english = last item
expect(chosenSelected.text()).toBe('english');
expect($scope.changed).toBe(true);
});
it('should disable chosen with ngDisabled', function() {
$scope.disabled = true;
// Compile a piece of HTML containing the directive
element = $compile('<select chosen ng-options="lang for lang in languages" ng-model="currentLanguage" ng-disabled="disabled"><option></option></select>')($scope);
$scope.$apply();
$timeout.flush();
var chosenContainer = element.next();
expect(chosenContainer.hasClass('chosen-disabled')).toBe(true);
$scope.disabled = false;
$scope.$apply();
expect(chosenContainer.hasClass('chosen-disabled')).toBe(false);
});
});
================================================
FILE: test/chosenAttrSpec.js
================================================
describe('chosen attributes', function() {
var element;
it('should inherit class customclass from select', function() {
var customClass = 'customclass';
var chosenContainer;
var select = function(inheritSelectClasses, customClass) {
return '<select chosen inherit-select-classes="' + inheritSelectClasses + '" class="' + customClass + '" ng-model="currentLanguage"><option></option></select>';
};
//inherit-select-classes = true
element = $compile(select(true, customClass))($scope);
$scope.$apply();
chosenContainer = element.next();
expect(chosenContainer.hasClass(customClass)).toBe(true);
//inherit-select-classes = false
element = $compile(select(false, customClass))($scope);
$scope.$apply();
chosenContainer = element.next();
expect(chosenContainer.hasClass(customClass)).toBe(false);
});
});
================================================
FILE: test/chosenOptions/allowSingleDeselected.spec.js
================================================
describe('Chosen options: allow-single-deselect', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
allowSingleDeselect: true
});
});
it('removes the model value when deselected', function () {
var removeButton = chosenSelectHelper.chosenContainer().find('abbr.search-choice-close');
removeButton.trigger('mouseup.chosen');
expect($scope.currentLanguage).toBeNull();
});
});
================================================
FILE: test/chosenOptions/disableSearch.spec.js
================================================
describe('Chosen options: disable-search', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
disableSearch: true
});
});
it('hides the search input', function () {
expect(chosenSelectHelper.searchInput().attr('readOnly')).toBeTruthy();
});
});
================================================
FILE: test/chosenOptions/disableSearchThreshold.spec.js
================================================
describe('Chosen options: disable-search-threshold', function () {
it('disables the search when the results are lower than the threshold', function () {
chosenSelectHelper.compileWithAttributes({
disableSearchThreshold: 3
});
expect(chosenSelectHelper.searchInput().attr('readOnly')).toBeTruthy();
});
it('does not disable the search when the results are higher than the threshold', function () {
chosenSelectHelper.compileWithAttributes({
disableSearchThreshold: 1
});
expect(chosenSelectHelper.searchInput().attr('readOnly')).toBeFalsy();
});
});
================================================
FILE: test/chosenOptions/inheritSelectClasses.spec.js
================================================
describe('Chosen options: inherit-select-classes', function () {
it('passes classes from the select tag to the chosen container', function () {
chosenSelectHelper.compileWithAttributes({
inheritSelectClasses: true,
'class': 'inherited-class'
});
expect(chosenSelectHelper.chosenContainer().hasClass('inherited-class')).toBeTruthy();
});
it('dont pass classes from the select tag to the chosen container', function () {
chosenSelectHelper.compileWithAttributes({
inheritSelectClasses: false,
'class': 'inherited-class'
});
expect(chosenSelectHelper.chosenContainer().hasClass('inherited-class')).toBeFalsy();
});
});
================================================
FILE: test/chosenOptions/maxShownResults.spec.js
================================================
describe('Chosen options: max-shown-results', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
maxShownResults: 1
});
chosenSelectHelper.selectTag.trigger('chosen:open.chosen');
chosenSelectHelper.chosenResults().last().trigger('mouseup.chosen');
});
it('displays only the maximum number of results specified', function () {
expect(chosenSelectHelper.chosenResults().length).toBe(1);
});
});
================================================
FILE: test/chosenOptions/noResultsText.spec.js
================================================
describe('Chosen options: no-results-text', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
noResultsText: "'testing no results text'"
});
chosenSelectHelper.searchInput().val('foo');
chosenSelectHelper.searchInput().trigger('keyup.chosen');
});
it('displays the specified message when a search returns no results', function () {
expect(chosenSelectHelper.chosenResults().html()).toMatch('testing no results text');
});
});
================================================
FILE: test/chosenOptions/placeholderTextMultiple.spec.js
================================================
describe('Chosen options: placeholder-text-multiple', function () {
beforeEach(function () {
$scope.emptyModel = [];
chosenSelectHelper.compileWithAttributes({
multiple: true,
placeholderTextMultiple: "'testing multi placeholder text'",
ngModel: 'emptyModel'
});
});
it('shows the specified placeholder text for a multi-select chosen tag', function () {
expect(chosenSelectHelper.chosenContainer().find('.search-field input').attr('value')).toMatch('testing multi placeholder text');
});
});
================================================
FILE: test/chosenOptions/placeholderTextSingle.spec.js
================================================
describe('Chosen options: placeholder-text-single', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
placeholderTextSingle: "'testing single placeholder text'",
ngModel: 'emptyModel'
});
});
it('shows the specified placeholder text for a single-select chosen tag', function () {
expect(chosenSelectHelper.chosenContainer().find('.chosen-default span').text()).toMatch('testing single placeholder text');
});
});
================================================
FILE: test/chosenOptions/searchContains.spec.js
================================================
describe('Chosen options: search-contains', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
searchContains: true
});
chosenSelectHelper.searchInput().val('erma');
chosenSelectHelper.searchInput().trigger('keyup.chosen');
});
it('finds a match in the search result that is not at the beginning of the option text', function () {
expect(chosenSelectHelper.chosenResults().length).toBeTruthy();
});
});
================================================
FILE: test/chosenOptions/width.spec.js
================================================
describe('Chosen options: width', function () {
beforeEach(function () {
chosenSelectHelper.compileWithAttributes({
width: 250
});
});
it('sets the dropdown width', function () {
expect(chosenSelectHelper.chosenContainer().attr('style')).toContain('width: 250');
});
});
================================================
FILE: test/form.spec.js
================================================
describe('form validations', function() {
var element, ngModel;
beforeEach(function() {
$scope.currentLanguage = null;
$scope.languages = ['german', 'english'];
// Compile a piece of HTML containing the directive
var form = $compile('<form name="form"><select chosen ng-options="lang for lang in languages" ng-model="currentLanguage" name="language" required><option></option></select></form>')($scope);
element = form.find('select');
ngModel = $scope.form.language;
$scope.$apply();
});
it('should work with required form validation', function() {
expect(ngModel.$valid).toBe(false);
expect(ngModel.$error.required).toBe(true);
$scope.currentLanguage = 'german';
$scope.$apply();
expect(ngModel.$valid).toBe(true);
});
it('should set $touched of ngModel to true (for e.g. form validation)', function() {
expect(ngModel.$touched).toBe(false);
element.trigger('chosen:open.chosen');
$scope.$apply();
element.trigger('chosen:hiding_dropdown');
$scope.$apply();
expect(ngModel.$touched).toBe(true);
});
});
================================================
FILE: test/issues/179-ng-if-breaks-inherit-select-classes.spec.js
================================================
describe('#179 inherit-select-classes inside ng-if', function () {
it('passes classes from the select tag to the chosen container inside ng-if', function () {
var element;
var customClass = 'customclass';
var chosenContainer;
$scope.test = true;
var select = function(inheritSelectClasses, customClass) {
return '<main><div ng-if="test">{{test}}<select chosen inherit-select-classes="' + inheritSelectClasses + '" class="' + customClass + '" ng-model="currentLanguage"><option></option></select></div></main>';
};
//inherit-select-classes = true
element = $compile(select(true, customClass))($scope);
$scope.$apply();
chosenContainer = element.find('select').next();
expect(chosenContainer.hasClass(customClass)).toBe(true);
});
});
================================================
FILE: test/support/caseConvertFilter.js
================================================
angular.module('caseConvertFilter', [])
.filter('caseConvert', function () {
var SNAKE_CASE_REGEXP = /[A-Z]/g;
return function (name, separator) {
var separator = separator || '_';
return name.replace(SNAKE_CASE_REGEXP, function (letter, pos) {
return (pos ? separator : '') + letter.toLowerCase();
});
};
});
================================================
FILE: test/support/chosenSelectHelper.js
================================================
angular.module('chosenSelectHelper', [])
.service('chosenSelectHelper', ['$filter', function ($filter) {
return {
compileWithAttributes: function (attributes) {
var attributes = attributes || {};
if (!attributes['ngModel']) {
$scope.currentLanguage = 'german';
attributes['ngModel'] = 'currentLanguage';
}
if (!attributes['ngOptions']) {
$scope.languages = ['german', 'english'];
attributes['ngOptions'] = 'lang for lang in languages';
}
for (attrName in attributes) {
this.selectTag.attr($filter('caseConvert')(attrName, '-'), attributes[attrName]);
}
$compile(this.selectTag)($scope);
$scope.$apply();
$timeout.flush();
},
selectTag: angular.element('<select chosen><option value=""></option></select>'),
chosenContainer: function () {
return this.selectTag.next();
},
chosenResults: function () {
return this.chosenContainer().find('.chosen-results li');
},
searchInput: function () {
return this.chosenContainer().find('.chosen-search input');
}
};
}]);
================================================
FILE: test/support/karma.conf.js
================================================
'use strict';
module.exports = function(config) {
config.set({
basePath: '../../',
frameworks: [
'jasmine',
'jasmine-matchers'
],
files: [
'node_modules/jquery/dist/jquery.js',
'node_modules/chosen-js/chosen.jquery.js',
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'src/**/*.coffee',
'test/support/*.js',
'test/**/*.spec.js'
],
preprocessors: {
'src/**/*.coffee': ['coffee']
},
reporters: ['mocha'],
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [
// 'PhantomJS', 'Chrome', 'Firefox', 'Safari'
'PhantomJS'
],
// Which plugins to enable
plugins: [
'karma-mocha-reporter',
'karma-phantomjs-launcher',
// 'karma-chrome-launcher',
// 'karma-firefox-launcher',
// 'karma-safari-launcher',
'karma-jasmine',
'karma-jasmine-matchers',
'karma-coffee-preprocessor'
],
singleRun: true
});
};
================================================
FILE: test/support/specHelper.js
================================================
beforeEach(function() {
angular.module('testApp', [
'localytics.directives',
'caseConvertFilter',
'chosenSelectHelper'
]);
angular.mock.module('testApp');
});
var $scope;
var $timeout;
var $compile;
var chosenSelectHelper;
/**
* Assigns $scope, $timeout and $compile, these will be used in every test.
*/
beforeEach(inject(function(_$rootScope_, _$timeout_, _$compile_, _chosenSelectHelper_) {
$scope = _$rootScope_.$new();
$timeout = _$timeout_;
$compile = _$compile_;
chosenSelectHelper = _chosenSelectHelper_;
}));
gitextract_uvf_2ben/
├── .gitignore
├── .npmignore
├── .travis.yml
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── bower.json
├── chosen-spinner.css
├── chosen.js
├── dist/
│ └── angular-chosen.js
├── example/
│ ├── index.html
│ └── index.js
├── gulpfile.js
├── package.json
├── src/
│ ├── .editorconfig
│ ├── chosen.coffee
│ └── coffeelint.json
└── test/
├── base.spec.js
├── chosenAttrSpec.js
├── chosenOptions/
│ ├── allowSingleDeselected.spec.js
│ ├── disableSearch.spec.js
│ ├── disableSearchThreshold.spec.js
│ ├── inheritSelectClasses.spec.js
│ ├── maxShownResults.spec.js
│ ├── noResultsText.spec.js
│ ├── placeholderTextMultiple.spec.js
│ ├── placeholderTextSingle.spec.js
│ ├── searchContains.spec.js
│ └── width.spec.js
├── form.spec.js
├── issues/
│ └── 179-ng-if-breaks-inherit-select-classes.spec.js
└── support/
├── caseConvertFilter.js
├── chosenSelectHelper.js
├── karma.conf.js
└── specHelper.js
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (55K chars).
[
{
"path": ".gitignore",
"chars": 32,
"preview": "bower_components/\nnode_modules/\n"
},
{
"path": ".npmignore",
"chars": 43,
"preview": "gulpfile.js\nsrc\ntest\n.gitignore\n.travis.yml"
},
{
"path": ".travis.yml",
"chars": 264,
"preview": "sudo: false\nlanguage: node_js\ncache:\n directories:\n - node_modules\nnotifications:\n email: false\nnode_js:\n - '6'\nbe"
},
{
"path": "ISSUE_TEMPLATE.md",
"chars": 1098,
"preview": "> If you are going to be lazy asking me properly, I'll be lazy answering to you (@leocaseiro)\n\n### Please make sure you "
},
{
"path": "LICENSE",
"chars": 1097,
"preview": "The MIT License\n\nCopyright (c) 2013 Localytics http://www.localytics.com\n\nPermission is hereby granted, free of charge, "
},
{
"path": "README.md",
"chars": 5445,
"preview": "Angular Chosen Localytics [](https://github.com/le"
},
{
"path": "bower.json",
"chars": 357,
"preview": "{\n \"name\": \"angular-chosen-localytics\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git://github.com/leocaseiro/an"
},
{
"path": "chosen-spinner.css",
"chars": 482,
"preview": "/* Additional styles to display a spinner image while options are loading */\n.localytics-chosen.loading+.chosen-containe"
},
{
"path": "chosen.js",
"chars": 135,
"preview": "console.warn('the file ./chosen.js is deprecated, you must include ./dist/angular-chosen.js or ./dist/angular-chosen.min"
},
{
"path": "dist/angular-chosen.js",
"chars": 6596,
"preview": "/**\n * angular-chosen-localytics - Angular Chosen directive is an AngularJS Directive that brings the Chosen jQuery in a"
},
{
"path": "example/index.html",
"chars": 4526,
"preview": "<html ng-app=\"chosenExampleApp\">\n<head>\n\n <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js\""
},
{
"path": "example/index.js",
"chars": 3169,
"preview": "// Generated by CoffeeScript 1.6.2\n(function() {\n angular.module('chosenExampleApp', ['localytics.directives'])\n ."
},
{
"path": "gulpfile.js",
"chars": 2549,
"preview": "var config = {\n test: './test',\n\tsrc: './src/',\n dist: './dist/',\n file: 'angular-chosen'\n};\n\nvar banner = ['/*"
},
{
"path": "package.json",
"chars": 1943,
"preview": "{\n \"name\": \"angular-chosen-localytics\",\n \"filename\": \"chosen.js\",\n \"main\": \"dist/angular-chosen.js\",\n \"version\": \"1."
},
{
"path": "src/.editorconfig",
"chars": 148,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ntrim_"
},
{
"path": "src/chosen.coffee",
"chars": 5995,
"preview": "angular.module('localytics.directives', [])\n\nchosenModule = angular.module('localytics.directives')\n\nchosenModule.provid"
},
{
"path": "src/coffeelint.json",
"chars": 2395,
"preview": "{\n \"coffeescript_error\": {\n \"level\": \"error\"\n },\n \"arrow_spacing\": {\n \"name\": \"arrow_spacing\",\n \"level\": \"wa"
},
{
"path": "test/base.spec.js",
"chars": 3091,
"preview": "describe('base functionality', function() {\n var element;\n\n it('should work without ngModel', function() {\n element"
},
{
"path": "test/chosenAttrSpec.js",
"chars": 876,
"preview": "describe('chosen attributes', function() {\n\n var element;\n\n it('should inherit class customclass from select', functio"
},
{
"path": "test/chosenOptions/allowSingleDeselected.spec.js",
"chars": 444,
"preview": "describe('Chosen options: allow-single-deselect', function () {\n beforeEach(function () {\n chosenSelectHelper.compil"
},
{
"path": "test/chosenOptions/disableSearch.spec.js",
"chars": 304,
"preview": "describe('Chosen options: disable-search', function () {\n beforeEach(function () {\n chosenSelectHelper.compileWithAt"
},
{
"path": "test/chosenOptions/disableSearchThreshold.spec.js",
"chars": 597,
"preview": "describe('Chosen options: disable-search-threshold', function () {\n it('disables the search when the results are lower "
},
{
"path": "test/chosenOptions/inheritSelectClasses.spec.js",
"chars": 677,
"preview": "describe('Chosen options: inherit-select-classes', function () {\n\n it('passes classes from the select tag to the chosen"
},
{
"path": "test/chosenOptions/maxShownResults.spec.js",
"chars": 462,
"preview": "describe('Chosen options: max-shown-results', function () {\n beforeEach(function () {\n chosenSelectHelper.compileWit"
},
{
"path": "test/chosenOptions/noResultsText.spec.js",
"chars": 494,
"preview": "describe('Chosen options: no-results-text', function () {\n beforeEach(function () {\n chosenSelectHelper.compileWithA"
},
{
"path": "test/chosenOptions/placeholderTextMultiple.spec.js",
"chars": 537,
"preview": "describe('Chosen options: placeholder-text-multiple', function () {\n beforeEach(function () {\n $scope.emptyModel = ["
},
{
"path": "test/chosenOptions/placeholderTextSingle.spec.js",
"chars": 478,
"preview": "describe('Chosen options: placeholder-text-single', function () {\n beforeEach(function () {\n chosenSelectHelper.comp"
},
{
"path": "test/chosenOptions/searchContains.spec.js",
"chars": 470,
"preview": "describe('Chosen options: search-contains', function () {\n beforeEach(function () {\n chosenSelectHelper.compileWithA"
},
{
"path": "test/chosenOptions/width.spec.js",
"chars": 298,
"preview": "describe('Chosen options: width', function () {\n beforeEach(function () {\n chosenSelectHelper.compileWithAttributes("
},
{
"path": "test/form.spec.js",
"chars": 1105,
"preview": "describe('form validations', function() {\n\n var element, ngModel;\n\n beforeEach(function() {\n $scope.currentLanguage"
},
{
"path": "test/issues/179-ng-if-breaks-inherit-select-classes.spec.js",
"chars": 792,
"preview": "describe('#179 inherit-select-classes inside ng-if', function () {\n\n it('passes classes from the select tag to the chos"
},
{
"path": "test/support/caseConvertFilter.js",
"chars": 336,
"preview": "angular.module('caseConvertFilter', [])\n.filter('caseConvert', function () {\n var SNAKE_CASE_REGEXP = /[A-Z]/g;\n\n retu"
},
{
"path": "test/support/chosenSelectHelper.js",
"chars": 1124,
"preview": "angular.module('chosenSelectHelper', [])\n.service('chosenSelectHelper', ['$filter', function ($filter) {\n return {\n "
},
{
"path": "test/support/karma.conf.js",
"chars": 1163,
"preview": "'use strict';\n\nmodule.exports = function(config) {\n config.set({\n basePath: '../../',\n\n frameworks: [\n 'jasm"
},
{
"path": "test/support/specHelper.js",
"chars": 549,
"preview": "beforeEach(function() {\n angular.module('testApp', [\n 'localytics.directives',\n 'caseConvertFilter',\n 'chosenS"
}
]
About this extraction
This page contains the full source code of the localytics/angular-chosen GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (48.9 KB), approximately 13.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.