├── .babelrc
├── .github
└── workflows
│ └── codeql.yml
├── .gitignore
├── .yarnrc.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist
└── lib
│ ├── angular-iscroll.js
│ ├── angular-iscroll.js.gz
│ └── scss
│ └── _iscroll.scss
├── package.json
├── postcss.config.js
├── src
└── lib
│ ├── _iscroll.scss
│ └── angular-iscroll.js
├── webpack.config.mjs
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "useBuiltIns": "usage",
7 | "corejs": "3.33"
8 | }
9 | ]
10 | ],
11 | "plugins": [
12 | [
13 | "angularjs-annotate",
14 | {
15 | "explicitOnly": true
16 | }
17 | ]
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "master" ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ "master" ]
20 | schedule:
21 | - cron: '15 8 * * 2'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v3
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v2
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 |
52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
53 | # queries: security-extended,security-and-quality
54 |
55 |
56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
57 | # If this step fails, then you should remove it and run the build manually (see below)
58 | - name: Autobuild
59 | uses: github/codeql-action/autobuild@v2
60 |
61 | # ℹ️ Command-line programs to run using the OS shell.
62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
63 |
64 | # If the Autobuild fails above, remove it and uncomment the following three lines.
65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
66 |
67 | # - run: |
68 | # echo "Run, Build Application using script"
69 | # ./location_of_script_within_repo/buildscript.sh
70 |
71 | - name: Perform CodeQL Analysis
72 | uses: github/codeql-action/analyze@v2
73 | with:
74 | category: "/language:${{matrix.language}}"
75 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 | dist/examples
22 |
23 | # Dependency directory
24 | # Commenting this out is preferred by some people, see
25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
26 | node_modules
27 | bower_components
28 |
29 | # Users Environment Variables
30 | .lock-wscript
31 |
32 | # IDEA-based editor project directory
33 | .idea/
34 |
35 | # Sass cache
36 | .sass-cache/
37 |
38 | # Modern Yarn
39 | .yarn/*
40 | !.yarn/cache
41 | !.yarn/patches
42 | !.yarn/plugins
43 | !.yarn/releases
44 | !.yarn/sdks
45 | !.yarn/versions
46 |
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v3.6.0](https://github.com/mtr/angular-iscroll/tree/v3.6.0) (2018-01-20)
4 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.5.1...v3.6.0)
5 |
6 | **Implemented enhancements:**
7 |
8 | - Automated detection is too strict on Android devices. [\#41](https://github.com/mtr/angular-iscroll/issues/41)
9 |
10 | **Fixed bugs:**
11 |
12 | - Automated detection is too strict on Android devices. [\#41](https://github.com/mtr/angular-iscroll/issues/41)
13 |
14 | **Closed issues:**
15 |
16 | - FF and IE directive service and scope reference problems. [\#15](https://github.com/mtr/angular-iscroll/issues/15)
17 |
18 | ## [v3.5.1](https://github.com/mtr/angular-iscroll/tree/v3.5.1) (2017-06-13)
19 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.5.0...v3.5.1)
20 |
21 | ## [v3.5.0](https://github.com/mtr/angular-iscroll/tree/v3.5.0) (2017-06-13)
22 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.4.1...v3.5.0)
23 |
24 | ## [v3.4.1](https://github.com/mtr/angular-iscroll/tree/v3.4.1) (2017-06-13)
25 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.4.0...v3.4.1)
26 |
27 | **Closed issues:**
28 |
29 | - Why does it always appear "scroll-off" [\#35](https://github.com/mtr/angular-iscroll/issues/35)
30 | - Keep getting "TypeError: IScroll is not a function" [\#16](https://github.com/mtr/angular-iscroll/issues/16)
31 |
32 | ## [v3.4.0](https://github.com/mtr/angular-iscroll/tree/v3.4.0) (2016-09-02)
33 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.2.0...v3.4.0)
34 |
35 | **Implemented enhancements:**
36 |
37 | - Refine the need-iScroll auto-detection rules [\#28](https://github.com/mtr/angular-iscroll/issues/28)
38 |
39 | **Merged pull requests:**
40 |
41 | - Fix. Fixed issue with overriding instance config with default options. [\#34](https://github.com/mtr/angular-iscroll/pull/34) ([egor-manjula](https://github.com/egor-manjula))
42 |
43 | ## [v3.2.0](https://github.com/mtr/angular-iscroll/tree/v3.2.0) (2016-01-27)
44 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.1.0...v3.2.0)
45 |
46 | **Merged pull requests:**
47 |
48 | - \#25 Add platform.js requirement to bower.json [\#27](https://github.com/mtr/angular-iscroll/pull/27) ([simison](https://github.com/simison))
49 |
50 | ## [v3.1.0](https://github.com/mtr/angular-iscroll/tree/v3.1.0) (2016-01-22)
51 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v3.0.0...v3.1.0)
52 |
53 | ## [v3.0.0](https://github.com/mtr/angular-iscroll/tree/v3.0.0) (2016-01-22)
54 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v2.0.1...v3.0.0)
55 |
56 | **Implemented enhancements:**
57 |
58 | - Automatically detect the need for using iScroll. [\#25](https://github.com/mtr/angular-iscroll/issues/25)
59 | - Support being initially disabled. [\#24](https://github.com/mtr/angular-iscroll/issues/24)
60 | - Address jshint issues [\#23](https://github.com/mtr/angular-iscroll/issues/23)
61 | - Remove unmaintained example code because core-layout is well maintained [\#22](https://github.com/mtr/angular-iscroll/issues/22)
62 | - Add bitHound configuration. [\#21](https://github.com/mtr/angular-iscroll/issues/21)
63 | - Address npm dependency issues found in master branch \[Opened by bitHound\] [\#20](https://github.com/mtr/angular-iscroll/issues/20)
64 |
65 | **Fixed bugs:**
66 |
67 | - iScrollServiceProvider.configureDefaults\(\) does not perform a deep merge of options with defaultOptions. [\#26](https://github.com/mtr/angular-iscroll/issues/26)
68 |
69 | ## [v2.0.1](https://github.com/mtr/angular-iscroll/tree/v2.0.1) (2015-12-17)
70 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v2.0.0...v2.0.1)
71 |
72 | ## [v2.0.0](https://github.com/mtr/angular-iscroll/tree/v2.0.0) (2015-12-16)
73 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.3.3...v2.0.0)
74 |
75 | **Merged pull requests:**
76 |
77 | - Add option to skip digest cycle when refresh option is turned on [\#19](https://github.com/mtr/angular-iscroll/pull/19) ([DinkoMiletic](https://github.com/DinkoMiletic))
78 | - Fixing bug where the argument passed to configureDefaults\(\) clobbers the built-in defaults [\#17](https://github.com/mtr/angular-iscroll/pull/17) ([mikechamberlain](https://github.com/mikechamberlain))
79 |
80 | ## [v1.3.3](https://github.com/mtr/angular-iscroll/tree/v1.3.3) (2015-06-07)
81 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.3.2...v1.3.3)
82 |
83 | **Implemented enhancements:**
84 |
85 | - Create simple configuration interface for defining event handlers. [\#10](https://github.com/mtr/angular-iscroll/issues/10)
86 |
87 | **Merged pull requests:**
88 |
89 | - Adds bower.json and bower install instructions [\#12](https://github.com/mtr/angular-iscroll/pull/12) ([brechtpm](https://github.com/brechtpm))
90 |
91 | ## [v1.3.2](https://github.com/mtr/angular-iscroll/tree/v1.3.2) (2015-05-23)
92 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.3.1...v1.3.2)
93 |
94 | ## [v1.3.1](https://github.com/mtr/angular-iscroll/tree/v1.3.1) (2015-05-23)
95 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.3.0...v1.3.1)
96 |
97 | ## [v1.3.0](https://github.com/mtr/angular-iscroll/tree/v1.3.0) (2015-05-23)
98 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.5...v1.3.0)
99 |
100 | ## [v1.2.5](https://github.com/mtr/angular-iscroll/tree/v1.2.5) (2015-05-23)
101 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.4...v1.2.5)
102 |
103 | **Merged pull requests:**
104 |
105 | - Add a Bitdeli Badge to README [\#9](https://github.com/mtr/angular-iscroll/pull/9) ([bitdeli-chef](https://github.com/bitdeli-chef))
106 |
107 | ## [v1.2.4](https://github.com/mtr/angular-iscroll/tree/v1.2.4) (2015-03-25)
108 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.3...v1.2.4)
109 |
110 | **Fixed bugs:**
111 |
112 | - Interval is not being closed after destroying instance of angular-iscroll [\#6](https://github.com/mtr/angular-iscroll/issues/6)
113 |
114 | **Merged pull requests:**
115 |
116 | - Cancelling intervals when destroying instance [\#7](https://github.com/mtr/angular-iscroll/pull/7) ([wkwiatek](https://github.com/wkwiatek))
117 |
118 | ## [v1.2.3](https://github.com/mtr/angular-iscroll/tree/v1.2.3) (2015-03-05)
119 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.2...v1.2.3)
120 |
121 | ## [v1.2.2](https://github.com/mtr/angular-iscroll/tree/v1.2.2) (2015-02-25)
122 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.1...v1.2.2)
123 |
124 | **Implemented enhancements:**
125 |
126 | - Documentation [\#4](https://github.com/mtr/angular-iscroll/issues/4)
127 |
128 | ## [v1.2.1](https://github.com/mtr/angular-iscroll/tree/v1.2.1) (2015-02-24)
129 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.2.0...v1.2.1)
130 |
131 | ## [v1.2.0](https://github.com/mtr/angular-iscroll/tree/v1.2.0) (2015-02-15)
132 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.1.2...v1.2.0)
133 |
134 | **Implemented enhancements:**
135 |
136 | - Support configuring the default options during myApp.config\(\) [\#3](https://github.com/mtr/angular-iscroll/issues/3)
137 |
138 | ## [v1.1.2](https://github.com/mtr/angular-iscroll/tree/v1.1.2) (2015-02-07)
139 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.1.1...v1.1.2)
140 |
141 | **Fixed bugs:**
142 |
143 | - Declare Sass variables as defaults, so they can easily be overridden. [\#2](https://github.com/mtr/angular-iscroll/issues/2)
144 |
145 | ## [v1.1.1](https://github.com/mtr/angular-iscroll/tree/v1.1.1) (2015-02-06)
146 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.1.0...v1.1.1)
147 |
148 | ## [v1.1.0](https://github.com/mtr/angular-iscroll/tree/v1.1.0) (2015-02-06)
149 | [Full Changelog](https://github.com/mtr/angular-iscroll/compare/v1.0.0...v1.1.0)
150 |
151 | **Implemented enhancements:**
152 |
153 | - Add support for periodic instance.refresh\(\) calls. [\#1](https://github.com/mtr/angular-iscroll/issues/1)
154 |
155 | ## [v1.0.0](https://github.com/mtr/angular-iscroll/tree/v1.0.0) (2015-02-05)
156 |
157 |
158 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Martin Thorsen Ranang
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-iscroll
2 | AngularJS module that enables iScroll 5 functionality, wrapping it in an easy-to-use directive
3 |
4 | ## Install
5 |
6 | Install the [angular-iscroll NPM package](https://www.npmjs.com/package/angular-iscroll)
7 | ```bash
8 | npm install --save angular-iscroll
9 | ```
10 |
11 | Install through Yarn
12 | ```bash
13 | yarn add angular-iscroll
14 | ```
15 |
16 | Or, to check out a development version, start by cloning the repository, by
17 | ```bash
18 | git clone git@github.com:mtr/angular-iscroll.git
19 | ```
20 | If you don't use `yarn` you may run `npm run-script [command]` instead of `yarn [command]`. So, to install the necessary dependencies:
21 | ```bash
22 | cd angular-iscroll/
23 | yarn install
24 | yarn build # or `npm run-script build`
25 | ```
26 |
27 | After that, you should have a `dist` directory with a subdirectory named `lib`:
28 | ```
29 | dist/
30 | └── lib
31 | ├── angular-iscroll.js
32 | ├── angular-iscroll.js.gz
33 | └── scss
34 | └── _iscroll.scss
35 | ```
36 |
37 | ### Build
38 |
39 | To rebuild the library, run
40 | ```bash
41 | yarn build # or `yarn watch`
42 | ```
43 |
44 |
45 | ## Demo
46 | You may have a look at [core-layout](http://mtr.github.io/core-layout/examples/) ([GitHub repo](https://github.com/mtr/core-layout/)), an Angular demo app that shows how you can use the `iscroll` directive in a responsive-design web-app with support for both drawers (slide-out menus) and modals. For example, the demo shows how to handle DOM content generated dynamically through [ngRepeat](https://docs.angularjs.org/api/ng/directive/ngRepeat).
47 |
48 | ## Usage
49 |
50 | In the following, `IScroll` (with capital 'I' and 'S') refers to instances
51 | of the [iScroll Javascript library](http://iscrolljs.com/) that this package provides an AngularJS wrapper for.
52 |
53 | The main usage pattern for `angular-iscroll` is to define a dependency on the `angular-iscroll` module in your AngularJS app. For example:
54 | ```js
55 | angular.module('myApp', ['angular-iscroll']);
56 | ```
57 | or, in a Browserify-based code base:
58 | ```js
59 | angular.module('myApp', [require('angular-iscroll').name]);
60 | ```
61 |
62 | The `angular-iscroll` module includes both a directive, `iscroll`, and a service, `iScrollService`, which gives you access to and control over a shared, global state of whether to enable, disable, or refresh the `IScroll` instances for each `iscroll` directive instance.
63 |
64 | Next, to use the directive, you should set up your HTML template like
65 | ```html
66 | …
67 |
72 |
76 | …
77 | ```
78 | Let me explain the essential parts of that HTML example. First of all, the `iscroll` directive is an attribute of an element belonging to the `iscroll-wrapper` class, which wraps an element of the `iscroll-scroller` class. Those two classes are defined in the [SASS](http://sass-lang.com/) file [dist/lib/scss/_iscroll.scss](dist/lib/scss/_iscroll.scss), but they don't have any meaning unless they occur inside an `iscroll-on` class; and that's where the shared, global state from iScrollService comes in. The controller, `MyAppController`, in the above example exposes the state variable shared by iScrollService in its scope
79 | ```js
80 | function MyAppController(iScrollService) {
81 | var vm = this; // Use 'controller as' syntax
82 |
83 | vm.iScrollState = iScrollService.state;
84 | }
85 | ```
86 | thereby providing a way to globally change the meaning of the `iscroll-wrapper` + `iscroll-scroller` combination. Please note: To get more info about the "controller as" syntax, you might enjoy [John Papa's AngularJS Style Guide](https://github.com/johnpapa/angularjs-styleguide#controlleras-with-vm).
87 |
88 | Furthermore, the global iScroll state exposed by the service should be changed through the service's `enable([signalOnly])`, `disable([signalOnly])`, and `toggle([signalOnly])` methods, where each method will change the state accordingly, and then emit a corresponding signal from `$rootScope` that gets picked up and handled by the available `angular-iscroll` directive instances. If the `signalOnly` flag is `true`, then the state is not changed by the service method, but the signal is sent nonetheless. If the directives receive an `iscroll:disabled` signal, they will destroy any existing `IScroll` instances, and if they receive an `iscroll:enabled` signal, they will create a new `IScroll` instances per directive instance if it doesn't already exist.
89 |
90 | It should also be noted that during instantiation, in the directive's post-link phase, the `iscroll` directive will check the `iScrollService`'s `useIScroll` state to decide whether or not it will create an actual `IScroll` instance. Consequently, if you would like to create an AngularJS solution that uses iScroll only on, for example, iOS devices, you should determine the current browser type early, probably inside the app controller's [configuration block](https://docs.angularjs.org/guide/module#module-loading-dependencies), and set the service's `useIscroll` state accordingly. Please note that `angular-iscroll` does not contain any code to detect which browser or platform it is currently running on, which is a separate, complex task better solved by specialized libraries, like [platform.js](https://github.com/bestiejs/platform.js).
91 |
92 |
93 | ### Manual Interaction with Each Directive's IScroll Instance
94 | If you want access to a scope's `IScroll` instance, you can supply an optional
95 | `iscroll-instance` attribute when applying the `iscroll` directive, like
96 | ```html
97 | …
98 |
102 | …
103 | ```
104 | That way, the scope's `instance` variable will hold a reference to the actual
105 | `IScroll` instance, so you can access the IScroll instance's own API, for
106 | example to define [custom events](http://iscrolljs.com/#custom-events) or
107 | access its [scroller info](http://iscrolljs.com/#scroller-info).
108 |
109 |
110 | ### Configuration
111 | I've designed this module so that it should be easy to configure. First of all, you can supply per-instance options, both for `IScroll` and the directive itself, when you apply the directive. For example
112 | ```html
113 | …
114 | ```
115 | would pass along the options `{mouseWheel: true, momentum: true}` to `IScroll`, while the directive-specific configuration parameter, `{refreshInterval: 500}`, is only interpreted by the directive. Any config option not recognized as a directive-specific option, will be forwarded to `IScroll`.
116 |
117 | There are lots of configuration options for IScroll itself; those are best [documented by iScroll](http://iscrolljs.com/#configuring).
118 |
119 | #### Directive Options
120 | The directive provides two configuration options:
121 |
122 | - `asyncRefreshDelay` (default `0`): defines the delay, in ms, before the directive asynchronously performs an IScroll.refresh(). If `false`, then no async refresh is performed. This can come in handy when you need to wait for the DOM to be rendered before `IScroll` can know the size of its scrolling area.
123 | - `refreshInterval` (default `false`): a delay, in ms, between each periodic iScroll.refresh(). If `false`, then no periodic refresh is performed. This functionality can be handy in complex applications, where it might be difficult to decide when `iScrollService.refresh()` should be called, and a periodic call to `IScroll.refresh()`, for example every 500 ms, might provide a smooth user experience. To avoid scroll stuttering caused by calls to refresh during an ongoing scroll operation, the `angular-iscroll` directive prevents `refresh()` calls if IScroll is currently performing a scroll operation.
124 | - `invokeApply` (default `false`, since version _2.0.0_): whether or not to invoke AngularJS' `$apply()` (and thereby `$digest()`) cycle on every refresh, as determined by `asyncRefreshDelay` or `refreshInterval`. When `false`, it will not invoke model dirty checking on every call to `IScroll.refresh()`. This can result in huge performance gain if `refreshInterval` is set to a low value (for example 500 ms). Example usage:
125 |
126 | iScrollServiceProvider.configureDefaults({
127 | iscroll: {
128 | invokeApply:false
129 | }
130 | });
131 |
132 | To test it, you can paste this code to your app `run` block:
133 |
134 | /**
135 | * This code measures `$digest()` performance
136 | * by logging digest times to the console.
137 | */
138 | var $oldDigest = $rootScope.$digest;
139 | var $newDigest = function() {
140 | console.time("$digest");
141 | $oldDigest.apply($rootScope);
142 | console.timeEnd("$digest");
143 | };
144 | $rootScope.$digest = $newDigest;
145 |
146 | With `invokeApply = true` and `refreshInterval = 500` you'll see that digest is run every 500ms.
147 | With `invokeApply = false` and `refreshInterval = 500` you'll see that digest is not invoked by `angular-iscroll`.
148 |
149 | Thanks to [DinkoMiletic](https://github.com/DinkoMiletic) for implementing this optimization.
150 |
151 |
152 | #### Globally Configuring the Directive's Default Options
153 |
154 | The `iscroll` directive gets its default configuration from the `iScrollService`. To provide a way to easily, globally configure the defaults for all `iscroll` instances, the module defines an `iScrollServiceProvider` which can be injected into the app controller's configuration block which is guaranteed to run before the controller is used anywhere. For example:
155 | ```js
156 | /* @ngInject */
157 | function _config(iScrollServiceProvider) {
158 | // Supply a default configuration object, eg:
159 | iScrollServiceProvider.configureDefaults({
160 | iScroll: {
161 | // Passed through to the iScroll library
162 | scrollbars: true,
163 | fadeScrollbars: true
164 | },
165 | directive: {
166 | // Interpreted by the directive
167 | refreshInterval: 500
168 | }
169 | });
170 | }
171 |
172 | angular
173 | .module('myApp', ['angular-iscroll'])
174 | .config(_config);
175 | ```
176 | The configuration you provide this way will serve as the updated global default for all `iscroll` directive instances.
177 |
178 | Please note that the above example relies on [ng-annotate](https://www.npmjs.com/package/ng-annotate) for adding AngularJS dependency-injection annotations during builds, as indicated by the `/* @ngInject */` comment.
179 |
180 | ## Support ##
181 | Thanks to a generous “free for Open Source” sponsorship from [BrowserStack](https://www.browserstack.com) I've been able to test [core-layout](http://mtr.github.io/core-layout/examples/), and thereby [angular-iscroll](https://github.com/mtr/angular-iscroll/), with a plethora of devices and browsers. The following browsers and devices has been tested successfully:
182 |
183 | * Desktop
184 | * Chrome 16–48 on OS X 10.10
185 | * Chrome 48 on Ubuntu 14.04
186 | * Firefox 6.0–43.0 on OS X 10.10
187 | * Firefox 43.0.4 on Ubuntu 14.04
188 | * Internet Explorer 9, 10, and 11 on Windows 7
189 | * Internet Explorer Edge 12 on Windows 10
190 | * Opera 12.12–34 on OS X 10.10
191 | * Safari 5.1.7 on Windows 10
192 | * Safari 8.0.8 on OS X 10.10.5
193 | * Yandex 14.12 on OS X 10.10
194 | * Mobile
195 | * Android Browser 4.0 with Android 4.0.4 on Samsung Galaxy Note 10.1
196 | * Android Browser 4.0 with Android 4.1.2 on Samsung Galaxy S3
197 | * Chrome Mobile 45 with Android 5.0.2 on Samsung Galaxy S6
198 | * Chrome Mobile 45 with Android 4.4 on Google Nexus 5
199 | * Safari 4.0.5 with iOS 4.0.1 on iPhone 4
200 | * Safari 5.0.2 with iOS 4.3.2 on iPad 2
201 | * Safari 5.1 with iOS 5.0 on iPad 2
202 | * Safari 5.1 with iOS 5.1 on iPhone 4S
203 | * Safari 6.0 with iOS 6.0 on iPhone 5
204 | * Safari 7.0 with iOS 7.0.4 on iPad Air
205 | * Safari 8.0 with iOS 8.1.1 on iPad Air 2
206 | * Safari 9.0 with iOS 9.0.2 on iPhone 6S
207 | * IE Mobile 11.0 with Windows Phone 8.1 on Nokia Lumia 520, 925, and 930
208 |
209 | ### Incompatible Browsers ###
210 | During testing, the [core-layout](http://mtr.github.io/core-layout/examples/) demo broke in the following browsers:
211 |
212 | * Firefox 3.6, 4, and 5 on OS X 10.10
213 | * Internet Explorer 8 on Windows 7 (fails during jQuery version 2.2.0 initialization):
214 | ```
215 | // Use the handy event callback
216 | document.addEventListener( "DOMContentLoaded", completed );
217 | ```
218 | Error message: `Object doesn't support this property or method`.
219 | * Safari 3 with iOS 3 on iPhone 3GS
220 |
221 | This does not necessarily mean that `angular-iscroll` itself breaks in the same browsers, but the demo code did.
222 |
--------------------------------------------------------------------------------
/dist/lib/angular-iscroll.js:
--------------------------------------------------------------------------------
1 | /*! For license information please see angular-iscroll.js.LICENSE.txt */
2 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("angular")):"function"==typeof define&&define.amd?define(["angular"],e):"object"==typeof exports?exports.angularIscroll=e(require("angular")):t.angularIscroll=e(t.angular)}(self,(function(t){return function(){var e={495:function(t,e,i){var s;!function(o,n,r){var a=o.requestAnimationFrame||o.webkitRequestAnimationFrame||o.mozRequestAnimationFrame||o.oRequestAnimationFrame||o.msRequestAnimationFrame||function(t){o.setTimeout(t,1e3/60)},l=function(){var t={},e=n.createElement("div").style,i=function(){for(var t=["t","webkitT","MozT","msT","OT"],i=0,s=t.length;i0&&(a=o?o/2.5*(c/8):0,l=(h=r.abs(t)+a)/c),{destination:r.round(a),duration:l}};var a=s("transform");return t.extend(t,{hasTransform:!1!==a,hasPerspective:s("perspective")in e,hasTouch:"ontouchstart"in o,hasPointer:!(!o.PointerEvent&&!o.MSPointerEvent),hasTransition:s("transition")in e}),t.isBadAndroid=function(){var t=o.navigator.appVersion;if(/Android/.test(t)&&!/Chrome\/\d/.test(t)){var e=t.match(/Safari\/(\d+.\d)/);return!(e&&"object"==typeof e&&e.length>=2)||parseFloat(e[1])<535.19}return!1}(),t.extend(t.style={},{transform:a,transitionTimingFunction:s("transitionTimingFunction"),transitionDuration:s("transitionDuration"),transitionDelay:s("transitionDelay"),transformOrigin:s("transformOrigin")}),t.hasClass=function(t,e){return new RegExp("(^|\\s)"+e+"(\\s|$)").test(t.className)},t.addClass=function(e,i){if(!t.hasClass(e,i)){var s=e.className.split(" ");s.push(i),e.className=s.join(" ")}},t.removeClass=function(e,i){if(t.hasClass(e,i)){var s=new RegExp("(^|\\s)"+i+"(\\s|$)","g");e.className=e.className.replace(s," ")}},t.offset=function(t){for(var e=-t.offsetLeft,i=-t.offsetTop;t=t.offsetParent;)e-=t.offsetLeft,i-=t.offsetTop;return{left:e,top:i}},t.preventDefaultException=function(t,e){for(var i in e)if(e[i].test(t[i]))return!0;return!1},t.extend(t.eventType={},{touchstart:1,touchmove:1,touchend:1,mousedown:2,mousemove:2,mouseup:2,pointerdown:3,pointermove:3,pointerup:3,MSPointerDown:3,MSPointerMove:3,MSPointerUp:3}),t.extend(t.ease={},{quadratic:{style:"cubic-bezier(0.25, 0.46, 0.45, 0.94)",fn:function(t){return t*(2-t)}},circular:{style:"cubic-bezier(0.1, 0.57, 0.1, 1)",fn:function(t){return r.sqrt(1- --t*t)}},back:{style:"cubic-bezier(0.175, 0.885, 0.32, 1.275)",fn:function(t){return(t-=1)*t*(5*t+4)+1}},bounce:{style:"",fn:function(t){return(t/=1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}},elastic:{style:"",fn:function(t){return 0===t?0:1==t?1:.4*r.pow(2,-10*t)*r.sin((t-.055)*(2*r.PI)/.22)+1}}}),t.tap=function(t,e){var i=n.createEvent("Event");i.initEvent(e,!0,!0),i.pageX=t.pageX,i.pageY=t.pageY,t.target.dispatchEvent(i)},t.click=function(t){var e,i=t.target;/(SELECT|INPUT|TEXTAREA)/i.test(i.tagName)||((e=n.createEvent("MouseEvents")).initMouseEvent("click",!0,!0,t.view,1,i.screenX,i.screenY,i.clientX,i.clientY,t.ctrlKey,t.altKey,t.shiftKey,t.metaKey,0,null),e._constructed=!0,i.dispatchEvent(e))},t}();function h(t,e){for(var i in this.wrapper="string"==typeof t?n.querySelector(t):t,this.scroller=this.wrapper.children[0],this.scrollerStyle=this.scroller.style,this.options={resizeScrollbars:!0,mouseWheelSpeed:20,snapThreshold:.334,disablePointer:!l.hasPointer,disableTouch:l.hasPointer||!l.hasTouch,disableMouse:l.hasPointer||l.hasTouch,startX:0,startY:0,scrollY:!0,directionLockThreshold:5,momentum:!0,bounce:!0,bounceTime:600,bounceEasing:"",preventDefault:!0,preventDefaultException:{tagName:/^(INPUT|TEXTAREA|BUTTON|SELECT)$/},HWCompositing:!0,useTransition:!0,useTransform:!0,bindToWrapper:void 0===o.onmousedown},e)this.options[i]=e[i];this.translateZ=this.options.HWCompositing&&l.hasPerspective?" translateZ(0)":"",this.options.useTransition=l.hasTransition&&this.options.useTransition,this.options.useTransform=l.hasTransform&&this.options.useTransform,this.options.eventPassthrough=!0===this.options.eventPassthrough?"vertical":this.options.eventPassthrough,this.options.preventDefault=!this.options.eventPassthrough&&this.options.preventDefault,this.options.scrollY="vertical"!=this.options.eventPassthrough&&this.options.scrollY,this.options.scrollX="horizontal"!=this.options.eventPassthrough&&this.options.scrollX,this.options.freeScroll=this.options.freeScroll&&!this.options.eventPassthrough,this.options.directionLockThreshold=this.options.eventPassthrough?0:this.options.directionLockThreshold,this.options.bounceEasing="string"==typeof this.options.bounceEasing?l.ease[this.options.bounceEasing]||l.ease.circular:this.options.bounceEasing,this.options.resizePolling=void 0===this.options.resizePolling?60:this.options.resizePolling,!0===this.options.tap&&(this.options.tap="tap"),"scale"==this.options.shrinkScrollbars&&(this.options.useTransition=!1),this.options.invertWheelDirection=this.options.invertWheelDirection?-1:1,this.x=0,this.y=0,this.directionX=0,this.directionY=0,this._events={},this._init(),this.refresh(),this.scrollTo(this.options.startX,this.options.startY),this.enable()}function c(t,e,i){var s=n.createElement("div"),o=n.createElement("div");return!0===i&&(s.style.cssText="position:absolute;z-index:9999",o.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px"),o.className="iScrollIndicator","h"==t?(!0===i&&(s.style.cssText+=";height:7px;left:2px;right:2px;bottom:0",o.style.height="100%"),s.className="iScrollHorizontalScrollbar"):(!0===i&&(s.style.cssText+=";width:7px;bottom:2px;top:2px;right:1px",o.style.width="100%"),s.className="iScrollVerticalScrollbar"),s.style.cssText+=";overflow:hidden",e||(s.style.pointerEvents="none"),s.appendChild(o),s}function p(t,e){for(var i in this.wrapper="string"==typeof e.el?n.querySelector(e.el):e.el,this.wrapperStyle=this.wrapper.style,this.indicator=this.wrapper.children[0],this.indicatorStyle=this.indicator.style,this.scroller=t,this.options={listenX:!0,listenY:!0,interactive:!1,resize:!0,defaultScrollbars:!1,shrink:!1,fade:!1,speedRatioX:0,speedRatioY:0},e)this.options[i]=e[i];if(this.sizeRatioX=1,this.sizeRatioY=1,this.maxPosX=0,this.maxPosY=0,this.options.interactive&&(this.options.disableTouch||(l.addEvent(this.indicator,"touchstart",this),l.addEvent(o,"touchend",this)),this.options.disablePointer||(l.addEvent(this.indicator,l.prefixPointerEvent("pointerdown"),this),l.addEvent(o,l.prefixPointerEvent("pointerup"),this)),this.options.disableMouse||(l.addEvent(this.indicator,"mousedown",this),l.addEvent(o,"mouseup",this))),this.options.fade){this.wrapperStyle[l.style.transform]=this.scroller.translateZ;var s=l.style.transitionDuration;this.wrapperStyle[s]=l.isBadAndroid?"0.0001ms":"0ms";var r=this;l.isBadAndroid&&a((function(){"0.0001ms"===r.wrapperStyle[s]&&(r.wrapperStyle[s]="0s")})),this.wrapperStyle.opacity="0"}}h.prototype={version:"5.2.0",_init:function(){this._initEvents(),(this.options.scrollbars||this.options.indicators)&&this._initIndicators(),this.options.mouseWheel&&this._initWheel(),this.options.snap&&this._initSnap(),this.options.keyBindings&&this._initKeys()},destroy:function(){this._initEvents(!0),clearTimeout(this.resizeTimeout),this.resizeTimeout=null,this._execEvent("destroy")},_transitionEnd:function(t){t.target==this.scroller&&this.isInTransition&&(this._transitionTime(),this.resetPosition(this.options.bounceTime)||(this.isInTransition=!1,this._execEvent("scrollEnd")))},_start:function(t){if((1==l.eventType[t.type]||0===(t.which?t.button:t.button<2?0:4==t.button?1:2))&&this.enabled&&(!this.initiated||l.eventType[t.type]===this.initiated)){!this.options.preventDefault||l.isBadAndroid||l.preventDefaultException(t.target,this.options.preventDefaultException)||t.preventDefault();var e,i=t.touches?t.touches[0]:t;this.initiated=l.eventType[t.type],this.moved=!1,this.distX=0,this.distY=0,this.directionX=0,this.directionY=0,this.directionLocked=0,this.startTime=l.getTime(),this.options.useTransition&&this.isInTransition?(this._transitionTime(),this.isInTransition=!1,e=this.getComputedPosition(),this._translate(r.round(e.x),r.round(e.y)),this._execEvent("scrollEnd")):!this.options.useTransition&&this.isAnimating&&(this.isAnimating=!1,this._execEvent("scrollEnd")),this.startX=this.x,this.startY=this.y,this.absStartX=this.x,this.absStartY=this.y,this.pointX=i.pageX,this.pointY=i.pageY,this._execEvent("beforeScrollStart")}},_move:function(t){if(this.enabled&&l.eventType[t.type]===this.initiated){this.options.preventDefault&&t.preventDefault();var e,i,s,o,n=t.touches?t.touches[0]:t,a=n.pageX-this.pointX,h=n.pageY-this.pointY,c=l.getTime();if(this.pointX=n.pageX,this.pointY=n.pageY,this.distX+=a,this.distY+=h,s=r.abs(this.distX),o=r.abs(this.distY),!(c-this.endTime>300&&s<10&&o<10)){if(this.directionLocked||this.options.freeScroll||(s>o+this.options.directionLockThreshold?this.directionLocked="h":o>=s+this.options.directionLockThreshold?this.directionLocked="v":this.directionLocked="n"),"h"==this.directionLocked){if("vertical"==this.options.eventPassthrough)t.preventDefault();else if("horizontal"==this.options.eventPassthrough)return void(this.initiated=!1);h=0}else if("v"==this.directionLocked){if("horizontal"==this.options.eventPassthrough)t.preventDefault();else if("vertical"==this.options.eventPassthrough)return void(this.initiated=!1);a=0}a=this.hasHorizontalScroll?a:0,h=this.hasVerticalScroll?h:0,e=this.x+a,i=this.y+h,(e>0||e0?0:this.maxScrollX),(i>0||i0?0:this.maxScrollY),this.directionX=a>0?-1:a<0?1:0,this.directionY=h>0?-1:h<0?1:0,this.moved||this._execEvent("scrollStart"),this.moved=!0,this._translate(e,i),c-this.startTime>300&&(this.startTime=c,this.startX=this.x,this.startY=this.y)}}},_end:function(t){if(this.enabled&&l.eventType[t.type]===this.initiated){this.options.preventDefault&&!l.preventDefaultException(t.target,this.options.preventDefaultException)&&t.preventDefault(),t.changedTouches&&t.changedTouches[0];var e,i,s=l.getTime()-this.startTime,o=r.round(this.x),n=r.round(this.y),a=r.abs(o-this.startX),h=r.abs(n-this.startY),c=0,p="";if(this.isInTransition=0,this.initiated=0,this.endTime=l.getTime(),!this.resetPosition(this.options.bounceTime)){if(this.scrollTo(o,n),!this.moved)return this.options.tap&&l.tap(t,this.options.tap),this.options.click&&l.click(t),void this._execEvent("scrollCancel");if(this._events.flick&&s<200&&a<100&&h<100)this._execEvent("flick");else{if(this.options.momentum&&s<300&&(e=this.hasHorizontalScroll?l.momentum(this.x,this.startX,s,this.maxScrollX,this.options.bounce?this.wrapperWidth:0,this.options.deceleration):{destination:o,duration:0},i=this.hasVerticalScroll?l.momentum(this.y,this.startY,s,this.maxScrollY,this.options.bounce?this.wrapperHeight:0,this.options.deceleration):{destination:n,duration:0},o=e.destination,n=i.destination,c=r.max(e.duration,i.duration),this.isInTransition=1),this.options.snap){var d=this._nearestSnap(o,n);this.currentPage=d,c=this.options.snapSpeed||r.max(r.max(r.min(r.abs(o-d.x),1e3),r.min(r.abs(n-d.y),1e3)),300),o=d.x,n=d.y,this.directionX=0,this.directionY=0,p=this.options.bounceEasing}if(o!=this.x||n!=this.y)return(o>0||o0||n0?e=0:this.x0?i=0:this.y-1&&this._events[t].splice(i,1)}},_execEvent:function(t){if(this._events[t]){var e=0,i=this._events[t].length;if(i)for(;e0;var o=this.options.useTransition&&s.style;!i||o?(o&&(this._transitionTimingFunction(s.style),this._transitionTime(i)),this._translate(t,e)):this._animate(t,e,i,s.fn)},scrollToElement:function(t,e,i,s,o){if(t=t.nodeType?t:this.scroller.querySelector(t)){var n=l.offset(t);n.left-=this.wrapperOffset.left,n.top-=this.wrapperOffset.top,!0===i&&(i=r.round(t.offsetWidth/2-this.wrapper.offsetWidth/2)),!0===s&&(s=r.round(t.offsetHeight/2-this.wrapper.offsetHeight/2)),n.left-=i||0,n.top-=s||0,n.left=n.left>0?0:n.left0?0:n.top0?s--:e<0&&s++,i>0?o--:i<0&&o++,void this.goToPage(s,o);s=this.x+r.round(this.hasHorizontalScroll?e:0),o=this.y+r.round(this.hasVerticalScroll?i:0),this.directionX=e>0?-1:e<0?1:0,this.directionY=i>0?-1:i<0?1:0,s>0?s=0:s0?o=0:o-this.scrollerWidth;){for(this.pages[a]=[],t=0,o=0;o>-this.scrollerHeight;)this.pages[a][t]={x:r.max(h,this.maxScrollX),y:r.max(o,this.maxScrollY),width:c,height:p,cx:h-i,cy:o-s},o-=p,t++;h-=c,a++}else for(t=(n=this.options.snap).length,e=-1;athis.maxScrollX&&l++;this.goToPage(this.currentPage.pageX||0,this.currentPage.pageY||0,0),this.options.snapThreshold%1==0?(this.snapThresholdX=this.options.snapThreshold,this.snapThresholdY=this.options.snapThreshold):(this.snapThresholdX=r.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width*this.options.snapThreshold),this.snapThresholdY=r.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height*this.options.snapThreshold))}})),this.on("flick",(function(){var t=this.options.snapSpeed||r.max(r.max(r.min(r.abs(this.x-this.startX),1e3),r.min(r.abs(this.y-this.startY),1e3)),300);this.goToPage(this.currentPage.pageX+this.directionX,this.currentPage.pageY+this.directionY,t)}))},_nearestSnap:function(t,e){if(!this.pages.length)return{x:0,y:0,pageX:0,pageY:0};var i=0,s=this.pages.length,o=0;if(r.abs(t-this.absStartX)0?t=0:t0?e=0:e=this.pages[i][0].cx){t=this.pages[i][0].x;break}for(s=this.pages[i].length;o=this.pages[0][o].cy){e=this.pages[0][o].y;break}return i==this.currentPage.pageX&&((i+=this.directionX)<0?i=0:i>=this.pages.length&&(i=this.pages.length-1),t=this.pages[i][0].x),o==this.currentPage.pageY&&((o+=this.directionY)<0?o=0:o>=this.pages[0].length&&(o=this.pages[0].length-1),e=this.pages[0][o].y),{x:t,y:e,pageX:i,pageY:o}},goToPage:function(t,e,i,s){s=s||this.options.bounceEasing,t>=this.pages.length?t=this.pages.length-1:t<0&&(t=0),e>=this.pages[t].length?e=this.pages[t].length-1:e<0&&(e=0);var o=this.pages[t][e].x,n=this.pages[t][e].y;i=void 0===i?this.options.snapSpeed||r.max(r.max(r.min(r.abs(o-this.x),1e3),r.min(r.abs(n-this.y),1e3)),300):i,this.currentPage={x:o,y:n,pageX:t,pageY:e},this.scrollTo(o,n,i,s)},next:function(t,e){var i=this.currentPage.pageX,s=this.currentPage.pageY;++i>=this.pages.length&&this.hasVerticalScroll&&(i=0,s++),this.goToPage(i,s,t,e)},prev:function(t,e){var i=this.currentPage.pageX,s=this.currentPage.pageY;--i<0&&this.hasVerticalScroll&&(i=0,s--),this.goToPage(i,s,t,e)},_initKeys:function(t){var e,i={pageUp:33,pageDown:34,end:35,home:36,left:37,up:38,right:39,down:40};if("object"==typeof this.options.keyBindings)for(e in this.options.keyBindings)"string"==typeof this.options.keyBindings[e]&&(this.options.keyBindings[e]=this.options.keyBindings[e].toUpperCase().charCodeAt(0));else this.options.keyBindings={};for(e in i)this.options.keyBindings[e]=this.options.keyBindings[e]||i[e];l.addEvent(o,"keydown",this),this.on("destroy",(function(){l.removeEvent(o,"keydown",this)}))},_key:function(t){if(this.enabled){var e,i=this.options.snap,s=i?this.currentPage.pageX:this.x,o=i?this.currentPage.pageY:this.y,n=l.getTime(),a=this.keyTime||0;switch(this.options.useTransition&&this.isInTransition&&(e=this.getComputedPosition(),this._translate(r.round(e.x),r.round(e.y)),this.isInTransition=!1),this.keyAcceleration=n-a<200?r.min(this.keyAcceleration+.25,50):0,t.keyCode){case this.options.keyBindings.pageUp:this.hasHorizontalScroll&&!this.hasVerticalScroll?s+=i?1:this.wrapperWidth:o+=i?1:this.wrapperHeight;break;case this.options.keyBindings.pageDown:this.hasHorizontalScroll&&!this.hasVerticalScroll?s-=i?1:this.wrapperWidth:o-=i?1:this.wrapperHeight;break;case this.options.keyBindings.end:s=i?this.pages.length-1:this.maxScrollX,o=i?this.pages[0].length-1:this.maxScrollY;break;case this.options.keyBindings.home:s=0,o=0;break;case this.options.keyBindings.left:s+=i?-1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.up:o+=i?1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.right:s-=i?-1:5+this.keyAcceleration>>0;break;case this.options.keyBindings.down:o-=i?1:5+this.keyAcceleration>>0;break;default:return}i?this.goToPage(s,o):(s>0?(s=0,this.keyAcceleration=0):s0?(o=0,this.keyAcceleration=0):o=c)return o.isAnimating=!1,o._translate(t,e),void(o.resetPosition(o.options.bounceTime)||o._execEvent("scrollEnd"));f=s(m=(m-h)/i),d=(t-n)*f+n,u=(e-r)*f+r,o._translate(d,u),o.isAnimating&&a(p)}()},handleEvent:function(t){switch(t.type){case"touchstart":case"pointerdown":case"MSPointerDown":case"mousedown":this._start(t);break;case"touchmove":case"pointermove":case"MSPointerMove":case"mousemove":this._move(t);break;case"touchend":case"pointerup":case"MSPointerUp":case"mouseup":case"touchcancel":case"pointercancel":case"MSPointerCancel":case"mousecancel":this._end(t);break;case"orientationchange":case"resize":this._resize();break;case"transitionend":case"webkitTransitionEnd":case"oTransitionEnd":case"MSTransitionEnd":this._transitionEnd(t);break;case"wheel":case"DOMMouseScroll":case"mousewheel":this._wheel(t);break;case"keydown":this._key(t);break;case"click":this.enabled&&!t._constructed&&(t.preventDefault(),t.stopPropagation())}}},p.prototype={handleEvent:function(t){switch(t.type){case"touchstart":case"pointerdown":case"MSPointerDown":case"mousedown":this._start(t);break;case"touchmove":case"pointermove":case"MSPointerMove":case"mousemove":this._move(t);break;case"touchend":case"pointerup":case"MSPointerUp":case"mouseup":case"touchcancel":case"pointercancel":case"MSPointerCancel":case"mousecancel":this._end(t)}},destroy:function(){this.options.fadeScrollbars&&(clearTimeout(this.fadeTimeout),this.fadeTimeout=null),this.options.interactive&&(l.removeEvent(this.indicator,"touchstart",this),l.removeEvent(this.indicator,l.prefixPointerEvent("pointerdown"),this),l.removeEvent(this.indicator,"mousedown",this),l.removeEvent(o,"touchmove",this),l.removeEvent(o,l.prefixPointerEvent("pointermove"),this),l.removeEvent(o,"mousemove",this),l.removeEvent(o,"touchend",this),l.removeEvent(o,l.prefixPointerEvent("pointerup"),this),l.removeEvent(o,"mouseup",this)),this.options.defaultScrollbars&&this.wrapper.parentNode.removeChild(this.wrapper)},_start:function(t){var e=t.touches?t.touches[0]:t;t.preventDefault(),t.stopPropagation(),this.transitionTime(),this.initiated=!0,this.moved=!1,this.lastPointX=e.pageX,this.lastPointY=e.pageY,this.startTime=l.getTime(),this.options.disableTouch||l.addEvent(o,"touchmove",this),this.options.disablePointer||l.addEvent(o,l.prefixPointerEvent("pointermove"),this),this.options.disableMouse||l.addEvent(o,"mousemove",this),this.scroller._execEvent("beforeScrollStart")},_move:function(t){var e,i,s,o,n=t.touches?t.touches[0]:t;l.getTime(),this.moved||this.scroller._execEvent("scrollStart"),this.moved=!0,e=n.pageX-this.lastPointX,this.lastPointX=n.pageX,i=n.pageY-this.lastPointY,this.lastPointY=n.pageY,s=this.x+e,o=this.y+i,this._pos(s,o),t.preventDefault(),t.stopPropagation()},_end:function(t){if(this.initiated){if(this.initiated=!1,t.preventDefault(),t.stopPropagation(),l.removeEvent(o,"touchmove",this),l.removeEvent(o,l.prefixPointerEvent("pointermove"),this),l.removeEvent(o,"mousemove",this),this.scroller.options.snap){var e=this.scroller._nearestSnap(this.scroller.x,this.scroller.y),i=this.options.snapSpeed||r.max(r.max(r.min(r.abs(this.scroller.x-e.x),1e3),r.min(r.abs(this.scroller.y-e.y),1e3)),300);this.scroller.x==e.x&&this.scroller.y==e.y||(this.scroller.directionX=0,this.scroller.directionY=0,this.scroller.currentPage=e,this.scroller.scrollTo(e.x,e.y,i,this.scroller.options.bounceEasing))}this.moved&&this.scroller._execEvent("scrollEnd")}},transitionTime:function(t){t=t||0;var e=l.style.transitionDuration;if(this.indicatorStyle[e]=t+"ms",!t&&l.isBadAndroid){this.indicatorStyle[e]="0.0001ms";var i=this;a((function(){"0.0001ms"===i.indicatorStyle[e]&&(i.indicatorStyle[e]="0s")}))}},transitionTimingFunction:function(t){this.indicatorStyle[l.style.transitionTimingFunction]=t},refresh:function(){this.transitionTime(),this.options.listenX&&!this.options.listenY?this.indicatorStyle.display=this.scroller.hasHorizontalScroll?"block":"none":this.options.listenY&&!this.options.listenX?this.indicatorStyle.display=this.scroller.hasVerticalScroll?"block":"none":this.indicatorStyle.display=this.scroller.hasHorizontalScroll||this.scroller.hasVerticalScroll?"block":"none",this.scroller.hasHorizontalScroll&&this.scroller.hasVerticalScroll?(l.addClass(this.wrapper,"iScrollBothScrollbars"),l.removeClass(this.wrapper,"iScrollLoneScrollbar"),this.options.defaultScrollbars&&this.options.customStyle&&(this.options.listenX?this.wrapper.style.right="8px":this.wrapper.style.bottom="8px")):(l.removeClass(this.wrapper,"iScrollBothScrollbars"),l.addClass(this.wrapper,"iScrollLoneScrollbar"),this.options.defaultScrollbars&&this.options.customStyle&&(this.options.listenX?this.wrapper.style.right="2px":this.wrapper.style.bottom="2px")),this.wrapper.offsetHeight,this.options.listenX&&(this.wrapperWidth=this.wrapper.clientWidth,this.options.resize?(this.indicatorWidth=r.max(r.round(this.wrapperWidth*this.wrapperWidth/(this.scroller.scrollerWidth||this.wrapperWidth||1)),8),this.indicatorStyle.width=this.indicatorWidth+"px"):this.indicatorWidth=this.indicator.clientWidth,this.maxPosX=this.wrapperWidth-this.indicatorWidth,"clip"==this.options.shrink?(this.minBoundaryX=8-this.indicatorWidth,this.maxBoundaryX=this.wrapperWidth-8):(this.minBoundaryX=0,this.maxBoundaryX=this.maxPosX),this.sizeRatioX=this.options.speedRatioX||this.scroller.maxScrollX&&this.maxPosX/this.scroller.maxScrollX),this.options.listenY&&(this.wrapperHeight=this.wrapper.clientHeight,this.options.resize?(this.indicatorHeight=r.max(r.round(this.wrapperHeight*this.wrapperHeight/(this.scroller.scrollerHeight||this.wrapperHeight||1)),8),this.indicatorStyle.height=this.indicatorHeight+"px"):this.indicatorHeight=this.indicator.clientHeight,this.maxPosY=this.wrapperHeight-this.indicatorHeight,"clip"==this.options.shrink?(this.minBoundaryY=8-this.indicatorHeight,this.maxBoundaryY=this.wrapperHeight-8):(this.minBoundaryY=0,this.maxBoundaryY=this.maxPosY),this.maxPosY=this.wrapperHeight-this.indicatorHeight,this.sizeRatioY=this.options.speedRatioY||this.scroller.maxScrollY&&this.maxPosY/this.scroller.maxScrollY),this.updatePosition()},updatePosition:function(){var t=this.options.listenX&&r.round(this.sizeRatioX*this.scroller.x)||0,e=this.options.listenY&&r.round(this.sizeRatioY*this.scroller.y)||0;this.options.ignoreBoundaries||(tthis.maxBoundaryX?"scale"==this.options.shrink?(this.width=r.max(this.indicatorWidth-(t-this.maxPosX),8),this.indicatorStyle.width=this.width+"px",t=this.maxPosX+this.indicatorWidth-this.width):t=this.maxBoundaryX:"scale"==this.options.shrink&&this.width!=this.indicatorWidth&&(this.width=this.indicatorWidth,this.indicatorStyle.width=this.width+"px"),ethis.maxBoundaryY?"scale"==this.options.shrink?(this.height=r.max(this.indicatorHeight-3*(e-this.maxPosY),8),this.indicatorStyle.height=this.height+"px",e=this.maxPosY+this.indicatorHeight-this.height):e=this.maxBoundaryY:"scale"==this.options.shrink&&this.height!=this.indicatorHeight&&(this.height=this.indicatorHeight,this.indicatorStyle.height=this.height+"px")),this.x=t,this.y=e,this.scroller.options.useTransform?this.indicatorStyle[l.style.transform]="translate("+t+"px,"+e+"px)"+this.scroller.translateZ:(this.indicatorStyle.left=t+"px",this.indicatorStyle.top=e+"px")},_pos:function(t,e){t<0?t=0:t>this.maxPosX&&(t=this.maxPosX),e<0?e=0:e>this.maxPosY&&(e=this.maxPosY),t=this.options.listenX?r.round(t/this.sizeRatioX):this.scroller.x,e=this.options.listenY?r.round(e/this.sizeRatioY):this.scroller.y,this.scroller.scrollTo(t,e)},fade:function(t,e){if(!e||this.visible){clearTimeout(this.fadeTimeout),this.fadeTimeout=null;var i=t?250:500,s=t?0:300;t=t?"1":"0",this.wrapperStyle[l.style.transitionDuration]=i+"ms",this.fadeTimeout=setTimeout(function(t){this.wrapperStyle.opacity=t,this.visible=+t}.bind(this,t),s)}}},h.utils=l,t.exports?t.exports=h:void 0===(s=function(){return h}.call(e,i,e,t))||(t.exports=s)}(window,document,Math)},795:function(t,e,i){var s;t=i.nmd(t),function(){"use strict";var o={function:!0,object:!0},n=o[typeof window]&&window||this,r=o[typeof e]&&e,a=o.object&&t&&!t.nodeType&&t,l=r&&a&&"object"==typeof i.g&&i.g;!l||l.global!==l&&l.window!==l&&l.self!==l||(n=l);var h=Math.pow(2,53)-1,c=/\bOpera/,p=Object.prototype,d=p.hasOwnProperty,u=p.toString;function f(t){return(t=String(t)).charAt(0).toUpperCase()+t.slice(1)}function m(t){return t=x(t),/^(?:webOS|i(?:OS|P))/.test(t)?t:f(t)}function b(t,e){for(var i in t)d.call(t,i)&&e(t[i],i,t)}function g(t){return null==t?f(t):u.call(t).slice(8,-1)}function v(t){return String(t).replace(/([ -])(?!$)/g,"$1?")}function S(t,e){var i=null;return function(t,e){var i=-1,s=t?t.length:0;if("number"==typeof s&&s>-1&&s<=h)for(;++i3?"WebKit":/\bOpera\b/.test(I)&&(/\bOPR\b/.test(e)?"Blink":"Presto"))||/\b(?:Midori|Nook|Safari)\b/i.test(e)&&!/^(?:Trident|EdgeHTML)$/.test(H)&&"WebKit"||!H&&/\bMSIE\b/i.test(e)&&("Mac OS"==F?"Tasman":"Trident")||"WebKit"==H&&/\bPlayStation\b(?! Vita\b)/i.test(I)&&"NetFront")&&(H=[a]),"IE"==I&&(a=(/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(e)||0)[1])?(I+=" Mobile",F="Windows Phone "+(/\+$/.test(a)?a:a+".x"),B.unshift("desktop mode")):/\bWPDesktop\b/i.test(e)?(I="IE Mobile",F="Windows Phone 8.x",B.unshift("desktop mode"),D||(D=(/\brv:([\d.]+)/.exec(e)||0)[1])):"IE"!=I&&"Trident"==H&&(a=/\brv:([\d.]+)/.exec(e))&&(I&&B.push("identifying as "+I+(D?" "+D:"")),I="IE",D=a[1]),z){if(p="global",d=null!=(h=i)?typeof h[p]:"number",/^(?:boolean|number|string|undefined)$/.test(d)||"object"==d&&!h[p])g(a=i.runtime)==w?(I="Adobe AIR",F=a.flash.system.Capabilities.os):g(a=i.phantom)==P?(I="PhantomJS",D=(a=a.version||null)&&a.major+"."+a.minor+"."+a.patch):"number"==typeof W.documentMode&&(a=/\bTrident\/(\d+)/i.exec(e))?(D=[D,W.documentMode],(a=+a[1]+4)!=D[1]&&(B.push("IE "+D[1]+" mode"),H&&(H[1]=""),D[1]=a),D="IE"==I?String(D[1].toFixed(1)):D[0]):"number"==typeof W.documentMode&&/^(?:Chrome|Firefox)\b/.test(I)&&(B.push("masking as "+I+" "+D),I="IE",D="11.0",H=["Trident"],F="Windows");else if(k&&(C=(a=k.lang.System).getProperty("os.arch"),F=F||a.getProperty("os.name")+" "+a.getProperty("os.version")),X){try{D=i.require("ringo/engine").version.join("."),I="RingoJS"}catch(t){(a=i.system)&&a.global.system==i.system&&(I="Narwhal",F||(F=a[0].os||null))}I||(I="Rhino")}else"object"==typeof i.process&&!i.process.browser&&(a=i.process)&&("object"==typeof a.versions&&("string"==typeof a.versions.electron?(B.push("Node "+a.versions.node),I="Electron",D=a.versions.electron):"string"==typeof a.versions.nw&&(B.push("Chromium "+D,"Node "+a.versions.node),I="NW.js",D=a.versions.nw)),I||(I="Node.js",C=a.arch,F=a.platform,D=(D=/[\d.]+/.exec(a.version))?D[0]:null));F=F&&m(F)}if(D&&(a=/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(D)||/(?:alpha|beta)(?: ?\d)?/i.exec(e+";"+(z&&o.appMinorVersion))||/\bMinefield\b/i.test(e)&&"a")&&(A=/b/i.test(a)?"beta":"alpha",D=D.replace(RegExp(a+"\\+?$"),"")+("beta"==A?M:Y)+(/\d+\+?/.exec(a)||"")),"Fennec"==I||"Firefox"==I&&/\b(?:Android|Firefox OS|KaiOS)\b/.test(F))I="Firefox Mobile";else if("Maxthon"==I&&D)D=D.replace(/\.[\d.]+/,".x");else if(/\bXbox\b/i.test(R))"Xbox 360"==R&&(F=null),"Xbox 360"==R&&/\bIEMobile\b/.test(e)&&B.unshift("mobile mode");else if(!/^(?:Chrome|IE|Opera)$/.test(I)&&(!I||R||/Browser|Mobi/.test(I))||"Windows CE"!=F&&!/Mobi/i.test(e))if("IE"==I&&z)try{null===i.external&&B.unshift("platform preview")}catch(t){B.unshift("embedded")}else(/\bBlackBerry\b/.test(R)||/\bBB10\b/.test(e))&&(a=(RegExp(R.replace(/ +/g," *")+"/([.\\d]+)","i").exec(e)||0)[1]||D)?(F=((a=[a,/BB10/.test(e)])[1]?(R=null,$="BlackBerry"):"Device Software")+" "+a[0],D=null):this!=b&&"Wii"!=R&&(z&&O||/Opera/.test(I)&&/\b(?:MSIE|Firefox)\b/i.test(e)||"Firefox"==I&&/\bOS X (?:\d+\.){2,}/.test(F)||"IE"==I&&(F&&!/^Win/.test(F)&&D>5.5||/\bWindows XP\b/.test(F)&&D>8||8==D&&!/\bTrident\b/.test(e)))&&!c.test(a=t.call(b,e.replace(c,"")+";"))&&a.name&&(a="ing as "+a.name+((a=a.version)?" "+a:""),c.test(I)?(/\bIE\b/.test(a)&&"Mac OS"==F&&(F=null),a="identify"+a):(a="mask"+a,I=_?m(_.replace(/([a-z])([A-Z])/g,"$1 $2")):"Opera",/\bIE\b/.test(a)&&(F=null),z||(D=null)),H=["Presto"],B.push(a));else I+=" Mobile";(a=(/\bAppleWebKit\/([\d.]+\+?)/i.exec(e)||0)[1])&&(a=[parseFloat(a.replace(/\.(\d)$/,".0$1")),a],"Safari"==I&&"+"==a[1].slice(-1)?(I="WebKit Nightly",A="alpha",D=a[1].slice(0,-1)):D!=a[1]&&D!=(a[2]=(/\bSafari\/([\d.]+\+?)/i.exec(e)||0)[1])||(D=null),a[1]=(/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(e)||0)[1],537.36==a[0]&&537.36==a[2]&&parseFloat(a[1])>=28&&"WebKit"==H&&(H=["Blink"]),z&&(f||a[1])?(H&&(H[1]="like Chrome"),a=a[1]||((a=a[0])<530?1:a<532?2:a<532.05?3:a<533?4:a<534.03?5:a<534.07?6:a<534.1?7:a<534.13?8:a<534.16?9:a<534.24?10:a<534.3?11:a<535.01?12:a<535.02?"13+":a<535.07?15:a<535.11?16:a<535.19?17:a<536.05?18:a<536.1?19:a<537.01?20:a<537.11?"21+":a<537.13?23:a<537.18?24:a<537.24?25:a<537.36?26:"Blink"!=H?"27":"28")):(H&&(H[1]="like Safari"),a=(a=a[0])<400?1:a<500?2:a<526?3:a<533?4:a<534?"4+":a<535?5:a<537?6:a<538?7:a<601?8:a<602?9:a<604?10:a<606?11:a<608?12:"12"),H&&(H[1]+=" "+(a+="number"==typeof a?".x":/[.+]/.test(a)?"":"+")),"Safari"==I&&(!D||parseInt(D)>45)?D=a:"Chrome"==I&&/\bHeadlessChrome/i.test(e)&&B.unshift("headless")),"Opera"==I&&(a=/\bzbov|zvav$/.exec(F))?(I+=" ",B.unshift("desktop mode"),"zvav"==a?(I+="Mini",D=null):I+="Mobile",F=F.replace(RegExp(" *"+a+"$"),"")):"Safari"==I&&/\bChrome\b/.exec(H&&H[1])?(B.unshift("desktop mode"),I="Chrome Mobile",D=null,/\bOS X\b/.test(F)?($="Apple",F="iOS 4.3+"):F=null):/\bSRWare Iron\b/.test(I)&&!D&&(D=L("Chrome")),D&&0==D.indexOf(a=/[\d.]+$/.exec(F))&&e.indexOf("/"+a+"-")>-1&&(F=x(F.replace(a,""))),F&&-1!=F.indexOf(I)&&!RegExp(I+" OS").test(F)&&(F=F.replace(RegExp(" *"+v(I)+" *"),"")),H&&!/\b(?:Avant|Nook)\b/.test(I)&&(/Browser|Lunascape|Maxthon/.test(I)||"Safari"!=I&&/^iOS/.test(F)&&/\bSafari\b/.test(H[1])||/^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(I)&&H[1])&&(a=H[H.length-1])&&B.push(a),B.length&&(B=["("+B.join("; ")+")"]),$&&R&&R.indexOf($)<0&&B.push("on "+$),R&&B.push((/^on /.test(B[B.length-1])?"":"on ")+R),F&&(a=/ ([\d.+]+)$/.exec(F),l=a&&"/"==F.charAt(F.length-a[0].length-1),F={architecture:32,family:a&&!l?F.replace(a[0],""):F,version:a?a[1]:null,toString:function(){var t=this.version;return this.family+(t&&!l?" "+t:"")+(64==this.architecture?" 64-bit":"")}}),(a=/\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(C))&&!/\bi686\b/i.test(C)?(F&&(F.architecture=64,F.family=F.family.replace(RegExp(" *"+a),"")),I&&(/\bWOW64\b/i.test(e)||z&&/\w(?:86|32)$/.test(o.cpuClass||o.platform)&&!/\bWin64; x64\b/i.test(e))&&B.unshift("32-bit")):F&&/^OS X/.test(F.family)&&"Chrome"==I&&parseFloat(D)>=39&&(F.architecture=64),e||(e=null);var j={};return j.description=e,j.layout=H&&H[0],j.manufacturer=$,j.name=I,j.prerelease=A,j.product=R,j.ua=e,j.version=I&&D,j.os=F||{architecture:null,family:null,version:null,toString:function(){return"null"}},j.parse=t,j.toString=function(){return this.description||""},j.version&&B.unshift(D),j.name&&B.unshift(I),F&&I&&(F!=String(F).split(" ")[0]||F!=I.split(" ")[0]&&!R)&&B.push(R?"("+F+")":"on "+F),B.length&&(j.description=B.join(" ")),j}();n.platform=y,void 0===(s=function(){return y}.call(e,i,e,t))||(t.exports=s)}.call(this)},703:function(e){"use strict";e.exports=t}},i={};function s(t){var o=i[t];if(void 0!==o)return o.exports;var n=i[t]={id:t,loaded:!1,exports:{}};return e[t].call(n.exports,n,n.exports,s),n.loaded=!0,n.exports}s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,{a:e}),e},s.d=function(t,e){for(var i in e)s.o(e,i)&&!s.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},s.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.nmd=function(t){return t.paths=[],t.children||(t.children=[]),t},function(){var t;s.g.importScripts&&(t=s.g.location+"");var e=s.g.document;if(!t&&e&&(e.currentScript&&(t=e.currentScript.src),!t)){var i=e.getElementsByTagName("script");if(i.length)for(var o=i.length-1;o>-1&&!t;)t=i[o--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),s.p=t}();var o={};return function(){"use strict";s.r(o),s.d(o,{default:function(){return f}});var t=s(703),e=s.n(t),i=s(495),n=s.n(i),r=s(795),a=s.n(r);s.p,u.$inject=["$rootScope","$timeout","$interval","iScrollSignals","iScrollService"];const l={on:"iscroll-on",off:"iscroll-off"},h={},c=e().isDefined(a())&&function(t){if("Opera Mini"===t.name)return!1;if("IE Mobile"===t.name)return p(t.version,"11.0")>=0;switch(t.os.family){case"Android":return function(t){return"Chrome Mobile"===t.name}(t)||function(t){return p(t.os.version,"4.0.4")>=0}(t);case"iOS":return p(t.version,"5.1")>=0;default:return!0}}(a());function p(t,e,i){const s=i&&i.lexicographical,o=i&&i.zeroExtend;let n=t.split("."),r=e.split(".");function a(t){return(s?/^\d+[A-Za-z]*$/:/^\d+$/).test(t)}if(!n.every(a)||!r.every(a))return NaN;if(o){for(;n.lengthr[t]?1:-1}return n.length!==r.length?-1:0}function d(t){t()}function u(t,i,s,o,r){function a(t,e){i((function(){t.refresh()}),e.directive.asyncRefreshDelay,e.directive.invokeApply)}return{restrict:"A",link:function(i,c,p){const u={iScroll:e().extend({},r.defaults.iScroll,i.iscroll||{}),directive:e().extend({},r.defaults.directive)};function f(){c.hasClass(l.on)||function(i,r,c,p){const u=[t.$on(o.disabled,g),t.$on(o.refresh,v),i.$on("$destroy",g)],f=new(n())(r[0],p.iScroll);let m=!0,b=null;function g(){null!==b&&s.cancel(b),e().isDefined(i.iscrollInstance)&&delete i.iscrollInstance,f.destroy(),r.removeClass(l.on).addClass(l.off),r.children(".iscroll-scroller").attr("style",null),e().forEach(u,d)}function v(){m&&(m=!1,a(f,p),m=!0)}e().forEach(h,(function(t,i){e().isDefined(p.directive[i])&&f.on(t,p.directive[i])})),r.removeClass(l.off).addClass(l.on),e().isDefined(c.iscrollInstance)&&(i.iscrollInstance=f),!1!==p.directive.asyncRefreshDelay&&a(f,p),f.on("scrollStart",(function(){m=!1})),f.on("scrollEnd",(function(){m=!0})),!1!==p.directive.refreshInterval&&(b=s(v,p.directive.refreshInterval,0,p.directive.invokeApply))}(i,c,p,u)}e().forEach(u.iScroll,(function(t,e){(r.defaults.directive.hasOwnProperty(e)||h.hasOwnProperty(e))&&(u.directive[e]=t,delete u.iScroll[e])}));const m=[t.$on(o.enabled,f)];r.state.useIScroll?f():c.removeClass(l.on).addClass(l.off),i.$on("$destroy",(function(){e().forEach(m,d)}))},scope:{iscroll:"=",iscrollInstance:"="}}}e().forEach(["beforeScrollStart","scrollCancel","scrollStart","scroll","scrollEnd","flick","zoomStart","zoomEnd"],(function(t){var e;this["on"+(e=t,e.substring(0,1).toLocaleUpperCase()+e.substring(1))]=t}),h);var f=e().module("angular-iscroll",[]).directive("iscroll",u).provider("iScrollService",(function(){i.$inject=["$rootScope","iScrollSignals"];const t={iScroll:{momentum:!0,mouseWheel:!0},directive:{initiallyEnabled:!c,asyncRefreshDelay:0,refreshInterval:!1,invokeApply:!1}};function i(e,i){const s={useIScroll:t.directive.initiallyEnabled,autoDetectedUseNativeScroll:c};function o(t){t||(s.useIScroll=!1),e.$emit(i.disabled)}function n(t){t||(s.useIScroll=!0),e.$emit(i.enabled)}return{defaults:t,state:s,versionCompare:p,platform:a(),enable:n,disable:o,toggle:function(t){s.useIScroll?o(t):n(t)},refresh:function(t){e.$emit(i.refresh,t)}}}e().forEach(h,(function(t,e){this[e]=void 0}),t.directive),this.useNativeScroll=c,this.platform=a(),this.configureDefaults=function(i){e().isDefined(i.directive)&&e().extend(t.directive,i.directive),e().isDefined(i.iScroll)&&e().extend(t.iScroll,i.iScroll)},this.getDefaults=function(){return t},this.$get=i})).constant("iScrollSignals",{disabled:"iscroll:disabled",enabled:"iscroll:enabled",refresh:"iscroll:refresh"}).name}(),o}()}));
--------------------------------------------------------------------------------
/dist/lib/angular-iscroll.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mtr/angular-iscroll/2498b30f9af2e92cc7e85355d90320a492e582b8/dist/lib/angular-iscroll.js.gz
--------------------------------------------------------------------------------
/dist/lib/scss/_iscroll.scss:
--------------------------------------------------------------------------------
1 | $iscroll-wrapper-background-color: #777 !default;
2 | $iscroll-scroller-background-color: #fff !default;
3 |
4 | .iscroll-on {
5 | .iscroll-wrapper {
6 | position: relative;
7 | width: 100%;
8 | height: 100%;
9 | overflow: hidden;
10 | background-color: $iscroll-wrapper-background-color;
11 | }
12 | .iscroll-scroller {
13 | position: absolute;
14 | width: 100%;
15 | min-height: 100%;
16 | background-color: $iscroll-scroller-background-color;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-iscroll",
3 | "version": "4.2.0",
4 | "description": "AngularJS module that enables iScroll 5 functionality, wrapping it in an easy-to-use directive.",
5 | "main": "dist/lib/angular-iscroll.js",
6 | "scripts": {
7 | "build": "NODE_ENV=production webpack --config-name=library",
8 | "build-dev": "NODE_ENV=development webpack --config-name=library",
9 | "watch": "NODE_ENV=development webpack --config-name=library --watch",
10 | "update-browserlist-db": "npx update-browserslist-db@latest",
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/mtr/angular-iscroll.git"
16 | },
17 | "keywords": [
18 | "iscroll",
19 | "angular",
20 | "directive"
21 | ],
22 | "author": {
23 | "name": "Martin Thorsen Ranang",
24 | "email": "mtr@ranang.org"
25 | },
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/mtr/angular-iscroll/issues"
29 | },
30 | "homepage": "https://github.com/mtr/angular-iscroll",
31 | "browserslist": "> 0.5%, last 3 versions, Firefox ESR, not dead",
32 | "dependencies": {
33 | "iscroll": "^5.2.0",
34 | "platform": "^1.3.6"
35 | },
36 | "peerDependencies": {
37 | "angular": ">=1.8"
38 | },
39 | "resolutions": {
40 | "loader-utils": "^2.0.4",
41 | "minimatch": "^3.0.8"
42 | },
43 | "devDependencies": {
44 | "@babel/core": "^7.23.5",
45 | "@babel/preset-env": "^7.23.5",
46 | "@uirouter/angularjs": "^1.1.0",
47 | "babel-loader": "^9.1.3",
48 | "babel-plugin-angularjs-annotate": "^0.10.0",
49 | "bootstrap-sass": "^3.4.3",
50 | "clean-webpack-plugin": "^4.0.0",
51 | "compression-webpack-plugin": "^10.0.0",
52 | "css-loader": "^6.8.1",
53 | "cssnano": "^6.0.1",
54 | "dateformat": "^5.0.3",
55 | "file-loader": "^6.2.0",
56 | "html-loader": "^4.2.0",
57 | "jquery": "^3.7.1",
58 | "jshint": "^2.13.6",
59 | "mini-css-extract-plugin": "^2.7.6",
60 | "postcss-loader": "^7.3.3",
61 | "postcss-preset-env": "^9.3.0",
62 | "sass": "^1.69.5",
63 | "sass-loader": "^13.3.2",
64 | "url-loader": "^4.1.1",
65 | "webpack": "^5.89.0",
66 | "webpack-cli": "^5.1.4"
67 | },
68 | "packageManager": "yarn@4.0.2"
69 | }
70 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = ({file, options, env}) => ({
2 | plugins: {
3 | 'postcss-preset-env': options.presetEnv,
4 | 'autoprefixer': options.autoprefixer,
5 | 'cssnano': options.cssnano
6 | }
7 | })
8 |
--------------------------------------------------------------------------------
/src/lib/_iscroll.scss:
--------------------------------------------------------------------------------
1 | $iscroll-wrapper-background-color: #777 !default;
2 | $iscroll-scroller-background-color: #fff !default;
3 |
4 | .iscroll-on {
5 | .iscroll-wrapper {
6 | position: relative;
7 | width: 100%;
8 | height: 100%;
9 | overflow: hidden;
10 | background-color: $iscroll-wrapper-background-color;
11 | }
12 | .iscroll-scroller {
13 | position: absolute;
14 | width: 100%;
15 | min-height: 100%;
16 | background-color: $iscroll-scroller-background-color;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/lib/angular-iscroll.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import angular from 'angular'
4 | import IScroll from 'iscroll'
5 | import platform from 'platform'
6 |
7 | import './_iscroll.scss'
8 |
9 | const signals = {
10 | disabled: 'iscroll:disabled',
11 | enabled: 'iscroll:enabled',
12 | refresh: 'iscroll:refresh'
13 | },
14 | classes = {
15 | on: 'iscroll-on',
16 | off: 'iscroll-off'
17 | },
18 | iScrollEvents = [
19 | 'beforeScrollStart',
20 | 'scrollCancel',
21 | 'scrollStart',
22 | 'scroll',
23 | 'scrollEnd',
24 | 'flick',
25 | 'zoomStart',
26 | 'zoomEnd'
27 | ],
28 | iScrollEventHandlerMap = {},
29 | useNativeScroll = angular.isDefined(platform) && _useNativeScroll(platform);
30 |
31 | /**
32 | * Compares two software version numbers (e.g. "1.7.1" or "1.2b").
33 | *
34 | * This function was born in http://stackoverflow.com/a/6832721.
35 | *
36 | * @param {string} v1 The first version to be compared.
37 | * @param {string} v2 The second version to be compared.
38 | * @param {object} [options] Optional flags that affect comparison behavior:
39 | *
40 | * -
41 | * lexicographical: true compares each part of the version strings lexicographically instead of
42 | * naturally; this allows suffixes such as "b" or "dev" but will cause "1.10" to be considered smaller than
43 | * "1.2".
44 | *
45 | * -
46 | * zeroExtend: true changes the result if one version string has less parts than the other. In
47 | * this case the shorter string will be padded with "zero" parts instead of being considered smaller.
48 | *
49 | *
50 | * @returns {number|NaN}
51 | *
52 | * - 0 if the versions are equal
53 | * - a negative integer iff v1 < v2
54 | * - a positive integer iff v1 > v2
55 | * - NaN if either version string is in the wrong format
56 | *
57 | *
58 | * @copyright by Jon Papaioannou (["john", "papaioannou"].join(".") + "@gmail.com")
59 | * @license This function is in the public domain. Do what you want with it, no strings attached.
60 | */
61 | function versionCompare(v1, v2, options) {
62 | const lexicographical = options && options.lexicographical,
63 | zeroExtend = options && options.zeroExtend;
64 | let v1parts = v1.split('.'),
65 | v2parts = v2.split('.');
66 |
67 | function isValidPart(x) {
68 | return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
69 | }
70 |
71 | if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
72 | return NaN;
73 | }
74 |
75 | if (zeroExtend) {
76 | while (v1parts.length < v2parts.length) v1parts.push('0');
77 | while (v2parts.length < v1parts.length) v2parts.push('0');
78 | }
79 |
80 | if (!lexicographical) {
81 | v1parts = v1parts.map(Number);
82 | v2parts = v2parts.map(Number);
83 | }
84 |
85 | for (let i = 0; i < v1parts.length; ++i) {
86 | if (v2parts.length === i) {
87 | return 1;
88 | }
89 |
90 | if (v1parts[i] === v2parts[i]) {
91 | /*continue; // Unnecessary as last statement in a loop. */
92 | } else if (v1parts[i] > v2parts[i]) {
93 | return 1;
94 | } else {
95 | return -1;
96 | }
97 | }
98 |
99 | if (v1parts.length !== v2parts.length) {
100 | return -1;
101 | }
102 |
103 | return 0;
104 | }
105 |
106 | function _isChromeMobile(platform) {
107 | return platform.name === 'Chrome Mobile';
108 | }
109 |
110 | function _isRecentOS(platform) {
111 | return versionCompare(platform.os.version, '4.0.4') >= 0;
112 | }
113 |
114 | function _useNativeScroll(platform) {
115 | if (platform.name === 'Opera Mini') {
116 | return false;
117 | }
118 |
119 | if (platform.name === 'IE Mobile') {
120 | return versionCompare(platform.version, '11.0') >= 0
121 | }
122 |
123 | switch (platform.os.family) {
124 | case 'Android':
125 | // In Chrome we trust, but also younger Android releases.
126 | return _isChromeMobile(platform) || _isRecentOS(platform);
127 | case 'iOS':
128 | // Buggy handling in older iOS versions.
129 | return versionCompare(platform.version, '5.1') >= 0;
130 | default:
131 | // Assuming desktop or other browser.
132 | return true;
133 | }
134 | }
135 |
136 | /**
137 | * Add handler name to event name mapping.
138 | *
139 | * Please note that the 'scroll' event is only available when using
140 | * iscroll-probe.js (for example, through angular-iscroll-probe).
141 | *
142 | * For example, the handler for the 'scrollEnd' event can be configured
143 | * by supplying the onScrollEnd option.
144 | **/
145 | angular.forEach(iScrollEvents, function _addPair(event) {
146 | this['on' + _capitalizeFirst(event)] = event;
147 | }, iScrollEventHandlerMap);
148 |
149 | function _capitalizeFirst(str) {
150 | return str.substring(0, 1).toLocaleUpperCase() + str.substring(1);
151 | }
152 |
153 | function iScrollServiceProvider() {
154 | const defaultOptions = {
155 | iScroll: {
156 | /**
157 | * The different options for iScroll are explained in
158 | * detail at http://iscrolljs.com/#configuring
159 | **/
160 | momentum: true,
161 | mouseWheel: true
162 | },
163 | directive: {
164 | /**
165 | * Whether or not to initially enable the use of iScroll.
166 | *
167 | * The `useNativeScroll` flag is automatically determined
168 | * by running _useNativeScroll();
169 | **/
170 | initiallyEnabled: !useNativeScroll,
171 | /**
172 | * Delay, in ms, before we asynchronously perform an
173 | * iScroll.refresh(). If false, then no async refresh is
174 | * performed.
175 | **/
176 | asyncRefreshDelay: 0,
177 | /**
178 | * Delay, in ms, between each iScroll.refresh(). If false,
179 | * then no periodic refresh is performed.
180 | **/
181 | refreshInterval: false,
182 | /**
183 | * If `false`, skip `$digest()` cycle on iScroll.refresh().
184 | */
185 | invokeApply: false
186 | /**
187 | * Event handler options are added below.
188 | **/
189 | }
190 | };
191 |
192 | angular.forEach(iScrollEventHandlerMap, function _default(event, handler) {
193 | this[handler] = undefined;
194 | }, defaultOptions.directive);
195 |
196 | function _configureDefaults(options) {
197 | /**
198 | * Since angular.extend is not performing a "deep" merge, we'll
199 | * do it in two steps.
200 | **/
201 | if (angular.isDefined(options.directive)) {
202 | angular.extend(defaultOptions.directive, options.directive);
203 | }
204 | if (angular.isDefined(options.iScroll)) {
205 | angular.extend(defaultOptions.iScroll, options.iScroll);
206 | }
207 | }
208 |
209 | // Export the auto-determined value of `useNativeScroll`.
210 | this.useNativeScroll = useNativeScroll;
211 | this.platform = platform;
212 |
213 | this.configureDefaults = _configureDefaults;
214 |
215 | function _getDefaults() {
216 | return defaultOptions;
217 | }
218 |
219 | //noinspection JSUnusedGlobalSymbols
220 | this.getDefaults = _getDefaults;
221 |
222 | /* @ngInject */
223 | function iScrollService($rootScope, iScrollSignals) {
224 | const _state = {
225 | useIScroll: defaultOptions.directive.initiallyEnabled,
226 | autoDetectedUseNativeScroll: useNativeScroll
227 | };
228 |
229 | function _disable(signalOnly) {
230 | if (!signalOnly) {
231 | _state.useIScroll = false;
232 | }
233 | //$log.debug('emit(iScrollSignals.disabled)',
234 | // iScrollSignals.disabled);
235 | $rootScope.$emit(iScrollSignals.disabled);
236 | }
237 |
238 | function _enable(signalOnly) {
239 | if (!signalOnly) {
240 | _state.useIScroll = true;
241 | }
242 | //$log.debug('emit(iScrollSignals.enabled)',
243 | // iScrollSignals.enabled);
244 | $rootScope.$emit(iScrollSignals.enabled);
245 | }
246 |
247 | function _toggle(signalOnly) {
248 | (_state.useIScroll) ?
249 | _disable(signalOnly) : _enable(signalOnly);
250 | }
251 |
252 | function _refresh(name) {
253 | // The name parameter is not really used for now.
254 | $rootScope.$emit(iScrollSignals.refresh, name);
255 | }
256 |
257 | return {
258 | defaults: defaultOptions,
259 | state: _state,
260 | versionCompare: versionCompare,
261 | platform: platform,
262 | enable: _enable,
263 | disable: _disable,
264 | toggle: _toggle,
265 | refresh: _refresh
266 | };
267 | }
268 |
269 | //noinspection JSUnusedGlobalSymbols
270 | this.$get = iScrollService;
271 | }
272 |
273 | function _call(functor) {
274 | functor();
275 | }
276 |
277 | /* @ngInject */
278 | function iscroll($rootScope, $timeout, $interval, iScrollSignals,
279 | iScrollService) {
280 | function asyncRefresh(instance, options) {
281 | $timeout(function _refreshAfterInitialRender() {
282 | instance.refresh();
283 | }, options.directive.asyncRefreshDelay, options.directive.invokeApply);
284 | }
285 |
286 | function _createInstance(scope, element, attrs, options) {
287 | const deregistrators = [
288 | $rootScope.$on(iScrollSignals.disabled, _destroyInstance),
289 | $rootScope.$on(iScrollSignals.refresh, _refreshInstance),
290 | scope.$on('$destroy', _destroyInstance)
291 | ];
292 | const instance = new IScroll(element[0], options.iScroll);
293 | let refreshEnabled = true,
294 | refreshInterval = null;
295 |
296 | angular.forEach(iScrollEventHandlerMap,
297 | function _addHandler(event, option) {
298 | if (angular.isDefined(options.directive[option])) {
299 | instance.on(event, options.directive[option]);
300 | }
301 | });
302 |
303 | element.removeClass(classes.off).addClass(classes.on);
304 |
305 | if (angular.isDefined(attrs.iscrollInstance)) {
306 | scope.iscrollInstance = instance;
307 | }
308 |
309 | if (options.directive.asyncRefreshDelay !== false) {
310 | asyncRefresh(instance, options);
311 | }
312 |
313 | function _destroyInstance() {
314 | if (refreshInterval !== null) {
315 | $interval.cancel(refreshInterval);
316 | }
317 |
318 | if (angular.isDefined(scope.iscrollInstance)) {
319 | delete scope.iscrollInstance;
320 | }
321 | instance.destroy();
322 |
323 | element.removeClass(classes.on).addClass(classes.off);
324 | // Remove element's CSS transition values:
325 | element.children('.iscroll-scroller').attr('style', null);
326 |
327 | angular.forEach(deregistrators, _call);
328 | //$log.debug('angular-iscroll: destroyInstance');
329 | }
330 |
331 | function _refreshInstance() {
332 | if (refreshEnabled) {
333 | //noinspection JSUnusedAssignment
334 | refreshEnabled = false;
335 | asyncRefresh(instance, options);
336 | refreshEnabled = true;
337 | }
338 | }
339 |
340 | function _disableRefresh() {
341 | refreshEnabled = false;
342 | }
343 |
344 | function _enableRefresh() {
345 | refreshEnabled = true;
346 | }
347 |
348 | instance.on('scrollStart', _disableRefresh);
349 | instance.on('scrollEnd', _enableRefresh);
350 |
351 | if (options.directive.refreshInterval !== false) {
352 | refreshInterval = $interval(_refreshInstance,
353 | options.directive.refreshInterval, 0, options.directive.invokeApply);
354 | }
355 |
356 | return instance;
357 | }
358 |
359 | function _link(scope, element, attrs) {
360 | const options = {
361 | iScroll: angular.extend({}, iScrollService.defaults.iScroll, scope.iscroll || {}),
362 | directive: angular.extend({}, iScrollService.defaults.directive)
363 | };
364 |
365 | angular.forEach(options.iScroll,
366 | function _extractOptions(value, key) {
367 | if (iScrollService.defaults.directive.hasOwnProperty(key) ||
368 | iScrollEventHandlerMap.hasOwnProperty(key)) {
369 | options.directive[key] = value;
370 | delete options.iScroll[key];
371 | }
372 | }
373 | );
374 |
375 | function _init() {
376 | if (!element.hasClass(classes.on)) {
377 | _createInstance(scope, element, attrs, options);
378 | }
379 | }
380 |
381 | const enableHandlers = [$rootScope.$on(iScrollSignals.enabled, _init)];
382 |
383 | function _removeEnableHandlers() {
384 | angular.forEach(enableHandlers, _call);
385 | }
386 |
387 | if (iScrollService.state.useIScroll) {
388 | _init();
389 | } else {
390 | element.removeClass(classes.on).addClass(classes.off);
391 | }
392 |
393 | scope.$on('$destroy', _removeEnableHandlers);
394 | }
395 |
396 | return {
397 | restrict: 'A',
398 | link: _link,
399 | scope: {
400 | iscroll: '=',
401 | iscrollInstance: '='
402 | }
403 | };
404 | }
405 |
406 | export default angular.module('angular-iscroll', [])
407 | .directive('iscroll', iscroll)
408 | .provider('iScrollService', iScrollServiceProvider)
409 | .constant('iScrollSignals', signals)
410 | .name;
411 |
412 |
--------------------------------------------------------------------------------
/webpack.config.mjs:
--------------------------------------------------------------------------------
1 | import {CleanWebpackPlugin} from 'clean-webpack-plugin';
2 | import CompressionPlugin from 'compression-webpack-plugin';
3 | import dateFormat from 'dateformat';
4 | import MiniCssExtractPlugin from 'mini-css-extract-plugin';
5 | import path from 'path';
6 | import {fileURLToPath} from 'url';
7 | import webpack from 'webpack';
8 |
9 | import _package from './package.json' assert {type: 'json'};
10 |
11 | const __filename = fileURLToPath(import.meta.url);
12 | const __dirname = path.dirname(__filename);
13 |
14 | const now = new Date(),
15 | timestamp = dateFormat(now, 'isoDateTime'),
16 | year = dateFormat(now, 'yyyy');
17 |
18 | export default {
19 | plugins: [
20 | new CleanWebpackPlugin(),
21 | new webpack.BannerPlugin({
22 | banner: `@license ${_package.name} v${_package.version}, ${timestamp}
23 | (c) ${year} ${_package.author.name} <${_package.author.email}>
24 | License: ${_package.license}`
25 | })
26 | ].concat([
27 | new MiniCssExtractPlugin({
28 | filename: 'angular-iscroll.css',
29 | }),
30 | new CompressionPlugin({
31 | test: /\.js(\?.*)?$/i,
32 | })
33 | ]),
34 | name: 'library',
35 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
36 | //mode: 'development',
37 | entry: './src/lib/angular-iscroll.js',
38 | output: {
39 | path: path.resolve(__dirname, 'dist/lib'),
40 | filename: 'angular-iscroll.js',
41 | library: 'angularIscroll',
42 | libraryTarget: 'umd'
43 | },
44 | optimization: {
45 | usedExports: true,
46 | },
47 | module: {
48 | rules: [
49 | {
50 | test: /\.m?js$/,
51 | exclude: /node_modules/,
52 | use: [{
53 | loader: 'babel-loader',
54 | options: {
55 | presets: ['@babel/preset-env']
56 | }
57 | }]
58 | },
59 | {
60 | test: /\.(sa|sc|c)ss$/,
61 | /* Exclude fonts while working with images, e.g. .svg can be both image or font. */
62 | exclude: /node_modules/,
63 | use: [
64 | {
65 | loader: 'file-loader',
66 | options: {
67 | name: '[name].[ext]',
68 | outputPath: 'scss/'
69 | }
70 | },
71 | ]
72 | }
73 | ],
74 | },
75 | externals: {
76 | lodash: {
77 | commonjs: 'lodash',
78 | commonjs2:
79 | 'lodash',
80 | amd:
81 | 'lodash',
82 | root:
83 | '_',
84 | },
85 | angular: {
86 | commonjs: 'angular',
87 | commonjs2:
88 | 'angular',
89 | amd:
90 | 'angular',
91 | root:
92 | 'angular',
93 | },
94 | },
95 | };
96 |
--------------------------------------------------------------------------------