├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── index.js ├── karma.conf.js ├── misc ├── changelog.tpl.md ├── demo │ ├── assets │ │ ├── app.js │ │ ├── demo.css │ │ ├── favicon.ico │ │ ├── github-16px.png │ │ ├── header.png │ │ ├── img │ │ │ ├── glyphicons-halflings-white.png │ │ │ └── glyphicons-halflings.png │ │ ├── plunker.js │ │ ├── rainbow-generic.js │ │ ├── rainbow-html.js │ │ ├── rainbow-javascript.js │ │ ├── rainbow.css │ │ ├── rainbow.js │ │ ├── smoothscroll-angular-custom.js │ │ └── uglifyjs.js │ └── index.html ├── raw-files-generator.js ├── test-lib │ ├── helpers.js │ └── jquery-1.8.2.min.js └── validate-commit-msg.js ├── package.json ├── src ├── accordion │ ├── accordion.js │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ └── test │ │ └── accordion.spec.js ├── alert │ ├── alert.js │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ └── test │ │ └── alert.spec.js ├── buttons │ ├── buttons.js │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ └── test │ │ └── buttons.spec.js ├── carousel │ ├── carousel.css │ ├── carousel.js │ ├── docs │ │ ├── README.md │ │ ├── demo.html │ │ └── demo.js │ ├── index-nocss.js │ ├── index.js │ └── test │ │ └── carousel.spec.js ├── collapse │ ├── collapse.js │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ └── test │ │ ├── collapse.spec.js │ │ └── collapseHorizontally.spec.js ├── dateparser │ ├── dateparser.js │ ├── docs │ │ ├── README.md │ │ ├── demo.html │ │ └── demo.js │ ├── index.js │ └── test │ │ └── dateparser.spec.js ├── datepicker │ ├── datepicker.css │ ├── datepicker.js │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ └── test │ │ └── datepicker.spec.js ├── datepickerPopup │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── popup.css │ ├── popup.js │ └── test │ │ └── popup.spec.js ├── debounce │ ├── debounce.js │ ├── index.js │ └── test │ │ └── debounce.spec.js ├── dropdown │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── dropdown.js │ ├── index-nocss.js │ ├── index.js │ └── test │ │ └── dropdown.spec.js ├── isClass │ ├── index.js │ ├── isClass.js │ └── test │ │ └── isClass.spec.js ├── modal │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── modal.js │ └── test │ │ └── modal.spec.js ├── multiMap │ ├── index.js │ ├── multiMap.js │ └── test │ │ └── multiMap.spec.js ├── pager │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ ├── pager.js │ └── test │ │ └── pager.spec.js ├── pagination │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ ├── pagination.js │ └── test │ │ └── pagination.spec.js ├── paging │ ├── index.js │ ├── paging.js │ └── test │ │ └── paging.spec.js ├── popover │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── popover.js │ └── test │ │ ├── popover-html.spec.js │ │ ├── popover-template.spec.js │ │ └── popover.spec.js ├── position │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── position.css │ ├── position.js │ └── test │ │ ├── position.spec.js │ │ └── test.html ├── progressbar │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ ├── progressbar.js │ └── test │ │ └── progressbar.spec.js ├── rating │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ ├── rating.js │ └── test │ │ └── rating.spec.js ├── stackedMap │ ├── index.js │ ├── stackedMap.js │ └── test │ │ └── stackedMap.spec.js ├── tabindex │ ├── index.js │ ├── tabindex.js │ └── test │ │ └── tabindex.spec.js ├── tabs │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index.js │ ├── tabs.js │ └── test │ │ └── tabs.spec.js ├── timepicker │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── test │ │ └── timepicker.spec.js │ ├── timepicker.css │ └── timepicker.js ├── tooltip │ ├── docs │ │ ├── demo.html │ │ ├── demo.js │ │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── test │ │ ├── tooltip-template.spec.js │ │ ├── tooltip.spec.js │ │ └── tooltip2.spec.js │ ├── tooltip.css │ └── tooltip.js └── typeahead │ ├── docs │ ├── demo.html │ ├── demo.js │ └── readme.md │ ├── index-nocss.js │ ├── index.js │ ├── test │ ├── typeahead-highlight-ngsanitize.spec.js │ ├── typeahead-highlight.spec.js │ ├── typeahead-parser.spec.js │ ├── typeahead-popup.spec.js │ └── typeahead.spec.js │ ├── typeahead.css │ └── typeahead.js └── template ├── accordion ├── accordion-group.html └── accordion.html ├── alert └── alert.html ├── carousel ├── carousel.html └── slide.html ├── datepicker ├── datepicker.html ├── day.html ├── month.html └── year.html ├── datepickerPopup └── popup.html ├── modal └── window.html ├── pager └── pager.html ├── pagination └── pagination.html ├── popover ├── popover-html.html ├── popover-template.html └── popover.html ├── progressbar ├── bar.html ├── progress.html └── progressbar.html ├── rating └── rating.html ├── tabs ├── tab.html └── tabset.html ├── timepicker └── timepicker.html ├── tooltip ├── tooltip-html-popup.html ├── tooltip-popup.html └── tooltip-template-popup.html └── typeahead ├── typeahead-match.html └── typeahead-popup.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # Tabs in JS unless otherwise specified 13 | [**.js] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.md] 18 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "rules": { 7 | "comma-dangle": 2, 8 | "no-cond-assign": 2, 9 | "no-control-regex": 2, 10 | "no-debugger": 2, 11 | "no-dupe-args": 2, 12 | "no-dupe-keys": 2, 13 | "no-duplicate-case": 2, 14 | "no-empty-character-class": 2, 15 | "no-empty": 2, 16 | "no-ex-assign": 2, 17 | "no-extra-boolean-cast": 2, 18 | "no-extra-parens": 2, 19 | "no-extra-semi": 2, 20 | "no-func-assign": 2, 21 | "no-inner-declarations": 2, 22 | "no-invalid-regexp": 2, 23 | "no-negated-in-lhs": 2, 24 | "no-regex-spaces": 2, 25 | "no-sparse-arrays": 2, 26 | "no-unexpected-multiline": 2, 27 | "no-unreachable": 2, 28 | "valid-typeof": 2, 29 | "accessor-pairs": 2, 30 | "block-scoped-var": 2, 31 | "complexity": 2, 32 | "curly": 2, 33 | "dot-notation": [2, {"allowKeywords": false}], 34 | "eqeqeq": 2, 35 | "guard-for-in": 2, 36 | "semi": 2, 37 | "no-alert": 2, 38 | "no-caller": 2, 39 | "no-case-declarations": 2, 40 | "no-div-regex": 2, 41 | "no-else-return": 2, 42 | "no-empty-label": 2, 43 | "no-empty-pattern": 2, 44 | "no-eq-null": 2, 45 | "no-eval": 2, 46 | "no-extend-native": 2, 47 | "no-extra-bind": 2, 48 | "no-floating-decimal": 2, 49 | "no-implied-eval": 2, 50 | "no-invalid-this": 2, 51 | "no-iterator": 2, 52 | "no-lone-blocks": 2, 53 | "no-loop-func": 2, 54 | "no-multi-spaces": 2, 55 | "no-native-reassign": 2, 56 | "no-new-func": 2, 57 | "no-new-wrappers": 2, 58 | "no-new": 2, 59 | "no-octal-escape": 2, 60 | "no-octal": 2, 61 | "no-proto": 2, 62 | "no-redeclare": 2, 63 | "no-script-url": 2, 64 | "no-self-compare": 2, 65 | "no-sequences": 2, 66 | "no-throw-literal": 2, 67 | "no-unused-expressions": 2, 68 | "no-useless-call": 2, 69 | "no-useless-concat": 2, 70 | "no-void": 2, 71 | "no-with": 2, 72 | "radix": 2, 73 | "wrap-iife": 2, 74 | "yoda": 2 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html eol=lf 2 | *.css eol=lf 3 | *.js eol=lf 4 | *.md eol=lf 5 | *.json eol=lf 6 | *.yml eol=lf 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # PLEASE READ 2 | 3 | As per the [README](https://github.com/angular-ui/bootstrap/blob/master/README.md), this project is no longer being maintained. Any issues entered will remain uninvestigated and unresolved. 4 | 5 | We thank you for your contributions over the years. This library would not have been successful without them. 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # PLEASE READ 2 | 3 | As per the [README](https://github.com/angular-ui/bootstrap/blob/master/README.md), this project is no longer being maintained. Any PRs entered will not be reviewed or merged and will remain open. 4 | 5 | We thank you for your contributions over the years. This library would not have been successful without them. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | *.swo 11 | .DS_Store 12 | .idea 13 | 14 | pids 15 | logs 16 | results 17 | dist 18 | # test coverage files 19 | .coverage/ 20 | 21 | node_modules 22 | npm-debug.log 23 | 24 | template/**/*.js 25 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "immed": true, 4 | "newcap": true, 5 | "noarg": true, 6 | "sub": true, 7 | "boss": true, 8 | "eqnull": true, 9 | "quotmark": "single", 10 | "trailing": true, 11 | "undef": true, 12 | "browser": true, 13 | "jquery": true, 14 | "globals": { 15 | "angular": false, 16 | 17 | // For Jasmine 18 | "after" : false, 19 | "afterEach" : false, 20 | "before" : false, 21 | "beforeEach" : false, 22 | "describe" : false, 23 | "expect" : false, 24 | "jasmine" : false, 25 | "module" : false, 26 | "spyOn" : false, 27 | "inject" : false, 28 | "it" : false 29 | } 30 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | *.swo 11 | .DS_Store 12 | 13 | pids 14 | logs 15 | results 16 | # test coverage files 17 | .coverage/ 18 | 19 | node_modules 20 | npm-debug.log 21 | 22 | .git 23 | docs 24 | misc 25 | .editorconfig 26 | .gitattributes 27 | .gitignore 28 | .jshintrc 29 | .travis.yml 30 | CONTRIBUTING.md 31 | Gruntfile.js 32 | karma.conf.js 33 | ROADMAP.md 34 | 35 | dist/assets 36 | dist/index.html 37 | dist/versions-mapping.json 38 | dist/*-SNAPSHOT* 39 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.9" 4 | env: 5 | - CXX=g++-4.8 6 | dist: trusty 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - g++-4.8 13 | 14 | before_install: 15 | - export DISPLAY=:99.0 16 | - sh -e /etc/init.d/xvfb start 17 | - npm install --quiet -g karma 18 | 19 | script: grunt 20 | sudo: false 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct. 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Got a question or problem? 2 | 3 | Firstly, please go over our FAQ: https://github.com/angular-ui/bootstrap/wiki/FAQ 4 | 5 | Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](http://stackoverflow.com/questions/tagged/angular-ui-bootstrap) where maintainers are looking at questions tagged with `angular-ui-bootstrap`. 6 | 7 | StackOverflow is a much better place to ask questions since: 8 | * there are hundreds of people willing to help on StackOverflow 9 | * questions and answers stay available for public viewing so your question / answer might help someone else 10 | * SO voting system assures that the best answers are prominently visible. 11 | 12 | To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow. 13 | 14 | ## You think you've found a bug? 15 | 16 | Oh, we are ashamed and want to fix it asap! But before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a _minimal_ reproduce scenario using http://plnkr.co/. Having a live reproduce scenario gives us wealth of important information without going back & forth to you with additional questions like: 17 | * version of AngularJS used 18 | * version of this library that you are using 19 | * 3rd-party libraries used, if any 20 | * and most importantly - a use-case that fails 21 | 22 | A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. 23 | 24 | We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. 25 | 26 | The best part is that you don't need to create plunks from scratch - you can use one from our [demo page](http://angular-ui.github.io/bootstrap/). 27 | 28 | Unfortunately we are not able to investigate / fix bugs without a minimal reproduce scenario using http://plnkr.co/, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced. 29 | 30 | 31 | ## You want to contribute some code? 32 | 33 | We are always looking for the quality contributions and will be happy to accept your Pull Requests as long as those adhere to some basic rules: 34 | 35 | * Please make sure that your contribution fits well in the project's context: 36 | * we are aiming at rebuilding bootstrap directives in pure AngularJS, without any dependencies on any external JavaScript library; 37 | * the only dependency should be bootstrap CSS and its markup structure; 38 | * directives should be html-agnostic as much as possible which in practice means: 39 | * templates should be referred to using the `templateUrl` property 40 | * it should be easy to change a default template to a custom one 41 | * directives shouldn't manipulate DOM structure directly (when possible) 42 | * Please assure that you are submitting quality code, specifically make sure that: 43 | * your directive has accompanying tests and all the tests are passing; don't hesitate to contact us (angular-ui@googlegroups.com) if you need any help with unit testing 44 | * your PR doesn't break the build; check the Travis-CI build status after opening a PR and push corrective commits if anything goes wrong 45 | * your commits conform to the conventions established [here](https://github.com/stevemao/conventional-changelog-angular/blob/master/convention.md) 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2012-2017 the AngularUI Team, https://github.com/organizations/angular-ui/teams/291112 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./dist/ui-bootstrap-tpls'); 2 | 3 | module.exports = 'ui.bootstrap'; 4 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sat Mar 28 2015 11:17:34 GMT-0700 (PDT) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['jasmine'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'misc/test-lib/jquery-1.8.2.min.js', 19 | 'node_modules/angular/angular.js', 20 | 'node_modules/angular-mocks/angular-mocks.js', 21 | 'node_modules/angular-sanitize/angular-sanitize.js', 22 | 'misc/test-lib/helpers.js', 23 | 'src/**/*.js', 24 | 'template/**/*.js' 25 | ], 26 | 27 | 28 | // list of files to exclude 29 | exclude: [ 30 | 'src/**/index.js', 31 | 'src/**/index-nocss.js', 32 | 'src/**/docs/*' 33 | ], 34 | 35 | 36 | // preprocess matching files before serving them to the browser 37 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 38 | preprocessors: { 39 | 'src/*/{*.js,!(test)/**/*.js}': ['coverage'] 40 | }, 41 | 42 | 43 | // test results reporter to use 44 | // possible values: 'dots', 'progress' 45 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 46 | reporters: ['progress', 'coverage'], 47 | 48 | coverageReporter: { 49 | dir: '.coverage/', 50 | type: 'html' 51 | }, 52 | 53 | reportSlowerThan: 100, 54 | 55 | // web server port 56 | port: 9876, 57 | 58 | 59 | // enable / disable colors in the output (reporters and logs) 60 | colors: true, 61 | 62 | 63 | // level of logging 64 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 65 | logLevel: config.LOG_INFO, 66 | 67 | 68 | // enable / disable watching file and executing tests whenever any file changes 69 | autoWatch: true, 70 | 71 | 72 | // start these browsers 73 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 74 | browsers: ['Chrome'], 75 | 76 | 77 | // Continuous Integration mode 78 | // if true, Karma captures browsers, runs the tests and exits 79 | singleRun: false 80 | }); 81 | }; 82 | -------------------------------------------------------------------------------- /misc/changelog.tpl.md: -------------------------------------------------------------------------------- 1 | # <%= version%> (<%= today%>) 2 | <% if (_(changelog.feat).size() > 0) { %> 3 | ## Features 4 | <% _(changelog.feat).keys().sort().forEach(function(scope) { %> 5 | - **<%= scope%>:** <% changelog.feat[scope].forEach(function(change) { %> 6 | - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>)<% }); %><% }); %> <% } %> 7 | <% if (_(changelog.fix).size() > 0) { %> 8 | ## Bug Fixes 9 | <% _(changelog.fix).keys().sort().forEach(function(scope) { %> 10 | - **<%= scope%>:** <% changelog.fix[scope].forEach(function(change) { %> 11 | - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>)<% }); %><% }); %> <% } %> 12 | <% if (_(changelog.breaking).size() > 0) { %> 13 | ## Breaking Changes 14 | <% _(changelog.breaking).keys().sort().forEach(function(scope) { %> 15 | - **<%= scope%>:** <% changelog.breaking[scope].forEach(function(change) { %> 16 | <%= change.msg%><% }); %><% }); %> <% } %> 17 | -------------------------------------------------------------------------------- /misc/demo/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-ui/bootstrap/baf0a567f9f4641848a9a4699695f9cde5f28f70/misc/demo/assets/favicon.ico -------------------------------------------------------------------------------- /misc/demo/assets/github-16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-ui/bootstrap/baf0a567f9f4641848a9a4699695f9cde5f28f70/misc/demo/assets/github-16px.png -------------------------------------------------------------------------------- /misc/demo/assets/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-ui/bootstrap/baf0a567f9f4641848a9a4699695f9cde5f28f70/misc/demo/assets/header.png -------------------------------------------------------------------------------- /misc/demo/assets/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-ui/bootstrap/baf0a567f9f4641848a9a4699695f9cde5f28f70/misc/demo/assets/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /misc/demo/assets/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-ui/bootstrap/baf0a567f9f4641848a9a4699695f9cde5f28f70/misc/demo/assets/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /misc/demo/assets/plunker.js: -------------------------------------------------------------------------------- 1 | angular.module('plunker', []) 2 | 3 | .factory('plunkGenerator', function ($document) { 4 | 5 | return function (ngVersion, bsVersion, version, module, content) { 6 | 7 | var form = angular.element('
'); 8 | var addField = function (name, value) { 9 | var input = angular.element(''); 10 | input.attr('value', value); 11 | form.append(input); 12 | }; 13 | 14 | var indexContent = function (content, version) { 15 | return '\n' + 16 | '\n' + 17 | ' \n' + 18 | ' \n' + 19 | ' \n' + 20 | ' \n' + 21 | ' \n' + 22 | ' \n' + 23 | ' \n' + 24 | ' \n' + 25 | ' \n\n' + 26 | content + '\n' + 27 | ' \n' + 28 | '\n'; 29 | }; 30 | 31 | var scriptContent = function(content) { 32 | return "angular.module('ui.bootstrap.demo', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']);" + "\n" + content; 33 | }; 34 | 35 | addField('description', 'http://angular-ui.github.io/bootstrap/'); 36 | addField('files[index.html]', indexContent(content.markup, version)); 37 | addField('files[example.js]', scriptContent(content.javascript)); 38 | 39 | $document.find('body').append(form); 40 | form[0].submit(); 41 | form.remove(); 42 | }; 43 | }) 44 | 45 | .controller('PlunkerCtrl', function ($scope, plunkGenerator) { 46 | 47 | $scope.content = {}; 48 | 49 | $scope.edit = function (ngVersion, bsVersion, version, module) { 50 | plunkGenerator(ngVersion, bsVersion, version, module, $scope.content); 51 | }; 52 | }) 53 | 54 | .directive('plunkerContent', function () { 55 | return { 56 | link:function (scope, element, attrs) { 57 | scope.content[attrs.plunkerContent] = element.text().trim(); 58 | } 59 | } 60 | }); 61 | -------------------------------------------------------------------------------- /misc/demo/assets/rainbow-generic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generic language patterns 3 | * 4 | * @author Craig Campbell 5 | * @version 1.0.9 6 | */ 7 | Rainbow.extend([ 8 | { 9 | 'matches': { 10 | 1: { 11 | 'name': 'keyword.operator', 12 | 'pattern': /\=/g 13 | }, 14 | 2: { 15 | 'name': 'string', 16 | 'matches': { 17 | 'name': 'constant.character.escape', 18 | 'pattern': /\\('|"){1}/g 19 | } 20 | } 21 | }, 22 | 'pattern': /(\(|\s|\[|\=|:)(('|")([^\\\1]|\\.)*?(\3))/gm 23 | }, 24 | { 25 | 'name': 'comment', 26 | 'pattern': /\/\*[\s\S]*?\*\/|(\/\/|\#)[\s\S]*?$/gm 27 | }, 28 | { 29 | 'name': 'constant.numeric', 30 | 'pattern': /\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi 31 | }, 32 | { 33 | 'matches': { 34 | 1: 'keyword' 35 | }, 36 | 'pattern': /\b(and|array|as|bool(ean)?|c(atch|har|lass|onst)|d(ef|elete|o(uble)?)|e(cho|lse(if)?|xit|xtends|xcept)|f(inally|loat|or(each)?|unction)|global|if|import|int(eger)?|long|new|object|or|pr(int|ivate|otected)|public|return|self|st(ring|ruct|atic)|switch|th(en|is|row)|try|(un)?signed|var|void|while)(?=\(|\b)/gi 37 | }, 38 | { 39 | 'name': 'constant.language', 40 | 'pattern': /true|false|null/g 41 | }, 42 | { 43 | 'name': 'keyword.operator', 44 | 'pattern': /\+|\!|\-|&(gt|lt|amp);|\||\*|\=/g 45 | }, 46 | { 47 | 'matches': { 48 | 1: 'function.call' 49 | }, 50 | 'pattern': /(\w+?)(?=\()/g 51 | }, 52 | { 53 | 'matches': { 54 | 1: 'storage.function', 55 | 2: 'entity.name.function' 56 | }, 57 | 'pattern': /(function)\s(.*?)(?=\()/g 58 | } 59 | ]); 60 | -------------------------------------------------------------------------------- /misc/demo/assets/rainbow-html.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HTML patterns 3 | * 4 | * @author Craig Campbell 5 | * @version 1.0.7 6 | */ 7 | Rainbow.extend('html', [ 8 | { 9 | 'name': 'source.php.embedded', 10 | 'matches': { 11 | 2: { 12 | 'language': 'php' 13 | } 14 | }, 15 | 'pattern': /<\?=?(?!xml)(php)?([\s\S]*?)(\?>)/gm 16 | }, 17 | { 18 | 'name': 'source.css.embedded', 19 | 'matches': { 20 | 0: { 21 | 'language': 'css' 22 | } 23 | }, 24 | 'pattern': /<style(.*?)>([\s\S]*?)<\/style>/gm 25 | }, 26 | { 27 | 'name': 'source.js.embedded', 28 | 'matches': { 29 | 0: { 30 | 'language': 'javascript' 31 | } 32 | }, 33 | 'pattern': /<script(?! src)(.*?)>([\s\S]*?)<\/script>/gm 34 | }, 35 | { 36 | 'name': 'comment.html', 37 | 'pattern': /<\!--[\S\s]*?-->/g 38 | }, 39 | { 40 | 'matches': { 41 | 1: 'support.tag.open', 42 | 2: 'support.tag.cclose' 43 | }, 44 | 'pattern': /(<)|(\/?\??>)/g 45 | }, 46 | { 47 | 'name': 'support.tag', 48 | 'matches': { 49 | 1: 'support.tag', 50 | 2: 'support.tag.special', 51 | 3: 'support.tag-name' 52 | }, 53 | 'pattern': /(<\??)(\/|\!?)(\w+)/g 54 | }, 55 | { 56 | 'matches': { 57 | 1: 'support.attribute' 58 | }, 59 | 'pattern': /([a-z-]+)(?=\=)/gi 60 | }, 61 | { 62 | 'matches': { 63 | 1: 'support.operator', 64 | 2: 'string.quote', 65 | 3: 'string.value', 66 | 4: 'string.quote' 67 | }, 68 | 'pattern': /(=)('|")(.*?)(\2)/g 69 | }, 70 | { 71 | 'matches': { 72 | 1: 'support.operator', 73 | 2: 'support.value' 74 | }, 75 | 'pattern': /(=)([a-zA-Z\-0-9]*)\b/g 76 | }, 77 | { 78 | 'matches': { 79 | 1: 'support.attribute' 80 | }, 81 | 'pattern': /\s(\w+)(?=\s|>)(?![\s\S]*<)/g 82 | } 83 | ], true); 84 | -------------------------------------------------------------------------------- /misc/demo/assets/rainbow-javascript.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Javascript patterns 3 | * 4 | * @author Craig Campbell 5 | * @version 1.0.7 6 | */ 7 | Rainbow.extend('javascript', [ 8 | 9 | /** 10 | * matches $. or $( 11 | */ 12 | { 13 | 'name': 'selector', 14 | 'pattern': /(\s|^)\$(?=\.|\()/g 15 | }, 16 | { 17 | 'name': 'support', 18 | 'pattern': /\b(window|document)\b/g 19 | }, 20 | { 21 | 'matches': { 22 | 1: 'support.property' 23 | }, 24 | 'pattern': /\.(length|node(Name|Value))\b/g 25 | }, 26 | { 27 | 'matches': { 28 | 1: 'support.function' 29 | }, 30 | 'pattern': /(setTimeout|setInterval)(?=\()/g 31 | 32 | }, 33 | { 34 | 'matches': { 35 | 1: 'support.method' 36 | }, 37 | 'pattern': /\.(getAttribute|push|getElementById|getElementsByClassName|log|setTimeout|setInterval)(?=\()/g 38 | }, 39 | { 40 | 'matches': { 41 | 1: 'support.tag.script', 42 | 2: [ 43 | { 44 | 'name': 'string', 45 | 'pattern': /('|")(.*?)(\1)/g 46 | }, 47 | { 48 | 'name': 'entity.tag.script', 49 | 'pattern': /(\w+)/g 50 | } 51 | ], 52 | 3: 'support.tag.script' 53 | }, 54 | 'pattern': /(<\/?)(script.*?)(>)/g 55 | }, 56 | 57 | /** 58 | * matches any escaped characters inside of a js regex pattern 59 | * 60 | * @see https://github.com/ccampbell/rainbow/issues/22 61 | * 62 | * this was causing single line comments to fail so it now makes sure 63 | * the opening / is not directly followed by a * 64 | * 65 | * @todo check that there is valid regex in match group 1 66 | */ 67 | { 68 | 'name': 'string.regexp', 69 | 'matches': { 70 | 1: 'string.regexp.open', 71 | 2: { 72 | 'name': 'constant.regexp.escape', 73 | 'pattern': /\\(.){1}/g 74 | }, 75 | 3: 'string.regexp.cclose', 76 | 4: 'string.regexp.modifier' 77 | }, 78 | 'pattern': /(\/)(?!\*)(.+)(\/)([igm]{0,3})/g 79 | }, 80 | 81 | /** 82 | * matches runtime function declarations 83 | */ 84 | { 85 | 'matches': { 86 | 1: 'storage', 87 | 3: 'entity.function' 88 | }, 89 | 'pattern': /(var)?(\s|^)(.*)(?=\s?=\s?function\()/g 90 | }, 91 | 92 | /** 93 | * matches constructor call 94 | */ 95 | { 96 | 'matches': { 97 | 1: 'keyword', 98 | 2: 'entity.function' 99 | }, 100 | 'pattern': /(new)\s+(.*)(?=\()/g 101 | }, 102 | 103 | /** 104 | * matches any function call in the style functionName: function() 105 | */ 106 | { 107 | 'name': 'entity.function', 108 | 'pattern': /(\w+)(?=:\s{0,}function)/g 109 | } 110 | ]); 111 | -------------------------------------------------------------------------------- /misc/demo/assets/rainbow.css: -------------------------------------------------------------------------------- 1 | /** 2 | * GitHub theme 3 | * 4 | * @author Craig Campbell 5 | * @version 1.0.4 6 | */ 7 | pre { 8 | border: 1px solid #ccc; 9 | word-wrap: break-word; 10 | padding: 6px 10px; 11 | line-height: 19px; 12 | margin-bottom: 20px; 13 | } 14 | 15 | code { 16 | border: 1px solid #eaeaea; 17 | margin: 0 2px; 18 | padding: 0 5px; 19 | font-size: 12px; 20 | } 21 | 22 | pre code { 23 | border: 0; 24 | padding: 0; 25 | margin: 0; 26 | -moz-border-radius: 0; 27 | -webkit-border-radius: 0; 28 | border-radius: 0; 29 | } 30 | 31 | pre, code { 32 | font-family: Consolas, 'Liberation Mono', Courier, monospace; 33 | color: #333; 34 | background: #f8f8f8; 35 | -moz-border-radius: 3px; 36 | -webkit-border-radius: 3px; 37 | border-radius: 3px; 38 | } 39 | 40 | pre, pre code { 41 | font-size: 13px; 42 | } 43 | 44 | pre .comment { 45 | color: #998; 46 | } 47 | 48 | pre .support { 49 | color: #0086B3; 50 | } 51 | 52 | pre .tag, pre .tag-name { 53 | color: navy; 54 | } 55 | 56 | pre .keyword, pre .css-property, pre .vendor-prefix, pre .sass, pre .class, pre .id, pre .css-value, pre .entity.function, pre .storage.function { 57 | font-weight: bold; 58 | } 59 | 60 | pre .css-property, pre .css-value, pre .vendor-prefix, pre .support.namespace { 61 | color: #333; 62 | } 63 | 64 | pre .constant.numeric, pre .keyword.unit, pre .hex-color { 65 | font-weight: normal; 66 | color: #099; 67 | } 68 | 69 | pre .entity.class { 70 | color: #458; 71 | } 72 | 73 | pre .entity.id, pre .entity.function { 74 | color: #900; 75 | } 76 | 77 | pre .attribute, pre .variable { 78 | color: teal; 79 | } 80 | 81 | pre .string, pre .support.value { 82 | font-weight: normal; 83 | color: #d14; 84 | } 85 | 86 | pre .regexp { 87 | color: #009926; 88 | } 89 | -------------------------------------------------------------------------------- /misc/demo/assets/smoothscroll-angular-custom.js: -------------------------------------------------------------------------------- 1 | /* 2 | * https://github.com/alicelieutier/smoothScroll/ 3 | * A teeny tiny, standard compliant, smooth scroll script with ease-in-out effect and no jQuery (or any other dependancy, FWIW). 4 | * MIT License 5 | */ 6 | window.smoothScroll = (function(){ 7 | // We do not want this script to be applied in browsers that do not support those 8 | // That means no smoothscroll on IE9 and below. 9 | if(document.querySelectorAll === void 0 || window.pageYOffset === void 0 || history.pushState === void 0) { return; } 10 | 11 | // Get the top position of an element in the document 12 | var getTop = function(element) { 13 | // return value of html.getBoundingClientRect().top ... IE : 0, other browsers : -pageYOffset 14 | if(element.nodeName === 'HTML') return -window.pageYOffset 15 | return element.getBoundingClientRect().top + window.pageYOffset; 16 | } 17 | // ease in out function thanks to: 18 | // http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/ 19 | var easeInOutCubic = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 } 20 | 21 | // calculate the scroll position we should be in 22 | // given the start and end point of the scroll 23 | // the time elapsed from the beginning of the scroll 24 | // and the total duration of the scroll (default 500ms) 25 | var position = function(start, end, elapsed, duration) { 26 | if (elapsed > duration) return end; 27 | return start + (end - start) * easeInOutCubic(elapsed / duration); // <-- you can change the easing funtion there 28 | // return start + (end - start) * (elapsed / duration); // <-- this would give a linear scroll 29 | } 30 | 31 | // we use requestAnimationFrame to be called by the browser before every repaint 32 | // if the first argument is an element then scroll to the top of this element 33 | // if the first argument is numeric then scroll to this location 34 | // if the callback exist, it is called when the scrolling is finished 35 | var smoothScroll = function(el, duration, callback){ 36 | duration = duration || 500; 37 | var start = window.pageYOffset; 38 | 39 | if (typeof el === 'number') { 40 | var end = parseInt(el); 41 | } else { 42 | var end = getTop(el); 43 | } 44 | 45 | var clock = Date.now(); 46 | var requestAnimationFrame = window.requestAnimationFrame || 47 | window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || 48 | function(fn){window.setTimeout(fn, 15);}; 49 | 50 | var step = function(){ 51 | var elapsed = Date.now() - clock; 52 | window.scroll(0, position(start, end, elapsed, duration)); 53 | if (elapsed > duration) { 54 | if (typeof callback === 'function') { 55 | callback(el); 56 | } 57 | } else { 58 | requestAnimationFrame(step); 59 | } 60 | } 61 | step(); 62 | } 63 | 64 | var linkHandler = function(ev) { 65 | ev.preventDefault(); 66 | 67 | if (location.hash !== this.hash) { 68 | //NOTE(@ajoslin): Changed this line to stop $digest errors 69 | //window.history.pushState(null, null, this.hash) 70 | angular.element(document).injector().get('$location').hash(this.hash); 71 | } 72 | // using the history api to solve issue #1 - back doesn't work 73 | // most browser don't update :target when the history api is used: 74 | // THIS IS A BUG FROM THE BROWSERS. 75 | // change the scrolling duration in this call 76 | var targetEl = document.getElementById(this.hash.substring(1)); 77 | if (targetEl) { 78 | smoothScroll(document.getElementById(this.hash.substring(1)), 500, function(el) { 79 | location.replace('#' + el.id) 80 | // this will cause the :target to be activated. 81 | }); 82 | } 83 | } 84 | 85 | // We look for all the internal links in the documents and attach the smoothscroll function 86 | document.addEventListener("DOMContentLoaded", function () { 87 | var internal = document.querySelectorAll('a[href^="#"]'), a; 88 | for(var i=internal.length; a=internal[--i];){ 89 | a.addEventListener("click", linkHandler, false); 90 | } 91 | }); 92 | 93 | // return smoothscroll API 94 | return smoothScroll; 95 | 96 | })(); 97 | 98 | -------------------------------------------------------------------------------- /misc/raw-files-generator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Forked from: 3 | * Bootstrap Grunt task for generating raw-files.min.js for the Customizer 4 | * http://getbootstrap.com 5 | * Copyright 2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | */ 8 | 9 | /* jshint node: true */ 10 | 11 | 'use strict'; 12 | var fs = require('fs'); 13 | 14 | function getFiles(filePaths) { 15 | var files = {}; 16 | filePaths 17 | .forEach(function (path) { 18 | files[path] = fs.readFileSync(path, 'utf8'); 19 | }); 20 | return files; 21 | } 22 | 23 | module.exports = function generateRawFilesJs(grunt, jsFilename, files, banner, cssBanner) { 24 | if (!banner) { 25 | banner = ''; 26 | } 27 | 28 | if (!cssBanner) { 29 | cssBanner = ''; 30 | } 31 | 32 | var filesJsObject = { 33 | banner: banner, 34 | cssBanner: cssBanner, 35 | files: getFiles(files), 36 | }; 37 | 38 | var filesJsContent = JSON.stringify(filesJsObject); 39 | try { 40 | fs.writeFileSync(jsFilename, filesJsContent); 41 | } 42 | catch (err) { 43 | grunt.fail.warn(err); 44 | } 45 | grunt.log.writeln('File ' + jsFilename.cyan + ' created.'); 46 | }; 47 | -------------------------------------------------------------------------------- /misc/test-lib/helpers.js: -------------------------------------------------------------------------------- 1 | // jasmine matcher for expecting an element to have a css class 2 | // https://github.com/angular/angular.js/blob/master/test/matchers.js 3 | beforeEach(function() { 4 | jasmine.addMatchers({ 5 | toHaveClass: function(util, customEqualityTesters) { 6 | return { 7 | compare: function(actual, expected) { 8 | var result = { 9 | pass: actual.hasClass(expected) 10 | }; 11 | 12 | if (result.pass) { 13 | result.message = 'Expected "' + actual + '" not to have the "' + expected + '" class.'; 14 | } else { 15 | result.message = 'Expected "' + actual + '" to have the "' + expected + '" class.'; 16 | } 17 | 18 | return result; 19 | } 20 | } 21 | }, 22 | toBeHidden: function(util, customEqualityTesters) { 23 | return { 24 | compare: function(actual) { 25 | var result = { 26 | pass: actual.hasClass('ng-hide') || actual.css('display') === 'none' 27 | }; 28 | 29 | if (result.pass) { 30 | result.message = 'Expected "' + actual + '" not to be hidden'; 31 | } else { 32 | result.message = 'Expected "' + actual + '" to be hidden'; 33 | } 34 | 35 | return result; 36 | } 37 | } 38 | }, 39 | toHaveFocus: function(util, customEqualityTesters) { 40 | return { 41 | compare: function(actual) { 42 | var result = { 43 | pass: document.activeElement === actual[0] 44 | }; 45 | 46 | if (result.pass) { 47 | result.message = 'Expected "' + actual + '" not to have focus'; 48 | } else { 49 | result.message = 'Expected "' + actual + '" to have focus'; 50 | } 51 | 52 | return result; 53 | } 54 | } 55 | } 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /misc/validate-commit-msg.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Git COMMIT-MSG hook for validating commit message 5 | * See https://docs.google.com/document/d/1rk04jEuGfk9kYzfqCuOlPTSJw3hEDZJTBN5E5f1SALo/edit 6 | * 7 | * Installation: 8 | * >> cd 9 | * >> ln -s validate-commit-msg.js .git/hooks/commit-msg 10 | */ 11 | var fs = require('fs'); 12 | var util = require('util'); 13 | 14 | 15 | var MAX_LENGTH = 70; 16 | var PATTERN = /^(?:fixup!\s*)?(\w*)(\((\w+)\))?\: (.*)$/; 17 | var IGNORED = /^WIP\:/; 18 | var TYPES = { 19 | chore: true, 20 | demo: true, 21 | docs: true, 22 | feat: true, 23 | fix: true, 24 | refactor: true, 25 | revert: true, 26 | style: true, 27 | test: true 28 | }; 29 | 30 | 31 | var error = function() { 32 | // gitx does not display it 33 | // http://gitx.lighthouseapp.com/projects/17830/tickets/294-feature-display-hook-error-message-when-hook-fails 34 | // https://groups.google.com/group/gitx/browse_thread/thread/a03bcab60844b812 35 | console.error('INVALID COMMIT MSG: ' + util.format.apply(null, arguments)); 36 | }; 37 | 38 | 39 | var validateMessage = function(message) { 40 | var isValid = true; 41 | 42 | if (IGNORED.test(message)) { 43 | console.log('Commit message validation ignored.'); 44 | return true; 45 | } 46 | 47 | if (message.length > MAX_LENGTH) { 48 | error('is longer than %d characters !', MAX_LENGTH); 49 | isValid = false; 50 | } 51 | 52 | var match = PATTERN.exec(message); 53 | 54 | if (!match) { 55 | error('does not match "(): " ! was: "' + message + '"\nNote: must be only letters.'); 56 | return false; 57 | } 58 | 59 | var type = match[1]; 60 | var scope = match[3]; 61 | var subject = match[4]; 62 | 63 | if (!TYPES.hasOwnProperty(type)) { 64 | error('"%s" is not allowed type !', type); 65 | return false; 66 | } 67 | 68 | // Some more ideas, do want anything like this ? 69 | // - allow only specific scopes (eg. fix(docs) should not be allowed ? 70 | // - auto correct the type to lower case ? 71 | // - auto correct first letter of the subject to lower case ? 72 | // - auto add empty line after subject ? 73 | // - auto remove empty () ? 74 | // - auto correct typos in type ? 75 | // - store incorrect messages, so that we can learn 76 | 77 | return isValid; 78 | }; 79 | 80 | 81 | var firstLineFromBuffer = function(buffer) { 82 | return buffer.toString().split('\n').shift(); 83 | }; 84 | 85 | 86 | 87 | // publish for testing 88 | exports.validateMessage = validateMessage; 89 | 90 | // hacky start if not run by jasmine :-D 91 | if (process.argv.join('').indexOf('jasmine-node') === -1) { 92 | var commitMsgFile = process.argv[2]; 93 | var incorrectLogFile = commitMsgFile.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs'); 94 | 95 | fs.readFile(commitMsgFile, function(err, buffer) { 96 | var msg = firstLineFromBuffer(buffer); 97 | 98 | if (!validateMessage(msg)) { 99 | fs.appendFile(incorrectLogFile, msg + '\n', function() { 100 | process.exit(1); 101 | }); 102 | } else { 103 | process.exit(0); 104 | } 105 | }); 106 | } 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "https://github.com/angular-ui/bootstrap/graphs/contributors", 3 | "name": "angular-ui-bootstrap", 4 | "version": "2.5.4", 5 | "description": "Native AngularJS (Angular) directives for Bootstrap", 6 | "homepage": "http://angular-ui.github.io/bootstrap/", 7 | "keywords": [ 8 | "angularjs", 9 | "angular", 10 | "bootstrap", 11 | "ui" 12 | ], 13 | "dependencies": {}, 14 | "directories": { 15 | "lib": "src/" 16 | }, 17 | "files": [ 18 | "index.js", 19 | "dist/", 20 | "src/", 21 | "template/" 22 | ], 23 | "main": "index.js", 24 | "scripts": { 25 | "demo": "grunt after-test && static dist -a 0.0.0.0 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}'", 26 | "test": "grunt" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/angular-ui/bootstrap.git" 31 | }, 32 | "devDependencies": { 33 | "angular": "1.6.1", 34 | "angular-mocks": "1.6.1", 35 | "angular-sanitize": "1.6.1", 36 | "grunt": "^0.4.5", 37 | "grunt-cli": "^1.2.0", 38 | "grunt-contrib-concat": "^1.0.0", 39 | "grunt-contrib-copy": "^1.0.0", 40 | "grunt-contrib-uglify": "^1.0.1", 41 | "grunt-contrib-watch": "^1.0.0", 42 | "grunt-conventional-changelog": "^6.1.0", 43 | "grunt-ddescribe-iit": "0.0.6", 44 | "grunt-eslint": "^17.3.1", 45 | "grunt-html2js": "^0.3.0", 46 | "grunt-karma": "^0.12.0", 47 | "jasmine-core": "^2.2.0", 48 | "karma": "0.13.22", 49 | "karma-chrome-launcher": "^0.2.0", 50 | "karma-coverage": "^0.5.0", 51 | "karma-firefox-launcher": "^0.1.4", 52 | "karma-jasmine": "^0.3.5", 53 | "load-grunt-tasks": "^3.3.0", 54 | "lodash": "^4.1.0", 55 | "marked": "^0.3.5", 56 | "node-static": "^0.7.8", 57 | "semver": "^5.0.1", 58 | "shelljs": "^0.6.0" 59 | }, 60 | "license": "MIT" 61 | } 62 | -------------------------------------------------------------------------------- /src/accordion/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 | 16 | 17 |

18 | 19 | 20 |

21 | 22 |
23 | 27 |
28 | 29 |
30 | This content is straight in the template. 31 |
32 |
33 | {{group.content}} 34 |
35 |
36 |

The body of the uib-accordion group grows to fit the contents

37 | 38 |
{{item}}
39 |
40 |
41 | Hello 42 |
43 |
44 | 45 | Custom template with custom header template 46 | 47 | World 48 |
49 |
50 |

Please, to delete your account, click the button below

51 | 52 |
53 |
54 | 55 | I can have markup, too! 56 | 57 | This is just some content to illustrate fancy headings. 58 |
59 |
60 |
61 | -------------------------------------------------------------------------------- /src/accordion/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function ($scope) { 2 | $scope.oneAtATime = true; 3 | 4 | $scope.groups = [ 5 | { 6 | title: 'Dynamic Group Header - 1', 7 | content: 'Dynamic Group Body - 1' 8 | }, 9 | { 10 | title: 'Dynamic Group Header - 2', 11 | content: 'Dynamic Group Body - 2' 12 | } 13 | ]; 14 | 15 | $scope.items = ['Item 1', 'Item 2', 'Item 3']; 16 | 17 | $scope.addItem = function() { 18 | var newItemNo = $scope.items.length + 1; 19 | $scope.items.push('Item ' + newItemNo); 20 | }; 21 | 22 | $scope.status = { 23 | isCustomHeaderOpen: false, 24 | isFirstOpen: true, 25 | isFirstDisabled: false 26 | }; 27 | }); -------------------------------------------------------------------------------- /src/accordion/docs/readme.md: -------------------------------------------------------------------------------- 1 | The **accordion directive** builds on top of the collapse directive to provide a list of items, with collapsible bodies that are collapsed or expanded by clicking on the item's header. 2 | 3 | The body of each accordion group is transcluded into the body of the collapsible element. 4 | 5 | ### uib-accordion settings 6 | 7 | * `close-others` 8 | $ 9 | C 10 | _(Default: `true`)_ - 11 | Control whether expanding an item will cause the other items to close. 12 | 13 | * `template-url` 14 | _(Default: `template/accordion/accordion.html`)_ - 15 | Add the ability to override the template used on the component. 16 | 17 | ### uib-accordion-group settings 18 | 19 | * `heading` 20 | _(Default: `none`)_ - 21 | The clickable text on the group's header. You need one to be able to click on the header for toggling. 22 | 23 | * `is-disabled` 24 | $ 25 | 26 | _(Default: `false`)_ - 27 | Whether the accordion group is disabled or not. 28 | 29 | * `is-open` 30 | $ 31 | 32 | _(Default: `false`)_ - 33 | Whether accordion group is open or closed. 34 | 35 | * `template-url` 36 | _(Default: `uib/template/accordion/accordion-group.html`)_ - 37 | Add the ability to override the template used on the component. 38 | 39 | ### Accordion heading 40 | 41 | Instead of the `heading` attribute on the `uib-accordion-group`, you can use an `uib-accordion-heading` element inside a group that will be used as the group's header. 42 | 43 | If you're using a custom template for the `uib-accordion-group`, you'll need to have an element for the heading to be transcluded into using `uib-accordion-header` (e.g. `
`). 44 | 45 | ### Known issues 46 | 47 | To use clickable elements within the accordion, you have to override the accordion-group template to use div elements instead of anchor elements, and add `cursor: pointer` in your CSS. This is due to browsers interpreting anchor elements as the target of any click event, which triggers routing when certain elements such as buttons are nested inside the anchor element. 48 | 49 | If custom classes on the accordion-group element are desired, one needs to either modify the template to remove the `ng-class` usage in the accordion-group template and use ng-class on the accordion-group element (not recommended), or use an interpolated expression in the class attribute, i.e. ``. 50 | -------------------------------------------------------------------------------- /src/accordion/index.js: -------------------------------------------------------------------------------- 1 | require('../collapse'); 2 | require('../tabindex'); 3 | require('../../template/accordion/accordion-group.html.js'); 4 | require('../../template/accordion/accordion.html.js'); 5 | require('./accordion'); 6 | 7 | var MODULE_NAME = 'ui.bootstrap.module.accordion'; 8 | 9 | angular.module(MODULE_NAME, ['ui.bootstrap.accordion', 'uib/template/accordion/accordion.html', 'uib/template/accordion/accordion-group.html']); 10 | 11 | module.exports = MODULE_NAME; 12 | -------------------------------------------------------------------------------- /src/alert/alert.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.alert', []) 2 | 3 | .controller('UibAlertController', ['$scope', '$element', '$attrs', '$interpolate', '$timeout', function($scope, $element, $attrs, $interpolate, $timeout) { 4 | $scope.closeable = !!$attrs.close; 5 | $element.addClass('alert'); 6 | $attrs.$set('role', 'alert'); 7 | if ($scope.closeable) { 8 | $element.addClass('alert-dismissible'); 9 | } 10 | 11 | var dismissOnTimeout = angular.isDefined($attrs.dismissOnTimeout) ? 12 | $interpolate($attrs.dismissOnTimeout)($scope.$parent) : null; 13 | 14 | if (dismissOnTimeout) { 15 | $timeout(function() { 16 | $scope.close(); 17 | }, parseInt(dismissOnTimeout, 10)); 18 | } 19 | }]) 20 | 21 | .directive('uibAlert', function() { 22 | return { 23 | controller: 'UibAlertController', 24 | controllerAs: 'alert', 25 | restrict: 'A', 26 | templateUrl: function(element, attrs) { 27 | return attrs.templateUrl || 'uib/template/alert/alert.html'; 28 | }, 29 | transclude: true, 30 | scope: { 31 | close: '&' 32 | } 33 | }; 34 | }); 35 | -------------------------------------------------------------------------------- /src/alert/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 |
{{alert.msg}}
7 |
A happy alert!
8 | 9 |
10 | -------------------------------------------------------------------------------- /src/alert/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('AlertDemoCtrl', function ($scope) { 2 | $scope.alerts = [ 3 | { type: 'danger', msg: 'Oh snap! Change a few things up and try submitting again.' }, 4 | { type: 'success', msg: 'Well done! You successfully read this important alert message.' } 5 | ]; 6 | 7 | $scope.addAlert = function() { 8 | $scope.alerts.push({msg: 'Another alert!'}); 9 | }; 10 | 11 | $scope.closeAlert = function(index) { 12 | $scope.alerts.splice(index, 1); 13 | }; 14 | }); -------------------------------------------------------------------------------- /src/alert/docs/readme.md: -------------------------------------------------------------------------------- 1 | This directive can be used both to generate alerts from static and dynamic model data (using the `ng-repeat` directive). 2 | 3 | ### uib-alert settings 4 | 5 | * `close()` 6 | $ - 7 | A callback function that gets fired when an `alert` is closed. If the attribute exists, a close button is displayed as well. 8 | 9 | * `dismiss-on-timeout` 10 | _(Default: `none`)_ - 11 | Takes the number of milliseconds that specify the timeout duration, after which the alert will be closed. This attribute requires the presence of the `close` attribute. 12 | 13 | * `template-url` 14 | _(Default: `uib/template/alert/alert.html`)_ - 15 | Add the ability to override the template used in the component. 16 | -------------------------------------------------------------------------------- /src/alert/index.js: -------------------------------------------------------------------------------- 1 | require('../../template/alert/alert.html.js'); 2 | require('./alert'); 3 | 4 | var MODULE_NAME = 'ui.bootstrap.module.alert'; 5 | 6 | angular.module(MODULE_NAME, ['ui.bootstrap.alert', 'uib/template/alert/alert.html']); 7 | 8 | module.exports = MODULE_NAME; 9 | -------------------------------------------------------------------------------- /src/alert/test/alert.spec.js: -------------------------------------------------------------------------------- 1 | describe('uib-alert', function() { 2 | var element, scope, $compile, $templateCache, $timeout; 3 | 4 | beforeEach(module('ui.bootstrap.alert')); 5 | beforeEach(module('uib/template/alert/alert.html')); 6 | 7 | beforeEach(inject(function($rootScope, _$compile_, _$templateCache_, _$timeout_) { 8 | scope = $rootScope; 9 | $compile = _$compile_; 10 | $templateCache = _$templateCache_; 11 | $timeout = _$timeout_; 12 | 13 | element = angular.element( 14 | '
' + 15 | '
{{alert.msg}}' + 18 | '
' + 19 | '
'); 20 | 21 | scope.alerts = [ 22 | { msg:'foo', type:'success'}, 23 | { msg:'bar', type:'error'}, 24 | { msg:'baz'} 25 | ]; 26 | })); 27 | 28 | function createAlerts() { 29 | $compile(element)(scope); 30 | scope.$digest(); 31 | return element.find('.alert'); 32 | } 33 | 34 | function findCloseButton(index) { 35 | return element.find('.close').eq(index); 36 | } 37 | 38 | function findContent(index) { 39 | return element.find('div[ng-transclude]').eq(index); 40 | } 41 | 42 | it('should expose the controller to the view', function() { 43 | $templateCache.put('uib/template/alert/alert.html', '
{{alert.text}}
'); 44 | 45 | element = $compile('
')(scope); 46 | scope.$digest(); 47 | 48 | var ctrl = element.controller('uib-alert'); 49 | expect(ctrl).toBeDefined(); 50 | 51 | ctrl.text = 'foo'; 52 | scope.$digest(); 53 | 54 | expect(element.html()).toBe('
foo
'); 55 | }); 56 | 57 | it('should support custom templates', function() { 58 | $templateCache.put('foo/bar.html', '
baz
'); 59 | 60 | element = $compile('
')(scope); 61 | scope.$digest(); 62 | 63 | expect(element.html()).toBe('
baz
'); 64 | }); 65 | 66 | it('should generate alerts using ng-repeat', function() { 67 | var alerts = createAlerts(); 68 | expect(alerts.length).toEqual(3); 69 | }); 70 | 71 | it('should show the alert content', function() { 72 | var alerts = createAlerts(); 73 | 74 | for (var i = 0, n = alerts.length; i < n; i++) { 75 | expect(findContent(i).text()).toBe(scope.alerts[i].msg); 76 | } 77 | }); 78 | 79 | it('should show close buttons and have the dismissible class', function() { 80 | var alerts = createAlerts(); 81 | 82 | for (var i = 0, n = alerts.length; i < n; i++) { 83 | expect(findCloseButton(i).css('display')).not.toBe('none'); 84 | expect(alerts.eq(i)).toHaveClass('alert-dismissible'); 85 | } 86 | }); 87 | 88 | it('should fire callback when closed', function() { 89 | var alerts = createAlerts(); 90 | 91 | scope.$apply(function() { 92 | scope.removeAlert = jasmine.createSpy(); 93 | }); 94 | 95 | expect(findCloseButton(0).css('display')).not.toBe('none'); 96 | findCloseButton(1).click(); 97 | 98 | expect(scope.removeAlert).toHaveBeenCalledWith(1); 99 | }); 100 | 101 | it('should not show close button and have the dismissible class if no close callback specified', function() { 102 | element = $compile('
No close
')(scope); 103 | scope.$digest(); 104 | expect(findCloseButton(0)).toBeHidden(); 105 | expect(element).not.toHaveClass('alert-dismissible'); 106 | }); 107 | 108 | it('should close automatically if dismiss-on-timeout is defined on the element', function() { 109 | scope.removeAlert = jasmine.createSpy(); 110 | $compile('
Default alert!
')(scope); 111 | scope.$digest(); 112 | 113 | $timeout.flush(); 114 | expect(scope.removeAlert).toHaveBeenCalled(); 115 | }); 116 | 117 | it('should not close immediately with a dynamic dismiss-on-timeout', function() { 118 | scope.removeAlert = jasmine.createSpy(); 119 | scope.dismissTime = 500; 120 | $compile('
Default alert!
')(scope); 121 | scope.$digest(); 122 | 123 | $timeout.flush(100); 124 | expect(scope.removeAlert).not.toHaveBeenCalled(); 125 | 126 | $timeout.flush(500); 127 | expect(scope.removeAlert).toHaveBeenCalled(); 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /src/buttons/buttons.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.buttons', []) 2 | 3 | .constant('uibButtonConfig', { 4 | activeClass: 'active', 5 | toggleEvent: 'click' 6 | }) 7 | 8 | .controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) { 9 | this.activeClass = buttonConfig.activeClass || 'active'; 10 | this.toggleEvent = buttonConfig.toggleEvent || 'click'; 11 | }]) 12 | 13 | .directive('uibBtnRadio', ['$parse', function($parse) { 14 | return { 15 | require: ['uibBtnRadio', 'ngModel'], 16 | controller: 'UibButtonsController', 17 | controllerAs: 'buttons', 18 | link: function(scope, element, attrs, ctrls) { 19 | var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; 20 | var uncheckableExpr = $parse(attrs.uibUncheckable); 21 | 22 | element.find('input').css({display: 'none'}); 23 | 24 | //model -> UI 25 | ngModelCtrl.$render = function() { 26 | element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio))); 27 | }; 28 | 29 | //ui->model 30 | element.on(buttonsCtrl.toggleEvent, function() { 31 | if (attrs.disabled) { 32 | return; 33 | } 34 | 35 | var isActive = element.hasClass(buttonsCtrl.activeClass); 36 | 37 | if (!isActive || angular.isDefined(attrs.uncheckable)) { 38 | scope.$apply(function() { 39 | ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio)); 40 | ngModelCtrl.$render(); 41 | }); 42 | } 43 | }); 44 | 45 | if (attrs.uibUncheckable) { 46 | scope.$watch(uncheckableExpr, function(uncheckable) { 47 | attrs.$set('uncheckable', uncheckable ? '' : undefined); 48 | }); 49 | } 50 | } 51 | }; 52 | }]) 53 | 54 | .directive('uibBtnCheckbox', function() { 55 | return { 56 | require: ['uibBtnCheckbox', 'ngModel'], 57 | controller: 'UibButtonsController', 58 | controllerAs: 'button', 59 | link: function(scope, element, attrs, ctrls) { 60 | var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; 61 | 62 | element.find('input').css({display: 'none'}); 63 | 64 | function getTrueValue() { 65 | return getCheckboxValue(attrs.btnCheckboxTrue, true); 66 | } 67 | 68 | function getFalseValue() { 69 | return getCheckboxValue(attrs.btnCheckboxFalse, false); 70 | } 71 | 72 | function getCheckboxValue(attribute, defaultValue) { 73 | return angular.isDefined(attribute) ? scope.$eval(attribute) : defaultValue; 74 | } 75 | 76 | //model -> UI 77 | ngModelCtrl.$render = function() { 78 | element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); 79 | }; 80 | 81 | //ui->model 82 | element.on(buttonsCtrl.toggleEvent, function() { 83 | if (attrs.disabled) { 84 | return; 85 | } 86 | 87 | scope.$apply(function() { 88 | ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); 89 | ngModelCtrl.$render(); 90 | }); 91 | }); 92 | } 93 | }; 94 | }); 95 | -------------------------------------------------------------------------------- /src/buttons/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 |

Single toggle

3 |
{{singleModel}}
4 | 7 |

Checkbox

8 |
Model: {{checkModel}}
9 |
Results: {{checkResults}}
10 |
11 | 12 | 13 | 14 |
15 |

Radio & Uncheckable Radio

16 |
{{radioModel || 'null'}}
17 |
18 | 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 |
27 |
28 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /src/buttons/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('ButtonsCtrl', function ($scope) { 2 | $scope.singleModel = 1; 3 | 4 | $scope.radioModel = 'Middle'; 5 | 6 | $scope.checkModel = { 7 | left: false, 8 | middle: true, 9 | right: false 10 | }; 11 | 12 | $scope.checkResults = []; 13 | 14 | $scope.$watchCollection('checkModel', function () { 15 | $scope.checkResults = []; 16 | angular.forEach($scope.checkModel, function (value, key) { 17 | if (value) { 18 | $scope.checkResults.push(key); 19 | } 20 | }); 21 | }); 22 | }); -------------------------------------------------------------------------------- /src/buttons/docs/readme.md: -------------------------------------------------------------------------------- 1 | With the buttons directive, we can make a group of buttons behave like a set of checkboxes (`uib-btn-checkbox`) or behave like a set of radio buttons (`uib-btn-radio`). 2 | 3 | ### uib-btn-checkbox settings 4 | 5 | * `btn-checkbox-false` 6 | _(Default: `false`)_ - 7 | Sets the value for the unchecked status. 8 | 9 | * `btn-checkbox-true` 10 | _(Default: `true`)_ - 11 | Sets the value for the checked status. 12 | 13 | * `ng-model` 14 | $ 15 | - 16 | Model where we set the checkbox status. By default `true` or `false`. 17 | 18 | ### uib-btn-radio settings 19 | 20 | * `ng-model` 21 | $ 22 | - 23 | Model where we set the radio status. All radio buttons in a group should use the same `ng-model`. 24 | 25 | * `uib-btn-radio` - 26 | $ 27 | Value to assign to the `ng-model` if we check this radio button. 28 | 29 | * `uib-uncheckable` 30 | $ 31 | _(Default: `null`)_ - 32 | An expression that evaluates to a truthy or falsy value that determines whether the `uncheckable` attribute is present. 33 | 34 | * `uncheckable` 35 | B - 36 | Whether a radio button can be unchecked or not. 37 | 38 | ### Additional settings `uibButtonConfig` 39 | 40 | * `activeClass` 41 | _(Default: `active`)_ - 42 | Class to apply to the checked buttons. 43 | 44 | * `toggleEvent` 45 | _(Default: `click`)_ - 46 | Event used to toggle the buttons. 47 | 48 | ### Known issues 49 | 50 | To use tooltips or popovers on elements within a `btn-group`, set the tooltip/popover `appendToBody` option to `true`. This is due to Bootstrap CSS styling. See [here](http://getbootstrap.com/components/#btn-groups) for more information. 51 | -------------------------------------------------------------------------------- /src/buttons/index.js: -------------------------------------------------------------------------------- 1 | require('./buttons'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.buttons'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.buttons']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/carousel/carousel.css: -------------------------------------------------------------------------------- 1 | .ng-animate.item:not(.left):not(.right) { 2 | -webkit-transition: 0s ease-in-out left; 3 | transition: 0s ease-in-out left 4 | } -------------------------------------------------------------------------------- /src/carousel/docs/README.md: -------------------------------------------------------------------------------- 1 | Carousel creates a carousel similar to bootstrap's image carousel. 2 | 3 | The carousel also offers support for touchscreen devices in the form of swiping. To enable swiping, load the `ngTouch` module as a dependency. 4 | 5 | Use a `` element with `` elements inside it. 6 | 7 | ### uib-carousel settings 8 | 9 | * `active` 10 | 11 | _(Default: `Index of first slide`)_ - 12 | Index of current active slide. 13 | 14 | * `interval` 15 | $ 16 | 17 | _(Default: `none`)_ - 18 | Sets an interval to cycle through the slides. You need a number bigger than 0 to make the interval work. 19 | 20 | * `no-pause` 21 | $ 22 | 23 | _(Default: `false`)_ - 24 | The interval pauses on mouseover. Setting this to truthy, disables this pause. 25 | 26 | * `no-transition` 27 | $ 28 | 29 | _(Default: `false`)_ - 30 | Whether to disable the transition animation between slides. Setting this to truthy, disables this transition. 31 | 32 | * `no-wrap` 33 | $ 34 | _(Default: `false`)_ - 35 | Disables the looping of slides. Setting `no-wrap` to an expression which evaluates to a truthy value will prevent looping. 36 | 37 | * `template-url` 38 | _(Default: `uib/template/carousel/carousel.html`)_ - 39 | Add the ability to override the template used on the component. 40 | 41 | ### uib-slide settings 42 | 43 | * `actual` 44 | $ 45 | 46 | _(Default: `none`)_ - 47 | Use this attribute to bind the slide model (or any object of interest) onto the slide scope, which makes it available for customization in the carousel template. 48 | 49 | * `index` 50 | $ 51 | 52 | _(Default: `none`)_ - 53 | The index of the slide. Must be unique. 54 | 55 | * `template-url` 56 | _(Default: `uib/template/carousel/slide.html`)_ - 57 | Add the ability to override the template used on the component. 58 | -------------------------------------------------------------------------------- /src/carousel/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 |
18 | 22 |
23 |
24 |
25 | Interval, in milliseconds: 26 |
Enter a negative number or 0 to stop the interval. 27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /src/carousel/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('CarouselDemoCtrl', function ($scope) { 2 | $scope.myInterval = 5000; 3 | $scope.noWrapSlides = false; 4 | $scope.active = 0; 5 | var slides = $scope.slides = []; 6 | var currIndex = 0; 7 | 8 | $scope.addSlide = function() { 9 | var newWidth = 600 + slides.length + 1; 10 | slides.push({ 11 | image: '//unsplash.it/' + newWidth + '/300', 12 | text: ['Nice image','Awesome photograph','That is so cool','I love that'][slides.length % 4], 13 | id: currIndex++ 14 | }); 15 | }; 16 | 17 | $scope.randomize = function() { 18 | var indexes = generateIndexesArray(); 19 | assignNewIndexesToSlides(indexes); 20 | }; 21 | 22 | for (var i = 0; i < 4; i++) { 23 | $scope.addSlide(); 24 | } 25 | 26 | // Randomize logic below 27 | 28 | function assignNewIndexesToSlides(indexes) { 29 | for (var i = 0, l = slides.length; i < l; i++) { 30 | slides[i].id = indexes.pop(); 31 | } 32 | } 33 | 34 | function generateIndexesArray() { 35 | var indexes = []; 36 | for (var i = 0; i < currIndex; ++i) { 37 | indexes[i] = i; 38 | } 39 | return shuffle(indexes); 40 | } 41 | 42 | // http://stackoverflow.com/questions/962802#962890 43 | function shuffle(array) { 44 | var tmp, current, top = array.length; 45 | 46 | if (top) { 47 | while (--top) { 48 | current = Math.floor(Math.random() * (top + 1)); 49 | tmp = array[current]; 50 | array[current] = array[top]; 51 | array[top] = tmp; 52 | } 53 | } 54 | 55 | return array; 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /src/carousel/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../../template/carousel/carousel.html.js'); 2 | require('../../template/carousel/slide.html.js'); 3 | require('./carousel'); 4 | 5 | var MODULE_NAME = 'ui.bootstrap.module.carousel'; 6 | 7 | angular.module(MODULE_NAME, ['ui.bootstrap.carousel', 'uib/template/carousel/carousel.html', 'uib/template/carousel/slide.html']); 8 | 9 | module.exports = MODULE_NAME; 10 | -------------------------------------------------------------------------------- /src/carousel/index.js: -------------------------------------------------------------------------------- 1 | require('./carousel.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/collapse/docs/demo.html: -------------------------------------------------------------------------------- 1 | 9 |
10 |

Resize window to less than 768 pixels to display mobile menu toggle button.

11 | 28 |
29 | 30 |
31 |
32 |
Some content
33 |
34 | 35 | 36 |
37 |
38 |
Some content
39 |
40 |
41 | -------------------------------------------------------------------------------- /src/collapse/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('CollapseDemoCtrl', function ($scope) { 2 | $scope.isNavCollapsed = true; 3 | $scope.isCollapsed = false; 4 | $scope.isCollapsedHorizontal = false; 5 | }); 6 | -------------------------------------------------------------------------------- /src/collapse/docs/readme.md: -------------------------------------------------------------------------------- 1 | **uib-collapse** provides a simple way to hide and show an element with a css transition 2 | 3 | ### uib-collapse settings 4 | 5 | * `collapsed()` 6 | $ - 7 | An optional expression called after the element finished collapsing. 8 | 9 | * `collapsing()` 10 | $ - 11 | An optional expression called before the element begins collapsing. 12 | If the expression returns a promise, animation won't start until the promise resolves. 13 | If the returned promise is rejected, collapsing will be cancelled. 14 | 15 | * `expanded()` 16 | $ - 17 | An optional expression called after the element finished expanding. 18 | 19 | * `expanding()` 20 | $ - 21 | An optional expression called before the element begins expanding. 22 | If the expression returns a promise, animation won't start until the promise resolves. 23 | If the returned promise is rejected, expanding will be cancelled. 24 | 25 | * `uib-collapse` 26 | $ 27 | 28 | _(Default: `false`)_ - 29 | Whether the element should be collapsed or not. 30 | 31 | * `horizontal` 32 | $ - 33 | An optional attribute that permit to collapse horizontally. 34 | 35 | ### Known Issues 36 | 37 | When using the `horizontal` attribute with this directive, CSS can reflow as the collapse element goes from `0px` to its desired end width, which can result in height changes. This can cause animations to not appear to run. The best way around this is to set a fixed height via CSS on the horizontal collapse element so that this situation does not occur, and so the animation can run as expected. 38 | -------------------------------------------------------------------------------- /src/collapse/index.js: -------------------------------------------------------------------------------- 1 | require('./collapse'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.collapse'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.collapse']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/dateparser/docs/README.md: -------------------------------------------------------------------------------- 1 | The `uibDateParser` is what the `uib-datepicker` uses internally to parse the dates. You can use it standalone by injecting the `uibDateParser` service where you need it. 2 | 3 | The public API for the dateParser is a single method called `parse`. 4 | 5 | Certain format codes support i18n. Check this [guide](https://docs.angularjs.org/guide/i18n) for more information. 6 | 7 | ### uibDateParser's parse function 8 | 9 | ##### parameters 10 | 11 | * `input` 12 | _(Type: `string`, Example: `2004/Sep/4`)_ - 13 | The input date to parse. 14 | 15 | * `format` 16 | _(Type: `string`, Example: `yyyy/MMM/d`)_ - 17 | The format we want to use. Check all the supported formats below. 18 | 19 | * `baseDate` 20 | _(Type: `Date`, Example: `new Date()`)_ - 21 | If you want to parse a date but maintain the timezone, you can pass an existing date here. 22 | 23 | ##### return 24 | 25 | * If the specified input matches the format, a new date with the input will be returned, otherwise, it will return undefined. 26 | 27 | ### uibDateParser's format codes 28 | 29 | * `yyyy` 30 | _(Example: `2015`)_ - 31 | Parses a 4 digits year. 32 | 33 | * `yy` 34 | _(Example: `15`)_ - 35 | Parses a 2 digits year. 36 | 37 | * `y` 38 | _(Example: `15`)_ - 39 | Parses a year with 1, 2, 3, or 4 digits. 40 | 41 | * `MMMM` 42 | _(Example: `February`, i18n support)_ - 43 | Parses the full name of a month. 44 | 45 | * `MMM` 46 | _(Example: `Feb`, i18n support)_ - 47 | Parses the short name of a month. 48 | 49 | * `MM` 50 | _(Example: `12`, Leading 0)_ - 51 | Parses a numeric month. 52 | 53 | * `M` 54 | _(Example: `3`)_ - 55 | Parses a numeric month. 56 | 57 | * `M!` 58 | _(Example: `3` or `03`)_ - 59 | Parses a numeric month, but allowing an optional leading zero 60 | 61 | * `LLLL` 62 | _(Example: `February`, i18n support)_ - Stand-alone month in year (January-December). Requires Angular version 1.5.1 or higher. 63 | 64 | * `dd` 65 | _(Example: `05`, Leading 0)_ - 66 | Parses a numeric day. 67 | 68 | * `d` 69 | _(Example: `5`)_ - 70 | Parses a numeric day. 71 | 72 | * `d!` 73 | _(Example: `3` or `03`)_ - 74 | Parses a numeric day, but allowing an optional leading zero 75 | 76 | * `EEEE` 77 | _(Example: `Sunday`, i18n support)_ - 78 | Parses the full name of a day. 79 | 80 | * `EEE` 81 | _(Example: `Mon`, i18n support)_ - 82 | Parses the short name of a day. 83 | 84 | * `HH` 85 | _(Example: `14`, Leading 0)_ - 86 | Parses a 24 hours time. 87 | 88 | * `H` 89 | _(Example: `3`)_ - 90 | Parses a 24 hours time. 91 | 92 | * `hh` 93 | _(Example: `11`, Leading 0)_ - 94 | Parses a 12 hours time. 95 | 96 | * `h` 97 | _(Example: `3`)_ - 98 | Parses a 12 hours time. 99 | 100 | * `mm` 101 | _(Example: `09`, Leading 0)_ - 102 | Parses the minutes. 103 | 104 | * `m` 105 | _(Example: `3`)_ - 106 | Parses the minutes. 107 | 108 | * `sss` 109 | _(Example: `094`, Leading 0)_ - 110 | Parses the milliseconds. 111 | 112 | * `ss` 113 | _(Example: `08`, Leading 0)_ - 114 | Parses the seconds. 115 | 116 | * `s` 117 | _(Example: `22`)_ - 118 | Parses the seconds. 119 | 120 | * `a` 121 | _(Example: `10AM`)_ - 122 | Parses a 12 hours time with AM/PM. 123 | 124 | * `Z` 125 | _(Example: `-0800`)_ - 126 | Parses the timezone offset in a signed 4 digit representation 127 | 128 | * `ww` 129 | _(Example: `03`, Leading 0)_ - 130 | Parses the week number 131 | 132 | * `w` 133 | _(Example: `03`)_ - 134 | Parses the week number 135 | 136 | * `G`, `GG`, `GGG` 137 | _(Example: `AD`)_ - 138 | Parses the era (`AD` or `BC`) 139 | * `GGGG` 140 | _(Example: `Anno Domini`)_ - 141 | Parses the long form of the era (`Anno Domini` or `Before Christ`) 142 | 143 | \* The ones marked with `Leading 0`, needs a leading 0 for values less than 10. Exception being milliseconds which needs it for values under 100. 144 | 145 | \** It also supports `fullDate|longDate|medium|mediumDate|mediumTime|short|shortDate|shortTime` as the format for parsing. 146 | 147 | \*** It supports template literals as a string between the single quote `'` character, i.e. `'The Date is' MM/DD/YYYY`. If one wants the literal single quote character, one must use `''''`. 148 | -------------------------------------------------------------------------------- /src/dateparser/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 |

Formatting codes playground

3 |

4 | 5 | 6 |

7 |

8 | 9 | 10 |

11 |
12 | -------------------------------------------------------------------------------- /src/dateparser/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('DateParserDemoCtrl', function ($scope, uibDateParser) { 2 | $scope.format = 'yyyy/MM/dd'; 3 | $scope.date = new Date(); 4 | }); 5 | -------------------------------------------------------------------------------- /src/dateparser/index.js: -------------------------------------------------------------------------------- 1 | require('./dateparser'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.dateparser'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.dateparser']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/datepicker/datepicker.css: -------------------------------------------------------------------------------- 1 | .uib-datepicker .uib-title { 2 | width: 100%; 3 | } 4 | 5 | .uib-day button, .uib-month button, .uib-year button { 6 | min-width: 100%; 7 | } 8 | 9 | .uib-left, .uib-right { 10 | width: 100% 11 | } 12 | -------------------------------------------------------------------------------- /src/datepicker/docs/demo.html: -------------------------------------------------------------------------------- 1 | 13 |
14 |
Selected date is: {{dt | date:'fullDate' }}
15 | 16 |

Inline

17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /src/datepicker/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('DatepickerDemoCtrl', function ($scope) { 2 | $scope.today = function() { 3 | $scope.dt = new Date(); 4 | }; 5 | $scope.today(); 6 | 7 | $scope.clear = function() { 8 | $scope.dt = null; 9 | }; 10 | 11 | $scope.options = { 12 | customClass: getDayClass, 13 | minDate: new Date(), 14 | showWeeks: true 15 | }; 16 | 17 | // Disable weekend selection 18 | function disabled(data) { 19 | var date = data.date, 20 | mode = data.mode; 21 | return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6); 22 | } 23 | 24 | $scope.toggleMin = function() { 25 | $scope.options.minDate = $scope.options.minDate ? null : new Date(); 26 | }; 27 | 28 | $scope.toggleMin(); 29 | 30 | $scope.setDate = function(year, month, day) { 31 | $scope.dt = new Date(year, month, day); 32 | }; 33 | 34 | var tomorrow = new Date(); 35 | tomorrow.setDate(tomorrow.getDate() + 1); 36 | var afterTomorrow = new Date(tomorrow); 37 | afterTomorrow.setDate(tomorrow.getDate() + 1); 38 | $scope.events = [ 39 | { 40 | date: tomorrow, 41 | status: 'full' 42 | }, 43 | { 44 | date: afterTomorrow, 45 | status: 'partially' 46 | } 47 | ]; 48 | 49 | function getDayClass(data) { 50 | var date = data.date, 51 | mode = data.mode; 52 | if (mode === 'day') { 53 | var dayToCheck = new Date(date).setHours(0,0,0,0); 54 | 55 | for (var i = 0; i < $scope.events.length; i++) { 56 | var currentDay = new Date($scope.events[i].date).setHours(0,0,0,0); 57 | 58 | if (dayToCheck === currentDay) { 59 | return $scope.events[i].status; 60 | } 61 | } 62 | } 63 | 64 | return ''; 65 | } 66 | }); 67 | -------------------------------------------------------------------------------- /src/datepicker/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../dateparser'); 2 | require('../isClass'); 3 | require('../../template/datepicker/datepicker.html.js'); 4 | require('../../template/datepicker/day.html.js'); 5 | require('../../template/datepicker/month.html.js'); 6 | require('../../template/datepicker/year.html.js'); 7 | require('./datepicker'); 8 | 9 | var MODULE_NAME = 'ui.bootstrap.module.datepicker'; 10 | 11 | angular.module(MODULE_NAME, ['ui.bootstrap.datepicker', 'uib/template/datepicker/datepicker.html', 'uib/template/datepicker/day.html', 'uib/template/datepicker/month.html', 'uib/template/datepicker/year.html']); 12 | 13 | module.exports = MODULE_NAME; 14 | -------------------------------------------------------------------------------- /src/datepicker/index.js: -------------------------------------------------------------------------------- 1 | require('./datepicker.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/datepickerPopup/docs/demo.html: -------------------------------------------------------------------------------- 1 | 13 |
14 |
Selected date is: {{dt | date:'fullDate' }}
15 | 16 |

Popup

17 |
18 |
19 |

20 | 21 | 22 | 23 | 24 |

25 |
26 | 27 |
28 |

29 | 30 | 31 | 32 | 33 |

34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | -------------------------------------------------------------------------------- /src/datepickerPopup/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('DatepickerPopupDemoCtrl', function ($scope) { 2 | $scope.today = function() { 3 | $scope.dt = new Date(); 4 | }; 5 | $scope.today(); 6 | 7 | $scope.clear = function() { 8 | $scope.dt = null; 9 | }; 10 | 11 | $scope.inlineOptions = { 12 | customClass: getDayClass, 13 | minDate: new Date(), 14 | showWeeks: true 15 | }; 16 | 17 | $scope.dateOptions = { 18 | dateDisabled: disabled, 19 | formatYear: 'yy', 20 | maxDate: new Date(2020, 5, 22), 21 | minDate: new Date(), 22 | startingDay: 1 23 | }; 24 | 25 | // Disable weekend selection 26 | function disabled(data) { 27 | var date = data.date, 28 | mode = data.mode; 29 | return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6); 30 | } 31 | 32 | $scope.toggleMin = function() { 33 | $scope.inlineOptions.minDate = $scope.inlineOptions.minDate ? null : new Date(); 34 | $scope.dateOptions.minDate = $scope.inlineOptions.minDate; 35 | }; 36 | 37 | $scope.toggleMin(); 38 | 39 | $scope.open1 = function() { 40 | $scope.popup1.opened = true; 41 | }; 42 | 43 | $scope.open2 = function() { 44 | $scope.popup2.opened = true; 45 | }; 46 | 47 | $scope.setDate = function(year, month, day) { 48 | $scope.dt = new Date(year, month, day); 49 | }; 50 | 51 | $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate']; 52 | $scope.format = $scope.formats[0]; 53 | $scope.altInputFormats = ['M!/d!/yyyy']; 54 | 55 | $scope.popup1 = { 56 | opened: false 57 | }; 58 | 59 | $scope.popup2 = { 60 | opened: false 61 | }; 62 | 63 | var tomorrow = new Date(); 64 | tomorrow.setDate(tomorrow.getDate() + 1); 65 | var afterTomorrow = new Date(); 66 | afterTomorrow.setDate(tomorrow.getDate() + 1); 67 | $scope.events = [ 68 | { 69 | date: tomorrow, 70 | status: 'full' 71 | }, 72 | { 73 | date: afterTomorrow, 74 | status: 'partially' 75 | } 76 | ]; 77 | 78 | function getDayClass(data) { 79 | var date = data.date, 80 | mode = data.mode; 81 | if (mode === 'day') { 82 | var dayToCheck = new Date(date).setHours(0,0,0,0); 83 | 84 | for (var i = 0; i < $scope.events.length; i++) { 85 | var currentDay = new Date($scope.events[i].date).setHours(0,0,0,0); 86 | 87 | if (dayToCheck === currentDay) { 88 | return $scope.events[i].status; 89 | } 90 | } 91 | } 92 | 93 | return ''; 94 | } 95 | }); 96 | -------------------------------------------------------------------------------- /src/datepickerPopup/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../datepicker/index-nocss.js'); 2 | require('../position/index-nocss.js'); 3 | require('../../template/datepickerPopup/popup.html.js'); 4 | require('./popup.js'); 5 | 6 | var MODULE_NAME = 'ui.bootstrap.module.datepickerPopup'; 7 | 8 | angular.module(MODULE_NAME, ['ui.bootstrap.datepickerPopup', 'uib/template/datepickerPopup/popup.html', 'ui.bootstrap.module.datepicker']); 9 | 10 | module.exports = MODULE_NAME; 11 | -------------------------------------------------------------------------------- /src/datepickerPopup/index.js: -------------------------------------------------------------------------------- 1 | require('../datepicker/datepicker.css'); 2 | require('../position/position.css'); 3 | require('./popup.css'); 4 | module.exports = require('./index-nocss.js'); 5 | -------------------------------------------------------------------------------- /src/datepickerPopup/popup.css: -------------------------------------------------------------------------------- 1 | .uib-datepicker-popup.dropdown-menu { 2 | display: block; 3 | float: none; 4 | margin: 0; 5 | } 6 | 7 | .uib-button-bar { 8 | padding: 10px 9px 2px; 9 | } 10 | -------------------------------------------------------------------------------- /src/debounce/debounce.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.debounce', []) 2 | /** 3 | * A helper, internal service that debounces a function 4 | */ 5 | .factory('$$debounce', ['$timeout', function($timeout) { 6 | return function(callback, debounceTime) { 7 | var timeoutPromise; 8 | 9 | return function() { 10 | var self = this; 11 | var args = Array.prototype.slice.call(arguments); 12 | if (timeoutPromise) { 13 | $timeout.cancel(timeoutPromise); 14 | } 15 | 16 | timeoutPromise = $timeout(function() { 17 | callback.apply(self, args); 18 | }, debounceTime); 19 | }; 20 | }; 21 | }]); 22 | -------------------------------------------------------------------------------- /src/debounce/index.js: -------------------------------------------------------------------------------- 1 | require('./debounce'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.debounce'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.debounce']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/debounce/test/debounce.spec.js: -------------------------------------------------------------------------------- 1 | describe('$$debounce', function() { 2 | var $$debounce, $timeout, debouncedFunction, i, args; 3 | 4 | beforeEach(module('ui.bootstrap.debounce')); 5 | beforeEach(inject(function(_$$debounce_, _$timeout_) { 6 | $$debounce = _$$debounce_; 7 | $timeout = _$timeout_; 8 | i = 0; 9 | debouncedFunction = $$debounce(function() { 10 | args = Array.prototype.slice.call(arguments); 11 | i++; 12 | }, 100); 13 | })); 14 | 15 | it('should function like a $timeout when called once during timeout', function() { 16 | debouncedFunction(); 17 | $timeout.flush(50); 18 | 19 | expect(i).toBe(0); 20 | 21 | $timeout.flush(50); 22 | 23 | expect(i).toBe(1); 24 | }); 25 | 26 | it('should only execute 100ms after last call when called twice', function() { 27 | debouncedFunction(); 28 | $timeout.flush(50); 29 | 30 | expect(i).toBe(0); 31 | 32 | debouncedFunction(); 33 | $timeout.flush(50); 34 | 35 | expect(i).toBe(0); 36 | 37 | $timeout.flush(50); 38 | 39 | expect(i).toBe(1); 40 | }); 41 | 42 | it('should properly pass arguments to debounced function', function() { 43 | debouncedFunction(1, 2, 3); 44 | $timeout.flush(100); 45 | 46 | expect(args).toEqual([1, 2, 3]); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/dropdown/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('DropdownCtrl', function ($scope, $log) { 2 | $scope.items = [ 3 | 'The first choice!', 4 | 'And another choice for you.', 5 | 'but wait! A third!' 6 | ]; 7 | 8 | $scope.status = { 9 | isopen: false 10 | }; 11 | 12 | $scope.toggled = function(open) { 13 | $log.log('Dropdown is now: ', open); 14 | }; 15 | 16 | $scope.toggleDropdown = function($event) { 17 | $event.preventDefault(); 18 | $event.stopPropagation(); 19 | $scope.status.isopen = !$scope.status.isopen; 20 | }; 21 | 22 | $scope.appendToEl = angular.element(document.querySelector('#dropdown-long-content')); 23 | }); 24 | -------------------------------------------------------------------------------- /src/dropdown/docs/readme.md: -------------------------------------------------------------------------------- 1 | Dropdown is a simple directive which will toggle a dropdown menu on click or programmatically. 2 | 3 | This directive is composed by three parts: 4 | 5 | * `uib-dropdown` which transforms a node into a dropdown. 6 | * `uib-dropdown-toggle` which allows the dropdown to be toggled via click. This directive is optional. 7 | * `uib-dropdown-menu` which transforms a node into the popup menu. 8 | 9 | Each of these parts need to be used as attribute directives. 10 | 11 | ### uib-dropdown settings 12 | 13 | * `auto-close` 14 | _(Default: `always`)_ - 15 | Controls the behavior of the menu when clicked. 16 | * `always` - Automatically closes the dropdown when any of its elements is clicked. 17 | * `disabled` - Disables the auto close. You can control it manually with `is-open`. It still gets closed if the toggle is clicked, `esc` is pressed or another dropdown is open. 18 | * `outsideClick` - Closes the dropdown automatically only when the user clicks any element outside the dropdown. 19 | 20 | * `dropdown-append-to` 21 | $ 22 | _(Default: `null`)_ - 23 | Appends the inner dropdown-menu to an arbitrary DOM element. 24 | 25 | * `dropdown-append-to-body` 26 | B 27 | _(Default: `false`)_ - 28 | Appends the inner dropdown-menu to the body element if the attribute is present without a value, or with a non `false` value. 29 | 30 | * `is-open` 31 | $ 32 | 33 | _(Default: `false`)_ - 34 | Defines whether or not the dropdown-menu is open. The `uib-dropdown-toggle` will toggle this attribute on click. 35 | 36 | * `keyboard-nav`: 37 | B 38 | _(Default: `false`)_ - 39 | Enables navigation of dropdown list elements with the arrow keys. 40 | 41 | * `on-toggle(open)` 42 | $ - 43 | An optional expression called when the dropdown menu is opened or closed. 44 | 45 | ### uib-dropdown-menu settings 46 | 47 | * `template-url` 48 | _(Default: `none`)_ - 49 | You may specify a template for the dropdown menu. Check the demos for an example. 50 | 51 | ### Additional settings `uibDropdownConfig` 52 | 53 | * `appendToOpenClass` 54 | _(Default: `uib-dropdown-open`)_ - 55 | Class to apply when the dropdown is open and appended to a different DOM element. 56 | 57 | * `openClass` 58 | _(Default: `open`)_ - 59 | Class to apply when the dropdown is open. 60 | 61 | ### Known issues 62 | 63 | For usage with ngTouch, it is recommended to use the programmatic `is-open` trigger with ng-click - this is due to ngTouch decorating ng-click to prevent propagation of the event. 64 | -------------------------------------------------------------------------------- /src/dropdown/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../multiMap'); 2 | require('../position/index-nocss.js'); 3 | require('./dropdown'); 4 | 5 | var MODULE_NAME = 'ui.bootstrap.module.dropdown'; 6 | 7 | angular.module(MODULE_NAME, ['ui.bootstrap.dropdown']); 8 | 9 | module.exports = MODULE_NAME; 10 | -------------------------------------------------------------------------------- /src/dropdown/index.js: -------------------------------------------------------------------------------- 1 | require('../position/position.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/isClass/index.js: -------------------------------------------------------------------------------- 1 | require('./isClass'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.isClass'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.isClass']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/isClass/isClass.js: -------------------------------------------------------------------------------- 1 | // Avoiding use of ng-class as it creates a lot of watchers when a class is to be applied to 2 | // at most one element. 3 | angular.module('ui.bootstrap.isClass', []) 4 | .directive('uibIsClass', [ 5 | '$animate', 6 | function ($animate) { 7 | // 11111111 22222222 8 | var ON_REGEXP = /^\s*([\s\S]+?)\s+on\s+([\s\S]+?)\s*$/; 9 | // 11111111 22222222 10 | var IS_REGEXP = /^\s*([\s\S]+?)\s+for\s+([\s\S]+?)\s*$/; 11 | 12 | var dataPerTracked = {}; 13 | 14 | return { 15 | restrict: 'A', 16 | compile: function(tElement, tAttrs) { 17 | var linkedScopes = []; 18 | var instances = []; 19 | var expToData = {}; 20 | var lastActivated = null; 21 | var onExpMatches = tAttrs.uibIsClass.match(ON_REGEXP); 22 | var onExp = onExpMatches[2]; 23 | var expsStr = onExpMatches[1]; 24 | var exps = expsStr.split(','); 25 | 26 | return linkFn; 27 | 28 | function linkFn(scope, element, attrs) { 29 | linkedScopes.push(scope); 30 | instances.push({ 31 | scope: scope, 32 | element: element 33 | }); 34 | 35 | exps.forEach(function(exp, k) { 36 | addForExp(exp, scope); 37 | }); 38 | 39 | scope.$on('$destroy', removeScope); 40 | } 41 | 42 | function addForExp(exp, scope) { 43 | var matches = exp.match(IS_REGEXP); 44 | var clazz = scope.$eval(matches[1]); 45 | var compareWithExp = matches[2]; 46 | var data = expToData[exp]; 47 | if (!data) { 48 | var watchFn = function(compareWithVal) { 49 | var newActivated = null; 50 | instances.some(function(instance) { 51 | var thisVal = instance.scope.$eval(onExp); 52 | if (thisVal === compareWithVal) { 53 | newActivated = instance; 54 | return true; 55 | } 56 | }); 57 | if (data.lastActivated !== newActivated) { 58 | if (data.lastActivated) { 59 | $animate.removeClass(data.lastActivated.element, clazz); 60 | } 61 | if (newActivated) { 62 | $animate.addClass(newActivated.element, clazz); 63 | } 64 | data.lastActivated = newActivated; 65 | } 66 | }; 67 | expToData[exp] = data = { 68 | lastActivated: null, 69 | scope: scope, 70 | watchFn: watchFn, 71 | compareWithExp: compareWithExp, 72 | watcher: scope.$watch(compareWithExp, watchFn) 73 | }; 74 | } 75 | data.watchFn(scope.$eval(compareWithExp)); 76 | } 77 | 78 | function removeScope(e) { 79 | var removedScope = e.targetScope; 80 | var index = linkedScopes.indexOf(removedScope); 81 | linkedScopes.splice(index, 1); 82 | instances.splice(index, 1); 83 | if (linkedScopes.length) { 84 | var newWatchScope = linkedScopes[0]; 85 | angular.forEach(expToData, function(data) { 86 | if (data.scope === removedScope) { 87 | data.watcher = newWatchScope.$watch(data.compareWithExp, data.watchFn); 88 | data.scope = newWatchScope; 89 | } 90 | }); 91 | } else { 92 | expToData = {}; 93 | } 94 | } 95 | } 96 | }; 97 | }]); -------------------------------------------------------------------------------- /src/isClass/test/isClass.spec.js: -------------------------------------------------------------------------------- 1 | describe('uibIsClass', function() { 2 | var $rootScope; 3 | 4 | beforeEach(module('ui.bootstrap.isClass')); 5 | beforeEach(inject(function($compile, _$rootScope_) { 6 | $rootScope = _$rootScope_; 7 | $rootScope.activeClass = 'active'; 8 | $rootScope.items = [1, 2, 3]; 9 | element = $compile('
{{ item }}
')($rootScope); 11 | $rootScope.$digest(); 12 | })); 13 | 14 | it('initializes classes correctly', function() { 15 | expect(element.find('.active').length).toEqual(0); 16 | }); 17 | 18 | it('sets classes correctly', function() { 19 | $rootScope.activeItem = 2; 20 | $rootScope.$digest(); 21 | expect(element.find('.active').text()).toEqual('2'); 22 | 23 | $rootScope.items.splice(1, 1); 24 | $rootScope.$digest(); 25 | expect(element.find('.active').length).toEqual(0); 26 | }); 27 | 28 | it('handles removal of items correctly', function() { 29 | $rootScope.activeItem = 2; 30 | $rootScope.$digest(); 31 | expect(element.find('.active').text()).toEqual('2'); 32 | 33 | $rootScope.items.splice(1, 1); 34 | $rootScope.$digest(); 35 | expect(element.find('.active').length).toEqual(0); 36 | 37 | $rootScope.activeItem = 1; 38 | $rootScope.$digest(); 39 | expect(element.find('.active').text()).toEqual('1'); 40 | }); 41 | 42 | it('handles moving of items', function() { 43 | $rootScope.activeItem = 2; 44 | $rootScope.items = [2, 1, 3]; 45 | $rootScope.$digest(); 46 | expect(element.find('.active').text()).toEqual('2'); 47 | expect(element.find('.active').length).toEqual(1); 48 | expect(element.find('.active').index()).toEqual(0); 49 | 50 | $rootScope.items = [4, 3, 2]; 51 | $rootScope.$digest(); 52 | expect(element.find('.active').text()).toEqual('2'); 53 | expect(element.find('.active').length).toEqual(1); 54 | expect(element.find('.active').index()).toEqual(2); 55 | }); 56 | 57 | it('handles emptying and re-adding the items', function() { 58 | $rootScope.activeItem = 2; 59 | $rootScope.items = []; 60 | $rootScope.$digest(); 61 | expect(element.find('.active').length).toEqual(0); 62 | 63 | $rootScope.items = [4, 3, 2]; 64 | $rootScope.$digest(); 65 | expect(element.find('.active').text()).toEqual('2'); 66 | expect(element.find('.active').index()).toEqual(2); 67 | }); 68 | 69 | it('handles undefined items', function() { 70 | $rootScope.activeItem = undefined; 71 | $rootScope.items = []; 72 | $rootScope.$digest(); 73 | expect(element.find('.active').length).toEqual(0); 74 | 75 | $rootScope.items = [4, 3, undefined]; 76 | $rootScope.$digest(); 77 | expect(element.find('.active').length).toEqual(1); 78 | expect(element.find('.active').text()).toEqual(''); 79 | }); 80 | }); -------------------------------------------------------------------------------- /src/modal/docs/demo.html: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /src/modal/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($uibModal, $log, $document) { 2 | var $ctrl = this; 3 | $ctrl.items = ['item1', 'item2', 'item3']; 4 | 5 | $ctrl.animationsEnabled = true; 6 | 7 | $ctrl.open = function (size, parentSelector) { 8 | var parentElem = parentSelector ? 9 | angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined; 10 | var modalInstance = $uibModal.open({ 11 | animation: $ctrl.animationsEnabled, 12 | ariaLabelledBy: 'modal-title', 13 | ariaDescribedBy: 'modal-body', 14 | templateUrl: 'myModalContent.html', 15 | controller: 'ModalInstanceCtrl', 16 | controllerAs: '$ctrl', 17 | size: size, 18 | appendTo: parentElem, 19 | resolve: { 20 | items: function () { 21 | return $ctrl.items; 22 | } 23 | } 24 | }); 25 | 26 | modalInstance.result.then(function (selectedItem) { 27 | $ctrl.selected = selectedItem; 28 | }, function () { 29 | $log.info('Modal dismissed at: ' + new Date()); 30 | }); 31 | }; 32 | 33 | $ctrl.openComponentModal = function () { 34 | var modalInstance = $uibModal.open({ 35 | animation: $ctrl.animationsEnabled, 36 | component: 'modalComponent', 37 | resolve: { 38 | items: function () { 39 | return $ctrl.items; 40 | } 41 | } 42 | }); 43 | 44 | modalInstance.result.then(function (selectedItem) { 45 | $ctrl.selected = selectedItem; 46 | }, function () { 47 | $log.info('modal-component dismissed at: ' + new Date()); 48 | }); 49 | }; 50 | 51 | $ctrl.openMultipleModals = function () { 52 | $uibModal.open({ 53 | animation: $ctrl.animationsEnabled, 54 | ariaLabelledBy: 'modal-title-bottom', 55 | ariaDescribedBy: 'modal-body-bottom', 56 | templateUrl: 'stackedModal.html', 57 | size: 'sm', 58 | controller: function($scope) { 59 | $scope.name = 'bottom'; 60 | } 61 | }); 62 | 63 | $uibModal.open({ 64 | animation: $ctrl.animationsEnabled, 65 | ariaLabelledBy: 'modal-title-top', 66 | ariaDescribedBy: 'modal-body-top', 67 | templateUrl: 'stackedModal.html', 68 | size: 'sm', 69 | controller: function($scope) { 70 | $scope.name = 'top'; 71 | } 72 | }); 73 | }; 74 | 75 | $ctrl.toggleAnimation = function () { 76 | $ctrl.animationsEnabled = !$ctrl.animationsEnabled; 77 | }; 78 | }); 79 | 80 | // Please note that $uibModalInstance represents a modal window (instance) dependency. 81 | // It is not the same as the $uibModal service used above. 82 | 83 | angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($uibModalInstance, items) { 84 | var $ctrl = this; 85 | $ctrl.items = items; 86 | $ctrl.selected = { 87 | item: $ctrl.items[0] 88 | }; 89 | 90 | $ctrl.ok = function () { 91 | $uibModalInstance.close($ctrl.selected.item); 92 | }; 93 | 94 | $ctrl.cancel = function () { 95 | $uibModalInstance.dismiss('cancel'); 96 | }; 97 | }); 98 | 99 | // Please note that the close and dismiss bindings are from $uibModalInstance. 100 | 101 | angular.module('ui.bootstrap.demo').component('modalComponent', { 102 | templateUrl: 'myModalContent.html', 103 | bindings: { 104 | resolve: '<', 105 | close: '&', 106 | dismiss: '&' 107 | }, 108 | controller: function () { 109 | var $ctrl = this; 110 | 111 | $ctrl.$onInit = function () { 112 | $ctrl.items = $ctrl.resolve.items; 113 | $ctrl.selected = { 114 | item: $ctrl.items[0] 115 | }; 116 | }; 117 | 118 | $ctrl.ok = function () { 119 | $ctrl.close({$value: $ctrl.selected.item}); 120 | }; 121 | 122 | $ctrl.cancel = function () { 123 | $ctrl.dismiss({$value: 'cancel'}); 124 | }; 125 | } 126 | }); 127 | -------------------------------------------------------------------------------- /src/modal/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../multiMap'); 2 | require('../position/index-nocss.js'); 3 | require('../stackedMap'); 4 | require('../../template/modal/window.html.js'); 5 | require('./modal'); 6 | 7 | var MODULE_NAME = 'ui.bootstrap.module.modal'; 8 | 9 | angular.module(MODULE_NAME, ['ui.bootstrap.modal', 'uib/template/modal/window.html']); 10 | 11 | module.exports = MODULE_NAME; 12 | -------------------------------------------------------------------------------- /src/modal/index.js: -------------------------------------------------------------------------------- 1 | require('../position/position.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/multiMap/index.js: -------------------------------------------------------------------------------- 1 | require('./multiMap.js'); 2 | -------------------------------------------------------------------------------- /src/multiMap/multiMap.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.multiMap', []) 2 | /** 3 | * A helper, internal data structure that stores all references attached to key 4 | */ 5 | .factory('$$multiMap', function() { 6 | return { 7 | createNew: function() { 8 | var map = {}; 9 | 10 | return { 11 | entries: function() { 12 | return Object.keys(map).map(function(key) { 13 | return { 14 | key: key, 15 | value: map[key] 16 | }; 17 | }); 18 | }, 19 | get: function(key) { 20 | return map[key]; 21 | }, 22 | hasKey: function(key) { 23 | return !!map[key]; 24 | }, 25 | keys: function() { 26 | return Object.keys(map); 27 | }, 28 | put: function(key, value) { 29 | if (!map[key]) { 30 | map[key] = []; 31 | } 32 | 33 | map[key].push(value); 34 | }, 35 | remove: function(key, value) { 36 | var values = map[key]; 37 | 38 | if (!values) { 39 | return; 40 | } 41 | 42 | var idx = values.indexOf(value); 43 | 44 | if (idx !== -1) { 45 | values.splice(idx, 1); 46 | } 47 | 48 | if (!values.length) { 49 | delete map[key]; 50 | } 51 | } 52 | }; 53 | } 54 | }; 55 | }); 56 | -------------------------------------------------------------------------------- /src/multiMap/test/multiMap.spec.js: -------------------------------------------------------------------------------- 1 | describe('multi map', function() { 2 | var multiMap; 3 | 4 | beforeEach(module('ui.bootstrap.multiMap')); 5 | beforeEach(inject(function($$multiMap) { 6 | multiMap = $$multiMap.createNew(); 7 | })); 8 | 9 | it('should add and remove objects by key', function() { 10 | multiMap.put('foo', 'bar'); 11 | 12 | expect(multiMap.get('foo')).toEqual(['bar']); 13 | 14 | multiMap.put('foo', 'baz'); 15 | 16 | expect(multiMap.get('foo')).toEqual(['bar', 'baz']); 17 | 18 | multiMap.remove('foo', 'bar'); 19 | 20 | expect(multiMap.get('foo')).toEqual(['baz']); 21 | 22 | multiMap.remove('foo', 'baz'); 23 | 24 | expect(multiMap.hasKey('foo')).toBe(false); 25 | }); 26 | 27 | it('should support getting the keys', function() { 28 | multiMap.put('foo', 'bar'); 29 | multiMap.put('baz', 'boo'); 30 | 31 | expect(multiMap.keys()).toEqual(['foo', 'baz']); 32 | }); 33 | 34 | it('should return all entries', function() { 35 | multiMap.put('foo', 'bar'); 36 | multiMap.put('foo', 'bar2'); 37 | multiMap.put('baz', 'boo'); 38 | 39 | expect(multiMap.entries()).toEqual([ 40 | { 41 | key: 'foo', 42 | value: ['bar', 'bar2'] 43 | }, 44 | { 45 | key: 'baz', 46 | value: ['boo'] 47 | } 48 | ]); 49 | }); 50 | 51 | it('should preserve semantic of an empty key', function() { 52 | expect(multiMap.get('key')).toBeUndefined(); 53 | }); 54 | 55 | it('should respect removal of non-existing elements', function() { 56 | expect(multiMap.remove('foo', 'bar')).toBeUndefined(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/pager/docs/demo.html: -------------------------------------------------------------------------------- 1 |
2 |

Pager

3 |
You are currently on page {{currentPage}}
4 |
    5 |
    6 | -------------------------------------------------------------------------------- /src/pager/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('PagerDemoCtrl', function($scope) { 2 | $scope.totalItems = 64; 3 | $scope.currentPage = 4; 4 | }); 5 | -------------------------------------------------------------------------------- /src/pager/docs/readme.md: -------------------------------------------------------------------------------- 1 | A lightweight pager directive that is focused on providing previous/next paging functionality 2 | 3 | ### uib-pager settings 4 | 5 | * `align` 6 | C 7 | _(Default: `true`)_ - 8 | Whether to align each link to the sides. 9 | 10 | * `items-per-page` 11 | $ 12 | C 13 | 14 | _(Default: `10`)_ - 15 | Maximum number of items per page. A value less than one indicates all items on one page. 16 | 17 | * `next-text` 18 | C 19 | _(Default: `Next »`)_ - 20 | Text for Next button. 21 | 22 | * `ng-disabled` 23 | $ 24 | 25 | _(Default: `false`)_ - 26 | Used to disable the pager component. 27 | 28 | * `ng-model` 29 | $ 30 | - 31 | Current page number. First page is 1. 32 | 33 | * `num-pages` 34 | $ 35 | readonly 36 | _(Default: `angular.noop`)_ - 37 | An optional expression assigned the total number of pages to display. 38 | 39 | * `previous-text` 40 | C 41 | _(Default: `« Previous`)_ - 42 | Text for Previous button. 43 | 44 | * `template-url` 45 | _(Default: `uib/template/pager/pager.html`)_ - 46 | Override the template for the component with a custom provided template. 47 | 48 | * `total-items` 49 | $ 50 | - 51 | Total number of items in all pages. 52 | -------------------------------------------------------------------------------- /src/pager/index.js: -------------------------------------------------------------------------------- 1 | require('../paging'); 2 | require('../tabindex'); 3 | require('../../template/pager/pager.html.js'); 4 | require('./pager'); 5 | 6 | var MODULE_NAME = 'ui.bootstrap.module.pager'; 7 | 8 | angular.module(MODULE_NAME, ['ui.bootstrap.pager', 'uib/template/pager/pager.html']); 9 | 10 | module.exports = MODULE_NAME; 11 | -------------------------------------------------------------------------------- /src/pager/pager.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging', 'ui.bootstrap.tabindex']) 2 | 3 | .controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) { 4 | $scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align; 5 | 6 | uibPaging.create(this, $scope, $attrs); 7 | }]) 8 | 9 | .constant('uibPagerConfig', { 10 | itemsPerPage: 10, 11 | previousText: '« Previous', 12 | nextText: 'Next »', 13 | align: true 14 | }) 15 | 16 | .directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) { 17 | return { 18 | scope: { 19 | totalItems: '=', 20 | previousText: '@', 21 | nextText: '@', 22 | ngDisabled: '=' 23 | }, 24 | require: ['uibPager', '?ngModel'], 25 | restrict: 'A', 26 | controller: 'UibPagerController', 27 | controllerAs: 'pager', 28 | templateUrl: function(element, attrs) { 29 | return attrs.templateUrl || 'uib/template/pager/pager.html'; 30 | }, 31 | link: function(scope, element, attrs, ctrls) { 32 | element.addClass('pager'); 33 | var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; 34 | 35 | if (!ngModelCtrl) { 36 | return; // do nothing if no ng-model 37 | } 38 | 39 | paginationCtrl.init(ngModelCtrl, uibPagerConfig); 40 | } 41 | }; 42 | }]); 43 | -------------------------------------------------------------------------------- /src/pagination/docs/demo.html: -------------------------------------------------------------------------------- 1 |
    2 |

    Default

    3 |
      4 |
        5 |
          6 |
            7 |
            The selected page no: {{currentPage}}
            8 | 9 | 10 |
            11 |

            Limit the maximum visible buttons

            12 |
            rotate defaulted to true:
            13 |
              14 |
              rotate defaulted to true and force-ellipses set to true:
              15 |
                16 |
                rotate set to false:
                17 |
                  18 |
                  boundary-link-numbers set to true and rotate defaulted to true:
                  19 |
                    20 |
                    boundary-link-numbers set to true and rotate set to false:
                    21 |
                      22 |
                      Page: {{bigCurrentPage}} / {{numPages}}
                      23 | 24 |
                      25 | -------------------------------------------------------------------------------- /src/pagination/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('PaginationDemoCtrl', function ($scope, $log) { 2 | $scope.totalItems = 64; 3 | $scope.currentPage = 4; 4 | 5 | $scope.setPage = function (pageNo) { 6 | $scope.currentPage = pageNo; 7 | }; 8 | 9 | $scope.pageChanged = function() { 10 | $log.log('Page changed to: ' + $scope.currentPage); 11 | }; 12 | 13 | $scope.maxSize = 5; 14 | $scope.bigTotalItems = 175; 15 | $scope.bigCurrentPage = 1; 16 | }); 17 | -------------------------------------------------------------------------------- /src/pagination/docs/readme.md: -------------------------------------------------------------------------------- 1 | A lightweight pagination directive that is focused on ... providing pagination & will take care of visualising a pagination bar and enable / disable buttons correctly! 2 | 3 | ### uib-pagination settings 4 | 5 | * `boundary-links` 6 | C 7 | _(Default: `false`)_ - 8 | Whether to display First / Last buttons. 9 | 10 | * `boundary-link-numbers` 11 | $ 12 | C 13 | _(Default: `false`)_ - 14 | Whether to always display the first and last page numbers. If `max-size` is smaller than the number of pages, then the first and last page numbers are still shown with ellipses in-between as necessary. NOTE: `max-size` refers to the center of the range. This option may add up to 2 more numbers on each side of the displayed range for the end value and what would be an ellipsis but is replaced by a number because it is sequential. 15 | 16 | * `direction-links` 17 | $ 18 | C 19 | _(Default: `true`)_ - 20 | Whether to display Previous / Next buttons. 21 | 22 | * `first-text` 23 | C 24 | _(Default: `First`)_ - 25 | Text for First button. 26 | 27 | * `force-ellipses` 28 | $ 29 | C 30 | _(Default: `false`)_ - 31 | Also displays ellipses when `rotate` is true and `max-size` is smaller than the number of pages. 32 | 33 | * `items-per-page` 34 | $ 35 | C 36 | 37 | _(Default: `10`)_ - 38 | Maximum number of items per page. A value less than one indicates all items on one page. 39 | 40 | * `last-text` 41 | C 42 | _(Default: `Last`)_ - 43 | Text for Last button. 44 | 45 | * `max-size` 46 | $ 47 | 48 | _(Default: `null`)_ - 49 | Limit number for pagination size. 50 | 51 | * `next-text` 52 | C 53 | _(Default: `Next`)_ - 54 | Text for Next button. 55 | 56 | * `ng-change` 57 | $ - 58 | This can be used to call a function whenever the page changes. 59 | 60 | * `ng-disabled` 61 | $ 62 | 63 | _(Default: `false`)_ - 64 | Used to disable the pagination component. 65 | 66 | * `ng-model` 67 | $ 68 | - 69 | Current page number. First page is 1. 70 | 71 | * `num-pages` 72 | $ 73 | readonly 74 | _(Default: `angular.noop`)_ - 75 | An optional expression assigned the total number of pages to display. 76 | 77 | * `page-label` 78 | _(Default: `angular.identity`)_ - 79 | An optional expression to override the page label based on passing the current page indexes. Supports page number with `$page` in the template. 80 | 81 | * `previous-text` 82 | C 83 | _(Default: `Previous`)_ - 84 | Text for Previous button. 85 | 86 | * `rotate` 87 | $ 88 | C 89 | _(Default: `true`)_ - 90 | Whether to keep current page in the middle of the visible ones. 91 | 92 | * `template-url` 93 | _(Default: `uib/template/pagination/pagination.html`)_ - 94 | Override the template for the component with a custom provided template 95 | 96 | * `total-items` 97 | $ 98 | - 99 | Total number of items in all pages. 100 | -------------------------------------------------------------------------------- /src/pagination/index.js: -------------------------------------------------------------------------------- 1 | require('../paging'); 2 | require('../tabindex'); 3 | require('../../template/pagination/pagination.html.js'); 4 | require('./pagination'); 5 | 6 | var MODULE_NAME = 'ui.bootstrap.module.pagination'; 7 | 8 | angular.module(MODULE_NAME, ['ui.bootstrap.pagination', 'uib/template/pagination/pagination.html']); 9 | 10 | module.exports = MODULE_NAME; 11 | -------------------------------------------------------------------------------- /src/paging/index.js: -------------------------------------------------------------------------------- 1 | require('./paging'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.paging'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.paging']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/paging/paging.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.paging', []) 2 | /** 3 | * Helper internal service for generating common controller code between the 4 | * pager and pagination components 5 | */ 6 | .factory('uibPaging', ['$parse', function($parse) { 7 | return { 8 | create: function(ctrl, $scope, $attrs) { 9 | ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; 10 | ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl 11 | ctrl._watchers = []; 12 | 13 | ctrl.init = function(ngModelCtrl, config) { 14 | ctrl.ngModelCtrl = ngModelCtrl; 15 | ctrl.config = config; 16 | 17 | ngModelCtrl.$render = function() { 18 | ctrl.render(); 19 | }; 20 | 21 | if ($attrs.itemsPerPage) { 22 | ctrl._watchers.push($scope.$parent.$watch($attrs.itemsPerPage, function(value) { 23 | ctrl.itemsPerPage = parseInt(value, 10); 24 | $scope.totalPages = ctrl.calculateTotalPages(); 25 | ctrl.updatePage(); 26 | })); 27 | } else { 28 | ctrl.itemsPerPage = config.itemsPerPage; 29 | } 30 | 31 | $scope.$watch('totalItems', function(newTotal, oldTotal) { 32 | if (angular.isDefined(newTotal) || newTotal !== oldTotal) { 33 | $scope.totalPages = ctrl.calculateTotalPages(); 34 | ctrl.updatePage(); 35 | } 36 | }); 37 | }; 38 | 39 | ctrl.calculateTotalPages = function() { 40 | var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage); 41 | return Math.max(totalPages || 0, 1); 42 | }; 43 | 44 | ctrl.render = function() { 45 | $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1; 46 | }; 47 | 48 | $scope.selectPage = function(page, evt) { 49 | if (evt) { 50 | evt.preventDefault(); 51 | } 52 | 53 | var clickAllowed = !$scope.ngDisabled || !evt; 54 | if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) { 55 | if (evt && evt.target) { 56 | evt.target.blur(); 57 | } 58 | ctrl.ngModelCtrl.$setViewValue(page); 59 | ctrl.ngModelCtrl.$render(); 60 | } 61 | }; 62 | 63 | $scope.getText = function(key) { 64 | return $scope[key + 'Text'] || ctrl.config[key + 'Text']; 65 | }; 66 | 67 | $scope.noPrevious = function() { 68 | return $scope.page === 1; 69 | }; 70 | 71 | $scope.noNext = function() { 72 | return $scope.page === $scope.totalPages; 73 | }; 74 | 75 | ctrl.updatePage = function() { 76 | ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable 77 | 78 | if ($scope.page > $scope.totalPages) { 79 | $scope.selectPage($scope.totalPages); 80 | } else { 81 | ctrl.ngModelCtrl.$render(); 82 | } 83 | }; 84 | 85 | $scope.$on('$destroy', function() { 86 | while (ctrl._watchers.length) { 87 | ctrl._watchers.shift()(); 88 | } 89 | }); 90 | } 91 | }; 92 | }]); 93 | -------------------------------------------------------------------------------- /src/popover/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 |

                      Dynamic

                      3 |
                      4 | 5 | 6 |
                      7 |
                      8 | 9 | 10 |
                      11 |
                      12 | 13 | 14 |
                      15 | 16 | 17 | 18 | 19 | 26 |
                      27 |

                      Positional

                      28 |
                      29 | 30 | 31 |
                      32 | 33 | 34 |
                      35 |

                      Triggers

                      36 |

                      37 | 38 |

                      39 | 40 | 41 |
                      42 |

                      Other

                      43 | 44 | 45 | 46 | 47 | 48 |
                      49 | -------------------------------------------------------------------------------- /src/popover/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('PopoverDemoCtrl', function ($scope, $sce) { 2 | $scope.dynamicPopover = { 3 | content: 'Hello, World!', 4 | templateUrl: 'myPopoverTemplate.html', 5 | title: 'Title' 6 | }; 7 | 8 | $scope.placement = { 9 | options: [ 10 | 'top', 11 | 'top-left', 12 | 'top-right', 13 | 'bottom', 14 | 'bottom-left', 15 | 'bottom-right', 16 | 'left', 17 | 'left-top', 18 | 'left-bottom', 19 | 'right', 20 | 'right-top', 21 | 'right-bottom' 22 | ], 23 | selected: 'top' 24 | }; 25 | 26 | $scope.htmlPopover = $sce.trustAsHtml('I can have
                      HTML
                      content'); 27 | }); 28 | -------------------------------------------------------------------------------- /src/popover/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../tooltip/index-nocss.js'); 2 | require('../../template/popover/popover.html.js'); 3 | require('../../template/popover/popover-html.html.js'); 4 | require('../../template/popover/popover-template.html.js'); 5 | require('./popover'); 6 | 7 | var MODULE_NAME = 'ui.bootstrap.module.popover'; 8 | 9 | angular.module(MODULE_NAME, ['ui.bootstrap.popover', 'uib/template/popover/popover.html', 'uib/template/popover/popover-html.html', 'uib/template/popover/popover-template.html']); 10 | 11 | module.exports = MODULE_NAME; 12 | -------------------------------------------------------------------------------- /src/popover/index.js: -------------------------------------------------------------------------------- 1 | require('../tooltip/tooltip.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/popover/popover.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The following features are still outstanding: popup delay, animation as a 3 | * function, placement as a function, inside, support for more triggers than 4 | * just mouse enter/leave, and selector delegatation. 5 | */ 6 | angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip']) 7 | 8 | .directive('uibPopoverTemplatePopup', function() { 9 | return { 10 | restrict: 'A', 11 | scope: { uibTitle: '@', contentExp: '&', originScope: '&' }, 12 | templateUrl: 'uib/template/popover/popover-template.html' 13 | }; 14 | }) 15 | 16 | .directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) { 17 | return $uibTooltip('uibPopoverTemplate', 'popover', 'click', { 18 | useContentExp: true 19 | }); 20 | }]) 21 | 22 | .directive('uibPopoverHtmlPopup', function() { 23 | return { 24 | restrict: 'A', 25 | scope: { contentExp: '&', uibTitle: '@' }, 26 | templateUrl: 'uib/template/popover/popover-html.html' 27 | }; 28 | }) 29 | 30 | .directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) { 31 | return $uibTooltip('uibPopoverHtml', 'popover', 'click', { 32 | useContentExp: true 33 | }); 34 | }]) 35 | 36 | .directive('uibPopoverPopup', function() { 37 | return { 38 | restrict: 'A', 39 | scope: { uibTitle: '@', content: '@' }, 40 | templateUrl: 'uib/template/popover/popover.html' 41 | }; 42 | }) 43 | 44 | .directive('uibPopover', ['$uibTooltip', function($uibTooltip) { 45 | return $uibTooltip('uibPopover', 'popover', 'click'); 46 | }]); 47 | -------------------------------------------------------------------------------- /src/position/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 |

                      $uibPosition service

                      3 |
                      4 |
                      5 | 8 |
                      9 |
                      10 | 13 |
                      14 | 15 | 16 |
                      17 | Demo element 18 |
                      19 |
                      20 |
                      21 | offsetParent: {{elemVals.offsetParent}} 22 |
                      23 | scrollParent: {{elemVals.scrollParent}} 24 |
                      25 | scrollbarWidth: {{scrollbarWidth}} 26 |
                      27 | position: {{elemVals.position}} 28 |
                      29 | offset: {{elemVals.offset}} 30 |
                      31 | viewportOffset: {{elemVals.viewportOffset}} 32 |
                      33 | positionElements: {{elemVals.positionElements}} 34 |
                      -------------------------------------------------------------------------------- /src/position/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('PositionDemoCtrl', function ($scope, $window, $uibPosition) { 2 | 3 | $scope.elemVals = {}; 4 | $scope.parentScrollable = true; 5 | $scope.parentRelative = true; 6 | 7 | $scope.getValues = function() { 8 | var divEl = $window.document.querySelector('#posdemodiv'); 9 | var btnEl = $window.document.querySelector('#posdemobtn'); 10 | 11 | var offsetParent = $uibPosition.offsetParent(divEl); 12 | $scope.elemVals.offsetParent = 'type: ' + offsetParent.tagName + ', id: ' + offsetParent.id; 13 | 14 | var scrollParent = $uibPosition.scrollParent(divEl); 15 | $scope.elemVals.scrollParent = 'type: ' + scrollParent.tagName + ', id: ' + scrollParent.id; 16 | 17 | $scope.scrollbarWidth = $uibPosition.scrollbarWidth(); 18 | 19 | $scope.elemVals.position = $uibPosition.position(divEl); 20 | 21 | $scope.elemVals.offset = $uibPosition.offset(divEl); 22 | 23 | $scope.elemVals.viewportOffset = $uibPosition.viewportOffset(divEl); 24 | 25 | $scope.elemVals.positionElements = $uibPosition.positionElements(btnEl, divEl, 'auto bottom-left'); 26 | }; 27 | }); -------------------------------------------------------------------------------- /src/position/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('./position'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.position'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.position']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/position/index.js: -------------------------------------------------------------------------------- 1 | require('./position.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/position/position.css: -------------------------------------------------------------------------------- 1 | .uib-position-measure { 2 | display: block !important; 3 | visibility: hidden !important; 4 | position: absolute !important; 5 | top: -9999px !important; 6 | left: -9999px !important; 7 | } 8 | 9 | .uib-position-scrollbar-measure { 10 | position: absolute !important; 11 | top: -9999px !important; 12 | width: 50px !important; 13 | height: 50px !important; 14 | overflow: scroll !important; 15 | } 16 | 17 | .uib-position-body-scrollbar-measure { 18 | overflow: scroll !important; 19 | } -------------------------------------------------------------------------------- /src/progressbar/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |

                      Static

                      4 |
                      5 |
                      6 |
                      22%
                      7 |
                      166 / 200
                      8 |
                      9 | 10 |
                      11 |

                      Dynamic

                      12 | {{dynamic}} / {{max}} 13 | 14 | No animation 15 | {{dynamic}}% 16 | 17 | Object (changes type based on value) 18 | {{type}} !!! Watch out !!! 19 | 20 |
                      21 |

                      Stacked

                      22 | {{bar.value}}% 23 | 24 |
                      -------------------------------------------------------------------------------- /src/progressbar/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('ProgressDemoCtrl', function ($scope) { 2 | $scope.max = 200; 3 | 4 | $scope.random = function() { 5 | var value = Math.floor(Math.random() * 100 + 1); 6 | var type; 7 | 8 | if (value < 25) { 9 | type = 'success'; 10 | } else if (value < 50) { 11 | type = 'info'; 12 | } else if (value < 75) { 13 | type = 'warning'; 14 | } else { 15 | type = 'danger'; 16 | } 17 | 18 | $scope.showWarning = type === 'danger' || type === 'warning'; 19 | 20 | $scope.dynamic = value; 21 | $scope.type = type; 22 | }; 23 | 24 | $scope.random(); 25 | 26 | $scope.randomStacked = function() { 27 | $scope.stacked = []; 28 | var types = ['success', 'info', 'warning', 'danger']; 29 | 30 | for (var i = 0, n = Math.floor(Math.random() * 4 + 1); i < n; i++) { 31 | var index = Math.floor(Math.random() * 4); 32 | $scope.stacked.push({ 33 | value: Math.floor(Math.random() * 30 + 1), 34 | type: types[index] 35 | }); 36 | } 37 | }; 38 | 39 | $scope.randomStacked(); 40 | }); 41 | -------------------------------------------------------------------------------- /src/progressbar/docs/readme.md: -------------------------------------------------------------------------------- 1 | A progress bar directive that is focused on providing feedback on the progress of a workflow or action. 2 | 3 | It supports multiple (stacked) `` into the same `` element or a single `` element with optional `max` attribute and transition animations. 4 | 5 | ### uib-progressbar settings 6 | 7 | * `value` 8 | $ 9 | - 10 | The current value of progress completed. 11 | 12 | * `type` 13 | _(Default: `null`)_ - 14 | Bootstrap style type. Possible values are 'success', 'info', 'warning', and, 'danger' to use Bootstrap's pre-existing styling, or any desired custom suffix. 15 | 16 | * `max` 17 | $ 18 | C 19 | 20 | _(Default: `100`)_ - 21 | A number that specifies the total value of bars that is required. 22 | 23 | * `animate` 24 | $ 25 | C 26 | _(Default: `true`)_ - 27 | Whether bars use transitions to achieve the width change. 28 | 29 | * `title` 30 | _(Default: `progressbar`)_ - 31 | Title to use as label (for accessibility). 32 | 33 | ### uib-progress settings 34 | 35 | * `max` 36 | $ 37 | C 38 | 39 | _(Default: `100`)_ - 40 | A number that specifies the total value of bars that is required. 41 | 42 | * `animate` 43 | $ 44 | C 45 | _(Default: `true`)_ - 46 | Whether bars use transitions to achieve the width change. 47 | 48 | * `title` 49 | _(Default: `progressbar`)_ - 50 | Title to use as label (for accessibility). 51 | 52 | ### uib-bar settings 53 | 54 | * `value` 55 | $ 56 | - 57 | The current value of progress completed. 58 | 59 | * `type` 60 | _(Default: `null`)_ - 61 | Bootstrap style type. Possible values are 'success', 'info', 'warning', and, 'danger' to use Bootstrap's pre-existing styling, or any desired custom suffix. 62 | 63 | * `title` 64 | _(Default: `progressbar`)_ - 65 | Title to use as label (for accessibility). 66 | -------------------------------------------------------------------------------- /src/progressbar/index.js: -------------------------------------------------------------------------------- 1 | require('../../template/progressbar/progressbar.html.js'); 2 | require('../../template/progressbar/progress.html.js'); 3 | require('../../template/progressbar/bar.html.js'); 4 | require('./progressbar'); 5 | 6 | var MODULE_NAME = 'ui.bootstrap.module.progressbar'; 7 | 8 | angular.module(MODULE_NAME, ['ui.bootstrap.progressbar', 'uib/template/progressbar/progressbar.html', 'uib/template/progressbar/progress.html', 'uib/template/progressbar/bar.html']); 9 | 10 | module.exports = MODULE_NAME; 11 | -------------------------------------------------------------------------------- /src/progressbar/progressbar.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.progressbar', []) 2 | 3 | .constant('uibProgressConfig', { 4 | animate: true, 5 | max: 100 6 | }) 7 | 8 | .controller('UibProgressController', ['$scope', '$attrs', 'uibProgressConfig', function($scope, $attrs, progressConfig) { 9 | var self = this, 10 | animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate; 11 | 12 | this.bars = []; 13 | $scope.max = getMaxOrDefault(); 14 | 15 | this.addBar = function(bar, element, attrs) { 16 | if (!animate) { 17 | element.css({'transition': 'none'}); 18 | } 19 | 20 | this.bars.push(bar); 21 | 22 | bar.max = getMaxOrDefault(); 23 | bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar'; 24 | 25 | bar.$watch('value', function(value) { 26 | bar.recalculatePercentage(); 27 | }); 28 | 29 | bar.recalculatePercentage = function() { 30 | var totalPercentage = self.bars.reduce(function(total, bar) { 31 | bar.percent = +(100 * bar.value / bar.max).toFixed(2); 32 | return total + bar.percent; 33 | }, 0); 34 | 35 | if (totalPercentage > 100) { 36 | bar.percent -= totalPercentage - 100; 37 | } 38 | }; 39 | 40 | bar.$on('$destroy', function() { 41 | element = null; 42 | self.removeBar(bar); 43 | }); 44 | }; 45 | 46 | this.removeBar = function(bar) { 47 | this.bars.splice(this.bars.indexOf(bar), 1); 48 | this.bars.forEach(function (bar) { 49 | bar.recalculatePercentage(); 50 | }); 51 | }; 52 | 53 | //$attrs.$observe('maxParam', function(maxParam) { 54 | $scope.$watch('maxParam', function(maxParam) { 55 | self.bars.forEach(function(bar) { 56 | bar.max = getMaxOrDefault(); 57 | bar.recalculatePercentage(); 58 | }); 59 | }); 60 | 61 | function getMaxOrDefault () { 62 | return angular.isDefined($scope.maxParam) ? $scope.maxParam : progressConfig.max; 63 | } 64 | }]) 65 | 66 | .directive('uibProgress', function() { 67 | return { 68 | replace: true, 69 | transclude: true, 70 | controller: 'UibProgressController', 71 | require: 'uibProgress', 72 | scope: { 73 | maxParam: '=?max' 74 | }, 75 | templateUrl: 'uib/template/progressbar/progress.html' 76 | }; 77 | }) 78 | 79 | .directive('uibBar', function() { 80 | return { 81 | replace: true, 82 | transclude: true, 83 | require: '^uibProgress', 84 | scope: { 85 | value: '=', 86 | type: '@' 87 | }, 88 | templateUrl: 'uib/template/progressbar/bar.html', 89 | link: function(scope, element, attrs, progressCtrl) { 90 | progressCtrl.addBar(scope, element, attrs); 91 | } 92 | }; 93 | }) 94 | 95 | .directive('uibProgressbar', function() { 96 | return { 97 | replace: true, 98 | transclude: true, 99 | controller: 'UibProgressController', 100 | scope: { 101 | value: '=', 102 | maxParam: '=?max', 103 | type: '@' 104 | }, 105 | templateUrl: 'uib/template/progressbar/progressbar.html', 106 | link: function(scope, element, attrs, progressCtrl) { 107 | progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title}); 108 | } 109 | }; 110 | }); 111 | -------------------------------------------------------------------------------- /src/rating/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 |

                      Default

                      3 | 4 | {{percent}}% 5 | 6 |
                      Rate: {{rate}} - Readonly is: {{isReadonly}} - Hovering over: {{overStar || "none"}}
                      7 | 8 | 9 | 10 |
                      11 | 12 |

                      Custom icons

                      13 |
                      (Rate: {{x}})
                      14 |
                      (Rate: {{y}})
                      15 |
                      16 | -------------------------------------------------------------------------------- /src/rating/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('RatingDemoCtrl', function ($scope) { 2 | $scope.rate = 7; 3 | $scope.max = 10; 4 | $scope.isReadonly = false; 5 | 6 | $scope.hoveringOver = function(value) { 7 | $scope.overStar = value; 8 | $scope.percent = 100 * (value / $scope.max); 9 | }; 10 | 11 | $scope.ratingStates = [ 12 | {stateOn: 'glyphicon-ok-sign', stateOff: 'glyphicon-ok-circle'}, 13 | {stateOn: 'glyphicon-star', stateOff: 'glyphicon-star-empty'}, 14 | {stateOn: 'glyphicon-heart', stateOff: 'glyphicon-ban-circle'}, 15 | {stateOn: 'glyphicon-heart'}, 16 | {stateOff: 'glyphicon-off'} 17 | ]; 18 | }); 19 | -------------------------------------------------------------------------------- /src/rating/docs/readme.md: -------------------------------------------------------------------------------- 1 | Rating directive that will take care of visualising a star rating bar. 2 | 3 | ### uib-rating settings 4 | 5 | * `max` 6 | $ 7 | C 8 | _(Default: `5`)_ - 9 | Changes the number of icons. 10 | 11 | * `ng-model` 12 | $ 13 | - 14 | The current rate. 15 | 16 | * `on-hover(value)` 17 | $ - 18 | An optional expression called when user's mouse is over a particular icon. 19 | 20 | * `on-leave()` 21 | $ - 22 | An optional expression called when user's mouse leaves the control altogether. 23 | 24 | * `rating-states` 25 | $ 26 | _(Default: `null`)_ - 27 | An array of objects defining properties for all icons. In default template, `stateOn` & `stateOff` property is used to specify the icon's class. 28 | 29 | * `read-only` 30 | $ 31 | 32 | _(Default: `false`)_ - 33 | Prevent user's interaction. 34 | 35 | * `titles` 36 | $ 37 | C 38 | _(Default: ['one', 'two', 'three', 'four', 'five']`)_ - 39 | An array of strings defining titles for all icons. 40 | 41 | * `enable-reset` 42 | $ 43 | _(Default: `true`)_ - 44 | Clicking the icon of the current rating will reset the rating to 0. 45 | 46 | * `state-off` 47 | $ 48 | C 49 | _(Default: `null`)_ - 50 | A variable used in the template to specify the state for unselected icons. 51 | 52 | * `state-on` 53 | $ 54 | C 55 | _(Default: `null`)_ - 56 | A variable used in the template to specify the state (class, src, etc) for selected icons. 57 | -------------------------------------------------------------------------------- /src/rating/index.js: -------------------------------------------------------------------------------- 1 | require('../../template/rating/rating.html.js'); 2 | require('./rating'); 3 | 4 | var MODULE_NAME = 'ui.bootstrap.module.rating'; 5 | 6 | angular.module(MODULE_NAME, ['ui.bootstrap.rating', 'uib/template/rating/rating.html']); 7 | 8 | module.exports = MODULE_NAME; 9 | -------------------------------------------------------------------------------- /src/rating/rating.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.rating', []) 2 | 3 | .constant('uibRatingConfig', { 4 | max: 5, 5 | stateOn: null, 6 | stateOff: null, 7 | enableReset: true, 8 | titles: ['one', 'two', 'three', 'four', 'five'] 9 | }) 10 | 11 | .controller('UibRatingController', ['$scope', '$attrs', 'uibRatingConfig', function($scope, $attrs, ratingConfig) { 12 | var ngModelCtrl = { $setViewValue: angular.noop }, 13 | self = this; 14 | 15 | this.init = function(ngModelCtrl_) { 16 | ngModelCtrl = ngModelCtrl_; 17 | ngModelCtrl.$render = this.render; 18 | 19 | ngModelCtrl.$formatters.push(function(value) { 20 | if (angular.isNumber(value) && value << 0 !== value) { 21 | value = Math.round(value); 22 | } 23 | 24 | return value; 25 | }); 26 | 27 | this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn; 28 | this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff; 29 | this.enableReset = angular.isDefined($attrs.enableReset) ? 30 | $scope.$parent.$eval($attrs.enableReset) : ratingConfig.enableReset; 31 | var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles; 32 | this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ? 33 | tmpTitles : ratingConfig.titles; 34 | 35 | var ratingStates = angular.isDefined($attrs.ratingStates) ? 36 | $scope.$parent.$eval($attrs.ratingStates) : 37 | new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max); 38 | $scope.range = this.buildTemplateObjects(ratingStates); 39 | }; 40 | 41 | this.buildTemplateObjects = function(states) { 42 | for (var i = 0, n = states.length; i < n; i++) { 43 | states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff, title: this.getTitle(i) }, states[i]); 44 | } 45 | return states; 46 | }; 47 | 48 | this.getTitle = function(index) { 49 | if (index >= this.titles.length) { 50 | return index + 1; 51 | } 52 | 53 | return this.titles[index]; 54 | }; 55 | 56 | $scope.rate = function(value) { 57 | if (!$scope.readonly && value >= 0 && value <= $scope.range.length) { 58 | var newViewValue = self.enableReset && ngModelCtrl.$viewValue === value ? 0 : value; 59 | ngModelCtrl.$setViewValue(newViewValue); 60 | ngModelCtrl.$render(); 61 | } 62 | }; 63 | 64 | $scope.enter = function(value) { 65 | if (!$scope.readonly) { 66 | $scope.value = value; 67 | } 68 | $scope.onHover({value: value}); 69 | }; 70 | 71 | $scope.reset = function() { 72 | $scope.value = ngModelCtrl.$viewValue; 73 | $scope.onLeave(); 74 | }; 75 | 76 | $scope.onKeydown = function(evt) { 77 | if (/(37|38|39|40)/.test(evt.which)) { 78 | evt.preventDefault(); 79 | evt.stopPropagation(); 80 | $scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1)); 81 | } 82 | }; 83 | 84 | this.render = function() { 85 | $scope.value = ngModelCtrl.$viewValue; 86 | $scope.title = self.getTitle($scope.value - 1); 87 | }; 88 | }]) 89 | 90 | .directive('uibRating', function() { 91 | return { 92 | require: ['uibRating', 'ngModel'], 93 | restrict: 'A', 94 | scope: { 95 | readonly: '=?readOnly', 96 | onHover: '&', 97 | onLeave: '&' 98 | }, 99 | controller: 'UibRatingController', 100 | templateUrl: 'uib/template/rating/rating.html', 101 | link: function(scope, element, attrs, ctrls) { 102 | var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1]; 103 | ratingCtrl.init(ngModelCtrl); 104 | } 105 | }; 106 | }); 107 | -------------------------------------------------------------------------------- /src/stackedMap/index.js: -------------------------------------------------------------------------------- 1 | require('./stackedMap'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.stackedMap'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.stackedMap']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/stackedMap/stackedMap.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.stackedMap', []) 2 | /** 3 | * A helper, internal data structure that acts as a map but also allows getting / removing 4 | * elements in the LIFO order 5 | */ 6 | .factory('$$stackedMap', function() { 7 | return { 8 | createNew: function() { 9 | var stack = []; 10 | 11 | return { 12 | add: function(key, value) { 13 | stack.push({ 14 | key: key, 15 | value: value 16 | }); 17 | }, 18 | get: function(key) { 19 | for (var i = 0; i < stack.length; i++) { 20 | if (key === stack[i].key) { 21 | return stack[i]; 22 | } 23 | } 24 | }, 25 | keys: function() { 26 | var keys = []; 27 | for (var i = 0; i < stack.length; i++) { 28 | keys.push(stack[i].key); 29 | } 30 | return keys; 31 | }, 32 | top: function() { 33 | return stack[stack.length - 1]; 34 | }, 35 | remove: function(key) { 36 | var idx = -1; 37 | for (var i = 0; i < stack.length; i++) { 38 | if (key === stack[i].key) { 39 | idx = i; 40 | break; 41 | } 42 | } 43 | return stack.splice(idx, 1)[0]; 44 | }, 45 | removeTop: function() { 46 | return stack.pop(); 47 | }, 48 | length: function() { 49 | return stack.length; 50 | } 51 | }; 52 | } 53 | }; 54 | }); -------------------------------------------------------------------------------- /src/stackedMap/test/stackedMap.spec.js: -------------------------------------------------------------------------------- 1 | describe('stacked map', function() { 2 | var stackedMap; 3 | 4 | beforeEach(module('ui.bootstrap.modal')); 5 | beforeEach(inject(function ($$stackedMap) { 6 | stackedMap = $$stackedMap.createNew(); 7 | })); 8 | 9 | it('should add and remove objects by key', function() { 10 | stackedMap.add('foo', 'foo_value'); 11 | expect(stackedMap.length()).toEqual(1); 12 | expect(stackedMap.get('foo').key).toEqual('foo'); 13 | expect(stackedMap.get('foo').value).toEqual('foo_value'); 14 | 15 | stackedMap.remove('foo'); 16 | expect(stackedMap.length()).toEqual(0); 17 | expect(stackedMap.get('foo')).toBeUndefined(); 18 | }); 19 | 20 | it('should support listing keys', function() { 21 | stackedMap.add('foo', 'foo_value'); 22 | stackedMap.add('bar', 'bar_value'); 23 | 24 | expect(stackedMap.keys()).toEqual(['foo', 'bar']); 25 | }); 26 | 27 | it('should get topmost element', function() { 28 | stackedMap.add('foo', 'foo_value'); 29 | stackedMap.add('bar', 'bar_value'); 30 | expect(stackedMap.length()).toEqual(2); 31 | 32 | expect(stackedMap.top().key).toEqual('bar'); 33 | expect(stackedMap.length()).toEqual(2); 34 | }); 35 | 36 | it('should remove topmost element', function() { 37 | stackedMap.add('foo', 'foo_value'); 38 | stackedMap.add('bar', 'bar_value'); 39 | 40 | expect(stackedMap.removeTop().key).toEqual('bar'); 41 | expect(stackedMap.removeTop().key).toEqual('foo'); 42 | }); 43 | 44 | it('should preserve semantic of an empty stackedMap', function() { 45 | expect(stackedMap.length()).toEqual(0); 46 | expect(stackedMap.top()).toBeUndefined(); 47 | }); 48 | 49 | it('should ignore removal of non-existing elements', function() { 50 | expect(stackedMap.remove('non-existing')).toBeUndefined(); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/tabindex/index.js: -------------------------------------------------------------------------------- 1 | require('./tabindex'); 2 | 3 | var MODULE_NAME = 'ui.bootstrap.module.tabindex'; 4 | 5 | angular.module(MODULE_NAME, ['ui.bootstrap.tabindex']); 6 | 7 | module.exports = MODULE_NAME; 8 | -------------------------------------------------------------------------------- /src/tabindex/tabindex.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.tabindex', []) 2 | 3 | .directive('uibTabindexToggle', function() { 4 | return { 5 | restrict: 'A', 6 | link: function(scope, elem, attrs) { 7 | attrs.$observe('disabled', function(disabled) { 8 | attrs.$set('tabindex', disabled ? -1 : null); 9 | }); 10 | } 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /src/tabindex/test/tabindex.spec.js: -------------------------------------------------------------------------------- 1 | describe('tabindex toggle directive', function() { 2 | var $rootScope, element; 3 | beforeEach(module('ui.bootstrap.tabindex')); 4 | beforeEach(inject(function($compile, _$rootScope_) { 5 | $rootScope = _$rootScope_; 6 | element = $compile('foo')($rootScope); 7 | $rootScope.$digest(); 8 | })); 9 | 10 | it('should toggle the tabindex on disabled toggle', function() { 11 | expect(element.prop('tabindex')).toBe(0); 12 | 13 | $rootScope.disabled = true; 14 | $rootScope.$digest(); 15 | 16 | expect(element.prop('tabindex')).toBe(-1); 17 | 18 | $rootScope.disabled = false; 19 | $rootScope.$digest(); 20 | 21 | expect(element.prop('tabindex')).toBe(0); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/tabs/docs/demo.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
                      8 |

                      Select a tab by setting active binding to true:

                      9 |

                      10 | 11 | 12 |

                      13 |

                      14 | 15 |

                      16 |
                      17 | 18 | 19 | Static content 20 | 21 | {{tab.content}} 22 | 23 | 24 | 25 | Alert! 26 | 27 | I've got an HTML heading, and a select callback. Pretty cool! 28 | 29 | 30 | 31 |
                      32 | 33 | 34 | Vertical content 1 35 | Vertical content 2 36 | 37 | 38 |
                      39 | 40 | 41 | Justified content 42 | Short Labeled Justified content 43 | Long Labeled Justified content 44 | 45 | 46 |
                      47 | 48 | Tabbed pills with CSS classes 49 | 50 | Tab 1 content 51 | Tab 2 content 52 | 53 | 54 |
                      55 | 56 | Tabs using nested forms: 57 |
                      58 | 59 | 60 | 61 |
                      62 | 63 | 64 |
                      65 |
                      66 |
                      67 | 68 | Some Tab Content 69 | 70 | 71 | More Tab Content 72 | 73 |
                      74 |
                      75 | Model: 76 |
                      {{ model | json }}
                      77 | Nested Form: 78 |
                      {{ outerForm.nestedForm | json }}
                      79 |
                      80 | -------------------------------------------------------------------------------- /src/tabs/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('TabsDemoCtrl', function ($scope, $window) { 2 | $scope.tabs = [ 3 | { title:'Dynamic Title 1', content:'Dynamic content 1' }, 4 | { title:'Dynamic Title 2', content:'Dynamic content 2', disabled: true } 5 | ]; 6 | 7 | $scope.alertMe = function() { 8 | setTimeout(function() { 9 | $window.alert('You\'ve selected the alert tab!'); 10 | }); 11 | }; 12 | 13 | $scope.model = { 14 | name: 'Tabs' 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /src/tabs/docs/readme.md: -------------------------------------------------------------------------------- 1 | AngularJS version of the tabs directive. 2 | 3 | ### uib-tabset settings 4 | 5 | * `active` 6 | 7 | _(Default: `Index of first tab`)_ - 8 | Active index of tab. Setting this to an existing tab index will make that tab active. 9 | 10 | * `justified` 11 | $ 12 | _(Default: `false`)_ - 13 | Whether tabs fill the container and have a consistent width. 14 | 15 | * `template-url` 16 | _(Default: `uib/template/tabs/tabset.html`)_ - 17 | A URL representing the location of a template to use for the main component. 18 | 19 | * `type` 20 | _(Defaults: `tabs`)_ - 21 | Navigation type. Possible values are 'tabs' and 'pills'. 22 | 23 | * `vertical` 24 | $ 25 | _(Default: `false`)_ - 26 | Whether tabs appear vertically stacked. 27 | 28 | ### uib-tab settings 29 | 30 | * `classes` 31 | $ - 32 | An optional string of space-separated CSS classes. 33 | 34 | * `deselect()` 35 | $ - 36 | An optional expression called when tab is deactivated. Supports `$event` and `$selectedIndex` in template for expression. You may call `$event.preventDefault()` in this event handler to prevent a tab change from occurring. The `$selectedIndex` can be used to determine which tab was attempted to be opened. 37 | 38 | * `disable` 39 | $ 40 | 41 | _(Default: `false`)_ - 42 | Whether tab is clickable and can be activated. 43 | 44 | * `heading` - 45 | Heading text. 46 | 47 | * `index` - 48 | Tab index. Must be unique number or string. 49 | 50 | * `select()` 51 | $ - 52 | An optional expression called when tab is activated. Supports $event in template for expression. 53 | 54 | * `template-url` 55 | _(Default: `uib/template/tabs/tab.html`)_ - 56 | A URL representing the location of a template to use for the tab heading. 57 | 58 | ### Tabset heading 59 | 60 | Instead of the `heading` attribute on the `uib-tabset`, you can use an `uib-tab-heading` element inside a tabset that will be used as the tabset's header. There you can use HTML as well. 61 | 62 | ### Known issues 63 | 64 | To use clickable elements within the tab, you have override the tab template to use div elements instead of anchor elements, and replicate the desired styles from Bootstrap's CSS. This is due to browsers interpreting anchor elements as the target of any click event, which triggers routing when certain elements such as buttons are nested inside the anchor element. 65 | -------------------------------------------------------------------------------- /src/tabs/index.js: -------------------------------------------------------------------------------- 1 | require('../../template/tabs/tab.html.js'); 2 | require('../../template/tabs/tabset.html.js'); 3 | require('./tabs'); 4 | 5 | var MODULE_NAME = 'ui.bootstrap.module.tabs'; 6 | 7 | angular.module(MODULE_NAME, ['ui.bootstrap.tabs', 'uib/template/tabs/tab.html', 'uib/template/tabs/tabset.html']); 8 | 9 | module.exports = MODULE_NAME; 10 | -------------------------------------------------------------------------------- /src/timepicker/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |
                      4 | 5 |
                      Time is: {{mytime | date:'shortTime' }}
                      6 | 7 |
                      8 |
                      9 | Hours step is: 10 | 11 |
                      12 |
                      13 | Minutes step is: 14 | 15 |
                      16 |
                      17 | 18 |
                      19 | 20 | 21 | 22 | 23 | 24 |
                      25 | -------------------------------------------------------------------------------- /src/timepicker/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('TimepickerDemoCtrl', function ($scope, $log) { 2 | $scope.mytime = new Date(); 3 | 4 | $scope.hstep = 1; 5 | $scope.mstep = 15; 6 | 7 | $scope.options = { 8 | hstep: [1, 2, 3], 9 | mstep: [1, 5, 10, 15, 25, 30] 10 | }; 11 | 12 | $scope.ismeridian = true; 13 | $scope.toggleMode = function() { 14 | $scope.ismeridian = ! $scope.ismeridian; 15 | }; 16 | 17 | $scope.update = function() { 18 | var d = new Date(); 19 | d.setHours( 14 ); 20 | d.setMinutes( 0 ); 21 | $scope.mytime = d; 22 | }; 23 | 24 | $scope.changed = function () { 25 | $log.log('Time changed to: ' + $scope.mytime); 26 | }; 27 | 28 | $scope.clear = function() { 29 | $scope.mytime = null; 30 | }; 31 | }); 32 | -------------------------------------------------------------------------------- /src/timepicker/docs/readme.md: -------------------------------------------------------------------------------- 1 | A lightweight & configurable timepicker directive. 2 | 3 | ### uib-timepicker settings 4 | 5 | * `arrowkeys` 6 | $ 7 | C 8 | _(Default: `true`)_ - 9 | Whether user can use up/down arrow keys inside the hours & minutes input to increase or decrease its values. 10 | 11 | * `hour-step` 12 | $ 13 | C 14 | 15 | _(Default: `1`)_ - 16 | Number of hours to increase or decrease when using a button. 17 | 18 | * `max` 19 | $ 20 | 21 | _(Default: `undefined`)_ - 22 | Maximum time a user can select. 23 | 24 | * `meridians` 25 | $ 26 | C 27 | _(Default: `null`)_ - 28 | Meridian labels based on locale. To override you must supply an array like `['AM', 'PM']`. 29 | 30 | * `min` 31 | $ 32 | 33 | _(Default: `undefined`)_ - 34 | Minimum time a user can select 35 | 36 | * `minute-step` 37 | $ 38 | C 39 | 40 | _(Default: `1`)_ - 41 | Number of minutes to increase or decrease when using a button. 42 | 43 | * `mousewheel` 44 | $ 45 | C 46 | _(Default: `true`)_ - 47 | Whether user can scroll inside the hours & minutes input to increase or decrease its values. 48 | 49 | * `ng-disabled` 50 | $ 51 | 52 | _(Default: `false`)_ - 53 | Whether or not to disable the component. 54 | 55 | * `ng-model` 56 | $ 57 | - 58 | Date object that provides the time state. 59 | 60 | * `pad-hours` 61 | $ 62 | _(Default: true)_ - 63 | Whether the hours column is padded with a 0. 64 | 65 | * `readonly-input` 66 | $ 67 | C 68 | _(Default: `false`)_ - 69 | Whether user can type inside the hours & minutes input. 70 | 71 | * `second-step` 72 | $ 73 | C 74 | 75 | _(Default: `1`)_ - 76 | Number of seconds to increase or decrease when using a button. 77 | 78 | * `show-meridian` 79 | $ 80 | C 81 | 82 | _(Default: `true`)_ - 83 | Whether to display 12H or 24H mode. 84 | 85 | * `show-seconds` 86 | $ 87 | C 88 | 89 | _(Default: `false`)_ - 90 | Show seconds input. 91 | 92 | * `show-spinners` 93 | $ 94 | C 95 | _(Default: `true`)_ - 96 | Show spinner arrows above and below the inputs. 97 | 98 | * `tabindex` 99 | _(Defaults: `0`)_ - 100 | Sets tabindex for each control in the timepicker. 101 | 102 | * `template-url` 103 | C 104 | _(Defaults: `uib/template/timepicker/timepicker.html`)_ - 105 | Add the ability to override the template used on the component. 106 | 107 | **Notes** 108 | 109 | This component makes no claims of absolutely supporting the preservation of dates in all cases, and it is highly recommended that model tracking of dates is encapsulated in a different object. This component should not be used with the same model as the datepicker. This is due to edge cases with situations such as Daylight Savings timezone changes which require a modification of the date in order to prevent an impossible to increment or decrement situation. See [#5485](https://github.com/angular-ui/bootstrap/issues/5485) for details. 110 | 111 | If the model value is updated (i.e. via `Date.prototype.setDate`), you must update the model value by breaking the reference by `modelValue = new Date(modelValue)` in order to have the timepicker update. 112 | -------------------------------------------------------------------------------- /src/timepicker/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../../template/timepicker/timepicker.html.js'); 2 | require('./timepicker'); 3 | 4 | var MODULE_NAME = 'ui.bootstrap.module.timepicker'; 5 | 6 | angular.module(MODULE_NAME, ['ui.bootstrap.timepicker', 'uib/template/timepicker/timepicker.html']); 7 | 8 | module.exports = MODULE_NAME; 9 | -------------------------------------------------------------------------------- /src/timepicker/index.js: -------------------------------------------------------------------------------- 1 | require('./timepicker.css'); 2 | module.exports = require('./index-nocss.js'); 3 | -------------------------------------------------------------------------------- /src/timepicker/timepicker.css: -------------------------------------------------------------------------------- 1 | .uib-time input { 2 | width: 50px; 3 | } 4 | -------------------------------------------------------------------------------- /src/tooltip/docs/demo.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      3 | 4 | 5 |
                      6 | 7 | 8 |
                      9 |
                      10 | 11 | 12 |
                      13 |
                      14 | 15 | 16 |
                      17 |

                      18 | Pellentesque {{dynamicTooltipText}}, 19 | sit amet venenatis urna cursus eget nunc scelerisque viverra mauris, in 20 | aliquam. Tincidunt lobortis feugiat vivamus at 21 | fading 22 | eget arcu dictum varius duis at consectetur lorem. Vitae elementum curabitur 23 | show delay 24 | nunc sed velit dignissim sodales ut eu sem integer vitae. Turpis egestas 25 | hide delay 26 | pharetra convallis posuere morbi leo urna, 27 | Custom template 28 | at elementum eu, facilisis sed odio morbi quis commodo odio. 29 |

                      30 | 31 |

                      32 | I can even contain HTML as a 33 | scope variable or 34 | inline string 35 |

                      36 | 37 |

                      38 | 50 | I can have a custom class. Check me out! 51 |

                      52 | 53 | 54 |
                      55 | 56 | 57 |
                      58 | 59 |
                      60 | 61 | 67 |
                      68 |
                      69 | 72 | 73 |
                      74 | 77 |
                      78 | -------------------------------------------------------------------------------- /src/tooltip/docs/demo.js: -------------------------------------------------------------------------------- 1 | angular.module('ui.bootstrap.demo').controller('TooltipDemoCtrl', function ($scope, $sce) { 2 | $scope.dynamicTooltip = 'Hello, World!'; 3 | $scope.dynamicTooltipText = 'dynamic'; 4 | $scope.htmlTooltip = $sce.trustAsHtml('I\'ve been made bold!'); 5 | $scope.placement = { 6 | options: [ 7 | 'top', 8 | 'top-left', 9 | 'top-right', 10 | 'bottom', 11 | 'bottom-left', 12 | 'bottom-right', 13 | 'left', 14 | 'left-top', 15 | 'left-bottom', 16 | 'right', 17 | 'right-top', 18 | 'right-bottom' 19 | ], 20 | selected: 'top' 21 | }; 22 | }); 23 | -------------------------------------------------------------------------------- /src/tooltip/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../position/index-nocss.js'); 2 | require('../stackedMap'); 3 | require('../../template/tooltip/tooltip-popup.html.js'); 4 | require('../../template/tooltip/tooltip-html-popup.html.js'); 5 | require('../../template/tooltip/tooltip-template-popup.html.js'); 6 | require('./tooltip'); 7 | 8 | var MODULE_NAME = 'ui.bootstrap.module.tooltip'; 9 | 10 | angular.module(MODULE_NAME, ['ui.bootstrap.tooltip', 'uib/template/tooltip/tooltip-popup.html', 'uib/template/tooltip/tooltip-html-popup.html', 'uib/template/tooltip/tooltip-template-popup.html']); 11 | 12 | module.exports = MODULE_NAME; 13 | -------------------------------------------------------------------------------- /src/tooltip/index.js: -------------------------------------------------------------------------------- 1 | require('../position/position.css'); 2 | require('./tooltip.css'); 3 | module.exports = require('./index-nocss.js'); 4 | -------------------------------------------------------------------------------- /src/tooltip/test/tooltip-template.spec.js: -------------------------------------------------------------------------------- 1 | describe('tooltip template', function() { 2 | var elm, 3 | elmBody, 4 | scope, 5 | elmScope, 6 | tooltipScope, 7 | $document; 8 | 9 | // load the popover code 10 | beforeEach(module('ui.bootstrap.tooltip')); 11 | 12 | // load the template 13 | beforeEach(module('uib/template/tooltip/tooltip-template-popup.html')); 14 | 15 | beforeEach(inject(function($templateCache) { 16 | $templateCache.put('myUrl', [200, '{{ myTemplateText }}', {}]); 17 | })); 18 | 19 | beforeEach(inject(function($rootScope, $compile, _$document_) { 20 | $document = _$document_; 21 | elmBody = angular.element( 22 | '
                      Selector Text
                      ' 23 | ); 24 | 25 | scope = $rootScope; 26 | $compile(elmBody)(scope); 27 | scope.templateUrl = 'myUrl'; 28 | 29 | scope.$digest(); 30 | elm = elmBody.find('span'); 31 | elmScope = elm.scope(); 32 | tooltipScope = elmScope.$$childTail; 33 | })); 34 | 35 | afterEach(function() { 36 | $document.off('keypress'); 37 | }); 38 | 39 | function trigger(element, evt) { 40 | element.trigger(evt); 41 | element.scope().$$childTail.$digest(); 42 | } 43 | 44 | it('should open on mouseenter', inject(function() { 45 | trigger(elm, 'mouseenter'); 46 | expect(tooltipScope.isOpen).toBe(true); 47 | 48 | expect(elmBody.children().length).toBe(2); 49 | })); 50 | 51 | it('should not open on mouseenter if templateUrl is empty', inject(function() { 52 | scope.templateUrl = null; 53 | scope.$digest(); 54 | 55 | trigger(elm, 'mouseenter'); 56 | expect(tooltipScope.isOpen).toBe(false); 57 | 58 | expect(elmBody.children().length).toBe(1); 59 | })); 60 | 61 | it('should show updated text', inject(function() { 62 | scope.myTemplateText = 'some text'; 63 | 64 | trigger(elm, 'mouseenter'); 65 | expect(tooltipScope.isOpen).toBe(true); 66 | scope.$digest(); 67 | 68 | expect(elmBody.children().eq(1).text().trim()).toBe('some text'); 69 | 70 | scope.myTemplateText = 'new text'; 71 | scope.$digest(); 72 | 73 | expect(elmBody.children().eq(1).text().trim()).toBe('new text'); 74 | })); 75 | 76 | it('should hide tooltip when template becomes empty', inject(function($timeout) { 77 | trigger(elm, 'mouseenter'); 78 | $timeout.flush(0); 79 | expect(tooltipScope.isOpen).toBe(true); 80 | 81 | scope.templateUrl = ''; 82 | scope.$digest(); 83 | 84 | expect(tooltipScope.isOpen).toBe(false); 85 | 86 | $timeout.flush(); 87 | expect(elmBody.children().length).toBe(1); 88 | })); 89 | }); 90 | -------------------------------------------------------------------------------- /src/tooltip/tooltip.css: -------------------------------------------------------------------------------- 1 | [uib-tooltip-popup].tooltip.top-left > .tooltip-arrow, 2 | [uib-tooltip-popup].tooltip.top-right > .tooltip-arrow, 3 | [uib-tooltip-popup].tooltip.bottom-left > .tooltip-arrow, 4 | [uib-tooltip-popup].tooltip.bottom-right > .tooltip-arrow, 5 | [uib-tooltip-popup].tooltip.left-top > .tooltip-arrow, 6 | [uib-tooltip-popup].tooltip.left-bottom > .tooltip-arrow, 7 | [uib-tooltip-popup].tooltip.right-top > .tooltip-arrow, 8 | [uib-tooltip-popup].tooltip.right-bottom > .tooltip-arrow, 9 | [uib-tooltip-html-popup].tooltip.top-left > .tooltip-arrow, 10 | [uib-tooltip-html-popup].tooltip.top-right > .tooltip-arrow, 11 | [uib-tooltip-html-popup].tooltip.bottom-left > .tooltip-arrow, 12 | [uib-tooltip-html-popup].tooltip.bottom-right > .tooltip-arrow, 13 | [uib-tooltip-html-popup].tooltip.left-top > .tooltip-arrow, 14 | [uib-tooltip-html-popup].tooltip.left-bottom > .tooltip-arrow, 15 | [uib-tooltip-html-popup].tooltip.right-top > .tooltip-arrow, 16 | [uib-tooltip-html-popup].tooltip.right-bottom > .tooltip-arrow, 17 | [uib-tooltip-template-popup].tooltip.top-left > .tooltip-arrow, 18 | [uib-tooltip-template-popup].tooltip.top-right > .tooltip-arrow, 19 | [uib-tooltip-template-popup].tooltip.bottom-left > .tooltip-arrow, 20 | [uib-tooltip-template-popup].tooltip.bottom-right > .tooltip-arrow, 21 | [uib-tooltip-template-popup].tooltip.left-top > .tooltip-arrow, 22 | [uib-tooltip-template-popup].tooltip.left-bottom > .tooltip-arrow, 23 | [uib-tooltip-template-popup].tooltip.right-top > .tooltip-arrow, 24 | [uib-tooltip-template-popup].tooltip.right-bottom > .tooltip-arrow, 25 | [uib-popover-popup].popover.top-left > .arrow, 26 | [uib-popover-popup].popover.top-right > .arrow, 27 | [uib-popover-popup].popover.bottom-left > .arrow, 28 | [uib-popover-popup].popover.bottom-right > .arrow, 29 | [uib-popover-popup].popover.left-top > .arrow, 30 | [uib-popover-popup].popover.left-bottom > .arrow, 31 | [uib-popover-popup].popover.right-top > .arrow, 32 | [uib-popover-popup].popover.right-bottom > .arrow, 33 | [uib-popover-html-popup].popover.top-left > .arrow, 34 | [uib-popover-html-popup].popover.top-right > .arrow, 35 | [uib-popover-html-popup].popover.bottom-left > .arrow, 36 | [uib-popover-html-popup].popover.bottom-right > .arrow, 37 | [uib-popover-html-popup].popover.left-top > .arrow, 38 | [uib-popover-html-popup].popover.left-bottom > .arrow, 39 | [uib-popover-html-popup].popover.right-top > .arrow, 40 | [uib-popover-html-popup].popover.right-bottom > .arrow, 41 | [uib-popover-template-popup].popover.top-left > .arrow, 42 | [uib-popover-template-popup].popover.top-right > .arrow, 43 | [uib-popover-template-popup].popover.bottom-left > .arrow, 44 | [uib-popover-template-popup].popover.bottom-right > .arrow, 45 | [uib-popover-template-popup].popover.left-top > .arrow, 46 | [uib-popover-template-popup].popover.left-bottom > .arrow, 47 | [uib-popover-template-popup].popover.right-top > .arrow, 48 | [uib-popover-template-popup].popover.right-bottom > .arrow { 49 | top: auto; 50 | bottom: auto; 51 | left: auto; 52 | right: auto; 53 | margin: 0; 54 | } 55 | 56 | [uib-popover-popup].popover, 57 | [uib-popover-html-popup].popover, 58 | [uib-popover-template-popup].popover { 59 | display: block !important; 60 | } 61 | -------------------------------------------------------------------------------- /src/typeahead/docs/demo.html: -------------------------------------------------------------------------------- 1 | 28 | 29 | 35 | 36 | 52 | 53 |
                      54 | 55 |

                      Static arrays

                      56 |
                      Model: {{selected | json}}
                      57 | 58 | 59 |

                      Asynchronous results

                      60 |
                      Model: {{asyncSelected | json}}
                      61 | 62 | 63 |
                      64 | No Results Found 65 |
                      66 | 67 |

                      ngModelOptions support

                      68 |
                      Model: {{ngModelOptionsSelected | json}}
                      69 | 70 | 71 |

                      Custom templates for results

                      72 |
                      Model: {{customSelected | json}}
                      73 | 74 | 75 |

                      Custom popup templates for typeahead's dropdown

                      76 |
                      Model: {{customPopupSelected | json}}
                      77 | 78 |
                      79 | -------------------------------------------------------------------------------- /src/typeahead/index-nocss.js: -------------------------------------------------------------------------------- 1 | require('../debounce'); 2 | require('../position/index-nocss.js'); 3 | require('../../template/typeahead/typeahead-match.html.js'); 4 | require('../../template/typeahead/typeahead-popup.html.js'); 5 | require('./typeahead'); 6 | 7 | var MODULE_NAME = 'ui.bootstrap.module.typeahead'; 8 | 9 | angular.module(MODULE_NAME, ['ui.bootstrap.typeahead', 'uib/template/typeahead/typeahead-match.html', 'uib/template/typeahead/typeahead-popup.html']); 10 | 11 | module.exports = MODULE_NAME; 12 | -------------------------------------------------------------------------------- /src/typeahead/index.js: -------------------------------------------------------------------------------- 1 | require('../position/position.css'); 2 | require('./typeahead.css'); 3 | module.exports = require('./index-nocss.js'); 4 | -------------------------------------------------------------------------------- /src/typeahead/test/typeahead-highlight-ngsanitize.spec.js: -------------------------------------------------------------------------------- 1 | describe('Security concerns', function() { 2 | var highlightFilter, $sanitize, logSpy; 3 | 4 | beforeEach(module('ui.bootstrap.typeahead', 'ngSanitize')); 5 | 6 | beforeEach(inject(function (uibTypeaheadHighlightFilter, _$sanitize_, $log) { 7 | highlightFilter = uibTypeaheadHighlightFilter; 8 | $sanitize = _$sanitize_; 9 | logSpy = spyOn($log, 'warn'); 10 | })); 11 | 12 | it('should not call the $log service when ngSanitize is present', function() { 13 | highlightFilter('before after', 'match'); 14 | expect(logSpy).not.toHaveBeenCalled(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/typeahead/test/typeahead-highlight.spec.js: -------------------------------------------------------------------------------- 1 | describe('typeaheadHighlight', function () { 2 | 3 | var highlightFilter, $log, $sce, logSpy; 4 | 5 | beforeEach(module('ui.bootstrap.typeahead')); 6 | 7 | beforeEach(inject(function(_$log_, _$sce_) { 8 | $log = _$log_; 9 | $sce = _$sce_; 10 | logSpy = spyOn($log, 'warn'); 11 | })); 12 | 13 | beforeEach(inject(function(uibTypeaheadHighlightFilter) { 14 | highlightFilter = uibTypeaheadHighlightFilter; 15 | })); 16 | 17 | it('should higlight a match', function() { 18 | expect($sce.getTrustedHtml(highlightFilter('before match after', 'match'))).toEqual('before match after'); 19 | }); 20 | 21 | it('should higlight a match with mixed case', function() { 22 | expect($sce.getTrustedHtml(highlightFilter('before MaTch after', 'match'))).toEqual('before MaTch after'); 23 | }); 24 | 25 | it('should higlight all matches', function() { 26 | expect($sce.getTrustedHtml(highlightFilter('before MaTch after match', 'match'))).toEqual('before MaTch after match'); 27 | }); 28 | 29 | it('should do nothing if no match', function() { 30 | expect($sce.getTrustedHtml(highlightFilter('before match after', 'nomatch'))).toEqual('before match after'); 31 | }); 32 | 33 | it('should do nothing if no or empty query', function() { 34 | expect($sce.getTrustedHtml(highlightFilter('before match after', ''))).toEqual('before match after'); 35 | expect($sce.getTrustedHtml(highlightFilter('before match after', null))).toEqual('before match after'); 36 | expect($sce.getTrustedHtml(highlightFilter('before match after', undefined))).toEqual('before match after'); 37 | }); 38 | 39 | it('issue 316 - should work correctly for regexp reserved words', function() { 40 | expect($sce.getTrustedHtml(highlightFilter('before (match after', '(match'))).toEqual('before (match after'); 41 | }); 42 | 43 | it('issue 1777 - should work correctly with numeric values', function() { 44 | expect($sce.getTrustedHtml(highlightFilter(123, '2'))).toEqual('123'); 45 | }); 46 | 47 | it('should show a warning when this component is being used unsafely', function() { 48 | highlightFilter('before match after', 'match'); 49 | expect(logSpy).toHaveBeenCalled(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /src/typeahead/test/typeahead-parser.spec.js: -------------------------------------------------------------------------------- 1 | describe('syntax parser', function() { 2 | var typeaheadParser, scope, filterFilter; 3 | 4 | beforeEach(module('ui.bootstrap.typeahead')); 5 | beforeEach(inject(function(_$rootScope_, _filterFilter_, uibTypeaheadParser) { 6 | typeaheadParser = uibTypeaheadParser; 7 | scope = _$rootScope_; 8 | filterFilter = _filterFilter_; 9 | })); 10 | 11 | it('should parse the simplest array-based syntax', function() { 12 | scope.states = ['Alabama', 'California', 'Delaware']; 13 | var result = typeaheadParser.parse('state for state in states | filter:$viewValue'); 14 | 15 | var itemName = result.itemName; 16 | var locals = {$viewValue:'al'}; 17 | expect(result.source(scope, locals)).toEqual(['Alabama', 'California']); 18 | 19 | locals[itemName] = 'Alabama'; 20 | expect(result.viewMapper(scope, locals)).toEqual('Alabama'); 21 | expect(result.modelMapper(scope, locals)).toEqual('Alabama'); 22 | }); 23 | 24 | it('should parse the simplest function-based syntax', function() { 25 | scope.getStates = function($viewValue) { 26 | return filterFilter(['Alabama', 'California', 'Delaware'], $viewValue); 27 | }; 28 | var result = typeaheadParser.parse('state for state in getStates($viewValue)'); 29 | 30 | var itemName = result.itemName; 31 | var locals = {$viewValue:'al'}; 32 | expect(result.source(scope, locals)).toEqual(['Alabama', 'California']); 33 | 34 | locals[itemName] = 'Alabama'; 35 | expect(result.viewMapper(scope, locals)).toEqual('Alabama'); 36 | expect(result.modelMapper(scope, locals)).toEqual('Alabama'); 37 | }); 38 | 39 | it('should allow to specify custom model mapping that is used as a label as well', function () { 40 | scope.states = [ 41 | {code:'AL', name:'Alabama'}, 42 | {code:'CA', name:'California'}, 43 | {code:'DE', name:'Delaware'} 44 | ]; 45 | var result = typeaheadParser.parse('state.name for state in states | filter:$viewValue | orderBy:"name":true'); 46 | 47 | var itemName = result.itemName; 48 | expect(itemName).toEqual('state'); 49 | expect(result.source(scope, {$viewValue:'al'})).toEqual([ 50 | {code:'CA', name:'California'}, 51 | {code:'AL', name:'Alabama'} 52 | ]); 53 | 54 | var locals = {$viewValue:'al'}; 55 | locals[itemName] = {code:'AL', name:'Alabama'}; 56 | expect(result.viewMapper(scope, locals)).toEqual('Alabama'); 57 | expect(result.modelMapper(scope, locals)).toEqual('Alabama'); 58 | }); 59 | 60 | it('should allow to specify custom view and model mappers', function() { 61 | scope.states = [ 62 | {code:'AL', name:'Alabama'}, 63 | {code:'CA', name:'California'}, 64 | {code:'DE', name:'Delaware'} 65 | ]; 66 | var result = typeaheadParser.parse('state.code as state.name + " ("+state.code+")" for state in states | filter:$viewValue | orderBy:"name":true'); 67 | 68 | var itemName = result.itemName; 69 | expect(result.source(scope, {$viewValue:'al'})).toEqual([ 70 | {code:'CA', name:'California'}, 71 | {code:'AL', name:'Alabama'} 72 | ]); 73 | 74 | var locals = {$viewValue:'al'}; 75 | locals[itemName] = {code:'AL', name:'Alabama'}; 76 | expect(result.viewMapper(scope, locals)).toEqual('Alabama (AL)'); 77 | expect(result.modelMapper(scope, locals)).toEqual('AL'); 78 | }); 79 | }); -------------------------------------------------------------------------------- /src/typeahead/test/typeahead-popup.spec.js: -------------------------------------------------------------------------------- 1 | describe('typeaheadPopup - result rendering', function() { 2 | var scope, $rootScope, $compile; 3 | 4 | beforeEach(module('ui.bootstrap.typeahead')); 5 | beforeEach(module('uib/template/typeahead/typeahead-popup.html')); 6 | beforeEach(module('uib/template/typeahead/typeahead-match.html')); 7 | beforeEach(inject(function(_$rootScope_, _$compile_) { 8 | $rootScope = _$rootScope_; 9 | scope = $rootScope.$new(); 10 | $compile = _$compile_; 11 | })); 12 | 13 | it('should render initial results', function() { 14 | scope.matches = ['foo', 'bar', 'baz']; 15 | scope.active = 1; 16 | 17 | var el = $compile('
                      ')(scope); 18 | $rootScope.$digest(); 19 | 20 | var liElems = el.find('li'); 21 | expect(liElems.length).toEqual(3); 22 | expect(liElems.eq(0)).not.toHaveClass('active'); 23 | expect(liElems.eq(1)).toHaveClass('active'); 24 | expect(liElems.eq(2)).not.toHaveClass('active'); 25 | }); 26 | 27 | it('should change active item on mouseenter', function() { 28 | scope.matches = ['foo', 'bar', 'baz']; 29 | scope.active = 1; 30 | 31 | var el = $compile('
                      ')(scope); 32 | $rootScope.$digest(); 33 | 34 | var liElems = el.find('li'); 35 | expect(liElems.eq(1)).toHaveClass('active'); 36 | expect(liElems.eq(2)).not.toHaveClass('active'); 37 | 38 | liElems.eq(2).trigger('mouseenter'); 39 | 40 | expect(liElems.eq(1)).not.toHaveClass('active'); 41 | expect(liElems.eq(2)).toHaveClass('active'); 42 | }); 43 | 44 | it('should select an item on mouse click', function() { 45 | scope.matches = ['foo', 'bar', 'baz']; 46 | scope.active = 1; 47 | $rootScope.select = angular.noop; 48 | spyOn($rootScope, 'select'); 49 | 50 | var el = $compile('
                      ')(scope); 51 | $rootScope.$digest(); 52 | 53 | var liElems = el.find('li'); 54 | liElems.eq(2).find('a').trigger('click'); 55 | expect($rootScope.select).toHaveBeenCalledWith(2); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/typeahead/typeahead.css: -------------------------------------------------------------------------------- 1 | [uib-typeahead-popup].dropdown-menu { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /template/accordion/accordion-group.html: -------------------------------------------------------------------------------- 1 | 6 |
                      7 |
                      8 |
                      9 | -------------------------------------------------------------------------------- /template/accordion/accordion.html: -------------------------------------------------------------------------------- 1 |
                      -------------------------------------------------------------------------------- /template/alert/alert.html: -------------------------------------------------------------------------------- 1 | 5 |
                      6 | -------------------------------------------------------------------------------- /template/carousel/carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | previous 5 | 6 | 7 | 8 | next 9 | 10 | 15 | -------------------------------------------------------------------------------- /template/carousel/slide.html: -------------------------------------------------------------------------------- 1 |
                      2 | -------------------------------------------------------------------------------- /template/datepicker/datepicker.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      3 |
                      4 |
                      5 |
                      6 | -------------------------------------------------------------------------------- /template/datepicker/day.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 |
                      {{::label.abbr}}
                      {{ weekNumbers[$index] }} 19 | 27 |
                      31 | -------------------------------------------------------------------------------- /template/datepicker/month.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 25 |
                      14 | 22 |
                      26 | -------------------------------------------------------------------------------- /template/datepicker/year.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 25 |
                      14 | 22 |
                      26 | -------------------------------------------------------------------------------- /template/datepickerPopup/popup.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /template/modal/window.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /template/pager/pager.html: -------------------------------------------------------------------------------- 1 |
                    • {{::getText('previous')}}
                    • 2 |
                    • {{::getText('next')}}
                    • 3 | -------------------------------------------------------------------------------- /template/pagination/pagination.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /template/popover/popover-html.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |
                      4 |

                      5 |
                      6 |
                      7 | -------------------------------------------------------------------------------- /template/popover/popover-template.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |
                      4 |

                      5 |
                      8 |
                      9 | -------------------------------------------------------------------------------- /template/popover/popover.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |
                      4 |

                      5 |
                      6 |
                      7 | -------------------------------------------------------------------------------- /template/progressbar/bar.html: -------------------------------------------------------------------------------- 1 |
                      2 | -------------------------------------------------------------------------------- /template/progressbar/progress.html: -------------------------------------------------------------------------------- 1 |
                      -------------------------------------------------------------------------------- /template/progressbar/progressbar.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      3 |
                      4 | -------------------------------------------------------------------------------- /template/rating/rating.html: -------------------------------------------------------------------------------- 1 | 2 | ({{ $index < value ? '*' : ' ' }}) 3 | 4 | 5 | -------------------------------------------------------------------------------- /template/tabs/tab.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /template/tabs/tabset.html: -------------------------------------------------------------------------------- 1 |
                      2 | 3 |
                      4 |
                      8 |
                      9 |
                      10 |
                      11 | -------------------------------------------------------------------------------- /template/timepicker/timepicker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
                        
                      13 | 14 | : 17 | 18 | : 21 | 22 |
                        
                      35 | -------------------------------------------------------------------------------- /template/tooltip/tooltip-html-popup.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      3 | -------------------------------------------------------------------------------- /template/tooltip/tooltip-popup.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      3 | -------------------------------------------------------------------------------- /template/tooltip/tooltip-template-popup.html: -------------------------------------------------------------------------------- 1 |
                      2 |
                      5 | -------------------------------------------------------------------------------- /template/typeahead/typeahead-match.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /template/typeahead/typeahead-popup.html: -------------------------------------------------------------------------------- 1 | 6 | --------------------------------------------------------------------------------