Compare commits

..

92 Commits

Author SHA1 Message Date
Pete Bacon Darwin be240b1176 docs(changelog): add 1.7.4 release notes 2018-09-07 09:57:37 +01:00
Martin Staffa 61b33543ff fix(ngAria.ngClick): preventDefault on space/enter only on non-interactive elements
Fixes #16664
Closes #16680
2018-09-06 15:59:19 +02:00
Martin Staffa 1dcba9cd88 chore(benchpress): add ngRepeat animation benchmark
Closes #13976
2018-09-06 15:46:25 +02:00
Michał Gołębiowski-Owczarek 8cd54d7794 docs(version-support-status): remove outdated info, resolve inconsistencies
Closes #16684
2018-09-06 15:42:24 +02:00
Martin Staffa 3105b2c26a fix(ngAnimate): remove prepare classes with multiple structural animations
Closes #16681
Closes #16677
2018-09-06 15:42:18 +02:00
Craig Johnson bc5a48d4a4 docs(guide): grammar correction in security guide
Closes #16683
2018-09-06 15:42:00 +02:00
George Kalpakas 2bbc7c464f refactor(ngMocks): simplify routeToRegExp by assuming path has query/hash stripped off
Closes #16672
2018-08-26 00:00:03 +03:00
George Kalpakas e85f91d582 refactor(ngMocks): clean up MockHttpExpectation 2018-08-26 00:00:01 +03:00
George Kalpakas 862a78dfd2 refactor(ngMocks): ignore query/hash when extracting path params for MockHttpExpectation 2018-08-25 23:59:59 +03:00
George Kalpakas bd772abf34 refactor(ngMocks): clean up MockHttpExpectation#params() 2018-08-25 23:59:57 +03:00
George Kalpakas b074d719ae refactor(ngRoute): do not unnecessarily return originalPath in routeToRegExp 2018-08-25 23:59:56 +03:00
George Kalpakas a43a40b778 test(ngMocks): use correct method name in $httpBackend test 2018-08-25 23:59:54 +03:00
Susisu 2ceeb739f3 fix($route): correctly extract path params if path contains question mark or hash
The `routeToRegExp()` function, introduced by 840b5f0, could not extract
path params if the path contained question mark or hash. Although these
characters would normally be encoded in the path, they are decoded by
`$location.path()`, before being passed to the RegExp returned by
`routeToRegExp()`.

`routeToRegExp()` has to be able to deal with both encoded URL and
decoded path, because it is being shared between `ngRoute` and
`ngMocks`.

This commit fixes the issue, by introducing an `isUrl` option that
allows creating an appropriate RegExp for each usecase.
2018-08-25 23:59:53 +03:00
George Kalpakas fa715abf45 chore(doc-gen): upgrade dgeni-packages to 0.26.5
Related: #16671, angular/dgeni-packages#271
2018-08-23 15:08:29 +03:00
George Kalpakas f943e377e8 docs(angular.copy): fix formatting
Using `<br>` messes formatting (due to a bug in
`dgeni`/`dgeni-packages`). This started breaking in c387e0d79.

Fixes #16671
2018-08-21 11:46:06 +03:00
Martin Staffa 30084c1369 fix(ngHref): allow numbers and other objects in interpolation
Interpolated content in ngHref must be stringified before being passed to $$sanitizeUri by $sce. Before 1.7.x, the sanitization had happened on the already interpolated value inside $compile.

Closes #16652
Fixes #16626
2018-08-20 20:05:20 +02:00
Martin Staffa 668a33da34 fix(select): allow to select first option with value undefined
Previously, the value observer incorrectly assumed a value had changed even if
it was the first time it was set, which caused it to remove an option with
the value `undefined` from the internal option map.

Fixes #16653
Closes #16656
2018-08-08 09:18:10 +02:00
John Mantas 19e2347759 docs(ngRepeat): redundant "and" on line 77
Closes #16657
2018-08-07 16:21:28 +03:00
George Kalpakas f17292e1b5 docs(guide/migration): fix typos, format inline code 2018-08-06 15:52:32 +03:00
Martin Staffa 77b4330011 docs(select): remove solved known issue
The issue in question has been resolved some time in 2017.
The bug report is still open, but the behavior has changed:
https://bugzilla.mozilla.org/show_bug.cgi?id=126379

Let's hope they have tests for this!

Related #9134
2018-08-03 18:20:53 +02:00
Martin Staffa 7717de4c51 docs(CHANGELOG.md): add changes for 1.7.3 2018-08-03 13:35:40 +02:00
Jason Bedard e68697e2e3 fix($location): fix infinite recursion/digest on URLs with special characters
Some characters are treated differently by `$location` compared to `$browser` and
the native browser. When comparing URLs across these two services this must be
taken into account.

Fixes #16592
Closes #16611
2018-08-03 13:12:28 +02:00
Martin Staffa a02ed88279 docs($compile): add docs for ngProp and ngOn bindings
The docs are written as if ngProp and ngOn were regular directives,
which makes them easier to find.

Closes #16627
2018-08-03 12:28:27 +02:00
Jason Bedard a5914c94a8 feat($compile): add support for arbitrary DOM property and event bindings
Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo="x"` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using directives such as `ng-click`,
`ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar="barOccured($event)"` will add a listener to the "bar" event and invoke the
`barOccured($event)` expression.

Since HTML attributes are case-insensitive, property and event names are specified in snake_case
for `ng-prop-*` and `ng-on-*`. For example, to bind property `fooBar` use `ng-prop-foo_bar`, to
listen to event `fooBar` use `ng-on-foo_bar`.

Fixes #16428
Fixes #16235
Closes #16614
2018-08-03 12:28:17 +02:00
Jason Bedard 63c9c9e8d7 refactor($compile): move img[srcset] sanitizing to helper method 2018-08-03 12:28:08 +02:00
Georgii Dolzhykov 4adbf82a84 fix(ngMock): pass failed HTTP expectations to $exceptionHandler
This was only partially fixed in f18dd2957.

Closes #16644
2018-07-31 14:36:33 +03:00
George Kalpakas 1144b1eccb fix($location): avoid unnecessary $locationChange* events due to empty hash
Fixes #16632

Closes #16636
2018-07-30 23:39:46 +03:00
George Kalpakas 8970087e58 test($location): add assertion 2018-07-30 23:39:45 +03:00
George Kalpakas 131e62a819 refactor($browser): correctly export helper used in specs
The helper is used in `fakeWindow.location.hash`. ATM, no test is using
the `hash` getter, so there were no errors.
2018-07-30 23:39:44 +03:00
George Kalpakas 2fad638237 refactor($location): remove unnecessary capturing group in RegExp 2018-07-30 23:39:44 +03:00
George Kalpakas a0940895a2 refactor($location): minor changes (unused deps, exported globals, unused deps, etc) 2018-07-30 23:39:43 +03:00
Martin Staffa 0a1db2ad5f fix(Angular): add workaround for Safari / Webdriver problem
Closes #16645
2018-07-28 13:50:25 +03:00
George Kalpakas 4bd4246906 fix($animate): avoid memory leak with $animate.enabled(element, enabled)
When disabling/enabling animations on a specific element (via
`$animate.enabled(element, enabled)`), the element is added in a map to
track its state. Previously, the element was never removed from the map,
causing AngularJS to hold on to the element even after it is removed
from the DOM, thus preventing it from being garbage collected.

This commit fixes it by removing the element from the map on `$destroy`.

Fixes #16637.

Closes #16649
2018-07-27 20:48:38 +03:00
Martin Staffa 05ac702bc7 fix($compile): use correct parent element when requiring on html element
Fixes #16535
Closes #16647
2018-07-27 17:11:16 +02:00
Martin Staffa 6882113bc1 fix(ngEventDirs): pass error in handler to $exceptionHandler when event was triggered in a digest
This ensures that the error handling is the same for events triggered inside and outside a digest.
2018-07-25 13:39:33 +02:00
Mark Gardner 535ee32a0b fix(ngEventDirs): don't wrap the event handler in $apply if already in $digest
Digest cycle already in progress error can inadvertently be caused when triggering an
element's click event while within an active digest cycle. This is due to the ngEventsDirs
event handler always calling $rootScope.$apply regardless of the status of $rootScope.$$phase.
Checking the phase and calling the function immediately if within an active digest cycle
will prevent the problem without reducing current functionality.

Closes #14673
Closes #14674
2018-07-25 13:39:29 +02:00
George Kalpakas 7cf4a2933c fix(angular.element): do not break on cleanData() if _data() returns undefined
This shouldn't happen in supported jQuery versions (2+), but if someone
uses the unsupported 1.x version the app will break. The change that
causes this new behavior was introduced in b7d396b8b.

Even though jQuery 1.x is not supported, it is worth avoiding the
unnecessary breakage (given how simple).

Fixes #16641

Closes #16642
2018-07-23 14:22:11 +03:00
George Kalpakas 7dd6c87eec docs(browserTrigger): document eventData.data property 2018-07-22 19:09:50 +03:00
George Kalpakas 17f963c5d8 docs($route): fix typo (inluding --> including) 2018-07-22 18:45:49 +03:00
Jason Bedard ba09ba5344 refactor($location): move repeated path normalization code into helper method (#16618)
Closes #16618
2018-07-22 18:01:03 +03:00
George Kalpakas 8c36a43e91 docs(ngMock/$interval.flush): fix param type (not optional)
Closes #16640
2018-07-22 17:33:16 +03:00
George Kalpakas af14d67b84 chore(saucelabs): upgrade sauce-connect to latest version
Closes #16639
2018-07-21 13:40:35 +03:00
George Kalpakas c8acff1cdc chore(karma): upgrade karma and related dependencies to latest versions 2018-07-21 13:40:34 +03:00
George Kalpakas 876e9842a2 docs(ngMocks): fix type for $flushPendingTasks/$verifyPendingsTasks
Closes #16638
2018-07-21 10:47:01 +03:00
George Kalpakas 5cb9465093 docs(ngMock/$timeout): deprecate flush() and verifyNoPendingTasks()
Closes #16603
2018-07-13 13:37:22 +03:00
George Kalpakas 58f9413ad3 docs(ngMock/$timeout): recommend $verifyNoPendingTasks() when appropriate
For historical reasons, `$timeout.verifyNoPendingTasks()` throws if
there is any type of task pending (even if it is not a timeout). When
calling `$timeout.verifyNoPendingTasks()`, the user is most likely
interested in verifying pending timeouts only, which is now possible
with `$verifyNoPendingTasks('$timeout')`.

To raise awareness of `$verifyNoPendingTasks()`, it is mentioned in the
error message thrown by `$timeoutverifyNoPendingTasks()` if none of the
pending tasks is a timeout.
2018-07-13 13:37:20 +03:00
George Kalpakas 6f7674a7d0 feat(ngMock): add $flushPendingTasks() and $verifyNoPendingTasks()
`$flushPendingTasks([delay])` allows flushing all pending tasks (or up
to a specific delay). This includes `$timeout`s, `$q` promises and tasks
scheduled via `$rootScope.$applyAsync()` and `$rootScope.$evalAsync()`.
(ATM, it only flushes tasks scheduled via `$browser.defer()`, which does
not include `$http` requests and `$route` transitions.)

`$verifyNoPendingTasks([taskType])` allows verifying that there are no
pending tasks (in general or of a specific type). This includes tasks
flushed by `$flushPendingTasks()` as well as pending `$http` requests
and in-progress `$route` transitions.

Background:
`ngMock/$timeout` has `flush()` and `verifyNoPendingTasks()` methods,
but they take all kinds of tasks into account which is confusing. For
example, `$timeout.verifyNoPendingTasks()` can fail (even if there are
no pending timeouts) because of an unrelated pending `$http` request.

This behavior is retained for backwards compatibility, but the new
methods are more generic (and thus less confusing) and also allow
more fine-grained control (when appropriate).

Closes #14336
2018-07-13 13:37:17 +03:00
George Kalpakas 8dc153db75 refactor($browser): share task-tracking code between $browser and ngMock/$browser
This avoids code/logic duplication and helps the implementations stay
in-sync.
2018-07-13 13:37:15 +03:00
George Kalpakas 4a6f0996f6 refactor($interval): share code between $interval and ngMock/$interval
This avoids code/logic duplication and helps the implementations stay
in-sync.
2018-07-13 13:37:12 +03:00
George Kalpakas 522d581fc9 refactor(ngMock/$interval): more closely follow actual $interval's internal implementation 2018-07-13 13:36:38 +03:00
George Kalpakas 17b139f107 feat(*): implement more granular pending task tracking
Previously, all pending async tasks (tracked via `$browser`) are treated
the same. I.e. things like `$$testability.whenStable()` and
`ngMock#$timeout.verifyNoPendingTasks()` take all tasks into account.

Yet, in some cases we might be interested in specific tasks only. For
example, if one wants to verify there are no pending `$timeout`s, they
don't care if there are other pending tasks, such as `$http` requests.
Similarly, one might want to get notified when all `$http` requests have
completed and does not care about pending promises.

This commit adds support for more granular task tracking, by enabling
callers to specify the type of task that is being added/removed from the
queue and enabling listeners to be triggered when specific types of
tasks are completed (even if there are more pending tasks of different
types).

The change is backwards compatible. I.e. calling the affected methods
with no explicit task-type, behaves the same as before.

Related to #14336.
2018-07-13 13:35:50 +03:00
George Kalpakas 10973c3366 fix($compile): work around Firefox DocumentFragment bug
DOM nodes passed to `compilationGenerator()` will eventually be wrapped
in `jqLite`, when the compilation actually happens. In Firefox 60+,
there seems to be a `DocumentFragment`-related bug that sometimes causes
the `childNodes` to be empty at the time the compilation happens.

This commit works around this bug by eagerly wrapping `childNodes` in
`jqLite`.

NOTE:
The wrapped nodes have references to their `DocumentFragment` container.
This is "by design", since we want to be able to traverse the nodes via
`nextSibling` (in order to correctly handle multi-element directives).

Once the nodes are compiled, they will be either moved to a new
container element or the `jqLite` wrapper is release making them
eligible for garbage collection. In both cases, the original
`DocumentFragment` container should be eligible for garbage collection
too.

Fixes #16607

Closes #16615
2018-07-09 21:27:26 +03:00
Martin Staffa fc64e68076 feat($animate): add option data to event callbacks
Closes #12697
Closes #13059
2018-07-09 17:11:24 +02:00
Martin Staffa ac5e92de9b docs($animate): clarify possible options and fired events 2018-07-09 17:11:19 +02:00
Matias Niemelä 0936353e9a perf(ngAnimate): avoid repeated calls to addClass/removeClass when animation has no duration
Background:
ngAnimate writes helper classes to DOM elements to see if animations are defined on them. If many
elements have the same definition, and the same parent, we can cache the definition and skip the
application of the helper classes altogether. This helps particularly with large ngRepeat
collections.

Closes #14165
Closes #14166
Closes #16613
2018-07-05 19:46:11 +02:00
Martin Staffa ed22d2fe7b docs(changelog, guide/Migration): add info about $sce BC in 1.7
Closes #16593
Closes #16622
2018-07-05 19:46:10 +02:00
Martin Staffa a5cfa88630 docs(guide/Using Location): change / remove obsolete information 2018-07-05 19:46:09 +02:00
Martin Staffa bbf74f9994 docs(*): fix headlines 2018-07-05 19:46:09 +02:00
Atef Ben Ali 62ad450d60 docs(guide/component): add missing :
Add `:` to `Components have a well-defined lifecycle` title.

Closes #16620
2018-06-29 11:10:55 +03:00
Martin Staffa faa4b17c86 chore: fix eslint error 2018-06-23 17:57:24 +02:00
Pete Bacon Darwin 4d980a8771 chore(docs-app): ensure ToC links contain the path
Without the path the link is always pointing to the
root page, rather than the current page, which means
that copying the link address or opening the page in
a new tab is broken.

Closes #16608
2018-06-22 21:59:46 +01:00
Ilia Choly 369469b4f3 fix(grunt-utils): correctly detect java 32bit support
Closes #16605
2018-06-20 21:14:19 +03:00
Georgii Dolzhykov be417f2854 fix(ngMock/$httpBackend): correctly ignore query params in {expect,when}Route
Previously, a route definition such as
`$httpBackend.whenRoute('GET', '/route/:id')` matched against a URL with
query params, for example `/route/1?q=foo`, would incorrectly include
the query params in `id`: `{id: '1?q=foo', q: 'foo'}`.

This commit fixes it, so that the extracted `params` will now be:
`{id: '1', q: 'foo'}`.

Fixes #14173

Closes #16589
2018-06-18 19:50:10 +03:00
George Kalpakas 3a517c25f6 fix(ngAria): do not scroll when pressing spacebar on custom buttons
By default, pressing spacebar causes the browser to scroll down.
However, when a native button is focused, the button is clicked instead.

`ngAria`'s `ngClick` directive, sets elements up to behave like buttons.
For example, it adds `role="button"` and forwards `ENTER` and `SPACEBAR`
keypresses to the `click` handler (to emulate the behavior of native
buttons).

Yet, pressing spacebar on such an element, still invokes the default
browser behavior of scrolling down.

This commit fixes this, by calling `preventDefault()` on the keyboard
event, thus preventing the default scrolling behavior and making custom
buttons behave closer to native ones.

Closes #14665

Closes #16604
2018-06-18 18:49:50 +03:00
George Kalpakas 29b8dcf387 refactor(ngAria): clean up accessible actions tests 2018-06-18 18:49:21 +03:00
Martin Staffa c9d1e690aa feat(form.FormController): add $getControls()
Closes #16601
Fixes #14749
Closes #14517
Closes #13202
2018-06-18 16:05:39 +02:00
Martin Staffa a47247b5e0 docs(downloading.ngdoc): remove link to Google CDN overview page
AngularJS is no longer listed on the CDN page, because the available versions
were almost always out of date due to the need to manually update the list
2018-06-15 16:18:14 +02:00
Martin Staffa b682213d72 feat(ngModelOptions): add timeStripZeroSeconds and timeSecondsFormat
Closes #10721
Closes #16510
Closes #16584
2018-06-13 13:20:37 +02:00
George Kalpakas 223cf2b5bb docs(CHANGELOG): add release notes for 1.7.2 2018-06-12 16:34:38 +03:00
George Kalpakas c387e0d79d chore(doc-gen): error on unmatched links
Closes #16597
2018-06-12 14:45:22 +03:00
George Kalpakas cbf74d5d64 docs(*): fix dangling or ambiguous links 2018-06-12 14:45:06 +03:00
George Kalpakas a812327acd revert: refactor($compile): remove preAssignBindingsEnabled leftovers
This reverts commit 8e104ee508.

This internal clean-up turned out to break popular UI libraries (e.g.
`ngMaterial`, `ui-bootstrap`) and cause pain to developers.

Fixes #16594

Closes #16595
2018-06-11 17:09:48 +03:00
George Kalpakas 35fce310e9 docs(CHANGELOG): fix links to issues/PRs 2018-06-08 17:10:08 +03:00
George Kalpakas 93a754a490 docs(CHANGELOG): add release notes for 1.7.1 2018-06-08 16:26:22 +03:00
Georgios Kalpakas 7d9d387195 feat(ngAria): add support for ignoring a specific element
Fixes #14602
Fixes #14672

Closes #14833
2018-06-08 11:23:37 +03:00
Georgios Kalpakas feac52d840 refactor(ngAria): move test helpers inside of closure 2018-06-08 11:23:26 +03:00
Georgios Kalpakas f4f571efdf feat($route): add support for the reloadOnUrl configuration option
Enables users to specify that a particular route should not be reloaded after a
URL change (including a change in `$location.path()`), if the new URL maps to
the same route.
The default behavior is still to always load the matched route when any part of
the URL changes.

Related to #1699, #5860, #14999 (potentially closing the first two).

Fixes #7925

Closes #15002
2018-06-08 11:01:35 +03:00
Martin Staffa a8c263c194 feat(ngMessages): add support for default message
add support for showing default message when a truthy value is not matched by an ng-message directive.

Closes #12008
Closes #12213
Closes #16587
2018-06-06 17:54:59 +02:00
Martin Staffa 3d6c45d76e feat(errorHandlingConfig): add option to exclude error params from url
Specific errors, such as those during nested module loading, can create very long
error urls because the error message includes the error stack. These urls create visual
clutter in the browser console, are often not clickable, and may be rejected
by the docs page because they are simply too long.

We've already made improvements to the error display in #16283, which excludes
the error url from error parameters, which results in cleaner error messages.

Further, modern browsers restrict console message length intelligently.

This option can still be useful for older browsers like Internet Explorer, or
in general to reduce visual clutter in the console.

Closes #14744
Closes #15707
Closes #16283
Closes #16299 
Closes #16591
2018-06-06 17:54:57 +02:00
Martin Staffa bf841d3512 feat(ngRef): add directive to publish controller, or element into scope
Thanks to @drpicox for the original implementation: PR #14080 

Closes #16511
2018-06-06 17:54:52 +02:00
Christian Oliff a1d88457de docs(.editorconfig): change link to use https 2018-06-06 17:54:40 +02:00
Jakub Freisler b011ae9544 docs(ngAnimate): add "animating between value changes" section
Add a section which covers use case when users need to animate upon
a variable's value changes (not between two states).

Refers #16561

Closes #16582
2018-06-05 23:24:52 +03:00
Georgii Dolzhykov 63fdee6b9c docs($httpBackend): headers param of expect* can be function
Closes #16588
2018-06-04 15:18:34 +03:00
Jakub Freisler 257ebbb514 docs(ngAnimate): refactor of ngAnimate docs
- Synced "animation aware" directives tables in API docs and "Animation"
  guide.
- Sorted tables alphabetically.
- Added info about `ngAnimateSwap` directive.

References #16561

Closes #16581
2018-06-02 11:49:37 +03:00
George Kalpakas 2b6c986736 fix(ngModel): do not throw if view value changes on destroyed scope
This could for example happen if updating the value is debounced (either
by asynchronously calling `$setViewValue()` or via `ngModelOptions`).

Fixes #16583

Closes #16585
2018-05-31 12:31:22 +03:00
Georgii Dolzhykov 2da4950406 refactor($compile): remove preAssignBindingsEnabled leftovers
Now that we don't need to support `preAssignBindingsEnabled` (removed in #15782),
complexity introduced in `$controller` by #7645 can be removed.

One difference with the previous implementation is that all non-ES2015-class controller instances
were available on the element before calling their constructors. Now it depends on the relative
order of controllers. Controller constructors shouldn't be used to access other controllers
(e.g. via `$element.controller(directiveName)`). The recommended way is to use the `require`
property of the directive definition object and the life cycle hooks `$onChanges` or `$onInit`.

See
https://docs.angularjs.org/api/ng/service/$compile#-require-
https://docs.angularjs.org/api/ng/service/$compile#life-cycle-hooks

Closes #16580
2018-05-30 23:05:29 +03:00
George Kalpakas 789db83a8a fix($compile): support transcluding multi-element directives
Previously, transcluding multi-element directives (e.g. `foo-start`/`foo-end`)
was not supported on elements with multi-slot transclusion (a `uterdir` error
was thrown).
This commit fixes it by putting the transcluded nodes into a DocumentFragment,
where they can be traversed via `.nextSibling`.

Fixes #15554
Closes #15555
2018-05-26 17:29:46 +02:00
Martin Staffa ce443792c4 docs(ngMockE2E): add docs for $httpBackend.matchLatestDefinitionEnabled()
Closes #16577
2018-05-26 17:29:43 +02:00
Martin Staffa dd47867bfb chore: try ios 11.2 2018-05-26 11:05:27 +02:00
George Kalpakas f2ebb82ba5 refactor(ngModelOptions): fix ng-closure-runner warning
Without this fix `grunt minall` emits the following warning:
> WARNING - Parse error. Non-JSDoc comment has annotations.
> Did you mean to start it with '/**'?

Closes #16575
2018-05-24 13:02:28 +03:00
Martin Staffa 12698755be chore: set ios 11 in saucelabs to 11.3 2018-05-24 00:02:17 +02:00
Martin Staffa f7d7954904 chore: add platform to ios saucelabs 2018-05-24 00:02:13 +02:00
161 changed files with 7473 additions and 13350 deletions
-455
View File
@@ -1,455 +0,0 @@
# Configuration file for https://circleci.com/gh/angular/angular.js
# Note: YAML anchors allow an object to be re-used, reducing duplication.
# The ampersand declares an alias for an object, then later the `<<: *name`
# syntax dereferences it.
# See http://blog.daemonl.com/2016/02/yaml.html
# To validate changes, use an online parser, eg.
# http://yaml-online-parser.appspot.com/
# CircleCI configuration version
# Version 2.1 allows for extra config reuse features
# https://circleci.com/docs/2.0/reusing-config/#getting-started-with-config-reuse
version: 2.1
# Workspace persisted by the `setup` job to share build artifacts with other jobs.
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
var_workspace_location: &workspace_location ~/
# Executor Definitions
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-executors
# **NOTE 1**: Pin to exact images using an ID (SHA). See https://circleci.com/docs/2.0/circleci-images/#using-a-docker-image-id-to-pin-an-image-to-a-fixed-version.
# (Using the tag in not necessary when pinning by ID, but include it anyway for documentation purposes.)
executors:
default-executor:
parameters:
resource_class:
type: string
default: medium
docker:
- image: circleci/node:12.16.3@sha256:8fe514dae7585bbee1c64bf5a6cd4dcdf393316b5c87565b47e31014872c8860
resource_class: << parameters.resource_class >>
working_directory: ~/ng
cloud-sdk:
description: The docker container to use when running gcp-gcs commands
docker:
- image: google/cloud-sdk:alpine@sha256:7d0cae28cb282b76f2d9babe278c63c910d54f0cceca7a65fdf6806e2b43882e
working_directory: ~/ng
# Filter Definitions
# Filter to run a job on all branches and any `v1.X.Y(-Z)` tags.
# Since the jobs need to run on tagged builds too, a `tags` section has to be explicitly specified.
# (The `branches` section could be omitted, since it defaults to all branches - just being explicit
# here).
# See also https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag.
var-filter-run-always: &run-always
filters:
branches:
only: /.*/
tags:
only: /v1\.\d+\.\d.*/
# Filter to run a job when code/docs might need to be deployed - i.e. on tagged builds and on builds
# for master and `v1.*.x` branches.
# (Further checks are needed to determine whether a deployment is actually needed, but these are not
# possible via filters.)
var-filter-run-on-tags-and-master-and-version-branches: &run-on-tags-and-master-and-version-branches
filters:
branches:
only:
- master
- /v1\.\d+\.x/
tags:
only: /v1\.\d+\.\d.*/
# Filter to run a job when docs might need to be deployed - i.e. on builds for `v1.*.x` branches,
# which might correspond to the stable branch.
# (Further checks are needed to determine whether a deployment is actually needed, but these are not
# possible via filters.)
var-filter-run-on-version-branches: &run-on-version-branches
filters:
branches:
only:
- /v1\.\d+\.x/
tags:
ignore: /.*/
# Command Definitions
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-commands
commands:
skip_on_pr_and_fork_builds:
description: Skip a job on pull request and fork builds
steps:
- run:
name: Skip this job if this is a pull request or fork build
# Note: Using `CIRCLE_*` env variables (instead of those defined in `env.sh` so that this
# step can be run before `init_environment`.
command: >
if [[ -n "$CIRCLE_PR_NUMBER" ]] ||
[[ "$CIRCLE_PROJECT_USERNAME" != "angular" ]] ||
[[ "$CIRCLE_PROJECT_REPONAME" != "angular.js" ]]; then
echo "Skipping this job, because this is either a pull request or a fork build."
circleci step halt
fi
skip_unless_stable_branch:
description: Skip a job unless this is the stable branch
steps:
- run:
name: Skip this job unless this is the stable branch
command: >
if [[ "$DIST_TAG" != "latest" ]]; then
echo "Skipping deployment, because this is not the stable branch."
circleci step halt
fi
skip_unless_tag_or_master_or_stable_branch:
description: Skip a job unless this is a tag or the master or stable branch
steps:
- run:
name: Skip this job unless this is a tag or the master or stable branch
command: >
if [[ "$CI_GIT_TAG" == "false" ]] &&
[[ "$CI_BRANCH" != "master" ]] &&
[[ "$DIST_TAG" != "latest" ]]; then
echo "Skipping this job, because this is neither a tag nor the master or stable branch."
circleci step halt
fi
custom_attach_workspace:
description: Attach workspace at a predefined location
steps:
- attach_workspace:
at: *workspace_location
# Java is needed for running the Closure Compiler (during the `minall` task).
install_java:
description: Install java
steps:
- run:
name: Install java
command: |
sudo apt-get update
# Install java runtime
sudo apt-get install default-jre
# Initializes the CI environment by setting up common environment variables.
init_environment:
description: Initializing environment (setting up variables)
steps:
- run:
name: Set up environment
environment:
CIRCLE_GIT_BASE_REVISION: << pipeline.git.base_revision >>
CIRCLE_GIT_REVISION: << pipeline.git.revision >>
command: ./.circleci/env.sh
- run:
# Configure git as the CircleCI `checkout` command does.
# This is needed because we only checkout on the setup job.
# Add GitHub to known hosts
name: Configure git
command: |
mkdir -p ~/.ssh
echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts
git config --global url."ssh://git@github.com".insteadOf "https://github.com" || true
git config --global gc.auto 0 || true
init_saucelabs_environment:
description: Sets up a domain that resolves to the local host.
steps:
- run:
name: Preparing environment for running tests on Saucelabs.
command: |
# For SauceLabs jobs, we set up a domain which resolves to the machine which launched
# the tunnel. We do this because devices are sometimes not able to properly resolve
# `localhost` or `127.0.0.1` through the SauceLabs tunnel. Using a domain that does not
# resolve to anything on SauceLabs VMs ensures that such requests are always resolved
# through the tunnel, and resolve to the actual tunnel host machine (i.e. the CircleCI VM).
# More context can be found in: https://github.com/angular/angular/pull/35171.
setPublicVar SAUCE_LOCALHOST_ALIAS_DOMAIN "angular-ci.local"
setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
- run:
# Sets up a local domain in the machine's host file that resolves to the local
# host. This domain is helpful in Saucelabs tests where devices are not able to
# properly resolve `localhost` or `127.0.0.1` through the sauce-connect tunnel.
name: Setting up alias domain for local host.
command: echo "127.0.0.1 $SAUCE_LOCALHOST_ALIAS_DOMAIN" | sudo tee -a /etc/hosts
start_saucelabs:
steps:
- run:
name: Starting Saucelabs tunnel service
command: ./lib/saucelabs/sauce-service.sh start-ready-wait
stop_saucelabs:
steps:
- run:
name: Stopping Saucelabs tunnel service
command: ./lib/saucelabs/sauce-service.sh stop
run_e2e_tests:
parameters:
specs:
type: string
steps:
- custom_attach_workspace
- init_environment
- init_saucelabs_environment
- start_saucelabs
- run:
command: yarn grunt test:circleci-protractor --specs="<< parameters.specs >>"
no_output_timeout: 30m
- stop_saucelabs
run_e2e_tests_jquery:
parameters:
specs:
type: string
steps:
- custom_attach_workspace
- init_environment
- init_saucelabs_environment
- start_saucelabs
- run:
environment:
USE_JQUERY: 1
command: yarn grunt test:circleci-protractor --specs="<< parameters.specs >>"
no_output_timeout: 30m
- stop_saucelabs
# Job definitions
# Jobs can include parameters that are passed in the workflow job invocation.
# https://circleci.com/docs/2.0/reusing-config/#authoring-parameterized-jobs
jobs:
setup:
executor: default-executor
steps:
- checkout
- init_environment
- install_java
- run:
name: Running Yarn install
command: yarn install --frozen-lockfile --non-interactive
# Yarn's requests sometimes take more than 10mins to complete.
no_output_timeout: 45m
- run: yarn grunt package
# Persist any changes at this point to be reused by further jobs.
# **NOTE**: To add new content to the workspace, always persist on the same root.
- persist_to_workspace:
root: *workspace_location
paths:
- ./ng
lint:
executor: default-executor
steps:
- custom_attach_workspace
- init_environment
- run: yarn grunt ci-checks
- run: yarn commitplease "$CI_COMMIT_RANGE"
- run: yarn grunt validate-angular-files
unit-test:
executor:
name: default-executor
steps:
- custom_attach_workspace
- init_environment
- install_java
- init_saucelabs_environment
- run: yarn grunt test:promises-aplus
- run:
command: yarn grunt test:jqlite --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
- run:
command: yarn grunt test:modules --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
- run:
command: yarn grunt test:docs --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
unit-test-jquery:
executor:
name: default-executor
steps:
- custom_attach_workspace
- init_environment
- init_saucelabs_environment
- run:
command: yarn grunt test:jquery --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
- run:
command: yarn grunt test:jquery-2.2 --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
- run:
command: yarn grunt test:jquery-2.1 --browsers="$BROWSERS" --reporters=spec
no_output_timeout: 10m
e2e-test-1:
executor:
name: default-executor
steps:
- run_e2e_tests:
specs: test/e2e/tests/**/*.js
e2e-test-2a:
executor:
name: default-executor
steps:
- run_e2e_tests:
specs: build/docs/ptore2e/example-ng*/**/default_test.js
e2e-test-2b:
executor:
name: default-executor
steps:
- run_e2e_tests:
specs: "build/docs/ptore2e/!(example-ng*)/**/default_test.js"
e2e-test-jquery-1:
executor:
name: default-executor
steps:
- run_e2e_tests_jquery:
specs: test/e2e/tests/**/*.js
e2e-test-jquery-2a:
executor:
name: default-executor
steps:
- run_e2e_tests_jquery:
specs: build/docs/ptore2e/example-ng*/**/jquery_test.js
e2e-test-jquery-2b:
executor:
name: default-executor
steps:
- run_e2e_tests_jquery:
specs: build/docs/ptore2e/!(example-ng*)/**/jquery_test.js
prepare-deployment:
executor:
name: default-executor
steps:
- skip_on_pr_and_fork_builds
- custom_attach_workspace
- init_environment
- run: yarn grunt prepareDeploy
# Write the deployment files to the workspace to be used by deploy-docs and deploy-code
- persist_to_workspace:
root: *workspace_location
paths:
- ./ng
# The `deploy-code` job should only run when all of these conditions are true for the build:
# - It is for the `angular/angular.js` repository (not a fork).
# - It is not for a pull request.
# - It is for a tag or the master branch or the stable branch(*).
#
# *: The stable branch is the one that has the value `latest` in `package.json > distTag`.
deploy-code:
executor:
name: cloud-sdk
steps:
- skip_on_pr_and_fork_builds
- custom_attach_workspace
- init_environment
- skip_unless_tag_or_master_or_stable_branch
- run: ls deploy/code
- run:
name: Authenticate and configure Docker
command: |
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
- run:
name: Sync files to code.angularjs.org
command: |
gsutil -m rsync -r deploy/code gs://code-angularjs-org-338b8.appspot.com
# The `deploy-docs` job should only run when all of these conditions are true for the build:
# - It is for the `angular/angular.js` repository (not a fork).
# - It is not for a pull request.
# - It is for the stable branch(*).
#
# *: The stable branch is the one that has the value `latest` in `package.json > distTag`.
deploy-docs:
executor:
name: default-executor
steps:
- skip_on_pr_and_fork_builds
- custom_attach_workspace
- init_environment
- skip_unless_stable_branch
# Install dependencies for Firebase functions to prevent parsing errors during deployment
# See https://github.com/angular/angular.js/pull/16453
- run: yarn --cwd scripts/docs.angularjs.org-firebase/functions --ignore-engines
- run: yarn firebase deploy --message "Commit:\ $CI_COMMIT" --non-interactive --only hosting --project "docs-angularjs-org-9p2" --token "$FIREBASE_TOKEN"
workflows:
version: 2
default_workflow:
jobs:
- setup:
<<: *run-always
- lint:
<<: *run-always
requires:
- setup
- unit-test:
<<: *run-always
requires:
- setup
- unit-test-jquery:
<<: *run-always
requires:
- setup
- e2e-test-1:
<<: *run-always
requires:
- setup
- e2e-test-2a:
<<: *run-always
requires:
- setup
- e2e-test-2b:
<<: *run-always
requires:
- setup
- e2e-test-jquery-1:
<<: *run-always
requires:
- setup
- e2e-test-jquery-2a:
<<: *run-always
requires:
- setup
- e2e-test-jquery-2b:
<<: *run-always
requires:
- setup
- prepare-deployment:
<<: *run-on-tags-and-master-and-version-branches
requires:
- setup
- lint
- unit-test
- unit-test-jquery
- e2e-test-1
- e2e-test-2a
- e2e-test-2b
- e2e-test-jquery-1
- e2e-test-jquery-2a
- e2e-test-jquery-2b
- deploy-code:
<<: *run-on-tags-and-master-and-version-branches
requires:
- prepare-deployment
- deploy-docs:
<<: *run-on-version-branches
requires:
- prepare-deployment
-73
View File
@@ -1,73 +0,0 @@
####################################################################################################
# Helpers for defining environment variables for CircleCI.
#
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
# the default `bash` shell).
#
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
####################################################################################################
# Set and print an environment variable.
#
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
# visible to anyone through the CI logs.
#
# Usage: `setPublicVar <name> <value>`
function setPublicVar() {
setSecretVar $1 "$2";
echo "$1=$2";
}
# Set (without printing) an environment variable.
#
# Use this function for setting environment variables that are secret, i.e. should not be visible to
# everyone through the CI logs.
#
# Usage: `setSecretVar <name> <value>`
function setSecretVar() {
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
# (Keep original shell options to restore at the end.)
local -r originalShellOptions=$(set +o);
set +x -eu -o pipefail;
echo "export $1=\"${2:-}\";" >> $BASH_ENV;
# Restore original shell options.
eval "$originalShellOptions";
}
# Create a function to set an environment variable, when called.
#
# Use this function for creating setter for public environment variables that require expensive or
# time-consuming computaions and may not be needed. When needed, you can call this function to set
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
#
# Arguments:
# - `<name>`: The name of the environment variable. The generated setter function will be
# `setPublicVar_<name>`.
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
# executed lazily, it must be properly escaped. For example:
# ```sh
# # DO NOT do this:
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
#
# # DO this isntead:
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
# ```
#
# Usage: `createPublicVarSetter <name> <code>`
#
# Example:
# ```sh
# createPublicVarSetter MY_VAR 'echo "FOO"';
# echo $MY_VAR; # Not defined
#
# setPublicVar_MY_VAR;
# source $BASH_ENV;
# echo $MY_VAR; # FOO
# ```
function createPublicVarSetter() {
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
}
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/env bash
# Variables
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
# Load helpers and make them available everywhere (through `$BASH_ENV`).
source $envHelpersPath;
echo "source $envHelpersPath;" >> $BASH_ENV;
####################################################################################################
# Define PUBLIC environment variables for CircleCI.
####################################################################################################
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
####################################################################################################
setPublicVar CI "$CI"
setPublicVar PROJECT_ROOT "$projectDir";
# This is the branch being built; e.g. `pull/12345` for PR builds.
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}";
setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}";
setPublicVar CI_GIT_TAG "${CIRCLE_TAG:-false}";
setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION";
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
setPublicVar CI_PR_REPONAME "$CIRCLE_PR_REPONAME";
setPublicVar CI_PR_USERNAME "$CIRCLE_PR_USERNAME";
####################################################################################################
# Define SauceLabs environment variables for CircleCI.
####################################################################################################
setPublicVar BROWSER_PROVIDER "saucelabs"
# The currently latest-1 version of desktop Safari on Saucelabs (v12.0) is unstable and disconnects
# consistently. The latest version (v12.1) works fine.
# TODO: Add `SL_Safari-1` back, once it no longer corresponds to v12.0.
setPublicVar BROWSERS "SL_Chrome,SL_Chrome-1,\
SL_Firefox,SL_Firefox-1,\
SL_Safari,\
SL_iOS,SL_iOS-1,\
SL_IE_9,SL_IE_10,SL_IE_11,\
SL_EDGE,SL_EDGE-1"
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
setPublicVar SAUCE_TUNNEL_IDENTIFIER "angularjs-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}"
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
####################################################################################################
# Define additional environment variables
####################################################################################################
# NOTE: Make sure the tools used to compute this are available in all executors in `config.yml`.
setPublicVar DIST_TAG $( cat package.json | grep distTag | sed -E 's/^\s*"distTag"\s*:\s*"([^"]+)"\s*,\s*$/\1/' )
####################################################################################################
####################################################################################################
## Source `$BASH_ENV` to make the variables available immediately. ##
## *** NOTE: This must remain the last command in this script. *** ##
####################################################################################################
####################################################################################################
source $BASH_ENV;
+1 -1
View File
@@ -15,7 +15,7 @@
// Stylistic issues
"block-spacing": ["error", "always"],
"comma-spacing": "error",
"id-denylist": ["error", "event"],
"id-blacklist": ["error", "event"],
"indent": ["error", 2],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
"object-curly-spacing": ["error", "never"],
+4 -9
View File
@@ -1,7 +1,3 @@
# AngularJS is in LTS mode
We are no longer accepting changes that are not critical bug fixes into this project.
See https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c for more detail.
<!--
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATION
-->
@@ -13,9 +9,8 @@ IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOU
**I'm submitting a ...**
<!-- (check one with "x") -->
- [ ] regression from 1.7.0
- [ ] security issue
- [ ] issue caused by a new browser version
- [ ] bug report
- [ ] feature request
- [ ] other <!--(Please do not submit support requests here - see above)-->
**Current behavior:**
@@ -31,11 +26,11 @@ please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:yBpEi4).
-->
**AngularJS version:** 1.8.x
**AngularJS version:** 1.x.y
<!-- Check whether this is still an issue in the most recent stable or in the snapshot AngularJS
version (https://code.angularjs.org/snapshot/) -->
**Browser:** [all | Chrome XX | Firefox XX | Edge XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView | Opera XX ]
**Browser:** [all | Chrome XX | Firefox XX | Edge XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
<!-- All browsers where this could be reproduced (and Operating System if relevant) -->
**Anything else:**
+1 -6
View File
@@ -1,11 +1,6 @@
# AngularJS is in LTS mode
We are no longer accepting changes that are not critical bug fixes into this project.
See https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c for more detail.
<!-- General PR submission guidelines https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#submit-pr -->
**Does this PR fix a regression since 1.7.0, a security flaw, or a problem caused by a new browser version?**
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
<!-- If the answer is no, then we will not merge this PR -->
**What is the current behavior? (You can also link to an open issue here)**
-3
View File
@@ -12,7 +12,6 @@ performance/temp*.html
angular.js.tmproj
node_modules/
angular.xcodeproj
.firebase/
.idea
*.iml
.agignore
@@ -23,5 +22,3 @@ npm-debug.log
.vscode
*.log
*.stackdump
scripts/docs.angularjs.org-firebase/functions/content
/firebase.json
+1 -1
View File
@@ -1 +1 @@
12
8
+103
View File
@@ -0,0 +1,103 @@
language: node_js
sudo: false
node_js:
- '8'
cache:
yarn: true
branches:
except:
- "/^g3_.*$/"
env:
matrix:
- JOB=ci-checks
- JOB=unit-core BROWSER_PROVIDER=saucelabs
- JOB=unit-jquery BROWSER_PROVIDER=saucelabs
- JOB=docs-app BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- LOGS_DIR=/tmp/angular-build/logs
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
- secure: oTBjhnOKhs0qDSKTf7fE4f6DYiNDPycvB7qfSF5QRIbJK/LK/J4UtFwetXuXj79HhUZG9qnoT+5e7lPaiaMlpsIKn9ann7ffqFWN1E8TMtpJF+AGigx3djYElwfgf5nEnFUFhwjFzvbfpZNnxVGgX5YbIZpe/WUbHkP4ffU0Wks=
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.3.2
- export PATH="$HOME/.yarn/bin:$PATH"
before_script:
- du -sh ./node_modules || true
- "./scripts/travis/before_build.sh"
script:
- "./scripts/travis/build.sh"
after_script:
- "./scripts/travis/tear_down_browser_provider.sh"
- "./scripts/travis/print_logs.sh"
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
on_success: always # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: always # default: false
jobs:
include:
- stage: deploy
# Don't deploy from PRs. Only deploy from our default branches, or if commit is tagged.
# This is a Travis-specific boolean language: https://docs.travis-ci.com/user/conditional-builds-stages-jobs#Specifying-conditions
# The deployment logic for pushed branches is further defined in scripts\travis\build.sh
if: type != pull_request and (branch =~ ^(v1\.\d+\.x|master)$ or tag IS present)
env:
- JOB=deploy
before_script: skip
script:
# Export the variables into the current process
- . ./scripts/travis/build.sh
- "echo DEPLOY_DOCS: $DEPLOY_DOCS, DEPLOY_CODE: $DEPLOY_CODE"
after_script: skip
# Work around the 10min Travis timeout so the code.angularjs firebase+gcs code deploy can complete
# Only run the keep_alive once (before_deploy is run for each provider)
before_deploy: |
if ! [ "$BEFORE_DEPLOY_RUN" ]; then
export BEFORE_DEPLOY_RUN=1;
function keep_alive() {
while true; do
echo -en "\a"
sleep 10
done
}
keep_alive &
fi
deploy:
- provider: firebase
# the upload folder for firebase is configured in /firebase.json
skip_cleanup: true
project: docs-angularjs-org-9p2
token:
secure: $FIREBASE_TOKEN
on:
repo: angular/angular.js
all_branches: true
condition: "$DEPLOY_DOCS == true"
- provider: gcs
skip_cleanup: true
access_key_id: GOOGLDB7W2J3LFHICF3R
secret_access_key:
secure: tHIFdSq55qkyZf9zT/3+VkhUrTvOTMuswxXU3KyWaBrSieZqG0UnUDyNm+n3lSfX95zEl/+rJAWbfvhVSxZi13ndOtvRF+MdI1cvow2JynP0aDSiPffEvVrZOmihD6mt2SlMfhskr5FTduQ69kZG6DfLcve1PPDaIwnbOv3phb8=
bucket: code-angularjs-org-338b8.appspot.com
local-dir: deploy/code
detect_encoding: true # detects gzip compression
on:
repo: angular/angular.js
all_branches: true
condition: "$DEPLOY_CODE == true"
+2 -182
View File
@@ -1,183 +1,3 @@
<a name="1.8.2"></a>
# 1.8.2 meteoric-mining (2020-10-21)
## Bug Fixes
- **$sceDelegate:** ensure that `resourceUrlWhitelist()` is identical `trustedResourceUrlList()`
([e41f01](https://github.com/angular/angular.js/commit/e41f018959934bfbf982ba996cd654b1fce88d43),
[#17090](https://github.com/angular/angular.js/issues/17090))
- **$sanitize:** do not trigger CSP alert/report in Firefox and Chrome
([2fab3d](https://github.com/angular/angular.js/commit/2fab3d4e00f4fe35bfa3cf255160cb97404baf24))
<a name="1.8.1"></a>
# 1.8.1 mutually-supporting (2020-09-30)
## Bug Fixes
- **$sanitize:** do not trigger CSP alert/report in Firefox and Chrome
([2fab3d](https://github.com/angular/angular.js/commit/2fab3d4e00f4fe35bfa3cf255160cb97404baf24))
## Refactorings
- **SanitizeUriProvider:** remove usages of whitelist
([76738102](https://github.com/angular/angular.js/commit/767381020d88bda2855ac87ca6f00748907e14ff))
- **httpProvider:** remove usages of whitelist and blacklist
([c953af6b](https://github.com/angular/angular.js/commit/c953af6b8cfeefe4acc0ca358550eed5da8cfe00))
- **sceDelegateProvider:** remove usages of whitelist and blacklist
([a206e267](https://github.com/angular/angular.js/commit/a206e2675c351c3cdcde3402978126774c1c5df9))
## Deprecation Notices
- Deprecated ~~`$compileProvider.aHrefSanitizationWhitelist`~~.
It is now [aHrefSanitizationTrustedUrlList](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationTrustedUrlList)`.
- Deprecated ~~`$compileProvider.imgSrcSanitizationWhitelist`~~.
It is now [imgSrcSanitizationTrustedUrlList](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationTrustedUrlList).
- Deprecated ~~`$httpProvider.xsrfWhitelistedOrigins`~~.
It is now [xsrfTrustedOrigins](https://docs.angularjs.org/api/ng/provider/$httpProvider#xsrfTrustedOrigins).
- Deprecated ~~`$sceDelegateProvider.resourceUrlWhitelist`~~.
It is now [trustedResourceUrlList](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#trustedResourceUrlList).
- Deprecated ~~`$sceDelegateProvider.resourceUrlBlacklist`~~.
It is now [bannedResourceUrlList](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#bannedResourceUrlList).
For the purposes of backward compatibility, the previous symbols are aliased to their new symbol.
<a name="1.8.0"></a>
# 1.8.0 nested-vaccination (2020-06-01)
_This release contains a breaking change to resolve a security issue which was discovered by
Krzysztof Kotowicz(@koto); and independently by Esben Sparre Andreasen (@esbena) while
performing a Variant Analysis of [CVE-2020-11022](https://github.com/advisories/GHSA-gxr4-xjj5-5px2)
which itself was found and reported by Masato Kinugawa (@masatokinugawa)._
## Bug Fixes
- **jqLite:**
- prevent possible XSS due to regex-based HTML replacement
([2df43c](https://github.com/angular/angular.js/commit/2df43c07779137d1bddf7f3b282a1287a8634acd))
## Breaking Changes
### **jqLite** due to:
- **[2df43c](https://github.com/angular/angular.js/commit/2df43c07779137d1bddf7f3b282a1287a8634acd)**: prevent possible XSS due to regex-based HTML replacement
JqLite no longer turns XHTML-like strings like `<div /><span />` to sibling elements `<div></div><span></span>`
when not in XHTML mode. Instead it will leave them as-is. The browser, in non-XHTML mode, will convert these to:
`<div><span></span></div>`.
This is a security fix to avoid an XSS vulnerability if a new jqLite element is created from a user-controlled HTML string.
If you must have this functionality and understand the risk involved then it is posible to restore the original behavior by calling
```js
angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
```
But you should adjust your code for this change and remove your use of this function as soon as possible.
Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details about the workarounds.
<a name="1.7.9"></a>
# 1.7.9 pollution-eradication (2019-11-19)
## Bug Fixes
- **angular.merge:** do not merge __proto__ property
([726f49](https://github.com/angular/angular.js/commit/726f49dcf6c23106ddaf5cfd5e2e592841db743a))
<br>(Thanks to the [Snyk Security Research Team](https://snyk.io/blog/snyk-research-team-discovers-severe-prototype-pollution-security-vulnerabilities-affecting-all-versions-of-lodash/) for identifyng this issue.)
- **ngStyle:** correctly remove old style when new style value is invalid
([5edd25](https://github.com/angular/angular.js/commit/5edd25364f617083363dc2bd61f9230b38267578),
[#16860](https://github.com/angular/angular.js/issues/16860),
[#16868](https://github.com/angular/angular.js/issues/16868))
<a name="1.7.8"></a>
# 1.7.8 enthusiastic-oblation (2019-03-11)
## Bug Fixes
- **required:** correctly validate required on non-input element surrounded by ngIf
([a4c7bd](https://github.com/angular/angular.js/commit/a4c7bdccd76c39c30e33f6215da9a00cc8acde2c),
[#16830](https://github.com/angular/angular.js/issues/16830),
[#16836](https://github.com/angular/angular.js/issues/16836))
<a name="1.7.7"></a>
# 1.7.7 kingly-exiting (2019-02-04)
## Bug Fixes
- **ngRequired:** set error correctly when inside ngRepeat and false by default
([5ad4f5](https://github.com/angular/angular.js/commit/5ad4f5562c37b1cb575e3e5fddd96e9dd10408e2),
[#16814](https://github.com/angular/angular.js/issues/16814),
[#16820](https://github.com/angular/angular.js/issues/16820))
<a name="1.7.6"></a>
# 1.7.6 gravity-manipulation (2019-01-17)
## Bug Fixes
- **$compile:** fix ng-prop-* with undefined values
([772440](https://github.com/angular/angular.js/commit/772440cdaf9a9bfa40de1675e20a5f0e356089ed),
[#16797](https://github.com/angular/angular.js/issues/16797),
[#16798](https://github.com/angular/angular.js/issues/16798))
- **compile:** properly handle false value for boolean attrs with jQuery
([27486b](https://github.com/angular/angular.js/commit/27486bd15e70946ece2ba713e4e8654b7f9bddad),
[#16778](https://github.com/angular/angular.js/issues/16778),
[#16779](https://github.com/angular/angular.js/issues/16779))
- **ngRepeat:**
- fix reference to last collection value remaining across linkages
([cf919a](https://github.com/angular/angular.js/commit/cf919a6fb7fc655f3fa37a74899a797ea5b8073e))
- fix trackBy function being invoked with incorrect scope
([d4d103](https://github.com/angular/angular.js/commit/d4d1031bcd9b30ae6a58bd60a79bcc9d20f0f2b7),
[#16776](https://github.com/angular/angular.js/issues/16776),
[#16777](https://github.com/angular/angular.js/issues/16777))
- **aria/ngClick:** check if element is `contenteditable` before blocking spacebar
([289374](https://github.com/angular/angular.js/commit/289374a43c1b2fd715ddf7455db225b17afebbaf),
[#16762](https://github.com/angular/angular.js/issues/16762))
- **input:** prevent browsers from autofilling hidden inputs
([7cbb10](https://github.com/angular/angular.js/commit/7cbb1044fcb3576cdad791bd22ebea3dfd533ff8))
- **Angular:** add workaround for Safari / Webdriver problem
([eb49f6](https://github.com/angular/angular.js/commit/eb49f6b7555cfd7ab03fd35581adb6b4bd49044e))
- **$browser:** normalize inputted URLs
([2f72a6](https://github.com/angular/angular.js/commit/2f72a69ded53a122afad3ec28d91f9bd2f41eb4f),
[#16606](https://github.com/angular/angular.js/issues/16606))
- **interpolate:** do not create directives for constant media URL attributes
([90a41d](https://github.com/angular/angular.js/commit/90a41d415c83abdbf28317f49df0fd0a7e07db86),
[#16734](https://github.com/angular/angular.js/issues/16734))
- **$q:** allow third-party promise libraries
([eefaa7](https://github.com/angular/angular.js/commit/eefaa76a90dbef08fdc7d734a205cc2de50d9f91),
[#16164](https://github.com/angular/angular.js/issues/16164),
[#16471](https://github.com/angular/angular.js/issues/16471))
- **urlUtils:** make IPv6 URL's hostname wrapped in square brackets in IE/Edge
([0e1bd7](https://github.com/angular/angular.js/commit/0e1bd7822e61822a48b8fd7ba5913a8702e6dabf),
[#16692](https://github.com/angular/angular.js/issues/16692),
[#16715](https://github.com/angular/angular.js/issues/16715))
- **ngAnimateSwap:** make it compatible with `ngIf` on the same element
([b27080](https://github.com/angular/angular.js/commit/b27080d52546409fb4e483f212f03616e2ca8037),
[#16616](https://github.com/angular/angular.js/issues/16616),
[#16729](https://github.com/angular/angular.js/issues/16729))
- **ngMock:** make matchLatestDefinitionEnabled work
([3cdffc](https://github.com/angular/angular.js/commit/3cdffcecbae71189b4db69b57fadda6608a23b61),
[#16702](https://github.com/angular/angular.js/issues/16702))
- **ngStyle:** skip setting empty value when new style has the property
([d6098e](https://github.com/angular/angular.js/commit/d6098eeb1c9510d599e9bd3cfdba7dd21e7a55a5),
[#16709](https://github.com/angular/angular.js/issues/16709))
## Performance Improvements
- **input:** prevent multiple validations on initialization
([692622](https://github.com/angular/angular.js/commit/69262239632027b373258e75c670b89132ad9edb),
[#14691](https://github.com/angular/angular.js/issues/14691),
[#16760](https://github.com/angular/angular.js/issues/16760))
<a name="1.7.5"></a>
# 1.7.5 anti-prettification (2018-10-04)
## Bug Fixes
- **ngClass:** do not break on invalid values
([f3a565](https://github.com/angular/angular.js/commit/f3a565872d802c94bb213944791b11b483d52f73),
[#16697](https://github.com/angular/angular.js/issues/16697),
[#16699](https://github.com/angular/angular.js/issues/16699))
<a name="1.7.4"></a>
# 1.7.4 interstellar-exploration (2018-09-07)
@@ -916,7 +736,7 @@ If you rely on the $modelValue validation, you can overwrite the `min`/`max` val
link: function(scope, element, attrs, ctrl) {
var maxValidator = ctrl.$validators.max;
ctrl.$validators.max = function(modelValue, viewValue) {
ctrk.$validators.max = function(modelValue, viewValue) {
return maxValidator(modelValue, modelValue);
};
}
@@ -1749,7 +1569,7 @@ If you rely on the $modelValue validation, you can overwrite the `min`/`max` val
link: function(scope, element, attrs, ctrl) {
var maxValidator = ctrl.$validators.max;
ctrl.$validators.max = function(modelValue, viewValue) {
ctrk.$validators.max = function(modelValue, viewValue) {
return maxValidator(modelValue, modelValue);
};
}
+5 -5
View File
@@ -125,8 +125,8 @@ Before you submit your pull request consider the following guidelines:
* Follow our [Coding Rules][developers.rules].
* If the changes affect public APIs, change or add relevant [documentation][developers.documentation].
* Run the AngularJS [unit][developers.tests-unit] and [E2E test][developers.tests-e2e] suites, and ensure that all tests
pass. It is generally sufficient to run the tests only on Chrome, as our continuous integration test will
run the tests on additional browsers.
pass. It is generally sufficient to run the tests only on Chrome, as our Travis integration will
run the tests on all supported browsers.
* Run `yarn grunt eslint` to check that you have followed the automatically enforced coding rules
* Commit your changes using a descriptive commit message that follows our
[commit message conventions][developers.commits]. Adherence to the
@@ -151,9 +151,9 @@ Before you submit your pull request consider the following guidelines:
```
* In GitHub, send a pull request to `angular.js:master`. This will trigger the check of the
[Contributor License Agreement](#cla) and the continuous integration tests.
[Contributor License Agreement](#cla) and the Travis integration.
* If you find that the continuous integration tests have failed, look into the logs to find out
* If you find that the Travis integration has failed, look into the logs on Travis to find out
if your changes caused test failures, the commit message was malformed etc. If you find that the
tests failed or times out for unrelated reasons, you can ping a team member so that the build can be
restarted.
@@ -172,7 +172,7 @@ restarted.
git push origin my-fix-branch -f
```
This is generally easier to follow, but separate commits are useful if the Pull Request contains
This is generally easier to follow, but seperate commits are useful if the Pull Request contains
iterations that might be interesting to see side-by-side.
That's it! Thank you for your contribution!
+3 -2
View File
@@ -249,7 +249,7 @@ format that includes a **type**, a **scope** and a **subject**:
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
### Revert
@@ -257,6 +257,7 @@ If the commit reverts a previous commit, it should begin with `revert: `, follow
of the reverted commit.
In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit
being reverted.
A commit with this format is automatically created by the [`git revert`][git-revert] command.
### Type
Must be one of the following:
@@ -428,7 +429,7 @@ if it is enclosed in &lt;pre&gt;...&lt;/pre&gt; tags and the code lines themselv
It is possible to embed examples in the documentation along with appropriate e2e tests. These
examples and scenarios will be converted to runnable code within the documentation. So it is
important that they work correctly. To ensure this, all these e2e scenarios are run as part of the
continuous integration tests.
automated Travis tests.
If you are adding an example with an e2e test, you should [run the test locally](#e2e-tests) first
to ensure it passes. You can change `it(...)` to `fit(...)` to run only your test,
+34 -66
View File
@@ -4,7 +4,6 @@ var serveFavicon = require('serve-favicon');
var serveStatic = require('serve-static');
var serveIndex = require('serve-index');
var files = require('./angularFiles').files;
var mergeFilesFor = require('./angularFiles').mergeFilesFor;
var util = require('./lib/grunt/utils.js');
var versionInfo = require('./lib/versions/version-info');
var path = require('path');
@@ -14,7 +13,7 @@ var semver = require('semver');
var exec = require('shelljs').exec;
var pkg = require(__dirname + '/package.json');
var docsScriptFolder = util.docsScriptFolder;
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
// Node.js version checks
if (!semver.satisfies(process.version, pkg.engines.node)) {
@@ -31,7 +30,7 @@ if (!semver.satisfies(currentYarnVersion, expectedYarnVersion)) {
}
// Grunt CLI version checks
var expectedGruntVersion = pkg.engines['grunt-cli'];
var expectedGruntVersion = pkg.engines.grunt;
var currentGruntVersions = exec('grunt --version', {silent: true}).stdout;
var match = /^grunt-cli v(.+)$/m.exec(currentGruntVersions);
if (!match) {
@@ -45,7 +44,7 @@ if (!match) {
}
// Ensure Node.js dependencies have been installed
if (!process.env.CI) {
if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
var yarnOutput = exec('yarn install');
if (yarnOutput.code !== 0) {
throw new Error('Yarn install failed: ' + yarnOutput.stderr);
@@ -109,14 +108,16 @@ module.exports = function(grunt) {
},
testserver: {
options: {
// We start the webserver as a separate process from the E2E tests
// We use end2end task (which does not start the webserver)
// and start the webserver as a separate process (in travis_build.sh)
// to avoid https://github.com/joyent/libuv/issues/826
port: 8000,
hostname: '0.0.0.0',
middleware: function(connect, options) {
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
return [
function(req, resp, next) {
// cache GET requests to speed up tests
// cache get requests to speed up tests on travis
if (req.method === 'GET') {
resp.setHeader('Cache-control', 'public, max-age=3600');
}
@@ -140,9 +141,7 @@ module.exports = function(grunt) {
'jquery-2.2': 'karma-jquery-2.2.conf.js',
'jquery-2.1': 'karma-jquery-2.1.conf.js',
docs: 'karma-docs.conf.js',
modules: 'karma-modules.conf.js',
'modules-ngAnimate': 'karma-modules-ngAnimate.conf.js',
'modules-ngMock': 'karma-modules-ngMock.conf.js'
modules: 'karma-modules.conf.js'
},
@@ -158,7 +157,8 @@ module.exports = function(grunt) {
protractor: {
normal: 'protractor-conf.js',
circleci: 'protractor-circleci-conf.js'
travis: 'protractor-travis-conf.js',
jenkins: 'protractor-jenkins-conf.js'
},
@@ -211,12 +211,6 @@ module.exports = function(grunt) {
dest: 'build/angular-touch.js',
src: util.wrap(files['angularModules']['ngTouch'], 'module')
},
touchModuleTestBundle: {
dest: 'build/test-bundles/angular-touch.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngTouch'),
suffix: 'src/module.suffix'
},
mocks: {
dest: 'build/angular-mocks.js',
src: util.wrap(files['angularModules']['ngMock'], 'module'),
@@ -226,42 +220,18 @@ module.exports = function(grunt) {
dest: 'build/angular-sanitize.js',
src: util.wrap(files['angularModules']['ngSanitize'], 'module')
},
sanitizeModuleTestBundle: {
dest: 'build/test-bundles/angular-sanitize.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngSanitize'),
suffix: 'src/module.suffix'
},
resource: {
dest: 'build/angular-resource.js',
src: util.wrap(files['angularModules']['ngResource'], 'module')
},
resourceModuleTestBundle: {
dest: 'build/test-bundles/angular-resource.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngResource'),
suffix: 'src/module.suffix'
},
messageformat: {
dest: 'build/angular-message-format.js',
src: util.wrap(files['angularModules']['ngMessageFormat'], 'module')
},
messageformatModuleTestBundle: {
dest: 'build/test-bundles/angular-message-format.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngMessageFormat'),
suffix: 'src/module.suffix'
},
messages: {
dest: 'build/angular-messages.js',
src: util.wrap(files['angularModules']['ngMessages'], 'module')
},
messagesModuleTestBundle: {
dest: 'build/test-bundles/angular-messages.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngMessages'),
suffix: 'src/module.suffix'
},
animate: {
dest: 'build/angular-animate.js',
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
@@ -270,32 +240,14 @@ module.exports = function(grunt) {
dest: 'build/angular-route.js',
src: util.wrap(files['angularModules']['ngRoute'], 'module')
},
routeModuleTestBundle: {
dest: 'build/test-bundles/angular-route.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngRoute'),
suffix: 'src/module.suffix'
},
cookies: {
dest: 'build/angular-cookies.js',
src: util.wrap(files['angularModules']['ngCookies'], 'module')
},
cookiesModuleTestBundle: {
dest: 'build/test-bundles/angular-cookies.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngCookies'),
suffix: 'src/module.suffix'
},
aria: {
dest: 'build/angular-aria.js',
src: util.wrap(files['angularModules']['ngAria'], 'module')
},
ariaModuleTestBundle: {
dest: 'build/test-bundles/angular-aria.js',
prefix: 'src/module.prefix',
src: mergeFilesFor('karmaModules-ngAria'),
suffix: 'src/module.suffix'
},
parseext: {
dest: 'build/angular-parse-ext.js',
src: util.wrap(files['angularModules']['ngParseExt'], 'module')
@@ -369,9 +321,10 @@ module.exports = function(grunt) {
},
deployFirebaseCode: {
files: [
// copy files that are not handled by compress
{
cwd: 'build',
src: '**',
src: '**/*.{zip,jpg,jpeg,png}',
dest: 'deploy/code/' + deployVersion + '/',
expand: true
}
@@ -419,6 +372,16 @@ module.exports = function(grunt) {
expand: true,
dot: true,
dest: dist + '/'
},
deployFirebaseCode: {
options: {
mode: 'gzip'
},
// Already compressed files should not be compressed again
src: ['**', '!**/*.{zip,png,jpeg,jpg}'],
cwd: 'build',
expand: true,
dest: 'deploy/code/' + deployVersion + '/'
}
},
@@ -467,9 +430,7 @@ module.exports = function(grunt) {
grunt.registerTask('test:jquery-2.1', 'Run the jQuery 2.1 unit tests with Karma', ['tests:jquery-2.1']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', [
'build',
'tests:modules',
'tests:modules-ngAnimate',
'tests:modules-ngMock'
'tests:modules'
]);
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', [
@@ -484,9 +445,14 @@ module.exports = function(grunt) {
'connect:testserver',
'protractor:normal'
]);
grunt.registerTask('test:circleci-protractor', 'Run the end to end tests with Protractor for CircleCI builds', [
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', [
'connect:testserver',
'protractor:circleci'
'protractor:travis'
]);
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', [
'webdriver',
'connect:testserver',
'protractor:jenkins'
]);
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
grunt.registerTask('test:promises-aplus',[
@@ -516,8 +482,10 @@ module.exports = function(grunt) {
'eslint'
]);
grunt.registerTask('prepareDeploy', [
'package',
'compress:deployFirebaseCode',
'copy:deployFirebaseCode',
'firebaseDocsJsonForCI',
'firebaseDocsJsonForTravis',
'copy:deployFirebaseDocs'
]);
grunt.registerTask('default', ['package']);
@@ -525,7 +493,7 @@ module.exports = function(grunt) {
function reportOrFail(message) {
if (process.env.CI) {
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
throw new Error(message);
} else {
console.log('===============================================================================');
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2020 Google LLC. http://angularjs.org
Copyright (c) 2010-2018 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+3 -3
View File
@@ -1,4 +1,4 @@
AngularJS [![CircleCI](https://circleci.com/gh/angular/angular.js/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular.js/tree/master)
AngularJS [![Build Status](https://travis-ci.org/angular/angular.js.svg?branch=master)](https://travis-ci.org/angular/angular.js)
=========
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
@@ -14,9 +14,9 @@ piece of cake. Best of all? It makes development fun!
--------------------
**On July 1, 2018 AngularJS entered a 3 year Long Term Support period:** [Find out more](https://docs.angularjs.org/misc/version-support-status)
##### AngularJS will be moving to Long Term Support (LTS) mode on July 1st 2018: [Find out more](https://docs.angularjs.org/misc/version-support-status)
**Looking for the new Angular? Go here:** https://github.com/angular/angular
##### Looking for the new Angular? Go here: https://github.com/angular/angular
--------------------
-98
View File
@@ -1,98 +0,0 @@
# AngularJS Release instructions
## Compare the list of commits between stable and unstable
There is a script - compare-master-to-stable.js - that helps with this.
We just want to make sure that good commits (low risk fixes + docs fixes) got cherry-picked into stable branch and nothing interesting got merged only into stable branch.
## Pick a release name (for this version)
A super-heroic power (adverb-verb phrase).
## Generate release notes
Example Commit: https://github.com/angular/angular.js/commit/7ab5098c14ee4f195dbfe2681e402fe2dfeacd78
1) Run
```bash
node_modules/.bin/changez -o changes.md -v <new version> <base branch>
```
2) Review the generated file and manually fix typos, group and reorder stuff if needed.
3) Move the content into CHANGELOG.md add release code-names to headers.
4) Push the changes to your private github repo and review.
5) cherry-pick the release notes commit to the appropriate branches.
## Pick a commit to release (for this version)
Usually this will be the commit containing the release notes, but it may also be in the past.
## Run "release" script
```bash
scripts/release/release.sh --git-push-dryrun=false --commit-sha=8822a4f --version-number=1.7.6 --version-name=gravity-manipulation
```
1) The SHA is of the commit to release (could be in the past).
2) The version number and code-name that should be released, not the next version number (e.g. to release 1.2.12 you enter 1.2.12 as release version and the code-name that was picked for 1.2.12, cauliflower-eradication).
3) You will need to have write access to all the AngularJS github dist repositories and publish rights for the AngularJS packages on npm.
## Update GitHub milestones
1) Create the next milestone if it doesn't exist yet-giving ita due date.
2) Move all open issues and PRs for the current milestone to the next milestone<br>
You can do this by filtering the current milestone, selecting via checklist, and moving to the next milestone within the GH issues page.
3) Close the current milestone click the milestones tab and close from there.
4) Create a new holding milestone for the release after next-but don't give it a due date otherwise that will mess up the dashboard.
## Push build artifacts to CDN
Google CDNs are fed with data from google3 every day at 11:15am PT it takes only few minutes for the import to propagate).
If we want to make our files available, we need submit our CLs before this time on the day of the release.
## Don't update the package.json (branchVersion) until the CDN has updated
This is the version used to compute what version to link to in the CDN. If you update this too early then the CDN lookup fails and you end up with 'null, for the version, which breaks the docs.
## Verify angularjs.org download modal has latest version (updates via CI job)
The versions in the modal are updated (based on the versions available on CDN) as part of the CI deploy stage.
(You may need to explicitly trigger the CI job. e.g. re-running the last `deploy` job.)
## Announce the release (via official Google accounts)
Double check that angularjs.org is up to date with the new release version before sharing.
1) Collect a list of contributors
use: `git log --format='%aN' v1.2.12..v1.2.13 | sort -u`
2) Write a blog post (for minor releases, not patch releases) and publish it with the "release" tag
3) Post on twitter as yourself (tweet from your heart; there is no template for this), retweet as @AngularJS
## Party!
## Major Release Tasks
1) Update angularjs.org to use the latest branch.
2) Write up a migration document.
3) Create a new git branch for the version that has been released (e.g. 1.8.x).
4) Check that the build and release scripts still work.
5) Update the dist-tag of the old branch, see https://github.com/angular/angular.js/pull/12722.
6) Write a blog post.
-20
View File
@@ -1,20 +0,0 @@
# Security Policy
## Supported Versions
| Version | Supported | Status | Comments |
| ----------- | ------------------ | --------------------- | ------------------------------------ |
| 1.8.x | :white_check_mark: | Long Term Support | See [Long Term Support policy][0] |
| 1.3.x-1.7.x | :x: | | |
| 1.2.x | :warning: | Security patches only | Last version to provide IE 8 support |
| <1.2.0 | :x: | | |
## Reporting a Vulnerability
Email us at [security@angularjs.org](mailto:security@angularjs.org) to report any potential security issues in AngularJS.
Please [use the latest AngularJS possible](https://docs.angularjs.org/guide/security#use-the-latest-angularjs-possible)
and keep in mind the guidance around AngularJS'
[expression language](https://docs.angularjs.org/guide/security#angularjs-templates-and-expressions).
[0]: https://docs.angularjs.org/misc/version-support-status#long-term-support
+13 -74
View File
@@ -189,72 +189,21 @@ var angularFiles = {
'src/angular.bind.js'
],
'karmaModules-ngAnimate': [
'karmaModules': [
'build/angular.js',
'build/angular-mocks.js',
'@angularSrcModules',
'test/modules/no_bootstrap.js',
'test/helpers/matchers.js',
'test/helpers/privateMocks.js',
'test/helpers/support.js',
'test/helpers/testabilityPatch.js',
'@angularSrcModuleNgAnimate',
'test/ngAnimate/**/*.js'
],
'karmaModules-ngAria': [
'@angularSrcModuleNgAria',
'test/ngAria/**/*.js'
],
'karmaModules-ngCookies': [
'@angularSrcModuleNgCookies',
'test/ngCookies/**/*.js'
],
'karmaModules-ngMessageFormat': [
'@angularSrcModuleNgMessageFormat',
'test/ngMessageFormat/**/*.js'
],
'karmaModules-ngMessages': [
'build/angular-animate.js',
'@angularSrcModuleNgMessages',
'test/ngMessages/**/*.js'
],
// ngMock doesn't include the base because it must use the ngMock src files
'karmaModules-ngMock': [
'build/angular.js',
'src/ngMock/*.js',
'test/modules/no_bootstrap.js',
'test/helpers/matchers.js',
'test/helpers/privateMocks.js',
'test/helpers/support.js',
'test/helpers/testabilityPatch.js',
'src/routeToRegExp.js',
'build/angular-animate.js',
'test/ngMock/**/*.js'
],
'karmaModules-ngResource': [
'@angularSrcModuleNgResource',
'test/ngResource/**/*.js'
],
'karmaModules-ngRoute': [
'build/angular-animate.js',
'@angularSrcModuleNgRoute',
'test/ngRoute/**/*.js'
],
'karmaModules-ngSanitize': [
'@angularSrcModuleNgSanitize',
'test/ngSanitize/**/*.js'
],
'karmaModules-ngTouch': [
'@angularSrcModuleNgTouch',
'test/ngTouch/**/*.js'
'test/helpers/*.js',
'test/ngAnimate/*.js',
'test/ngMessageFormat/*.js',
'test/ngMessages/*.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngRoute/**/*.js',
'test/ngResource/*.js',
'test/ngSanitize/**/*.js',
'test/ngTouch/**/*.js',
'test/ngAria/*.js'
],
'karmaJquery': [
@@ -283,16 +232,6 @@ var angularFiles = {
});
});
angularFiles['angularSrcModuleNgAnimate'] = angularFiles['angularModules']['ngAnimate'];
angularFiles['angularSrcModuleNgAria'] = angularFiles['angularModules']['ngAria'];
angularFiles['angularSrcModuleNgCookies'] = angularFiles['angularModules']['ngCookies'];
angularFiles['angularSrcModuleNgMessageFormat'] = angularFiles['angularModules']['ngMessageFormat'];
angularFiles['angularSrcModuleNgMessages'] = angularFiles['angularModules']['ngMessages'];
angularFiles['angularSrcModuleNgResource'] = angularFiles['angularModules']['ngResource'];
angularFiles['angularSrcModuleNgRoute'] = angularFiles['angularModules']['ngRoute'];
angularFiles['angularSrcModuleNgSanitize'] = angularFiles['angularModules']['ngSanitize'];
angularFiles['angularSrcModuleNgTouch'] = angularFiles['angularModules']['ngTouch'];
angularFiles['angularSrcModules'] = [].concat(
angularFiles['angularModules']['ngAnimate'],
angularFiles['angularModules']['ngMessageFormat'],
+2 -2
View File
@@ -55,7 +55,7 @@ angular.module('examples', [])
return function(url, newWindow, fields) {
/**
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
* If a user chooses to bypass pop-up blocker one time and click the link, they will arrive at
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
* newWindow param allows for this possibility.
@@ -74,7 +74,7 @@ angular.module('examples', [])
}])
.factory('createCopyrightNotice', function() {
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google LLC. All Rights Reserved.\n'
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
+ 'Use of this source code is governed by an MIT-style license that\n'
+ 'can be found in the LICENSE file at http://angular.io/license';
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
+4 -4
View File
@@ -47,13 +47,13 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
}
areasToSearch = _.keyBy(this.areasToSearch);
propertiesToIgnore = _.keyBy(this.propertiesToIgnore);
areasToSearch = _.indexBy(this.areasToSearch);
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
log.debug('Properties to ignore', propertiesToIgnore);
docTypesToIgnore = _.keyBy(this.docTypesToIgnore);
docTypesToIgnore = _.indexBy(this.docTypesToIgnore);
log.debug('Doc types to ignore', docTypesToIgnore);
var ignoreWordsMap = _.keyBy(wordsToIgnore);
var ignoreWordsMap = _.indexBy(wordsToIgnore);
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
// without the ng to the title text, e.g. "controller".
+1 -1
View File
@@ -224,7 +224,7 @@ module.exports = function generatePagesDataProcessor(log) {
.map(function(doc) {
return _.pick(doc, ['name', 'area', 'path']);
})
.keyBy('path')
.indexBy('path')
.value();
docs.push({
+4 -4
View File
@@ -13,11 +13,11 @@ module.exports = function generateVersionDocProcessor(gitData) {
return {
$runAfter: ['generatePagesDataProcessor'],
$runBefore: ['rendering-docs'],
// Remove rogue builds that are in the npm repository but not on code.angularjs.org
ignoredBuilds: ['1.3.4-build.3588'],
// the blacklist is to remove rogue builds that are in the npm repository but not on code.angularjs.org
blacklist: ['1.3.4-build.3588'],
$process: function(docs) {
var ignoredBuilds = this.ignoredBuilds;
var blacklist = this.blacklist;
var currentVersion = require('../../../build/version.json');
var output = exec('yarn info angular versions --json', { silent: true }).stdout.split('\n')[0];
var allVersions = processAllVersionsResponse(JSON.parse(output).data);
@@ -57,7 +57,7 @@ module.exports = function generateVersionDocProcessor(gitData) {
versions = versions
.filter(function(versionStr) {
return ignoredBuilds.indexOf(versionStr) === -1;
return blacklist.indexOf(versionStr) === -1;
})
.map(function(versionStr) {
return semver.parse(versionStr);
@@ -15,7 +15,7 @@ var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
// docs.angularjs.org and code.angularjs.org need them.
var versionPath = versionInfo.currentVersion.isSnapshot ?
'snapshot' :
versionInfo.currentVersion.version;
(versionInfo.currentVersion.version || versionInfo.currentVersion.version);
var examplesDependencyPath = angularCodeUrl + versionPath + '/';
module.exports = function productionDeployment(getVersion) {
@@ -1,12 +1,3 @@
{# Macros #}
{%- macro addTag(name, attributes) %}
<{$ name $}
{%- for attrName, attrValue in attributes -%}
{$ ' ' + attrName $}="{$ attrValue $}"
{%- endfor -%}
></{$ name $}>
{%- endmacro -%}
<!doctype html>
<html lang="en" ng-app="docsApp" ng-strict-di ng-controller="DocsController">
<head>
@@ -33,27 +24,50 @@
})();
</script>
<script type="text/javascript">
// Dynamically add `<base>` tag.
// dynamically add base tag as well as css and javascript files.
// we can't add css/js the usual way, because some browsers (FF) eagerly prefetch resources
// before the base attribute is added, causing 404 and terribly slow loading of the docs app.
(function() {
var indexFile = (location.pathname.match(/\/(index[^.]*\.html)/) || ['', ''])[1],
rUrl = /(#!\/|api|guide|misc|tutorial|error|index[^.]*\.html).*$/,
var indexFile = (location.pathname.match(/\/(index[^\.]*\.html)/) || ['', ''])[1],
rUrl = /(#!\/|api|guide|misc|tutorial|error|index[^\.]*\.html).*$/,
baseUrl = location.href.replace(rUrl, indexFile),
production = location.hostname === 'docs.angularjs.org',
headEl = document.getElementsByTagName('head')[0],
baseEl = document.createElement('base');
sync = true;
baseEl.setAttribute('href', baseUrl);
headEl.appendChild(baseEl);
addTag('base', {href: baseUrl});
{% for stylesheet in doc.stylesheets %}addTag('link', {rel: 'stylesheet', href: '{$ stylesheet $}', type: 'text/css'});
{% endfor %}
{% for script in doc.scripts %}addTag('script', {src: '{$ script $}' }, sync);
{% endfor %}
function addTag(name, attributes, sync) {
var el = document.createElement(name),
attrName;
for (attrName in attributes) {
el.setAttribute(attrName, attributes[attrName]);
}
sync ? document.write(outerHTML(el)) : headEl.appendChild(el);
}
function outerHTML(node){
// if IE, Chrome take the internal method otherwise build one
return node.outerHTML || (
function(n){
var div = document.createElement('div'), h;
div.appendChild(n);
h = div.innerHTML;
div = null;
return h;
})(node);
}
})();
</script>
{% for stylesheet in doc.stylesheets %}
{$- addTag('link', {rel: 'stylesheet', href: stylesheet, type: 'text/css'}) -$}
{% endfor %}
{% for script in doc.scripts %}
{$- addTag('script', {src: script}) -$}
{% endfor %}
<script type="text/javascript">
// GA asynchronous tracker
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-8594346-3']);
@@ -208,7 +222,7 @@
<p class="pull-right"><a back-to-top>Back to top</a></p>
<p>
Super-powered by Google ©2010-2020
Super-powered by Google ©2010-2018
(<a id="version"
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
ng-bind-template="v{{version}}" title="Changelog of this version of AngularJS">
@@ -17,7 +17,7 @@
{% endif %}
{% if method.this %}
<h4>Method's `this`</h4>
<h4>Method's {% code %}this{% endcode %}</h4>
{$ method.this | marked $}
{% endif %}
@@ -1,4 +1,4 @@
{% if doc.this %}
<h3>Method's `this`</h3>
<h3>Method's {% code %}this{% endcode %}</h3>
{$ doc.this | marked $}
{% endif %}
{% endif %}
+1 -1
View File
@@ -5,7 +5,7 @@
# AngularJS API Docs
<div class="alert alert-warning">
**On July 1, 2018 AngularJS entered a 3 year Long Term Support period:** [Find out more](misc/version-support-status).
**AngularJS will be moving to Long Term Support (LTS) mode on July 1st 2018.**: [Find out more](misc/version-support-status).
</div>
## Welcome to the AngularJS API docs page.
+3 -3
View File
@@ -3,7 +3,7 @@
@fullName Invalid matcher (only string patterns and RegExp instances are supported)
@description
Please see {@link $sceDelegateProvider#trustedResourceUrlList
$sceDelegateProvider.trustedResourceUrlList} and {@link
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} for the
Please see {@link $sceDelegateProvider#resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
list of acceptable items.
+2 -2
View File
@@ -15,8 +15,8 @@ By default, only URLs that belong to the same origin are trusted. These are urls
The {@link ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
To load templates from other domains and/or protocols, either adjust the {@link
ng.$sceDelegateProvider#trustedResourceUrlList trusted resource URL list}/ {@link
ng.$sceDelegateProvider#bannedResourceUrlList banned resource URL list} or wrap the URL with a call to {@link
ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
**Note**: The browser's [Same Origin
+3 -3
View File
@@ -3,7 +3,7 @@
@fullName The sequence *** is not a valid pattern wildcard
@description
The strings in {@link $sceDelegateProvider#trustedResourceUrlList
$sceDelegateProvider.trustedResourceUrlList} and {@link
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} may not
The strings in {@link $sceDelegateProvider#resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
+2 -3
View File
@@ -327,7 +327,7 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
<h2><span id="ngclick">ngClick</span> and <span id="ngdblclick">ngDblclick</span></h2>
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` to any element not in
the list of built in aria nodes:
a node blacklist:
* Button
* Anchor
@@ -337,8 +337,7 @@ the list of built in aria nodes:
* Details/Summary
To fix widespread accessibility problems with `ng-click` on `div` elements, ngAria will
dynamically bind a keypress event by default as long as the element isn't in a node from the list of
built in aria nodes.
dynamically bind a keypress event by default as long as the element isn't in the node blacklist.
You can turn this functionality on or off with the `bindKeypress` configuration option.
ngAria will also add the `button` role to communicate to users of assistive technologies. This can
+3 -3
View File
@@ -186,7 +186,7 @@ Right now, the `InvoiceController` contains all logic of our example. When the a
is a good practice to move view-independent logic from the controller into a
<a name="service">{@link services service}</a>, so it can be reused by other parts
of the application as well. Later on, we could also change that service to load the exchange rates
from the web, e.g. by calling the [exchangeratesapi.io](https://exchangeratesapi.io) exchange rate API, without changing the controller.
from the web, e.g. by calling the [Fixer.io](http://fixer.io) exchange rate API, without changing the controller.
Let's refactor our example and move the currency conversion into a service in another file:
@@ -300,7 +300,7 @@ to something shorter like `a`.
## Accessing the backend
Let's finish our example by fetching the exchange rates from the [exchangeratesapi.io](https://exchangeratesapi.io) exchange rate API.
Let's finish our example by fetching the exchange rates from the [Fixer.io](http://fixer.io) exchange rate API.
The following example shows how this is done with AngularJS:
<example name="guide-concepts-3" ng-app-included="true">
@@ -331,7 +331,7 @@ The following example shows how this is done with AngularJS:
};
var refresh = function() {
var url = 'https://api.exchangeratesapi.io/latest?base=USD&symbols=' + currencies.join(",");
var url = 'https://api.fixer.io/latest?base=USD&symbols=' + currencies.join(",");
return $http.get(url).then(function(response) {
usdToForeignRates = response.data.rates;
usdToForeignRates['USD'] = 1;
+3 -8
View File
@@ -279,20 +279,15 @@ construction and lookup of dependencies.
Here is an example of using the injector service:
First create an AngularJS module that will hold the service definition. (The empty array passed as
the second parameter means that this module does not depend on any other modules.)
```js
// Create a module to hold the service definition
// Provide the wiring information in a module
var myModule = angular.module('myModule', []);
```
Teach the injector how to build a `greeter` service, which is just an object that contains a `greet`
method. Notice that `greeter` is dependent on the `$window` service, which will be provided
(injected into `greeter`) by the injector.
Teach the injector how to build a `greeter` service. Notice that `greeter` is dependent on the
`$window` service. The `greeter` service is an object that contains a `greet` method.
```js
// Define the `greeter` service
myModule.factory('greeter', function($window) {
return {
greet: function(text) {
+3 -2
View File
@@ -17,8 +17,9 @@ attributes and tags. Read this document if you are planning on deploying your An
on IE.
The project currently supports and will attempt to fix bugs for IE9 and above. The continuous
integration server runs all unit tests against IE9, IE10, and IE11. See
[CircleCI](https://circleci.com/gh/angular/workflows/angular.js/tree/master).
integration server runs all the tests against IE9, IE10, and IE11. See
[Travis CI](https://travis-ci.org/angular/angular.js) and
[ci.angularjs.org](https://ci.angularjs.org).
We do not run tests on IE8 and below. A subset of the AngularJS functionality may work on these
browsers, but it is up to you to test and decide whether it works for your particular app.
+1 -1
View File
@@ -43,7 +43,7 @@ In AngularJS applications, you move the job of filling page templates with data
* **Animation:** {@link guide/animations Core concepts}, {@link ngAnimate ngAnimate API}
* **Security:** {@link guide/security Security Docs}, {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
* **Internationalization and Localization:** {@link guide/i18n AngularJS Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](https://blog.novanet.no/creating-multilingual-support-using-angularjs/)
* **Internationalization and Localization:** {@link guide/i18n AngularJS Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
* **Touch events:** {@link ngTouch Touch events}
* **Accessibility:** {@link guide/accessibility ngAria}
+16 -42
View File
@@ -15,30 +15,6 @@ which drives many of these changes.
* Several new features, especially animations, would not be possible without a few changes.
* Finally, some outstanding bugs were best fixed by changing an existing API.
## Migrating from 1.7 to 1.8
Generally updating to 1.8.0 from 1.7.x should be a straightforward process and is highly recommended.
AngularJS 1.8 is a breaking change release from 1.7 to mitigate a security issue.
JqLite no longer turns XHTML-like strings like `<div /><span />` to sibling elements when not in XHTML
mode: `<div></div><span></span>`.
Instead it will leave the elements alone. In non-XHTML mode the browser will convert these to nested
elements: `<div><span></span></div>`.
This is a security fix to avoid an XSS vulnerability if a new jqLite element is created from a
user-controlled HTML string. If you must have this functionality and understand the risk involved
then it is posible to restore the original behavior by calling
```js
angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
```
But you should adjust your code for this change and remove your use of this function as soon as
possible.
Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
[jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details about the workarounds.
## Migrating from 1.6 to 1.7
@@ -172,7 +148,7 @@ custom directive, as seen in the following example directive definition object:
link: function(scope, element, attrs, ctrl) {
var maxValidator = ctrl.$validators.max;
ctrl.$validators.max = function(modelValue, viewValue) {
ctrk.$validators.max = function(modelValue, viewValue) {
return maxValidator(modelValue, modelValue);
};
}
@@ -276,16 +252,15 @@ statement.
**Due to [6ccbfa](https://github.com/angular/angular.js/commit/6ccbfa65d60a3dc396d0cf6da21b993ad74653fd)**,
the `xlink:href` security context for SVG's `a` and `image` elements has been lowered.
In the unlikely case that an app relied on `RESOURCE_URL` trusted list for the
In the unlikely case that an app relied on `RESOURCE_URL` whitelisting for the
purpose of binding to the `xlink:href` property of SVG's `<a>` or `<image>`
elements and if the values do not pass the regular URL sanitization, they will
break.
To fix this you need to ensure that the values used for binding to the affected
`xlink:href` contexts are considered safe URLs, e.g. by trusting them in
`$compileProvider`'s `aHrefSanitizationWhitelist` (called `aHrefSanitizationTrustedUrlList` form
1.8.1 onwards) (for `<a>` elements) or `imgSrcSanitizationWhitelist` (called
`imgSrcSanitizationTrustedUrlList` from 1.8.1 onwards) (for `<image>` elements).
`xlink:href` contexts are considered safe URLs, e.g. by whitelisting them in
`$compileProvider`'s `aHrefSanitizationWhitelist` (for `<a>` elements) or
`imgSrcSanitizationWhitelist` (for `<image>` elements).
<hr />
@@ -602,7 +577,7 @@ orderByFilter(['a', undefined, 'o', null, 'z']);
<a name="migrate1.6to1.7-ng-misc"></a>
### Core: _Miscellaneous_
### Core: _Misceallenous_
#### **jqLite**
@@ -1310,7 +1285,7 @@ running at `https://docs.angularjs.org` then the following will fail:
By default, only URLs with the same domain and protocol as the application document are considered
safe in the `RESOURCE_URL` context. To use URLs from other domains and/or protocols, you may either
add them to the trusted source URL list or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
whitelist them or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
<hr />
<minor />
@@ -1388,7 +1363,7 @@ $http.json('other/trusted/url', {jsonpCallbackParam: 'cb'});
all JSONP requests now require the URL to be trusted as a resource URL. There are two approaches to
trust a URL:
1. **Setting trusted resource URLs with the `$sceDelegateProvider.resourceUrlWhitelist()` (called `trustedResourceUrlList()` from 1.8.1 onwards) method.**
1. **Whitelisting with the `$sceDelegateProvider.resourceUrlWhitelist()` method.**
You configure this list in a module configuration block:
```js
@@ -2208,7 +2183,7 @@ service does not have access to the resource in order to sanitize it.
Similarly, due to [234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094),
the `$sanitize` service will now also remove instances of the `usemap` attribute from any elements
passed to it. This attribute is used to reference another element by `name` or `id`. Since the
`name` and `id` attributes are already banned, a sanitized `usemap` attribute could only
`name` and `id` attributes are already blacklisted, a sanitized `usemap` attribute could only
reference unsanitized content, which is a security risk.
Due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
@@ -2648,8 +2623,8 @@ $scope.findTemplate = function(templateName) {
};
```
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the trusted resource
URL list in the `config()` function:
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the resource
whitelist in the `config()` function:
After:
@@ -2663,8 +2638,7 @@ $scope.findTemplate = function(templateName) {
return templateCache[templateName];
};
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()` (called
// `trustedResourceUrlList()` from 1.8.1 onwards), which means you don't
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()`, which means you don't
// have to use `$sce.trustAsResourceUrl()` at all:
angular.module('myApp', []).config(function($sceDelegateProvider) {
@@ -3355,7 +3329,7 @@ below should still apply, but you may want to consult the
<li>{@link guide/migration#directive-priority Directive priority}</li>
<li>{@link guide/migration#ngscenario ngScenario}</li>
<li>{@link guide/migration#nginclude-and-ngview-replace-its-entire-element-on-update ngInclude and ngView replace its entire element on update}</li>
<li>{@link guide/migration#urls-are-now-sanitized-against-a-trusted-uri-matcher URLs are now sanitized against a trusted URI matcher}</li>
<li>{@link guide/migration#urls-are-now-sanitized-against-a-whitelist URLs are now sanitized against a whitelist}</li>
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-scope-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
<li>{@link guide/migration#change-to-interpolation-priority Change to interpolation priority}</li>
<li>{@link guide/migration#underscore-prefixed-suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
@@ -3845,10 +3819,10 @@ See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d
[aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a).
### URLs are now sanitized against a trusted URI matcher
### URLs are now sanitized against a whitelist
A trusted URI matcher configured via `$compileProvider` can be used to configure what URLs are considered safe.
By default all common protocol prefixes are trusted including `data:` URIs with mime types `image/*`.
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
This change shouldn't impact apps that don't contain malicious image links.
See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97),
+2 -3
View File
@@ -174,9 +174,8 @@ Yes, AngularJS can use [jQuery](http://jquery.com/) if it's present in your app
application is being bootstrapped. If jQuery is not present in your script path, AngularJS falls back
to its own implementation of the subset of jQuery that we call {@link angular.element jQLite}.
For AngularJS 1.8 we support jQuery 2.1+ but we suggest jQuery 3.5.1 or above to avoid a potential
security issue. Earlier versions of jQuery might work correctly with AngularJS but we don't guarantee
that.
AngularJS 1.3 only supports jQuery 2.1 or above. jQuery 1.7 and newer might work correctly with AngularJS
but we don't guarantee that.
### What is testability like in AngularJS?
+7 -21
View File
@@ -7,14 +7,10 @@
This page describes the support status of the significant versions of AngularJS.
<div class="alert alert-info">
On July 1, 2018 AngularJS entered a 3 year Long Term Support period.<br />
<br />
_**UPDATE (2020-07-27):**_<br />
_Due to COVID-19 affecting teams migrating from AngularJS, we are extending the LTS by six months
(until December 31, 2021)._
On July 1, 2018 AngularJS entered a 3 year Long Term Support period.
</div>
Any version branch not shown in the following table (e.g. 1.7.x) is no longer being developed.
Any version branch not shown in the following table (e.g. 1.6.x) is no longer being developed.
<table class="dev-status table table-bordered">
<thead>
@@ -27,7 +23,7 @@ Any version branch not shown in the following table (e.g. 1.7.x) is no longer be
<td>Last version to provide IE 8 support</td>
</tr>
<tr class="stable">
<td><span>1.8.x</span></td>
<td><span>1.7.x</span></td>
<td>Long Term Support</td>
<td>See {@link version-support-status#long-term-support Long Term Support} section below.</td>
</tr>
@@ -36,26 +32,16 @@ Any version branch not shown in the following table (e.g. 1.7.x) is no longer be
### Long Term Support
On July 1st 2018, AngularJS entered a Long Term Support period.
On July 1st 2018, AngularJS entered a Long Term Support period for AngularJS.
We now focus exclusively on providing fixes to bugs that satisfy at least one of the following criteria:
* A security flaw is detected in the 1.8.x branch of the framework
* One of the major browsers releases a version that will cause current production applications using AngularJS 1.8.x to stop working
* The jQuery library releases a version that will cause current production applications using AngularJS 1.8.x to stop working.
* A security flaw is detected in the 1.7.x branch of the framework
* One of the major browsers releases a version that will cause current production applications using AngularJS 1.7.x to stop working
* The jQuery library releases a version that will cause current production applications using AngularJS 1.7.x to stop working.
AngularJS 1.2.x will get a new version if and only if a new severe security issue is discovered.
### Blog Post
You can read more about these plans in our [blog post announcement](https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c).
### Extended Long Term Support
If you need support for AngularJS beyond December 2021, you should consider:
* [XLTS.dev](https://angularjs.xlts.dev)
+23 -67
View File
@@ -64,7 +64,7 @@ a few git commands.
### Install Git
You can download and install Git from https://git-scm.com/download. Once installed, you should have
You can download and install Git from http://git-scm.com/download. Once installed, you should have
access to the `git` command line tool. The main commands that you will need to use are:
* `git clone ...`: Clone a remote repository onto your local machine.
@@ -99,8 +99,8 @@ The tutorial instructions, from now on, assume you are running all commands from
### Install Node.js
In order to install dependencies (such as the test tools and AngularJS itself) and run the
preconfigured local web server, you will also need [Node.js v6+][node].
If you want to run the preconfigured local web server and the test tools then you will also need
[Node.js v4+][node].
You can download a Node.js installer for your operating system from https://nodejs.org/en/download/.
@@ -125,25 +125,22 @@ npm --version
[Node Version Manager (nvm)][nvm] or [Node Version Manager (nvm) for Windows][nvm-windows].
</div>
By installing Node.js, you also get [npm][npm], which is a command line executable for downloading
and managing Node.js packages. We use it to download the AngularJS framework as well as development
and testing tools.
Once you have Node.js installed on your machine, you can download these dependencies by running:
Once you have Node.js installed on your machine, you can download the tool dependencies by running:
```
npm install
```
This command reads angular-phonecat's `package.json` file and downloads the following dependencies
into the `node_modules` directory:
This command reads angular-phonecat's `package.json` file and downloads the following tools into the
`node_modules` directory:
* [Bower][bower] - client-side code package manager
* [Http-Server][http-server] - simple local static web server
* [Karma][karma] - unit test runner
* [Protractor][protractor] - end-to-end (E2E) test runner
Running `npm install` will also automatically copy the AngularJS framework and other dependencies
necessary for our app to work into the `app/lib/` directory.
Running `npm install` will also automatically use bower to download the AngularJS framework into the
`app/bower_components` directory.
<div class="alert alert-info">
Note the angular-phonecat project is setup to install and run these utilities via npm scripts.
@@ -163,23 +160,23 @@ tasks that you will need while developing:
### Install Helper Tools (optional)
The Http-Server, Karma and Protractor modules are also executables, which can be installed globally
and run directly from a terminal/command prompt. You don't need to do this to follow the tutorial,
but if you decide you do want to run them directly, you can install these modules globally using,
`sudo npm install --global ...`.
The Bower, Http-Server, Karma and Protractor modules are also executables, which can be installed
globally and run directly from a terminal/command prompt. You don't need to do this to follow the
tutorial, but if you decide you do want to run them directly, you can install these modules globally
using, `sudo npm install -g ...`.
For instance, to install the `http-server` command line executable you would do:
For instance, to install the Bower command line executable you would do:
```
sudo npm install --global http-server
sudo npm install -g bower
```
_(Omit the sudo if running on Windows.)_
_(Omit the sudo if running on Windows)_
Then you can run the `http-server` tool directly, such as:
Then you can run the bower tool directly, such as:
```
http-server ./app
bower install
```
@@ -281,45 +278,6 @@ It is good to run the E2E tests whenever you make changes to the HTML views or w
the application as a whole is executing correctly. It is very common to run E2E tests before pushing
a new commit of changes to a remote repository.
<div class="alert alert-warning">
<p>
Each version of Protractor is compatible with specific browser versions. If you are reading this
some time in the future, it is possible that the specified Protractor version is no longer
compatible with the latest version of Chrome that you are using.
</p>
<p>
If that is the case, you can try upgrading Protractor to newer version. For instructions on how
to upgrade dependencies see [Updating dependencies](tutorial/#updating-dependencies).
</p>
</div>
### Updating dependencies
In order to avoid surprises, all dependencies listed in `package.json` are pinned to specific
versions (this is what the [package-lock.json][package-lock] file is about). This ensures that the
same version of a dependency is installed every time.
Since all dependencies are acquired via npm, you can use the same tool to easily update them as
well (although you probably don't need to for the purpose of this tutorial). Simply run the
preconfigured script:
```
npm run update-deps
```
This will update all packages to the latest version that satisfy their version ranges (as specified
in `package.json`) and also copy the necessary files into `app/lib/`. For example, if `package.json`
contains `"some-package": "1.2.x"`, it will be updated to the latest 1.2.x version (e.g. 1.2.99),
but not to 1.3.x (e.g. 1.3.0).
If you want to update a dependency to a version newer than what the specificed range would permit,
you can change the version range in `package.json` and then run `npm run update-deps` as usual.
<div class="alert alert-info">
See [here][semver-ranges] for more info on the various version range formats.
</div>
### Common Issues
@@ -366,16 +324,14 @@ Now that you have set up your local machine, let's get started with the tutorial
[angular-phonecat]: https://github.com/angular/angular-phonecat
[git]: https://git-scm.com/
[bower]: http://bower.io/
[git]: http://git-scm.com/
[http-server]: https://github.com/nodeapps/http-server
[jdk]: https://en.wikipedia.org/wiki/Java_Development_Kit
[jdk-download]: https://www.oracle.com/technetwork/java/javase/downloads/index.html
[jdk-download]: http://www.oracle.com/technetwork/java/javase/downloads/index.html
[karma]: https://karma-runner.github.io/
[node]: https://nodejs.org/
[npm]: https://www.npmjs.com/
[node]: http://nodejs.org/
[nvm]: https://github.com/creationix/nvm
[nvm-windows]: https://github.com/coreybutler/nvm-windows
[package-lock]: https://docs.npmjs.com/files/package-lock.json
[protractor]: https://github.com/angular/protractor
[selenium]: https://docs.seleniumhq.org/
[semver-ranges]: https://docs.npmjs.com/misc/semver#ranges
[selenium]: http://docs.seleniumhq.org/
+6 -7
View File
@@ -51,8 +51,8 @@ The code contains some key AngularJS elements that we will need as we progress.
<head>
<meta charset="utf-8">
<title>My HTML File</title>
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" />
<script src="lib/angular/angular.js"></script>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
<script src="bower_components/angular/angular.js"></script>
</head>
<body>
@@ -84,7 +84,7 @@ For more info on `ngApp`, check out the {@link ngApp API Reference}.
**`angular.js` script tag:**
```html
<script src="lib/angular/angular.js"></script>
<script src="bower_components/angular/angular.js"></script>
```
This code downloads the `angular.js` script which registers a callback that will be executed by the
@@ -154,8 +154,8 @@ and one static binding, and our model is empty. That will soon change!
Most of the files in your working directory come from the [angular-seed project][angular-seed],
which is typically used to bootstrap new AngularJS projects. The seed project is pre-configured to
install the AngularJS framework (via `npm` into the `app/lib/` directory) and tools for developing
and testing a typical web application (via `npm`).
install the AngularJS framework (via `bower` into the `app/bower_components/` directory) and tools
for developing and testing a typical web application (via `npm`).
For the purposes of this tutorial, we modified the angular-seed with the following changes:
@@ -163,7 +163,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi
* Removed unused dependencies.
* Added phone images to `app/img/phones/`.
* Added phone data files (JSON) to `app/phones/`.
* Added a dependency on [Bootstrap][bootstrap-3.3] in the `package.json` file.
* Added a dependency on [Bootstrap](http://getbootstrap.com) in the `bower.json` file.
## Experiments
@@ -186,4 +186,3 @@ Now let's go to {@link step_01 step 1} and add some content to the web app.
[angular-seed]: https://github.com/angular/angular-seed
[bootstrap-3.3]: https://getbootstrap.com/docs/3.3
+4 -4
View File
@@ -33,7 +33,7 @@ The view is constructed by AngularJS from this template.
<html ng-app="phonecatApp">
<head>
...
<script src="lib/angular/angular.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="PhoneListController">
@@ -317,7 +317,7 @@ by utilizing components.
<ul doc-tutorial-nav="2"></ul>
[jasmine-docs]: https://jasmine.github.io/api/3.3/global
[jasmine-home]: https://jasmine.github.io/
[jasmine-docs]: http://jasmine.github.io/2.4/introduction.html
[jasmine-home]: http://jasmine.github.io/
[karma]: https://karma-runner.github.io/
[mvc-pattern]: https://en.wikipedia.org/wiki/ModelViewController
[mvc-pattern]: http://en.wikipedia.org/wiki/ModelViewController
+6 -13
View File
@@ -88,13 +88,6 @@ Let's see an example:
});
```
```html
<body>
<!-- The following line is how to use the `greetUser` component above in your html doc. -->
<greet-user></greet-user>
</body>
```
Now, every time we include `<greet-user></greet-user>` in our view, AngularJS will expand it into a
DOM sub-tree constructed using the provided `template` and managed by an instance of the specified
controller.
@@ -127,14 +120,14 @@ acquired skill.
<html ng-app="phonecatApp">
<head>
...
<script src="lib/angular/angular.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="app.js"></script>
<script src="phone-list.component.js"></script>
</head>
<body>
<!-- Use a custom component to render a list of phones -->
<phone-list></phone-list> <!-- This tells AngularJS to instantiate a `phoneList` component here. -->
<phone-list></phone-list>
</body>
</html>
@@ -155,7 +148,7 @@ angular.module('phonecatApp', []);
// Register `phoneList` component, along with its associated controller and template
angular.
module('phonecatApp').
component('phoneList', { // This name is what AngularJS uses to match to the `<phone-list>` element.
component('phoneList', {
template:
'<ul>' +
'<li ng-repeat="phone in $ctrl.phones">' +
@@ -284,7 +277,7 @@ files, so it remains easy to locate as our application grows.
[case-styles]: https://en.wikipedia.org/wiki/Letter_case#Special_case_styles
[jasmine-docs]: https://jasmine.github.io/api/3.3/global
[jasmine-home]: https://jasmine.github.io/
[jasmine-docs]: http://jasmine.github.io/2.4/introduction.html
[jasmine-home]: http://jasmine.github.io/
[karma]: https://karma-runner.github.io/
[mvc-pattern]: https://en.wikipedia.org/wiki/ModelViewController
[mvc-pattern]: http://en.wikipedia.org/wiki/ModelViewController
-2
View File
@@ -230,8 +230,6 @@ You can now rerun `npm run protractor` to see the tests run.
* Reverse the sort order by adding a `-` symbol before the sorting value:
`<option value="-age">Oldest</option>`
After making this change, you'll notice that the drop-down list has a blank option selected and does not default to age anymore.
Fix this by updating the `orderProp` value in `phone-list.component.js` to match the new value on the `<option>` element.
## Summary
+2 -2
View File
@@ -8,8 +8,8 @@
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
from our server using one of AngularJS's built-in {@link guide/services services} called
{@link ng.$http $http}. We will use AngularJS's {@link guide/di dependency injection (DI)} to
provide the service to the `phoneList` component's controller.
{@link ng.$http $http}. We will use AngularJS's {@link guide/di dependency injection (DI)} to provide
the service to the `phoneList` component's controller.
* There is now a list of 20 phones, loaded from the server.
+5 -6
View File
@@ -47,10 +47,10 @@ URLs point to the `app/img/phones/` directory.
...
<ul class="phones">
<li ng-repeat="phone in $ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp" class="thumbnail">
<a href="#!/phones/{{phone.id}}" class="thumb">
<a href="#/phones/{{phone.id}}" class="thumb">
<img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}" />
</a>
<a href="#!/phones/{{phone.id}}">{{phone.name}}</a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
@@ -83,7 +83,7 @@ HTTP request to an invalid location.
query.sendKeys('nexus');
element.all(by.css('.phones li a')).first().click();
expect(browser.getCurrentUrl()).toContain('index.html#!/phones/nexus-s');
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
});
...
@@ -110,9 +110,8 @@ You can now rerun `npm run protractor` to see the tests run.
## Summary
Now that you have added phone images and links, go to {@link step_09 step 9} to learn about
AngularJS layout templates and how AngularJS makes it easy to create applications that have
multiple views.
Now that you have added phone images and links, go to {@link step_09 step 9} to learn about AngularJS
layout templates and how AngularJS makes it easy to create applications that have multiple views.
<ul doc-tutorial-nav="8"></ul>
+50 -39
View File
@@ -23,33 +23,49 @@ has multiple views by adding routing, using an AngularJS module called {@link ng
The routing functionality added in this step is provided by AngularJS in the `ngRoute` module, which
is distributed separately from the core AngularJS framework.
Since we are using [npm][npm] to install client-side dependencies, this step updates the
`package.json` configuration file to include the new dependency:
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
`bower.json` configuration file to include the new dependency:
<br />
**`package.json`:**
**`bower.json`:**
```json
{
"name": "angular-phonecat",
...
"description": "A starter project for AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/angular/angular-phonecat",
"license": "MIT",
"private": true,
"dependencies": {
"angular": "1.8.x",
"angular-route": "1.8.x",
"angular": "1.5.x",
"angular-mocks": "1.5.x",
"angular-route": "1.5.x",
"bootstrap": "3.3.x"
},
...
}
}
```
The new dependency `"angular-route": "1.8.x"` tells npm to install a version of the angular-route
module that is compatible with version 1.8.x of AngularJS. We must tell npm to download and install
The new dependency `"angular-route": "1.5.x"` tells bower to install a version of the angular-route
module that is compatible with version 1.5.x of AngularJS. We must tell bower to download and install
this dependency.
```
npm install
```
<div class="alert alert-info">
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
we have preconfigured `npm install` to run bower for us.
</div>
<div class="alert alert-warning">
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
you may have a problem with the `bower install` due to a conflict between the versions of
angular.js that need to be installed. If you run into this issue, simply delete your
`app/bower_components` directory and then run `npm install`.
</div>
## Multiple Views, Routing and Layout Templates
@@ -111,8 +127,8 @@ service, the `$routeProvider` exposes APIs that allow you to define routes for y
</div>
AngularJS modules solve the problem of removing global variables from the application and provide a
way of configuring the injector. As opposed to AMD or require.js modules, AngularJS modules don't
try to solve the problem of script load ordering or lazy script fetching. These goals are totally
way of configuring the injector. As opposed to AMD or require.js modules, AngularJS modules don't try
to solve the problem of script load ordering or lazy script fetching. These goals are totally
independent and both module systems can live side-by-side and fulfill their goals.
To deepen your understanding on AngularJS's DI, see [Understanding Dependency Injection][wiki-di].
@@ -130,8 +146,8 @@ into the layout template. This makes it a perfect fit for our `index.html` templ
```html
<head>
...
<script src="lib/angular/angular.js"></script>
<script src="lib/angular-route/angular-route.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="app.module.js"></script>
<script src="app.config.js"></script>
...
@@ -187,8 +203,10 @@ code, we put it into a separate file and used the `.config` suffix.
```js
angular.
module('phonecatApp').
config(['$routeProvider',
function config($routeProvider) {
config(['$locationProvider', '$routeProvider',
function config($locationProvider, $routeProvider) {
$locationProvider.hashPrefix('!');
$routeProvider.
when('/phones', {
template: '<phone-list></phone-list>'
@@ -208,6 +226,18 @@ the corresponding services. Here, we use the
{@link ngRoute.$routeProvider#otherwise $routeProvider.otherwise()} methods to define our
application routes.
<div class="alert alert-success">
<p>
We also used {@link $locationProvider#hashPrefix $locationProvider.hashPrefix()} to set the
hash-prefix to `!`. This prefix will appear in the links to our client-side routes, right after
the hash (`#`) symbol and before the actual path (e.g. `index.html#!/some/path`).
</p>
<p>
Setting a prefix is not necessary, but it is considered a good practice (for reasons that are
outside the scope of this tutorial). `!` is the most commonly used prefix.
</p>
</div>
Our routes are defined as follows:
* `when('/phones')`: Determines the view that will be shown, when the URL hash fragment is
@@ -231,25 +261,6 @@ the route declaration — `'/phones/:phoneId'` — as a template that is matched
URL. All variables defined with the `:` prefix are extracted into the (injectable)
{@link ngRoute.$routeParams $routeParams} object.
<div class="alert alert-info">
<p>
You may have noticed, that &mdash; while the configured route paths start with `/` (e.g.
`/phones`) &mdash; the URLs used in templates start with `#!/` (e.g. `#!/phones`).
</p>
<p>
Without getting into much detail, AngularJS (by default) uses the hash part of the URL (i.e.
what comes after the hash (`#`) symbol) to determine the current route. In addition to that, you
can also specify a {@link $locationProvider#hashPrefix hash-prefix} (`!` by default) that needs
to appear after the hash symbol in order for AngularJS to consider the value an "AngularJS path"
and process it (for example, try to match it to a route).
</p>
<p>
You can find out more about how all this works in the [Using $location](guide/$location) section
of the Developer Guide. But all you need to know for now, is that the URLs to our various routes
should be prefixed with `#!`.
</p>
</div>
## The `phoneDetail` Component
@@ -334,8 +345,8 @@ any modification.
```js
files: [
'lib/angular/angular.js',
'lib/angular-route/angular-route.js',
'bower_components/angular/angular.js',
'bower_components/angular-route/angular-route.js',
...
],
```
@@ -352,7 +363,7 @@ various URLs and verifying that the correct view was rendered.
it('should redirect `index.html` to `index.html#!/phones', function() {
browser.get('index.html');
expect(browser.getCurrentUrl()).toContain('index.html#!/phones');
expect(browser.getLocationAbsUrl()).toBe('/phones');
});
...
@@ -413,6 +424,6 @@ With the routing set up and the phone list view implemented, we are ready to go
<ul doc-tutorial-nav="9"></ul>
[bower]: http://bower.io
[deep-linking]: https://en.wikipedia.org/wiki/Deep_linking
[npm]: https://www.npmjs.com/
[wiki-di]: https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
+35 -20
View File
@@ -21,34 +21,50 @@ In this step, we will change the way our application fetches data.
The RESTful functionality is provided by AngularJS in the {@link ngResource ngResource} module, which
is distributed separately from the core AngularJS framework.
Since we are using [npm][npm] to install client-side dependencies, this step updates the
`package.json` configuration file to include the new dependency:
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
`bower.json` configuration file to include the new dependency:
<br />
**`package.json`:**
**`bower.json`:**
```json
```
{
"name": "angular-phonecat",
...
"description": "A starter project for AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/angular/angular-phonecat",
"license": "MIT",
"private": true,
"dependencies": {
"angular": "1.8.x",
"angular-resource": "1.8.x",
"angular-route": "1.8.x",
"angular": "1.5.x",
"angular-mocks": "1.5.x",
"angular-resource": "1.5.x",
"angular-route": "1.5.x",
"bootstrap": "3.3.x"
},
...
}
}
```
The new dependency `"angular-resource": "1.8.x"` tells npm to install a version of the
angular-resource module that is compatible with version 1.8.x of AngularJS. We must tell npm to
The new dependency `"angular-resource": "1.5.x"` tells bower to install a version of the
angular-resource module that is compatible with version 1.5.x of AngularJS. We must tell bower to
download and install this dependency.
```
npm install
```
<div class="alert alert-info">
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
we have preconfigured `npm install` to run bower for us.
</div>
<div class="alert alert-warning">
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
you may have a problem with the `bower install` due to a conflict between the versions of
angular.js that need to be installed. If you run into this issue, simply delete your
`app/bower_components` directory and then run `npm install`.
</div>
## Service
@@ -113,7 +129,7 @@ need to load the `angular-resource.js` file, which contains the `ngResource` mod
```html
<head>
...
<script src="lib/angular-resource/angular-resource.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
...
<script src="core/phone/phone.module.js"></script>
<script src="core/phone/phone.service.js"></script>
@@ -125,10 +141,9 @@ need to load the `angular-resource.js` file, which contains the `ngResource` mod
## Component Controllers
We can now simplify our component controllers (`PhoneListController` and `PhoneDetailController`) by
factoring out the lower-level `$http` service, replacing it with the new `Phone` service.
AngularJS's `$resource` service is easier to use than `$http` for interacting with data sources
exposed as RESTful resources. It is also easier now to understand what the code in our controllers
is doing.
factoring out the lower-level `$http` service, replacing it with the new `Phone` service. AngularJS's
`$resource` service is easier to use than `$http` for interacting with data sources exposed as
RESTful resources. It is also easier now to understand what the code in our controllers is doing.
<br />
**`app/phone-list/phone-list.module.js`:**
@@ -225,8 +240,8 @@ Karma configuration file with angular-resource.
```js
files: [
'lib/angular/angular.js',
'lib/angular-resource/angular-resource.js',
'bower_components/angular/angular.js',
'bower_components/angular-resource/angular-resource.js',
...
],
```
@@ -304,6 +319,6 @@ Now that we have seen how to build a custom service as a RESTful client, we are
<ul doc-tutorial-nav="13"></ul>
[bower]: http://bower.io/
[jasmine-equality]: https://jasmine.github.io/2.4/custom_equality.html
[npm]: https://www.npmjs.com/
[restful]: https://en.wikipedia.org/wiki/Representational_State_Transfer
+43 -27
View File
@@ -22,43 +22,59 @@ the template code we created earlier.
## Dependencies
The animation functionality is provided by AngularJS in the `ngAnimate` module, which is distributed
separately from the core AngularJS framework. In addition we will use [jQuery][jquery] in this
project to do extra JavaScript animations.
separately from the core AngularJS framework. In addition we will use [jQuery][jquery] in this project
to do extra JavaScript animations.
Since we are using [npm][npm] to install client-side dependencies, this step updates the
`package.json` configuration file to include the new dependencies:
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
`bower.json` configuration file to include the new dependencies:
<br />
**`package.json`:**
**`bower.json`:**
```json
```
{
"name": "angular-phonecat",
...
"description": "A starter project for AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/angular/angular-phonecat",
"license": "MIT",
"private": true,
"dependencies": {
"angular": "1.8.x",
"angular-animate": "1.8.x",
"angular-resource": "1.8.x",
"angular-route": "1.8.x",
"angular": "1.5.x",
"angular-animate": "1.5.x",
"angular-mocks": "1.5.x",
"angular-resource": "1.5.x",
"angular-route": "1.5.x",
"bootstrap": "3.3.x",
"jquery": "^3.5.1"
},
...
"jquery": "3.2.x"
}
}
```
* `"angular-animate": "1.8.x"` tells npm to install a version of the angular-animate module that
is compatible with version 1.8.x of AngularJS.
* `"jquery": "^3.5.1"` tells npm to install a version of jQuery that is compatible with 3.5.x and at least 3.5.1.
Note that this is not an AngularJS library; it is the standard jQuery library. We can use npm to
* `"angular-animate": "1.5.x"` tells bower to install a version of the angular-animate module that
is compatible with version 1.5.x of AngularJS.
* `"jquery": "3.2.x"` tells bower to install the latest patch release of the 3.2 version of jQuery.
Note that this is not an AngularJS library; it is the standard jQuery library. We can use bower to
install a wide range of 3rd party libraries.
Now, we must tell npm to download and install these dependencies.
Now, we must tell bower to download and install these dependencies.
```
npm install
```
<div class="alert alert-info">
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
we have preconfigured `npm install` to run bower for us.
</div>
<div class="alert alert-warning">
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
you may have a problem with the `bower install` due to a conflict between the versions of
angular.js that need to be installed. If you run into this issue, simply delete your
`app/bower_components` directory and then run `npm install`.
</div>
## How Animations work with `ngAnimate`
@@ -85,12 +101,12 @@ code necessary to make your application "animation aware".
...
<!-- Used for JavaScript animations (include this before angular.js) -->
<script src="lib/jquery/dist/jquery.js"></script>
<script src="bower_components/jquery/dist/jquery.js"></script>
...
<!-- Adds animation support in AngularJS -->
<script src="lib/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<!-- Defines JavaScript animations -->
<script src="app.animations.js"></script>
@@ -99,8 +115,8 @@ code necessary to make your application "animation aware".
```
<div class="alert alert-error">
**Important:** Be sure to use jQuery version 2.1 or newer, when using AngularJS 1.5 or newer;
jQuery 1.x is not officially supported.
**Important:** Be sure to use jQuery version 2.1 or newer, when using AngularJS 1.5 or newer; jQuery 1.x is
not officially supported.
In order for AngularJS to detect jQuery and take advantage of it, make sure to include `jquery.js`
before `angular.js`.
</div>
@@ -540,9 +556,9 @@ There you have it! We have created a web application in a relatively short amoun
<ul doc-tutorial-nav="14"></ul>
[caniuse-css-animation]: https://caniuse.com/#feat=css-animation
[caniuse-css-transitions]: https://caniuse.com/#feat=css-transitions
[bower]: http://bower.io/
[caniuse-css-animation]: http://caniuse.com/#feat=css-animation
[caniuse-css-transitions]: http://caniuse.com/#feat=css-transitions
[jquery]: https://jquery.com/
[jquery-animate]: https://api.jquery.com/animate
[jquery-animate]: https://api.jquery.com/animate/
[mdn-animations]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations
[npm]: https://www.npmjs.com/
+1 -1
View File
@@ -22,5 +22,5 @@ If you have questions or feedback or just want to say "hi", please post a messag
[angular-seed]: https://github.com/angular/angular-seed
[gitter]: https://gitter.im/angular/angular.js
[irc]: https://webchat.freenode.net/?channels=angularjs&uio=d4
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[mailing-list]: https://groups.google.com/forum/#!forum/angular
+1 -1
View File
@@ -20,7 +20,7 @@ function main() {
} catch (e) {
fs.mkdirSync(__dirname + '/../../../src/ngParseExt');
}
fs.writeFileSync(__dirname + '/../../../src/ngParseExt/ucd.js', code);
fs.writeFile(__dirname + '/../../../src/ngParseExt/ucd.js', code);
}
}
-12
View File
@@ -1,12 +0,0 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
module.exports = function(config) {
sharedConfig(config, {testName: 'AngularJS: isolated module tests (ngAnimate)', logFile: 'karma-ngAnimate-isolated.log'});
config.set({
files: angularFiles.mergeFilesFor('karmaModules-ngAnimate')
});
};
-12
View File
@@ -1,12 +0,0 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
module.exports = function(config) {
sharedConfig(config, {testName: 'AngularJS: isolated module tests (ngMock)', logFile: 'karma-ngMock-isolated.log'});
config.set({
files: angularFiles.mergeFilesFor('karmaModules-ngMock')
});
};
+8 -11
View File
@@ -1,20 +1,17 @@
'use strict';
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
module.exports = function(config) {
sharedConfig(config, {testName: 'AngularJS: isolated module tests', logFile: 'karma-modules-isolated.log'});
sharedConfig(config, {testName: 'AngularJS: modules', logFile: 'karma-modules.log'});
config.set({
files: [
'build/angular.js',
'build/angular-mocks.js',
'test/modules/no_bootstrap.js',
'test/helpers/matchers.js',
'test/helpers/privateMocks.js',
'test/helpers/support.js',
'test/helpers/testabilityPatch.js',
'build/test-bundles/angular-*.js'
]
files: angularFiles.mergeFilesFor('karmaModules'),
junitReporter: {
outputFile: 'test_out/modules.xml',
suite: 'modules'
}
});
};
+47 -8
View File
@@ -23,7 +23,12 @@ module.exports = function(config, specificOptions) {
// SauceLabs config for local development.
sauceLabs: {
testName: specificOptions.testName || 'AngularJS',
startConnect: true
startConnect: true,
options: {
// We need selenium version +2.46 for Firefox 39 and the last selenium version for OS X is 2.45.
// TODO: Uncomment when there is a selenium 2.46 available for OS X.
// 'selenium-version': '2.46.0'
}
},
// BrowserStack config for local development.
@@ -60,11 +65,13 @@ module.exports = function(config, specificOptions) {
'SL_Safari-1': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.12',
version: 'latest-1'
},
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.12',
version: 'latest'
},
'SL_IE_9': {
@@ -97,15 +104,17 @@ module.exports = function(config, specificOptions) {
platform: 'Windows 10',
version: 'latest-1'
},
'SL_iOS': {
'SL_iOS_10': {
base: 'SauceLabs',
browserName: 'iphone',
version: 'latest'
platform: 'OS X 10.12',
version: '10.3'
},
'SL_iOS-1': {
'SL_iOS_11': {
base: 'SauceLabs',
browserName: 'iphone',
version: 'latest-1'
platform: 'OS X 10.12',
version: '11.2'
},
'BS_Chrome': {
@@ -169,9 +178,39 @@ module.exports = function(config, specificOptions) {
});
if (process.env.TRAVIS) {
var buildLabel = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
// Karma (with socket.io 1.x) buffers by 50 and 50 tests can take a long time on IEs;-)
config.browserNoActivityTimeout = 120000;
config.browserStack.build = buildLabel;
config.browserStack.startTunnel = false;
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
config.sauceLabs.build = buildLabel;
config.sauceLabs.startConnect = false;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
config.sauceLabs.recordScreenshots = true;
// Debug logging into a file, that we print out at the end of the build.
config.loggers.push({
type: 'file',
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log')
});
if (process.env.BROWSER_PROVIDER === 'saucelabs' || !process.env.BROWSER_PROVIDER) {
// Allocating a browser can take pretty long (eg. if we are out of capacity and need to wait
// for another build to finish) and so the `captureTimeout` typically kills
// an in-queue-pending request, which makes no sense.
config.captureTimeout = 0;
}
}
// Terrible hack to workaround inflexibility of log4js:
// - ignore web-server's 404 warnings,
// - ignore DEBUG logs (on CI), we log them into a file instead.
// - ignore DEBUG logs (on Travis), we log them into a file instead.
var IGNORED_404 = [
'/favicon.ico',
'/%7B%7BtestUrl%7D%7D',
@@ -197,8 +236,8 @@ module.exports = function(config, specificOptions) {
return;
}
// on CI, ignore DEBUG statements
if (process.env.CI && log.level.levelStr === config.LOG_DEBUG) {
// on Travis, ignore DEBUG statements
if (process.env.TRAVIS && log.level.levelStr === config.LOG_DEBUG) {
return;
}
+50
View File
@@ -0,0 +1,50 @@
'use strict';
var fs = require('fs');
var http = require('http');
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
var HOSTNAME = 'localhost';
var PORTS = [9876, 8000];
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
var READY_FILE = process.env.BROWSER_PROVIDER_READY_FILE;
var TUNNEL_IDENTIFIER = process.env.TRAVIS_JOB_NUMBER;
// We need to start fake servers, otherwise the tunnel does not start.
var fakeServers = [];
var hosts = [];
PORTS.forEach(function(port) {
fakeServers.push(http.createServer(function() {}).listen(port));
hosts.push({
name: HOSTNAME,
port: port,
sslFlag: 0
});
});
var tunnel = new BrowserStackTunnel({
key: ACCESS_KEY,
localIdentifier: TUNNEL_IDENTIFIER,
hosts: hosts
});
console.log('Starting tunnel on ports', PORTS.join(', '));
tunnel.start(function(error) {
if (error) {
console.error('Can not establish the tunnel', error);
} else {
console.log('Tunnel established.');
fakeServers.forEach(function(server) {
server.close();
});
if (READY_FILE) {
fs.writeFile(READY_FILE, '');
}
}
});
tunnel.on('error', function(error) {
console.error(error);
});
+3
View File
@@ -0,0 +1,3 @@
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
node ./lib/browserstack/start_tunnel.js &
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -e -o pipefail
echo "Shutting down Browserstack tunnel"
echo "TODO: implement me"
exit 1
+2 -2
View File
@@ -63,8 +63,8 @@ module.exports = function(grunt) {
util.collectErrors();
});
grunt.registerTask('firebaseDocsJsonForCI', function() {
util.firebaseDocsJsonForCI();
grunt.registerTask('firebaseDocsJsonForTravis', function() {
util.firebaseDocsJsonForTravis();
});
};
+11 -20
View File
@@ -7,7 +7,6 @@ var spawn = require('npm-run').spawn;
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
const docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
module.exports = {
@@ -33,8 +32,8 @@ module.exports = {
updateWebdriver: function(done) {
if (process.env.CI) {
// Skip the webdriver-manager update on CI, since the browsers will
if (process.env.TRAVIS) {
// Skip the webdriver-manager update on Travis, since the browsers will
// be provided remotely.
done();
return;
@@ -76,8 +75,10 @@ module.exports = {
},
wrap(src, name) {
return [`src/${name}.prefix`, ...src, `src/${name}.suffix`];
wrap: function(src, name) {
src.unshift('src/' + name + '.prefix');
src.push('src/' + name + '.suffix');
return src;
},
@@ -111,7 +112,7 @@ module.exports = {
.replace(/\\/g, '\\\\')
.replace(/'/g, '\\\'')
.replace(/\r?\n/g, '\\n');
js = '!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(window.angular.element(\'<style>\').text(\'' + css + '\'));';
js = '!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(\'<style type="text/css">' + css + '</style>\');';
state.js.push(js);
return state;
@@ -134,16 +135,6 @@ module.exports = {
build: function(config, fn) {
var files = grunt.file.expand(config.src);
// grunt.file.expand might reorder the list of files
// when it is expanding globs, so we use prefix and suffix
// fields to ensure that files are at the start of end of
// the list (primarily for wrapping in an IIFE).
if (config.prefix) {
files = grunt.file.expand(config.prefix).concat(files);
}
if (config.suffix) {
files = files.concat(grunt.file.expand(config.suffix));
}
var styles = config.styles;
var processedStyles;
//concat
@@ -303,11 +294,11 @@ module.exports = {
};
},
docsScriptFolder,
// Our Firebase projects are in subfolders, but the firebase tool expects them in the root,
// Our Firebase projects are in subfolders, but Travis expects them in the root,
// so we need to modify the upload folder path and copy the file into the root
firebaseDocsJsonForCI: function() {
firebaseDocsJsonForTravis: function() {
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
var fileName = docsScriptFolder + '/firebase.json';
var json = grunt.file.readJSON(fileName);
-459
View File
@@ -1,459 +0,0 @@
#!/usr/bin/env bash
set -u -e -o pipefail
####################################################################################################
# Some helper funtions
@echo() {
echo "# $*"
}
@warn() {
@echo "Warning: $*" >&2
}
@fail() {
@echo "Error! $*" >&2
exit 1
}
@remove() {
local f="$1"
if [[ -f ${f} ]]; then
@echo "Removing ${f}"
rm -f "${f}" || @fail "Can not delete ${f} file"
fi
}
@kill() {
for p in $1; do
if kill -0 ${p} >/dev/null 2>&1; then
kill ${p}
sleep 2
if kill -0 ${p} >/dev/null 2>&1; then
kill -9 ${p}
sleep 2
fi
fi
done
}
@wait_for() {
local m="$1"
local f="$2"
if [[ ! -f "${f}" ]]; then
printf "# ${m} (${f})"
while [[ ! -f "${f}" ]]; do
printf "."
sleep 0.5
done
printf "\n"
fi
}
####################################################################################################
# Sauce service functions
readonly SCRIPT_DIR=$(cd $(dirname $0); pwd)
readonly TMP_DIR="/tmp/angular/sauce-service"
mkdir -p ${TMP_DIR}
# Location for the saucelabs log file.
readonly SAUCE_LOG_FILE="${TMP_DIR}/sauce-connect.log"
# Location for the saucelabs ready to connection process id lock file.
readonly SAUCE_PID_FILE="${TMP_DIR}/sauce-connect.pid"
# Location for the saucelabs ready to connect lock file.
readonly SAUCE_READY_FILE="${TMP_DIR}/sauce-connect.lock"
# Location for the saucelabs params file for use by test runner.
readonly SAUCE_PARAMS_JSON_FILE="${TMP_DIR}/sauce-connect-params.json"
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
# acquire CircleCI instances for too long if sauceconnect fails, we need a connect timeout.
readonly SAUCE_READY_FILE_TIMEOUT=120
readonly SERVICE_LOCK_FILE="${TMP_DIR}/service.lock"
readonly SERVICE_START_FILE="${TMP_DIR}/service.start"
readonly SERVICE_PID_FILE="${TMP_DIR}/service.pid"
readonly SERVICE_LOG_FILE="${TMP_DIR}/service.log"
service-setup-command() {
if [[ -z "${SAUCE_USERNAME:-}" ]]; then
@fail "SAUCE_USERNAME environment variable required"
fi
if [[ -z "${SAUCE_ACCESS_KEY:-}" ]]; then
@fail "SAUCE_ACCESS_KEY environment variable required"
fi
if [[ -z "${SAUCE_TUNNEL_IDENTIFIER:-}" ]]; then
@fail "SAUCE_TUNNEL_IDENTIFIER environment variable required"
fi
local unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) local machine=linux ;;
Darwin*) local machine=darwin ;;
CYGWIN*) local machine=windows ;;
MINGW*) local machine=windows ;;
MSYS_NT*) local machine=windows ;;
*) local machine=linux
printf "\nUnrecongized uname '${unameOut}'; defaulting to use node for linux.\n" >&2
printf "Please file an issue to https://github.com/bazelbuild/rules_nodejs/issues if \n" >&2
printf "you would like to add your platform to the supported rules_nodejs node platforms.\n\n" >&2
;;
esac
case "${machine}" in
# Path to sauce connect executable
linux)
if [[ -z "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
# Started manually
SAUCE_CONNECT="${SCRIPT_DIR}/../../node_modules/sauce-connect/bin/sc"
else
# Started via `bazel run`
SAUCE_CONNECT="${BUILD_WORKSPACE_DIRECTORY}/node_modules/sauce-connect/bin/sc"
fi
;;
*)
if [[ -z "${SAUCE_CONNECT:-}" ]]; then
@fail "SAUCE_CONNECT environment variable is required on non-linux environments"
exit 1
fi
;;
esac
if [[ ! -f ${SAUCE_CONNECT} ]]; then
@fail "sc binary not found at ${SAUCE_CONNECT}"
fi
echo "{ \"SAUCE_USERNAME\": \"${SAUCE_USERNAME}\", \"SAUCE_ACCESS_KEY\": \"${SAUCE_ACCESS_KEY}\", \"SAUCE_TUNNEL_IDENTIFIER\": \"${SAUCE_TUNNEL_IDENTIFIER}\", \"SAUCE_LOCALHOST_ALIAS_DOMAIN\": \"${SAUCE_LOCALHOST_ALIAS_DOMAIN:-}\" }" > ${SAUCE_PARAMS_JSON_FILE}
# Command arguments that will be passed to sauce-connect.
# By default we disable SSL bumping for all requests. This is because SSL bumping is
# not needed for our test setup and in order to perform the SSL bumping, Saucelabs
# intercepts all HTTP requests in the tunnel VM and modifies them. This can cause
# flakiness as it makes all requests dependent on the SSL bumping middleware.
# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping
local sauce_args=(
"--no-ssl-bump-domains all"
"--logfile ${SAUCE_LOG_FILE}"
"--pidfile ${SAUCE_PID_FILE}"
"--readyfile ${SAUCE_READY_FILE}"
"--tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}"
"--user ${SAUCE_USERNAME}"
# Don't add the --api-key here so we don't echo it out in service-pre-start
)
if [[ -n "${SAUCE_LOCALHOST_ALIAS_DOMAIN:-}" ]]; then
# Ensures that requests to the localhost alias domain are always resolved through the tunnel.
# This environment variable is usually configured on CI, and refers to a domain that has been
# locally configured in the current machine's hosts file (e.g. `/etc/hosts`). The domain should
# resolve to the current machine in Saucelabs VMs, so we need to ensure that it is resolved
# through the tunnel we going to create.
sauce_args+=("--tunnel-domains ${SAUCE_LOCALHOST_ALIAS_DOMAIN}")
fi
@echo "Sauce connect will be started with:"
echo " ${SAUCE_CONNECT} ${sauce_args[@]}"
SERVICE_COMMAND="${SAUCE_CONNECT} ${sauce_args[@]} --api-key ${SAUCE_ACCESS_KEY}"
}
# Called by pre-start & post-stop
service-cleanup() {
if [[ -f "${SAUCE_PID_FILE}" ]]; then
local p=$(cat "${SAUCE_PID_FILE}")
@echo "Stopping Sauce Connect (pid $p)..."
@kill $p
fi
@remove "${SAUCE_PID_FILE}"
@remove "${SAUCE_READY_FILE}"
@remove "${SAUCE_PARAMS_JSON_FILE}"
}
# Called before service is setup
service-pre-setup() {
service-cleanup
}
# Called after service is setup
service-post-setup() {
@echo " sauce params : ${SAUCE_PARAMS_JSON_FILE}"
}
# Called before service is started
service-pre-start() {
return
}
# Called after service is started
service-post-start() {
if [[ ! -f "${SAUCE_PID_FILE}" ]]; then
printf "# Waiting for Sauce Connect Proxy process (${SAUCE_PID_FILE})"
while [[ ! -f "${SAUCE_PID_FILE}" ]]; do
if ! @serviceStatus >/dev/null 2>&1; then
printf "\n"
@serviceStop
@echo "Service failed to start!"
service-failed-setup
exit 1
fi
printf "."
sleep 0.5
done
printf "\n"
fi
@echo "Sauce Connect Proxy started (pid $(cat "${SAUCE_PID_FILE}"))"
}
# Called if service fails to start
service-failed-setup() {
if [[ -f "${SERVICE_LOG_FILE}" ]]; then
@echo "tail ${SERVICE_LOG_FILE}:"
echo "--------------------------------------------------------------------------------"
tail "${SERVICE_LOG_FILE}"
echo "--------------------------------------------------------------------------------"
echo "^^^^^ ${SERVICE_LOG_FILE} ^^^^^"
fi
}
# Called by ready-wait action
service-ready-wait() {
if [[ ! -f "${SAUCE_PID_FILE}" ]]; then
@fail "Sauce Connect not running"
fi
if [[ ! -f "${SAUCE_READY_FILE}" ]]; then
# Wait for saucelabs tunnel to connect
printf "# Waiting for saucelabs tunnel to connect (${SAUCE_READY_FILE})"
counter=0
while [[ ! -f "${SAUCE_READY_FILE}" ]]; do
counter=$((counter + 1))
# Counter needs to be multiplied by two because the while loop only sleeps a half second.
# This has been made in favor of better progress logging (printing dots every half second)
if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then
@echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file."
if [[ -f "${SAUCE_LOG_FILE}" ]]; then
echo "================================================================================"
echo "${SAUCE_LOG_FILE}:"
cat "${SAUCE_LOG_FILE}"
fi
exit 5
fi
printf "."
sleep 0.5
done
printf "\n"
@echo "Saucelabs tunnel connected"
else
@echo "Saucelabs tunnel already connected"
fi
}
# Called before service is stopped
service-pre-stop() {
return
}
# Called after service is stopped
service-post-stop() {
service-cleanup
}
####################################################################################################
# Generic service functions
# This uses functions setup above but nothing below should be specific to saucelabs
@serviceLock() {
# Check is Lock File exists, if not create it and set trap on exit
printf "# Waiting for service action lock (${SERVICE_LOCK_FILE})"
while true; do
if { set -C; 2>/dev/null >"${SERVICE_LOCK_FILE}"; }; then
trap "rm -f \"${SERVICE_LOCK_FILE}\"" EXIT
printf "\n"
break
fi
printf "."
sleep 0.5
done
@echo "Acquired service action lock"
}
@serviceStatus() {
if [ -f "${SERVICE_PID_FILE}" ] && [ ! -z "$(cat "${SERVICE_PID_FILE}")" ]; then
local p=$(cat "${SERVICE_PID_FILE}")
if kill -0 $p >/dev/null 2>&1; then
@echo "Service is running (pid $p)"
return 0
else
@echo "Service is not running (process PID $p not exists)"
return 1
fi
else
@echo "Service is not running"
return 2
fi
}
@serviceSetup() {
if @serviceStatus >/dev/null 2>&1; then
@echo "Service already running (pid $(cat "${SERVICE_PID_FILE}"))"
return 0
fi
@echo "Setting up service..."
@remove "${SERVICE_PID_FILE}"
@remove "${SERVICE_START_FILE}"
touch "${SERVICE_LOG_FILE}" >/dev/null 2>&1 || @fail "Can not create ${SERVICE_LOG_FILE} file"
@echo " service pid : ${SERVICE_PID_FILE}"
@echo " service logs : ${SERVICE_LOG_FILE}"
service-pre-setup
service-setup-command
(
(
if [[ -z "${SERVICE_COMMAND:-}" ]]; then
@fail "No SERVICE_COMMAND is set"
fi
@wait_for "Waiting for start file" "${SERVICE_START_FILE}"
${SERVICE_COMMAND}
) >>"${SERVICE_LOG_FILE}" 2>&1
) &
echo $! >"${SERVICE_PID_FILE}"
if @serviceStatus >/dev/null 2>&1; then
@echo "Service setup (pid $(cat "${SERVICE_PID_FILE}"))"
service-post-setup
else
@echo "Error setting up Service!"
service-failed-setup
exit 1
fi
return $?
}
@serviceStart() {
if @serviceStatus >/dev/null 2>&1; then
@echo "Service already setup (pid $(cat "${SERVICE_PID_FILE}"))"
else
@serviceSetup
fi
if [[ -f "${SERVICE_START_FILE}" ]]; then
@echo "Service already started"
else
@echo "Starting service..."
service-pre-start
touch "${SERVICE_START_FILE}" >/dev/null 2>&1 || @err "Can not create ${SERVICE_START_FILE} file"
service-post-start
@echo "Service started"
fi
}
@serviceStop() {
if @serviceStatus >/dev/null 2>&1; then
touch "${SERVICE_PID_FILE}" >/dev/null 2>&1 || @fail "Can not touch ${SERVICE_PID_FILE} file"
service-pre-stop
@echo "Stopping sevice (pid $(cat "${SERVICE_PID_FILE}"))..."
@kill $(cat "${SERVICE_PID_FILE}")
if @serviceStatus >/dev/null 2>&1; then
@fail "Error stopping Service! Service already running with PID $(cat "${SERVICE_PID_FILE}")"
else
@echo "Service stopped"
@remove "${SERVICE_PID_FILE}"
@remove "${SERVICE_START_FILE}"
service-post-stop
fi
return 0
else
@warn "Service is not running"
@remove "${SERVICE_PID_FILE}"
@remove "${SERVICE_START_FILE}"
service-post-stop
fi
}
@serviceStartReadyWait() {
@serviceStart
@serviceReadyWait
}
@serviceReadyWait() {
service-ready-wait
}
@serviceRestart() {
@serviceStop
@serviceStart
}
@serviceTail() {
@echo "tail ${SERVICE_LOG_FILE}:"
tail -f "${SERVICE_LOG_FILE}"
}
@serviceLog() {
@echo "cat ${SERVICE_LOG_FILE}:"
echo "--------------------------------------------------------------------------------"
cat "${SERVICE_LOG_FILE}"
echo "--------------------------------------------------------------------------------"
echo "^^^^^ ${SERVICE_LOG_FILE} ^^^^^"
}
case "${1:-}" in
setup)
@serviceLock
@serviceSetup
;;
start)
@serviceLock
@serviceStart
;;
start-ready-wait)
@serviceLock
@serviceStartReadyWait
;;
ready-wait)
@serviceLock
@serviceReadyWait
;;
stop)
@serviceLock
@serviceStop
;;
restart)
@serviceLock
@serviceRestart
;;
status)
@serviceLock
@serviceStatus
;;
run)
(
service-setup-command
if [[ -z "${SERVICE_COMMAND:-}" ]]; then
@fail "No SERVICE_COMMAND is set"
fi
${SERVICE_COMMAND}
)
;;
log)
@serviceLog
;;
tail)
@serviceTail
;;
*)
@echo "Actions: [setup|start|start-read-wait|ready-wait|stop|restart|status|run|tail]"
exit 1
;;
esac
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
set -e
# Setup and start Sauce Connect for your TravisCI build
# This script requires your .travis.yml to include the following two private env variables:
# SAUCE_USERNAME
# SAUCE_ACCESS_KEY
# Follow the steps at https://saucelabs.com/opensource/travis to set that up.
#
# Curl and run this script as part of your .travis.yml before_script section:
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
SC_VERSION="4.4.12"
CONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-$SC_VERSION-linux.tar.gz"
CONNECT_LOG="$LOGS_DIR/sauce-connect"
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
CONNECT_STDERR="$LOGS_DIR/sauce-connect.stderr"
# Get Connect and start it
mkdir -p $CONNECT_DIR
cd $CONNECT_DIR
curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null
mkdir sauce-connect
tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null
rm $CONNECT_DOWNLOAD
SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
ARGS=""
# Set tunnel-id only on Travis, to make local testing easier.
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
fi
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
fi
echo "Starting Sauce Connect in the background, logging into:"
echo " $CONNECT_LOG"
echo " $CONNECT_STDOUT"
echo " $CONNECT_STDERR"
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
--logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e -o pipefail
echo "Shutting down Sauce Connect tunnel"
killall sc
while [[ -n `ps -ef | grep "sauce-connect-" | grep -v "grep"` ]]; do
printf "."
sleep .5
done
echo ""
echo "Sauce Connect tunnel has been shut down"
+3 -3
View File
@@ -65,7 +65,7 @@ var getCodeName = function(tagName) {
/**
* Compute a build segment for the version, from the CI build number and current commit SHA
* Compute a build segment for the version, from the Jenkins build number and current commit SHA
* @return {String} The build segment of the version
*/
function getBuild() {
@@ -189,7 +189,7 @@ var getSnapshotVersion = function() {
// We need to clone to ensure that we are not modifying another version
version = semver(version.raw);
var ciBuild = process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER;
var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER;
if (!version.prerelease || !version.prerelease.length) {
// last release was a non beta release. Increment the patch level to
// indicate the next release that we will be doing.
@@ -203,7 +203,7 @@ var getSnapshotVersion = function() {
// as this is bigger than 1.3.0-beta.2 according to semver
version.patch++;
}
version.prerelease = ciBuild ? ['build', ciBuild] : ['local'];
version.prerelease = jenkinsBuild ? ['build', jenkinsBuild] : ['local'];
version.build = getBuild();
version.codeName = 'snapshot';
version.isSnapshot = true;
+24 -32
View File
@@ -1,28 +1,29 @@
{
"name": "angular",
"name": "angularjs",
"license": "MIT",
"branchVersion": "^1.8.0",
"branchPattern": "1.8.*",
"branchVersion": "^1.7.0",
"branchPattern": "1.7.*",
"distTag": "latest",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": ">=12.14.1",
"yarn": ">=1.21.1",
"grunt-cli": "^1.2.0"
"node": "^8.9.1",
"yarn": ">=1.3.2",
"grunt": "^1.2.0"
},
"scripts": {
"commit": "git-cz",
"test-i18n": "jasmine-node i18n/spec",
"test-i18n-ucd": "jasmine-node i18n/ucd/spec"
"test-i18n-ucd": "jasmine-node i18n/ucd/spec",
"grunt": "grunt"
},
"devDependencies": {
"angular-benchpress": "0.x.x",
"benchmark": "1.x.x",
"bootstrap": "3.1.1",
"browserstacktunnel-wrapper": "2.0.4",
"browserstacktunnel-wrapper": "2.0.0",
"canonical-path": "0.0.2",
"changez": "^2.1.1",
"changez-angular": "^2.1.2",
@@ -35,7 +36,6 @@
"dgeni-packages": "^0.26.5",
"eslint-plugin-promise": "^3.6.0",
"event-stream": "~3.1.0",
"firebase-tools": "^8.3.0",
"glob": "^6.0.1",
"google-code-prettify": "1.0.1",
"grunt": "^1.0.1",
@@ -60,23 +60,23 @@
"jasmine-core": "^2.8.0",
"jasmine-node": "^2.0.0",
"jasmine-reporters": "^2.2.0",
"jquery": "3.5.1",
"jquery": "3.2.1",
"jquery-2.1": "npm:jquery@2.1.4",
"jquery-2.2": "npm:jquery@2.2.4",
"karma": "4.4.1",
"karma-browserstack-launcher": "1.5.1",
"karma-chrome-launcher": "3.1.0",
"karma-edge-launcher": "0.4.2",
"karma-firefox-launcher": "1.2.0",
"karma-ie-launcher": "1.0.0",
"karma": "^2.0.4",
"karma-browserstack-launcher": "^1.3.0",
"karma-chrome-launcher": "^2.2.0",
"karma-edge-launcher": "^0.4.2",
"karma-firefox-launcher": "^1.1.0",
"karma-ie-launcher": "^1.0.0",
"karma-jasmine": "^1.1.2",
"karma-junit-reporter": "2.0.1",
"karma-safari-launcher": "1.0.0",
"karma-sauce-launcher": "2.0.2",
"karma-script-launcher": "1.0.0",
"karma-spec-reporter": "0.0.32",
"karma-junit-reporter": "^1.2.0",
"karma-safari-launcher": "^1.0.0",
"karma-sauce-launcher": "^1.2.0",
"karma-script-launcher": "^1.0.0",
"karma-spec-reporter": "^0.0.32",
"load-grunt-tasks": "^3.5.0",
"lodash": "~4.17.19",
"lodash": "~2.4.1",
"log4js": "^0.6.27",
"lunr": "^0.7.2",
"marked": "~0.3.0",
@@ -84,14 +84,13 @@
"npm-run": "^4.1.0",
"open-sans-fontface": "^1.4.0",
"promises-aplus-tests": "~2.1.0",
"protractor": "^7.0.0",
"protractor": "^5.1.2",
"q": "~1.0.0",
"q-io": "^1.10.9",
"qq": "^0.3.5",
"rewire": "~2.1.0",
"sauce-connect": "https://saucelabs.com/downloads/sc-4.6.2-linux.tar.gz",
"sax": "^1.1.1",
"selenium-webdriver": "^4.0.0-alpha.1",
"selenium-webdriver": "^2.53.1",
"semver": "^5.4.1",
"serve-favicon": "^2.3.0",
"serve-index": "^1.8.0",
@@ -101,13 +100,6 @@
"stringmap": "^0.2.2"
},
"dependencies": {},
"resolutions": {
"//1": "`natives@1.1.0` does not work with Node.js 10.x on Windows 10",
"//2": "(E.g. see https://github.com/gulpjs/gulp/issues/2162 and https://github.com/nodejs/node/issues/25132.)",
"natives": "1.1.6",
"//3": "`graceful-fs` needs to be pinned to support gulp 3, on Node v12+",
"graceful-fs": "^4.2.3"
},
"commitplease": {
"style": "angular",
"nohook": true
-44
View File
@@ -1,44 +0,0 @@
'use strict';
var config = require('./protractor-shared-conf').config;
// Using SauceLabs.
config.capabilities = undefined;
config.sauceUser = process.env.SAUCE_USERNAME;
config.sauceKey = process.env.SAUCE_ACCESS_KEY;
config.multiCapabilities = [
capabilitiesForSauceLabs({
browserName: 'chrome',
platform: 'OS X 10.14',
version: '81'
}),
capabilitiesForSauceLabs({
browserName: 'firefox',
platform: 'OS X 10.14',
version: '76'
})
];
config.allScriptsTimeout = 30000;
config.getPageTimeout = 30000;
exports.config = config;
function capabilitiesForSauceLabs(capabilities) {
return {
'tunnel-identifier': process.env.SAUCE_TUNNEL_IDENTIFIER,
'name': 'AngularJS E2E',
'build': `${process.env.CIRCLE_BUILD_NUM}-${process.env.CIRCLE_NODE_INDEX}`,
'browserName': capabilities.browserName,
'platform': capabilities.platform,
'version': capabilities.version,
'elementScrollBehavior': 1,
// Allow e2e test sessions to run for a maximum of 40 minutes, instead of the default 30 minutes.
'maxDuration': 2400
};
}
+42
View File
@@ -0,0 +1,42 @@
'use strict';
exports.config = {
allScriptsTimeout: 11000,
specs: [
'test/e2e/tests/**/*.js',
'build/docs/ptore2e/**/*.js',
'docs/app/e2e/*.scenario.js'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:8000/',
framework: 'jasmine2',
onPrepare: function() {
/* global angular: false, browser: false, jasmine: false */
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
$animate.enabled(false);
}]);
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
var reporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new reporters.JUnitXmlReporter({
savePath: 'test_out/docs-e2e-' + exports.config.capabilities.browserName + '-'
}));
},
jasmineNodeOpts: {
defaultTimeoutInterval: 30000,
showColors: false
}
};
+84
View File
@@ -0,0 +1,84 @@
'use strict';
var config = require('./protractor-shared-conf').config;
if (process.env.BROWSER_PROVIDER === 'browserstack') {
// Using BrowserStack.
config.seleniumAddress = 'http://hub.browserstack.com/wd/hub';
config.multiCapabilities = [
capabilitiesForBrowserStack({
browserName: 'chrome',
platform: 'MAC',
version: '49'
}),
capabilitiesForBrowserStack({
browserName: 'firefox',
version: '47'
}),
capabilitiesForBrowserStack({
browserName: 'safari',
platform: 'MAC',
version: '9'
})
];
} else {
// Using SauceLabs.
config.sauceUser = process.env.SAUCE_USERNAME;
config.sauceKey = process.env.SAUCE_ACCESS_KEY;
config.multiCapabilities = [
capabilitiesForSauceLabs({
browserName: 'chrome',
platform: 'OS X 10.11',
version: '48'
}),
capabilitiesForSauceLabs({
browserName: 'firefox',
version: '47'
}),
capabilitiesForSauceLabs({
browserName: 'safari',
platform: 'OS X 10.11',
version: '9'
})
];
}
config.allScriptsTimeout = 30000;
config.getPageTimeout = 30000;
exports.config = config;
function capabilitiesForBrowserStack(capabilities) {
return {
'browserstack.user': process.env.BROWSER_STACK_USERNAME,
'browserstack.key': process.env.BROWSER_STACK_ACCESS_KEY,
'browserstack.local': 'true',
'browserstack.debug': 'true',
'browserstack.tunnelIdentifier': process.env.TRAVIS_JOB_NUMBER,
'tunnelIdentifier': process.env.TRAVIS_JOB_NUMBER,
'name': 'AngularJS E2E',
'build': process.env.TRAVIS_BUILD_NUMBER,
'browserName': capabilities.browserName,
'platform': capabilities.platform,
'version': capabilities.version,
'elementScrollBehavior': 1
};
}
function capabilitiesForSauceLabs(capabilities) {
return {
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
'name': 'AngularJS E2E',
'build': process.env.TRAVIS_BUILD_NUMBER,
'browserName': capabilities.browserName,
'platform': capabilities.platform,
'version': capabilities.version,
'elementScrollBehavior': 1
};
}
+1
View File
@@ -1,6 +1,7 @@
#!/bin/bash
# Tags a release
# so that travis can do the actual release.
echo "#################################"
echo "## Tag angular.js for a release #"
+1 -1
View File
@@ -27,7 +27,7 @@ function prepare {
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone https://github.com/angular/bower-$repo.git $TMP_DIR/bower-$repo --depth=1
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo --depth=1
done
@@ -1,22 +1,16 @@
'use strict';
const functions = require('firebase-functions');
const {Storage} = require('@google-cloud/storage');
const gcs = require('@google-cloud/storage')();
const path = require('path');
const storage = new Storage();
const gcsBucketId = `${process.env.GCLOUD_PROJECT}.appspot.com`;
const BROWSER_CACHE_DURATION = 60 * 10;
const CDN_CACHE_DURATION = 60 * 60 * 12;
function sendStoredFile(request, response) {
// Request paths will be URI-encoded, so we need to decode them to match the file names in the
// storage bucket. Failing to do so will result in a 404 error from the bucket and `index.html`
// will be returned instead.
// Example of path requiring decoding: `.../input%5Btext%5D.html` --> `.../input[text].html`
const requestPath = decodeURI(request.path || '/');
let filePathSegments = requestPath.split('/').filter((segment) => {
let filePathSegments = request.path.split('/').filter((segment) => {
// Remove empty leading or trailing path parts
return segment !== '';
});
@@ -24,7 +18,7 @@ function sendStoredFile(request, response) {
const version = filePathSegments[0];
const isDocsPath = filePathSegments[1] === 'docs';
const lastSegment = filePathSegments[filePathSegments.length - 1];
const bucket = storage.bucket(gcsBucketId);
const bucket = gcs.bucket(gcsBucketId);
let downloadSource;
let fileName;
@@ -165,11 +159,7 @@ function sendStoredFile(request, response) {
const nextQuery = data[1];
const apiResponse = data[2];
if (
// we got no files or directories from previous query pages
!fileList.length && !directoryList.length &&
// this query page has no file or directories
!files.length && (!apiResponse || !apiResponse.prefixes)) {
if (!files.length && (!apiResponse || !apiResponse.prefixes)) {
return Promise.reject({
code: 404
});
@@ -200,16 +190,22 @@ const snapshotRegex = /^snapshot(-stable)?\//;
* When a new zip file is uploaded into snapshot or snapshot-stable,
* delete the previous zip file.
*/
function deleteOldSnapshotZip(object) {
function deleteOldSnapshotZip(event) {
const object = event.data;
const bucketId = object.bucket;
const filePath = object.name;
const contentType = object.contentType;
const resourceState = object.resourceState;
const bucket = storage.bucket(bucketId);
const bucket = gcs.bucket(bucketId);
const snapshotFolderMatch = filePath.match(snapshotRegex);
if (!snapshotFolderMatch || contentType !== 'application/zip') {
if (!snapshotFolderMatch ||
contentType !== 'application/zip' ||
resourceState === 'not_exists' // Deletion event
) {
return;
}
@@ -234,4 +230,4 @@ function deleteOldSnapshotZip(object) {
}
exports.sendStoredFile = functions.https.onRequest(sendStoredFile);
exports.deleteOldSnapshotZip = functions.storage.object().onFinalize(deleteOldSnapshotZip);
exports.deleteOldSnapshotZip = functions.storage.object().onChange(deleteOldSnapshotZip);
File diff suppressed because it is too large Load Diff
@@ -1,13 +1,10 @@
{
"name": "functions-firebase-code.angularjs.org",
"description": "Cloud Functions to serve files from gcs to code.angularjs.org",
"engines": {
"node": "10"
},
"dependencies": {
"@google-cloud/storage": "^4.7.0",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.0"
"@google-cloud/storage": "^1.1.1",
"firebase-admin": "^4.2.1",
"firebase-functions": "^0.5.9"
},
"private": true
}
@@ -9,7 +9,7 @@ in functions/index.js that serves the docs from the Firebase Google Cloud Storag
functions/index.js also contains a rule that deletes outdated build zip files
from the snapshot and snapshot-stable folders when new zip files are uploaded.
The deployment to the Google Cloud Storage bucket happens automatically via CI.
See the .circleci/config.yml file in the repository root.
The deployment to the Google Cloud Storage bucket happens automatically via Travis. See the travis.yml
file in the repository root.
See /readme.firebase.docs.md for the firebase deployment to docs.angularjs.org
+2 -2
View File
@@ -25,7 +25,7 @@ function init {
function prepare {
echo "-- Cloning code.angularjs.org"
git clone https://github.com/angular/code.angularjs.org $REPO_DIR --depth=1
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR --depth=1
echo "-- Updating code.angularjs.org"
@@ -63,7 +63,7 @@ function _update_code() {
function publish {
# publish updates the code.angularjs.org Github repository
# the deployment to Firebase happens via CI
# the deployment to Firebase happens via Travis
_update_code
}
File diff suppressed because it is too large Load Diff
@@ -1,9 +1,6 @@
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"engines": {
"node": "10"
},
"scripts": {
"lint": "eslint .",
"serve": "firebase serve --only functions",
@@ -13,8 +10,8 @@
"logs": "firebase functions:log"
},
"dependencies": {
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.0"
"firebase-admin": "~5.8.1",
"firebase-functions": "^0.8.1"
},
"devDependencies": {
"eslint": "^4.12.0",
File diff suppressed because it is too large Load Diff
@@ -3,23 +3,18 @@ Firebase for docs.angularjs.org
# Continuous integration
The docs are deployed to Google Firebase hosting via a CI deployment config, which expects
firebase.json to be in the repository root, which is done by a Grunt task
(`firebaseDocsJsonForCI` which is included in `prepareDeploy`).
The `firebaseDocsJsonForCI` task modifies the paths in the `firebase.json` and copies it to the
repository root.
The docs are deployed to Google Firebase hosting via Travis deployment config, which expects
firebase.json in the repository root, which is done by a Grunt task (firebaseDocsJsonForTravis)
that modifies the paths in the firebase.json and copies it into the repository root.
See .circleci/config.yml for the complete deployment config and build steps.
See travis.yml for the complete deployment config, and scripts/travis/build.sh for the full deployment
build steps.
# Serving locally:
- Run `yarn grunt package`.
This builds the files that will be deployed.
- Run `yarn grunt prepareDeploy`.
- Run `grunt:prepareDeploy`.
This copies docs content files into deploy/docs and the partials for Search Engine AJAX
Crawling into ./functions/content.
It also moves the firebase.json file to the root folder, where the firebase-cli expects it
- Run `firebase serve --only functions,hosting`
Creates a server at localhost:5000 that serves from deploy/docs and uses the local function
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
echo "#################################"
echo "#### Jenkins Build ############"
echo "#################################"
source scripts/jenkins/init-node.sh
# Enable tracing and exit on first failure
set -xe
# This is the default set of browsers to use on the CI server unless overridden via env variable
if [[ -z "$BROWSERS" ]]
then
BROWSERS="Chrome"
fi
# CLEAN #
rm -f angular.min.js.gzip.size
rm -f angular.js.size
# BUILD #
yarn run grunt -- ci-checks package --no-color
mkdir -p test_out
# UNIT TESTS #
yarn run grunt -- test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
# END TO END TESTS #
yarn run grunt -- test:ci-protractor
# DOCS APP TESTS #
yarn run grunt -- test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
# Promises/A+ TESTS #
yarn run grunt -- test:promises-aplus --no-color
# CHECK SIZE #
gzip -c < build/angular.min.js > build/angular.min.js.gzip
echo "YVALUE=`ls -l build/angular.min.js | cut -d" " -f 8`" > angular.min.js.size
echo "YVALUE=`ls -l build/angular.min.js.gzip | cut -d" " -f 8`" > angular.min.js.gzip.size
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# Install nvm for this shell
source ~/.nvm/nvm.sh
# Use version of node.js found in .nvmrc
nvm install
# clean out and install yarn
rm -rf ~/.yarn
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.3.2
export PATH="$HOME/.yarn/bin:$PATH"
# Ensure that we have the local dependencies installed
yarn install
echo testing grunt version
yarn run grunt -- --version
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
echo "#################################"
echo "#### Update master ##############"
echo "#################################"
ARG_DEFS=()
function init {
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
}
function build {
cd ../..
scripts/jenkins/build.sh
cd $SCRIPT_DIR
}
function phase {
ACTION_ARG="--action=$1"
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
}
function run {
build
# First prepare all scripts (build, test, commit, tag, ...),
# so we are sure everything is all right
phase prepare
# only then publish to github
phase publish
}
source $(dirname $0)/../utils.inc
@@ -36,7 +36,8 @@ function init {
function build {
cd ../..
yarn grunt ci-checks package --no-color
source scripts/jenkins/init-node.sh
yarn run grunt -- ci-checks package --no-color
cd $SCRIPT_DIR
}
@@ -64,4 +65,4 @@ function run {
phase publish
}
source $(dirname $0)/../utils.inc
source $(dirname $0)/../utils.inc
@@ -38,4 +38,4 @@ function run {
phase publish
}
source $(dirname $0)/../utils.inc
source $(dirname $0)/../utils.inc
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
set -e
yarn global add grunt-cli@1.2.0
mkdir -p "$LOGS_DIR"
if [ "$JOB" != "ci-checks" ]; then
echo "start_browser_provider"
./scripts/travis/start_browser_provider.sh
fi
# ci-checks and unit tests do not run against the packaged code
if [[ "$JOB" != "ci-checks" ]] && [[ "$JOB" != unit-* ]]; then
grunt package
fi
# unit runs the docs tests too which need a built version of the code
if [[ "$JOB" = unit-* ]]; then
grunt validate-angular-files
grunt build
fi
# check this after the package, because at this point the browser_provider
# has probably arrived
if [ "$JOB" != "ci-checks" ]; then
echo "wait_for_browser_provider"
./scripts/travis/wait_for_browser_provider.sh
fi
+110
View File
@@ -0,0 +1,110 @@
#!/bin/bash
set -e
readonly THIS_DIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd)
readonly ROOT_DIR="$THIS_DIR/../.."
export BROWSER_STACK_ACCESS_KEY
export SAUCE_ACCESS_KEY
BROWSER_STACK_ACCESS_KEY=$(echo "$BROWSER_STACK_ACCESS_KEY" | rev)
SAUCE_ACCESS_KEY=$(echo "$SAUCE_ACCESS_KEY" | rev)
# TODO: restore "SL_EDGE-1" once Sauce Labs adds Edge 17 and "SL_EDGE-1" refers
# to version 16. Edge 15 disconnects from Karma frequently causing extreme build instability.
BROWSERS="SL_Chrome,SL_Chrome-1,\
SL_Firefox,SL_Firefox-1,\
SL_Safari,SL_Safari-1,\
SL_iOS_10,SL_iOS_11,\
SL_IE_9,SL_IE_10,SL_IE_11,\
SL_EDGE"
case "$JOB" in
"ci-checks")
grunt ci-checks
if [[ $TRAVIS_PULL_REQUEST != 'false' ]]; then
# validate commit messages of all commits in the PR
# convert commit range to 2 dots, as commitplease uses `git log`.
# See https://github.com/travis-ci/travis-ci/issues/4596 for more info
echo "Validate commit messages in PR:"
yarn run commitplease -- "${TRAVIS_COMMIT_RANGE/.../..}"
fi
;;
"unit-core")
grunt test:promises-aplus
grunt test:jqlite --browsers="$BROWSERS" --reporters=spec
grunt test:modules --browsers="$BROWSERS" --reporters=spec
;;
"unit-jquery")
grunt test:jquery --browsers="$BROWSERS" --reporters=spec
grunt test:jquery-2.2 --browsers="$BROWSERS" --reporters=spec
grunt test:jquery-2.1 --browsers="$BROWSERS" --reporters=spec
;;
"docs-app")
grunt tests:docs --browsers="$BROWSERS" --reporters=spec
grunt test:travis-protractor --specs="docs/app/e2e/**/*.scenario.js"
;;
"e2e")
if [[ $TEST_TARGET == jquery* ]]; then
export USE_JQUERY=1
fi
if [[ "$TEST_TARGET" == jquery* ]]; then
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
else
TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
fi
TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
grunt test:travis-protractor --specs="$TARGET_SPECS"
;;
"deploy")
export DEPLOY_DOCS
export DEPLOY_CODE
DIST_TAG=$( jq ".distTag" "package.json" | tr -d "\"[:space:]" )
# upload docs if the branch distTag from package.json is "latest" (i.e. stable branch)
if [[ "$DIST_TAG" == latest ]]; then
DEPLOY_DOCS=true
else
DEPLOY_DOCS=false
fi
# upload the build (code + docs) if ...
# the commit is tagged
# - or the branch is "master"
# - or the branch distTag from package.json is "latest" (i.e. stable branch)
if [[ "$TRAVIS_TAG" != '' || "$TRAVIS_BRANCH" == master || "$DIST_TAG" == latest ]]; then
DEPLOY_CODE=true
else
DEPLOY_CODE=false
fi
if [[ "$DEPLOY_DOCS" == true || "$DEPLOY_CODE" == true ]]; then
grunt prepareDeploy
if [[ "$DEPLOY_DOCS" == true ]]; then
# Install npm dependencies for Firebase functions.
(
cd "$ROOT_DIR/scripts/docs.angularjs.org-firebase/functions"
npm install
)
fi
else
echo "Skipping deployment build because conditions have not been met."
fi
;;
*)
echo "Unknown job type. Please set JOB to one of\
'ci-checks',\
'unit-core',\
'unit-jquery',\
'docs-app',\
'e2e',\
or\
'deploy'."
;;
esac
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
LOG_FILES=$LOGS_DIR/*
for FILE in $LOG_FILES; do
echo -e "\n\n\n"
echo "================================================================================"
echo " $FILE"
echo "================================================================================"
cat $FILE
done
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# Has to be run from project root directory.
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
echo "Using BrowserStack"
elif [ "$BROWSER_PROVIDER" == "saucelabs" ]; then
echo "Using SauceLabs"
else
echo "Invalid BROWSER_PROVIDER. Please set env var BROWSER_PROVIDER to 'saucelabs' or 'browserstack'."
exit 1
fi
./lib/${BROWSER_PROVIDER}/start_tunnel.sh
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
# Has to be run from project root directory.
./lib/${BROWSER_PROVIDER}/teardown_tunnel.sh
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# Wait for Connect to be ready before exiting
# Time out if we wait for more than 2 minutes, so that we can print logs.
let "counter=0"
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
let "counter++"
if [ $counter -gt 240 ]; then
echo "Timed out after 2 minutes waiting for browser provider ready file"
# We must manually print logs here because travis will not run
# after_script commands if the failure occurs before the script
# phase.
./scripts/travis/print_logs.sh
exit 5
fi
sleep .5
done
-1
View File
@@ -100,7 +100,6 @@
"VALIDITY_STATE_PROPERTY": false,
"reloadWithDebugInfo": false,
"stringify": false,
"UNSAFE_restoreLegacyJqLiteXHTMLReplacement": false,
"NODE_TYPE_ELEMENT": false,
"NODE_TYPE_ATTRIBUTE": false,
+12 -53
View File
@@ -93,7 +93,6 @@
hasOwnProperty,
createMap,
stringify,
UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
NODE_TYPE_ELEMENT,
NODE_TYPE_ATTRIBUTE,
@@ -343,10 +342,8 @@ function baseExtend(dst, objs, deep) {
} else if (isElement(src)) {
dst[key] = src.clone();
} else {
if (key !== '__proto__') {
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
baseExtend(dst[key], [src], true);
}
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
baseExtend(dst[key], [src], true);
}
} else {
dst[key] = src;
@@ -399,8 +396,8 @@ function extend(dst) {
* sinceVersion="1.6.5"
* This function is deprecated, but will not be removed in the 1.x lifecycle.
* There are edge cases (see {@link angular.merge#known-issues known issues}) that are not
* supported by this function. We suggest using another, similar library for all-purpose merging,
* such as [lodash's merge()](https://lodash.com/docs/4.17.4#merge).
* supported by this function. We suggest
* using [lodash's merge()](https://lodash.com/docs/4.17.4#merge) instead.
*
* @knownIssue
* This is a list of (known) object types that are not handled correctly by this function:
@@ -409,8 +406,6 @@ function extend(dst) {
* - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient)
* - AngularJS {@link $rootScope.Scope scopes};
*
* `angular.merge` also does not support merging objects with circular references.
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
* @returns {Object} Reference to `dst`.
@@ -788,9 +783,7 @@ function arrayRemove(array, value) {
* @kind function
*
* @description
* Creates a deep copy of `source`, which should be an object or an array. This functions is used
* internally, mostly in the change-detection code. It is not intended as an all-purpose copy
* function, and has several limitations (see below).
* Creates a deep copy of `source`, which should be an object or an array.
*
* * If no destination is supplied, a copy of the object or array is created.
* * If a destination is provided, all of its elements (for arrays) or properties (for objects)
@@ -805,25 +798,6 @@ function arrayRemove(array, value) {
* and on `destination`) will be ignored.
* </div>
*
* <div class="alert alert-warning">
* `angular.copy` does not check if destination and source are of the same type. It's the
* developer's responsibility to make sure they are compatible.
* </div>
*
* @knownIssue
* This is a non-exhaustive list of object types / features that are not handled correctly by
* `angular.copy`. Note that since this functions is used by the change detection code, this
* means binding or watching objects of these types (or that include these types) might not work
* correctly.
* - [`File`](https://developer.mozilla.org/docs/Web/API/File)
* - [`Map`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map)
* - [`ImageData`](https://developer.mozilla.org/docs/Web/API/ImageData)
* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
* - [`Set`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set)
* - [`WeakMap`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
* - [`getter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/
* [`setter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)
*
* @param {*} source The source that will be used to make a copy. Can be any type, including
* primitives, `null`, and `undefined`.
* @param {(Object|Array)=} destination Destination into which the source is copied. If provided,
@@ -1532,7 +1506,7 @@ function allowAutoBootstrap(document) {
link.href = src.value;
if (document.location.origin === link.origin) {
// Same-origin resources are always allowed, even for banned URL schemes.
// Same-origin resources are always allowed, even for non-whitelisted schemes.
return true;
}
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
@@ -1722,8 +1696,13 @@ function angularInit(element, bootstrap) {
});
if (appElement) {
if (!isAutoBootstrapAllowed) {
window.console.error('AngularJS: disabling automatic bootstrap. <script> protocol indicates ' +
try {
window.console.error('AngularJS: disabling automatic bootstrap. <script> protocol indicates ' +
'an extension, document.location.href does not match.');
} catch (e) {
// Support: Safari 11 w/ Webdriver
// The console.error will throw and make the test fail
}
return;
}
config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
@@ -1950,26 +1929,6 @@ function bindJQuery() {
bindJQueryFired = true;
}
/**
* @ngdoc function
* @name angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement
* @module ng
* @kind function
*
* @description
* Restores the pre-1.8 behavior of jqLite that turns XHTML-like strings like
* `<div /><span />` to `<div></div><span></span>` instead of `<div><span></span></div>`.
* The new behavior is a security fix. Thus, if you need to call this function, please try to adjust
* your code for this change and remove your use of this function as soon as possible.
* Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
* [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
* about the workarounds.
*/
function UNSAFE_restoreLegacyJqLiteXHTMLReplacement() {
JQLite.legacyXHTMLReplacement = true;
}
/**
* throw error if the argument is falsy.
*/
+2 -4
View File
@@ -7,7 +7,7 @@
htmlAnchorDirective,
inputDirective,
hiddenInputBrowserCacheDirective,
inputDirective,
formDirective,
scriptDirective,
selectDirective,
@@ -156,7 +156,6 @@ function publishExternalAPI(angular) {
'callbacks': {$$counter: 0},
'getTestability': getTestability,
'reloadWithDebugInfo': reloadWithDebugInfo,
'UNSAFE_restoreLegacyJqLiteXHTMLReplacement': UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
'$$minErr': minErr,
'$$csp': csp,
'$$encodeUriSegment': encodeUriSegment,
@@ -222,8 +221,7 @@ function publishExternalAPI(angular) {
ngModelOptions: ngModelOptionsDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective,
input: hiddenInputBrowserCacheDirective
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2020 Google LLC. http://angularjs.org
* (c) 2010-2018 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window) {
+15 -58
View File
@@ -90,16 +90,6 @@
* - [`val()`](http://api.jquery.com/val/)
* - [`wrap()`](http://api.jquery.com/wrap/)
*
* jqLite also provides a method restoring pre-1.8 insecure treatment of XHTML-like tags.
* This legacy behavior turns input like `<div /><span />` to `<div></div><span></span>`
* instead of `<div><span></span></div>` like version 1.8 & newer do. To restore it, invoke:
* ```js
* angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
* ```
* Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
* [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
* about the workarounds.
*
* ## jQuery/jqLite Extras
* AngularJS also provides the following additional methods and events to both jQuery and jqLite:
*
@@ -179,36 +169,20 @@ var HTML_REGEXP = /<|&#?\w+;/;
var TAG_NAME_REGEXP = /<([\w:-]+)/;
var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
// Table parts need to be wrapped with `<table>` or they're
// stripped to their contents when put in a div.
// XHTML parsers do not magically insert elements in the
// same way that tag soup parsers do, so we cannot shorten
// this by omitting <tbody> or other required elements.
var wrapMap = {
thead: ['table'],
col: ['colgroup', 'table'],
tr: ['tbody', 'table'],
td: ['tr', 'tbody', 'table']
'option': [1, '<select multiple="multiple">', '</select>'],
'thead': [1, '<table>', '</table>'],
'col': [2, '<table><colgroup>', '</colgroup></table>'],
'tr': [2, '<table><tbody>', '</tbody></table>'],
'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
'_default': [0, '', '']
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
// Support: IE <10 only
// IE 9 requires an option wrapper & it needs to have the whole table structure
// set up in advance; assigning `"<td></td>"` to `tr.innerHTML` doesn't work, etc.
var wrapMapIE9 = {
option: [1, '<select multiple="multiple">', '</select>'],
_default: [0, '', '']
};
for (var key in wrapMap) {
var wrapMapValueClosing = wrapMap[key];
var wrapMapValue = wrapMapValueClosing.slice().reverse();
wrapMapIE9[key] = [wrapMapValue.length, '<' + wrapMapValue.join('><') + '>', '</' + wrapMapValueClosing.join('></') + '>'];
}
wrapMapIE9.optgroup = wrapMapIE9.option;
function jqLiteIsTextNode(html) {
return !HTML_REGEXP.test(html);
@@ -229,7 +203,7 @@ function jqLiteHasData(node) {
}
function jqLiteBuildFragment(html, context) {
var tmp, tag, wrap, finalHtml,
var tmp, tag, wrap,
fragment = context.createDocumentFragment(),
nodes = [], i;
@@ -240,30 +214,13 @@ function jqLiteBuildFragment(html, context) {
// Convert html into DOM nodes
tmp = fragment.appendChild(context.createElement('div'));
tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
finalHtml = JQLite.legacyXHTMLReplacement ?
html.replace(XHTML_TAG_REGEXP, '<$1></$2>') :
html;
wrap = wrapMap[tag] || wrapMap._default;
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];
if (msie < 10) {
wrap = wrapMapIE9[tag] || wrapMapIE9._default;
tmp.innerHTML = wrap[1] + finalHtml + wrap[2];
// Descend through wrappers to the right content
i = wrap[0];
while (i--) {
tmp = tmp.firstChild;
}
} else {
wrap = wrapMap[tag] || [];
// Create wrappers & descend into them
i = wrap.length;
while (--i > -1) {
tmp.appendChild(window.document.createElement(wrap[i]));
tmp = tmp.firstChild;
}
tmp.innerHTML = finalHtml;
// Descend through wrappers to the right content
i = wrap[0];
while (i--) {
tmp = tmp.lastChild;
}
nodes = concat(nodes, tmp.childNodes);
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2020 Google LLC. http://angularjs.org
* (c) 2010-2018 Google, Inc. http://angularjs.org
* License: MIT
*/
'use strict';
+2 -2
View File
@@ -32,7 +32,7 @@ var minErrConfig = {
* non-positive or non-numeric value, removes the max depth limit.
* Default: 5
*
* * `urlErrorParamsEnabled` **{Boolean}** - Specifies whether the generated error url will
* * `urlErrorParamsEnabled` **{Boolean}** - Specifies wether the generated error url will
* contain the parameters of the thrown error. Disabling the parameters can be useful if the
* generated error url is very long.
*
@@ -82,7 +82,7 @@ function isValidObjectMaxDepth(maxDepth) {
* Since data will be parsed statically during a build step, some restrictions
* are applied with respect to how minErr instances are created and called.
* Instances should have names of the form namespaceMinErr for a minErr created
* using minErr('namespace'). Error codes, namespaces and template strings
* using minErr('namespace') . Error codes, namespaces and template strings
* should all be static strings, not variables or general expressions.
*
* @param {string} module The namespace to use for the new minErr instance.
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @license AngularJS v"NG_VERSION_FULL"
* (c) 2010-2020 Google LLC. http://angularjs.org
* (c) 2010-2018 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {
-3
View File
@@ -108,9 +108,6 @@ function Browser(window, document, $log, $sniffer, $$taskTrackerFactory) {
if (url) {
var sameState = lastHistoryState === state;
// Normalize the inputted URL
url = urlResolve(url).href;
// Don't change anything if previous and current URLs and states match. This also prevents
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
// See https://github.com/angular/angular.js/commit/ffb2701
+65 -117
View File
@@ -205,7 +205,7 @@
*
* This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
* actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
* arrays or objects can have a negative impact on your application performance.)
* arrays or objects can have a negative impact on your application performance)
*
* <example name="doCheckArrayExample" module="do-check-module">
* <file name="index.html">
@@ -528,7 +528,7 @@
* would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
* case when only one deeply nested directive has `templateUrl`.
*
* Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}.
* Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
*
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
@@ -589,7 +589,7 @@
* own templates or compile functions. Compiling these directives results in an infinite loop and
* stack overflow errors.
*
* This can be avoided by manually using `$compile` in the postLink function to imperatively compile
* This can be avoided by manually using $compile in the postLink function to imperatively compile
* a directive's template instead of relying on automatic template compilation via `template` or
* `templateUrl` declaration or manual compilation inside the compile function.
* </div>
@@ -693,17 +693,17 @@
*
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
* * `'element'` - transclude the whole of the directive's element including any directives on this
* element that are defined at a lower priority than this directive. When used, the `template`
* element that defined at a lower priority than this directive. When used, the `template`
* property is ignored.
* * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
*
* **Multi-slot transclusion** is declared by providing an object for the `transclude` property.
* **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
*
* This object is a map where the keys are the name of the slot to fill and the value is an element selector
* used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
* and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
*
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}.
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
*
* If the element selector is prefixed with a `?` then that slot is optional.
*
@@ -728,7 +728,7 @@
* </div>
*
* If you want to manually control the insertion and removal of the transcluded content in your directive
* then you must use this transclude function. When you call a transclude function it returns a jqLite/JQuery
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
*
* When you call a transclusion function you can pass in a **clone attach function**. This function accepts
@@ -813,8 +813,8 @@
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
* `link()` or `compile()` functions. It has a variety of uses.
*
* * *Accessing normalized attribute names:* Directives like `ngBind` can be expressed in many ways:
* `ng:bind`, `data-ng-bind`, or `x-ng-bind`. The attributes object allows for normalized access
* * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
* 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
* to the attributes.
*
* * *Directive inter-communication:* All directives share the same instance of the attributes
@@ -855,24 +855,25 @@
<file name="index.html">
<script>
angular.module('compileExample', [], function($compileProvider) {
// Configure new 'compile' directive by passing a directive
// factory function. The factory function injects '$compile'.
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('compile', function($compile) {
// The directive factory creates a link function.
// directive factory creates a link function
return function(scope, element, attrs) {
scope.$watch(
function(scope) {
// Watch the 'compile' expression for changes.
// watch the 'compile' expression for changes
return scope.$eval(attrs.compile);
},
function(value) {
// When the 'compile' expression changes
// assign it into the current DOM.
// when the 'compile' expression changes
// assign it into the current DOM
element.html(value);
// Compile the new DOM and link it to the current scope.
// NOTE: we only compile '.childNodes' so that we
// don't get into an infinite loop compiling ourselves.
// compile the new DOM and link it to the current
// scope.
// NOTE: we only compile .childNodes so that
// we don't get into infinite loop compiling ourselves
$compile(element.contents())(scope);
}
);
@@ -945,13 +946,13 @@
* }
* ```
* * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
* the cloned elements; only needed for transcludes that are allowed to contain non HTML
* elements (e.g. SVG elements). See also the `directive.controller` property.
* the cloned elements; only needed for transcludes that are allowed to contain non html
* elements (e.g. SVG elements). See also the directive.controller property.
*
* Calling the linking function returns the element of the template. It is either the original
* element passed in, or the clone of the element if the `cloneAttachFn` is provided.
*
* After linking the view is not updated until after a call to `$digest`, which typically is done by
* After linking the view is not updated until after a call to $digest which typically is done by
* AngularJS automatically.
*
* If you need access to the bound view, there are two ways to do it:
@@ -959,23 +960,21 @@
* - If you are not asking the linking function to clone the template, create the DOM element(s)
* before you send them to the compiler and keep this reference around.
* ```js
* var element = angular.element('<p>{{total}}</p>');
* $compile(element)(scope);
* var element = $compile('<p>{{total}}</p>')(scope);
* ```
*
* - if on the other hand, you need the element to be cloned, the view reference from the original
* example would not point to the clone, but rather to the original template that was cloned. In
* this case, you can access the clone either via the `cloneAttachFn` or the value returned by the
* linking function:
* this case, you can access the clone via the cloneAttachFn:
* ```js
* var templateElement = angular.element('<p>{{total}}</p>');
* var templateElement = angular.element('<p>{{total}}</p>'),
* scope = ....;
*
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
* // Attach the clone to DOM document at the right place.
* //attach the clone to DOM document at the right place
* });
*
* // Now we have reference to the cloned DOM via `clonedElement`.
* // NOTE: The `clonedElement` returned by the linking function is the same as the
* // `clonedElement` passed to `cloneAttachFn`.
* //now we have reference to the cloned DOM via `clonedElement`
* ```
*
*
@@ -1026,7 +1025,7 @@
*
* When the original node and the replace template declare the same directive(s), they will be
* {@link guide/compiler#double-compilation-and-how-to-avoid-it compiled twice} because the compiler
* does not deduplicate them. In many cases, this is not noticeable, but e.g. {@link ngModel} will
* does not deduplicate them. In many cases, this is not noticable, but e.g. {@link ngModel} will
* attach `$formatters` and `$parsers` twice.
*
* See issue [#2573](https://github.com/angular/angular.js/issues/2573).
@@ -1106,8 +1105,8 @@
*
* Based on the context, other options may exist to mark a value as trusted / configure the behavior
* of {@link ng.$sce}. For example, to restrict the `RESOURCE_URL` context to specific origins, use
* the {@link $sceDelegateProvider#trustedResourceUrlList trustedResourceUrlList()}
* and {@link $sceDelegateProvider#bannedResourceUrlList bannedResourceUrlList()}.
* the {@link $sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist()}
* and {@link $sceDelegateProvider#resourceUrlBlacklist resourceUrlBlacklist()}.
*
* {@link ng.$sce#what-trusted-context-types-are-supported- Find out more about the different context types}.
*
@@ -1116,7 +1115,7 @@
* By default, `$sce` will throw an error if it detects untrusted HTML content, and will not bind the
* content.
* However, if you include the {@link ngSanitize ngSanitize module}, it will try to sanitize the
* potentially dangerous HTML, e.g. strip non-trusted tags and attributes when binding to
* potentially dangerous HTML, e.g. strip non-whitelisted tags and attributes when binding to
* `innerHTML`.
*
* @example
@@ -1501,9 +1500,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @description
* Register a new directive with the compiler.
*
* @param {string|Object} name Name of the directive in camel-case (i.e. `ngBind` which will match
* as `ng-bind`), or an object map of directives where the keys are the names and the values
* are the factories.
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
* names and the values are the factories.
* @param {Function|Array} directiveFactory An injectable directive factory function. See the
* {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
* @returns {ng.$compileProvider} Self for chaining.
@@ -1698,81 +1697,30 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
/**
* @ngdoc method
* @name $compileProvider#aHrefSanitizationTrustedUrlList
* @name $compileProvider#aHrefSanitizationWhitelist
* @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for determining trusted safe
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
* urls during a[href] sanitization.
*
* The sanitization is a security measure aimed at preventing XSS attacks via html links.
*
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationTrustedUrlList`
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
*
* @param {RegExp=} regexp New regexp to trust urls with.
* @param {RegExp=} regexp New regexp to whitelist urls with.
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
* chaining otherwise.
*/
this.aHrefSanitizationTrustedUrlList = function(regexp) {
this.aHrefSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
$$sanitizeUriProvider.aHrefSanitizationTrustedUrlList(regexp);
$$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
return this;
} else {
return $$sanitizeUriProvider.aHrefSanitizationTrustedUrlList();
}
};
/**
* @ngdoc method
* @name $compileProvider#aHrefSanitizationWhitelist
* @kind function
*
* @deprecated
* sinceVersion="1.8.1"
*
* This method is deprecated. Use {@link $compileProvider#aHrefSanitizationTrustedUrlList
* aHrefSanitizationTrustedUrlList} instead.
*/
Object.defineProperty(this, 'aHrefSanitizationWhitelist', {
get: function() {
return this.aHrefSanitizationTrustedUrlList;
},
set: function(value) {
this.aHrefSanitizationTrustedUrlList = value;
}
});
/**
* @ngdoc method
* @name $compileProvider#imgSrcSanitizationTrustedUrlList
* @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for determining trusted safe
* urls during img[src] sanitization.
*
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
*
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationTrustedUrlList`
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
*
* @param {RegExp=} regexp New regexp to trust urls with.
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
* chaining otherwise.
*/
this.imgSrcSanitizationTrustedUrlList = function(regexp) {
if (isDefined(regexp)) {
$$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList(regexp);
return this;
} else {
return $$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList();
return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
}
};
@@ -1782,20 +1730,29 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @name $compileProvider#imgSrcSanitizationWhitelist
* @kind function
*
* @deprecated
* sinceVersion="1.8.1"
* @description
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
* urls during img[src] sanitization.
*
* This method is deprecated. Use {@link $compileProvider#imgSrcSanitizationTrustedUrlList
* imgSrcSanitizationTrustedUrlList} instead.
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
*
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
*
* @param {RegExp=} regexp New regexp to whitelist urls with.
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
* chaining otherwise.
*/
Object.defineProperty(this, 'imgSrcSanitizationWhitelist', {
get: function() {
return this.imgSrcSanitizationTrustedUrlList;
},
set: function(value) {
this.imgSrcSanitizationTrustedUrlList = value;
this.imgSrcSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
$$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
return this;
} else {
return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
}
});
};
/**
* @ngdoc method
@@ -2274,16 +2231,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
this.$$element.removeAttr(attrName);
} else {
if (SIMPLE_ATTR_NAME.test(attrName)) {
// jQuery skips special boolean attrs treatment in XML nodes for
// historical reasons and hence AngularJS cannot freely call
// `.attr(attrName, false) with such attributes. To avoid issues
// in XHTML, call `removeAttr` in such cases instead.
// See https://github.com/jquery/jquery/issues/4249
if (booleanKey && value === false) {
this.$$element.removeAttr(attrName);
} else {
this.$$element.attr(attrName, value);
}
this.$$element.attr(attrName, value);
} else {
setSpecialAttr(this.$$element[0], attrName, value);
}
@@ -3880,7 +3828,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
pre: function ngPropPreLinkFn(scope, $element) {
function applyPropValue() {
var propValue = ngPropGetter(scope);
$element[0][propName] = sanitizer(propValue);
$element.prop(propName, sanitizer(propValue));
}
applyPropValue();
+3 -6
View File
@@ -181,6 +181,7 @@
</file>
</example>
*
* @element INPUT
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
* then the `disabled` attribute will be set on the element
*/
@@ -407,7 +408,7 @@ forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
// ng-src, ng-srcset, ng-href are interpolated
forEach(['src', 'srcset', 'href'], function(attrName) {
var normalized = directiveNormalize('ng-' + attrName);
ngAttributeAliasDirectives[normalized] = ['$sce', function($sce) {
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 99, // it needs to run after the attributes are interpolated
link: function(scope, element, attr) {
@@ -421,10 +422,6 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
propName = null;
}
// We need to sanitize the url at least once, in case it is a constant
// non-interpolated attribute.
attr.$set(normalized, $sce.getTrustedMediaUrl(attr[normalized]));
attr.$observe(normalized, function(value) {
if (!value) {
if (attrName === 'href') {
@@ -444,5 +441,5 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
});
}
};
}];
};
});

Some files were not shown because too many files have changed in this diff Show More