Compare commits

..

21 Commits

Author SHA1 Message Date
Caitlin Potter e4adebd07a revert: chore(npm): Make require()-able as part of publish script
This reverts commit c5686c5271.

(We wanted to get some feedback before doin this)
2015-01-13 14:29:29 -05:00
Peter Bacon Darwin ac94f6125f docs(CHANGELOG): add changes for 1.3.9 and 1.4.0-beta.0 2015-01-13 00:58:04 +00:00
Ben Clinkinbeard c5686c5271 chore(npm): Make require()-able as part of publish script
(This has not been tested locally with browserify --- but it should work!
If it doesn't, please file a bug rather than just leaving a comment on this
commit :)

Closes #10731
2015-01-12 19:09:46 -05:00
Julie Ralph 7fdb54d12b chore(testing): bump protractor to version 1.6.0 2015-01-12 11:47:47 -08:00
Jason Bedard 869008140a fix($parse): allow use of locals in assignments Fixes #4664 2015-01-12 13:38:34 +00:00
Julie Ralph 26ee32ec79 chore(travis): split out the docs e2e tests into their own travis job
Previously, they were in the 'unit' job to save travis VMs, but this
was confusing and made it more difficult to track down errors easily.
2015-01-09 14:29:26 -08:00
Julie Ralph a06193f97b chore(travis): make browserstack unit tests allowed failures 2015-01-09 10:45:23 -08:00
Uri Goldshtein ba9dee170c docs(guide/index): add angular-easyfb with Facebook login to login libraries
Merci~

Closes #5792
2015-01-06 13:41:45 -05:00
Andrey Pushkarev d4b60ada1e fix(filterFilter): use isArray() to determine array type
In JavaScript, an array is a special type of object, therefore typeof [] returns object.
Added corresponding unit tests.

Changed condition for array type to isArray.

Closes #10621
2015-01-02 13:26:51 -05:00
Rus1 b839f73ad0 docs(ngInclude): replace <tt> with <code>
Using obsolete <tt> HTML tag may not be good for Angular examples

Closes #10594
2014-12-30 15:48:19 -05:00
Peter Bacon Darwin aee32931fd test(input): split tests into smaller files
This is complement to the previous commit.
It also refactors the input compile helpers to make it cleaner and more
consistent.
2014-12-24 23:26:34 +00:00
Peter Bacon Darwin 7ee5f46bbc refact(input): split input.js into smaller files
The input.js file is unnecessarily large, containing many directives including the
vast `ngModel`. This change moves ngModel and a few other directives into their
own files, which will make maintenance easier.
2014-12-24 13:01:03 +00:00
David Souther 2b97854bf4 feat(ngMock/$exceptionHandler): log errors when rethrowing
Now the `rethrow` mode will also record a log of the error in the same
way as the `log` mode.

Closes #10540
Closes #10564
2014-12-23 18:35:49 +00:00
David Souther 316ee8f7ca test($exceptionHandlerProvider): call inject() to run tests
In the current angular-mocksSpec, the tests for $exceptionHandlerProvider
call `module` to run tests on `$exceptionHandlerProvider.mode()`, but do
not call `inject()` to pump the module definitions.

Closes #10563
2014-12-23 18:11:21 +00:00
gokulkrishh 2e18f44fcd docs(guide/*): spelling/grammar improvements
Closes #10552
2014-12-22 10:44:54 -05:00
Caitlin Potter c85d064ecf docs($rootScope): remove erroneous closing parenthesis
Closes #10549
2014-12-22 08:34:29 -05:00
Kevin Primat 7b9b82281a docs(guide/location): add missing definite article
The sentence was missing a definite article so was unclear. Added one to clarify.

Closes #10547
2014-12-22 08:25:24 -05:00
Olivier Giulieri aab632b330 docs(guide): fix spaces
Closes #10539
2014-12-22 01:08:06 +00:00
gdi2290 4c8d8ad508 perf(ngStyleDirective): use $watchCollection
Since we are simply watching a flat object collection it is more performant
to use $watchCollection than a deepWatch...

Closes #10535
2014-12-22 00:58:45 +00:00
Dan Cancro 3a8f3dc9ea docs(guide/index): Link to starter options
Add a link to a comparison spreadsheet of alternative generators, examples,
tutorials and seeds that one can use to get started on a new Angular project.

Closes #10526
2014-12-22 00:30:30 +00:00
Robert Haritonov c139e68d99 docs(tutorial/12): fix path to jquery in bower
Closes #10504
2014-12-22 00:21:27 +00:00
1520 changed files with 56595 additions and 247157 deletions
-11
View File
@@ -1,11 +0,0 @@
bower_components/**
build/**
docs/bower_components/**
docs/app/assets/js/angular-bootstrap/**
docs/config/templates/**
node_modules/**
lib/htmlparser/**
src/angular.bind.js
src/ngParseExt/ucd.js
i18n/closure/**
tmp/**
-117
View File
@@ -1,117 +0,0 @@
{
"rules": {
// Rules are divided into sections from http://eslint.org/docs/rules/
// Possible errors
"comma-dangle": ["error", "never"],
"no-cond-assign": ["error", "except-parens"],
"no-constant-condition": ["error", {"checkLoops": false}],
"no-control-regex": "error",
"no-debugger": "error",
"no-dupe-args": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty-character-class": "error",
"no-empty": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-extra-semi": "error",
"no-func-assign": "error",
"no-inner-declarations": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-negated-in-lhs": "error",
"no-obj-calls": "error",
"no-regex-spaces": "error",
"no-sparse-arrays": "error",
"no-unreachable": "error",
"use-isnan": "error",
"no-unsafe-finally": "error",
"valid-typeof": "error",
"no-unexpected-multiline": "error",
// Best practices
"accessor-pairs": "error",
"array-callback-return": "error",
"eqeqeq": ["error", "allow-null"],
"no-alert": "error",
"no-caller": "error",
"no-case-declarations": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"no-iterator": "error",
"no-multi-str": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-new": "error",
"no-octal-escape": "error",
"no-octal": "error",
"no-proto": "error",
"no-redeclare": "error",
"no-return-assign": "error",
"no-script-url": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"no-useless-escape": "error",
"no-void": "error",
"no-with": "error",
"radix": "error",
"wrap-iife": ["error", "inside"],
// Strict mode
"strict": ["error", "global"],
// Variables
"no-delete-var": "error",
"no-label-var": "error",
"no-restricted-globals": ["error", "event"],
"no-shadow-restricted-names": "error",
"no-undef-init": "error",
"no-undef": "error",
"no-unused-vars": ["error", { "vars": "local", "args": "none" }],
// Node.js
"handle-callback-err": "error",
// Stylistic issues
"array-bracket-spacing": ["error", "never"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"comma-style": ["error", "last"],
"eol-last": "error",
"keyword-spacing": "error",
"linebreak-style": ["error", "unix"],
"max-len": ["error", { "code": 200, "ignoreComments": true, "ignoreUrls": true }],
"new-cap": "error",
"new-parens": "error",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-mixed-spaces-and-tabs": "error",
"no-multiple-empty-lines": ["error", { "max": 3, "maxEOF": 1 }],
"no-whitespace-before-property": "error",
"no-spaced-func": "error",
"no-trailing-spaces": "error",
"no-unneeded-ternary": "error",
"quotes": ["error", "single"],
"semi-spacing": "error",
"semi": "error",
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "never"],
"space-in-parens": ["error", "never"],
"space-infix-ops": "error",
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"unicode-bom": ["error", "never"]
}
}
-17
View File
@@ -1,17 +0,0 @@
{
"extends": "./.eslintrc-base.json",
"env": {
// Note: don't set `"browser": true`; code in "src/" should be compatible with
// non-browser environments like Node.js with a custom window implementation
// like jsdom. All browser globals should be taken from window.
"browser": false,
"node": false
},
"globals": {
"window": false,
"angular": false
}
}
-8
View File
@@ -1,8 +0,0 @@
{
"extends": "./.eslintrc-base.json",
"env": {
"browser": false,
"node": true
}
}
-25
View File
@@ -1,25 +0,0 @@
{
// This config contains proposed rules that we'd like to have enabled but haven't
// converted the code to adhere yet. If a decision comes to not enable one of these
// rules, it should be removed from the file. Every rule that got enabled in the
// end should be moved from here to a respective section in .eslintrc.json
"rules": {
// Rules are divided into sections from http://eslint.org/docs/rules/
// Best practices
"complexity": ["error", 10],
"dot-notation": "error",
"dot-location": ["error", "property"],
// Stylistic issues
"block-spacing": ["error", "always"],
"comma-spacing": "error",
"id-blacklist": ["error", "event"],
"indent": ["error", 2],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
"object-curly-spacing": ["error", "never"],
"object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
"operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" }}]
}
}
-4
View File
@@ -1,4 +0,0 @@
{
"root": true,
"extends": "./.eslintrc-node.json"
}
-5
View File
@@ -1,5 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
# JS files must always use LF for tools to work
*.js eol=lf
-27
View File
@@ -1,27 +0,0 @@
***Note*: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.**
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).**
**What is the expected behavior?**
**What is the motivation / use case for changing the behavior?**
**Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.**
**Other information (e.g. stacktraces, related issues, suggestions how to fix)**
-23
View File
@@ -1,23 +0,0 @@
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
**What is the current behavior? (You can also link to an open issue here)**
**What is the new behavior (if this is a feature change)?**
**Does this PR introduce a breaking change?**
**Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
**Other information**:
-3
View File
@@ -20,6 +20,3 @@ libpeerconnection.log
npm-debug.log
/tmp/
/scripts/bower/bower-*
.vscode
*.log
*.stackdump
+41
View File
@@ -0,0 +1,41 @@
{
"excludeFiles": ["src/ngLocale/**"],
"disallowKeywords": ["with"],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleLineStrings": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
"disallowSpaceBeforeBinaryOperators": [","],
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
"disallowSpacesInAnonymousFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInFunctionDeclaration": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInNamedFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"disallowTrailingComma": true,
"disallowTrailingWhitespace": true,
"requireCommaBeforeLineBreak": true,
"requireLineFeedAtFileEnd": true,
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInConditionalExpression": {
"afterTest": true,
"beforeConsequent": true,
"afterConsequent": true,
"beforeAlternate": true
},
"requireSpacesInFunction": {
"beforeOpeningCurlyBrace": true
},
"validateLineBreaks": "LF",
"validateParameterSeparator": ", "
}
+15
View File
@@ -0,0 +1,15 @@
// This is an incomplete TODO list of checks we want to start enforcing
//
// The goal is to enable these checks one by one by moving them to .jscs.json along with commits
// that correct the existing code base issues and make the new check pass.
{
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
"disallowImplicitTypeConversion": ["string"],
"disallowMultipleLineBreaks": true,
"disallowKeywordsOnNewLine": ["else"],
"validateJSDoc": {
"checkParamNames": true,
"requireParamTypes": true
}
}
+2
View File
@@ -0,0 +1,2 @@
node_modules/**
lib/htmlparser/**
+5
View File
@@ -0,0 +1,5 @@
{
"extends": ".jshintrc-base",
"node": true,
"globals": {}
}
+19
View File
@@ -0,0 +1,19 @@
{
"bitwise": true,
"immed": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"trailing": true,
"maxlen": 200,
"boss": true,
"eqnull": true,
"expr": true,
"globalstrict": true,
"laxbreak": true,
"loopfunc": true,
"sub": true,
"undef": true,
"indent": 2
}
-1
View File
@@ -1 +0,0 @@
6
+25 -27
View File
@@ -1,13 +1,6 @@
language: node_js
sudo: false
node_js:
- '6'
cache:
directories:
- node_modules
- bower_components
- docs/bower_components
- '0.10'
branches:
except:
@@ -15,47 +8,52 @@ branches:
env:
matrix:
- JOB=ci-checks
- JOB=unit BROWSER_PROVIDER=saucelabs
- JOB=docs-e2e BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
- JOB=unit BROWSER_PROVIDER=browserstack
- JOB=docs-e2e BROWSER_PROVIDER=browserstack
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack
global:
- CXX=g++-4.8 # node 4 likes the G++ v4.8 compiler
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- BROWSER_STACK_USERNAME=VojtaJina
- BROWSER_STACK_ACCESS_KEY=QCQJ1ZpWXpBkSwEdD8ev
- LOGS_DIR=/tmp/angular-build/logs
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
# node 4 likes the G++ v4.8 compiler
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
matrix:
allow_failures:
- env: "JOB=unit BROWSER_PROVIDER=browserstack"
before_install:
- curl -o- -L https://raw.githubusercontent.com/yarnpkg/yarn/2a0afc73210c7a82082585283e518eeb88ca19ae/scripts/install-latest.sh | bash -s -- --version 0.17.9
- export PATH=$HOME/.yarn/bin:$PATH
install:
# - npm config set registry http://23.251.144.68
# Disable the spinner, it looks bad on Travis
- npm config set spin false
# Log HTTP requests
- npm config set loglevel http
- time ./scripts/travis/npm-bundle-deps.sh
- time npm install
before_script:
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
- ./scripts/travis/before_build.sh
- mkdir -p $LOGS_DIR
- ./scripts/travis/start_browser_provider.sh
- npm install -g grunt-cli
- grunt package
- ./scripts/travis/wait_for_browser_provider.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_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: always # default: false
on_start: false # default: false
+61 -6648
View File
File diff suppressed because it is too large Load Diff
+52 -92
View File
@@ -1,4 +1,4 @@
# Contributing to AngularJS
#Contributing to AngularJS
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
@@ -14,77 +14,64 @@ today! Here are the guidelines we'd like you to follow:
- [Further Info](#info)
## <a name="coc"></a> Code of Conduct
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][coc].
## <a name="question"></a> Got a Question or Problem?
If you have questions about how to use AngularJS, please direct these to the [Google Group][groups]
discussion list or [StackOverflow][stackoverflow]. We are also available on [IRC][irc] and
[Gitter][gitter].
discussion list or [StackOverflow][stackoverflow]. We are also available on [IRC][irc].
## <a name="issue"></a> Found an Issue?
If you find a bug in the source code or a mistake in the documentation, you can help us by
submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
with a fix.
**Localization Issues:** Angular.js uses the [Google Closure I18N library] to generate
its own I18N files (the ngLocale module). This means that any changes to these files would be lost
the next time that we import the library.
Since the Closure library i18n data is itself auto-generated from the data of the
[Common Locale Data Repository (CLDR)] project, errors in the data should
be reported there. See also the [Closure guide to i18n changes].
***Localization Issue:*** *Angular.js uses the [Google Closure I18N library], to generate its own I18N files. This means that
any changes to these files would be lost the next time that we import the library. The recommended
approach is to submit a patch to the I18N project directly, instead of submitting it here.*
**Please see the [Submission Guidelines](#submit) below.**
**Please see the Submission Guidelines below**.
## <a name="feature"></a> Want a Feature?
You can request a new feature by submitting an issue to our [GitHub Repository][github]. If you
would like to implement a new feature then consider what kind of change it is:
* **Major Changes** that you wish to contribute to the project should be discussed first on our
[dev mailing list][angular-dev] or [IRC][irc] so that we can better coordinate our efforts,
prevent duplication of work, and help you to craft the change so that it is successfully accepted
into the project.
* **Small Changes** can be crafted and submitted to the [GitHub Repository][github] as a Pull
Request.
[dev mailing list][angular-dev] or [IRC][irc] so that we can better coordinate our efforts, prevent
duplication of work, and help you to craft the change so that it is successfully accepted into the
project.
* **Small Changes** can be crafted and submitted to the [GitHub Repository][github] as a Pull Request.
## <a name="docs"></a> Want a Doc Fix?
If you want to help improve the docs, it's a good idea to let others know what you're working on to
minimize duplication of effort. Create a new issue (or comment on a related existing one) to let
others know what you're working on.
minimize duplication of effort. Before starting, check out the issue queue for
[Milestone:Docs Only](https://github.com/angular/angular.js/issues?milestone=24&state=open).
Comment on an issue to let others know what you're working on, or create a new issue if your work
doesn't fit within the scope of any of the existing doc fix projects.
For large fixes, please build and test the documentation before submitting the PR to be sure you
haven't accidentally introduced any layout or formatting issues. You should also make sure that your
commit message starts with "docs" and follows the **[Commit Message Guidelines](#commit)** outlined
below.
For large fixes, please build and test the documentation before submitting the PR to be sure you haven't
accidentally introduced any layout or formatting issues. You should also make sure that your commit message
is labeled "docs:" and follows the **Git Commit Guidelines** outlined below.
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue
"Improve this doc" button at the top right of the doc page to fork the repository in-place and make
a quick change on the fly. When naming the commit, it is advised to follow the commit message
guidelines below, by starting the commit message with **docs** and referencing the filename. Since
this is not obvious and some changes are made on the fly, this is not strictly necessary and we will
understand if this isn't done the first few times.
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue "Improve this doc" button at the top right of the doc page to fork the repository in-place and make a quick change on the fly. When naming the commit, it is advised to still label it according to the commit guidelines below, by starting the commit message with **docs** and referencing the filename. Since this is not obvious and some changes are made on the fly, this is not strictly necessary and we will understand if this isn't done the first few times.
## <a name="submit"></a> Submission Guidelines
### Submitting an Issue
Before you submit your issue search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue. Help us to maximize
the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.
Providing the following information will increase the chances of your issue being dealt with
quickly:
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues. Providing the following information will increase the
chances of your issue being dealt with quickly:
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
* **Motivation for or Use Case** - explain why this is a bug for you
* **Angular Version(s)** - is it a regression?
* **Browsers and Operating System** - is this a problem with all browsers or only specific ones?
* **Browsers and Operating System** - is this a problem with all browsers or only IE8?
* **Reproduce the Error** - provide a live example (using [Plunker][plunker] or
[JSFiddle][jsfiddle]) or an unambiguous set of steps.
[JSFiddle][jsfiddle]) or a unambiguous set of steps.
* **Related Issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
@@ -100,27 +87,27 @@ Before you submit your pull request consider the following guidelines:
that relates to your submission. You don't want to duplicate effort.
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull
requests. We cannot accept code without this.
* Make your changes in a new git branch:
* Make your changes in a new git branch
```shell
git checkout -b my-fix-branch master
```
```shell
git checkout -b my-fix-branch master
```
* Create your patch, **including appropriate test cases**.
* Follow our [Coding Rules](#rules).
* Run the full Angular test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass.
* Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit) and passes our commit message presubmit hook
(`validate-commit-msg.js`). Adherence to the [commit message conventions](#commit) is required,
because release notes are automatically generated from these messages.
[commit message conventions](#commit-message-format) and passes our commit message presubmit hook
`validate-commit-msg.js`. Adherence to the [commit message conventions](#commit-message-format)
is required because release notes are automatically generated from these messages.
```shell
git commit -a
```
```shell
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
* Build your changes locally to ensure all the tests pass:
* Build your changes locally to ensure all the tests pass
```shell
grunt test
@@ -132,24 +119,16 @@ Before you submit your pull request consider the following guidelines:
git push origin my-fix-branch
```
In GitHub, send a pull request to `angular:master`.
If we suggest changes, then:
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then
* Make the required updates.
* Re-run the Angular test suite to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
* Make the required updates.
* Re-run the Angular test suite to ensure tests are still passing.
* Commit your changes to your branch (e.g. `my-fix-branch`).
* Push the changes to your GitHub repository (this will update your Pull Request).
If the PR gets too outdated we may ask you to rebase and force push to update the PR:
```shell
git rebase master -i
git push origin my-fix-branch -f
```
_WARNING: Squashing or reverting commits and force-pushing thereafter may remove GitHub comments
on code that were previously made by you or others in your commits. Avoid any form of rebasing
unless necessary._
```shell
git rebase master -i
git push origin my-fix-branch -f
```
That's it! Thank you for your contribution!
@@ -183,7 +162,6 @@ from the main (upstream) repository:
```
## <a name="rules"></a> Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more [specs][unit-testing].
@@ -209,10 +187,6 @@ We have very precise rules over how our git commit messages can be formatted. T
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the AngularJS change log**.
The commit message formatting can be added using a typical git workflow or through the use of a CLI
wizard ([Commitizen](https://github.com/commitizen/cz-cli)). To use the wizard, run `yarn run commit`
in your terminal after staging your changes in git.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
@@ -225,14 +199,8 @@ format that includes a **type**, a **scope** and a **subject**:
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
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
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header 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.
to read on github as well as in various git tools.
### Type
Must be one of the following:
@@ -242,9 +210,9 @@ Must be one of the following:
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **refactor**: A code change that neither fixes a bug or adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing or correcting existing tests
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
@@ -252,8 +220,6 @@ Must be one of the following:
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
You can use `*` when the change affects more than a single scope.
### Subject
The subject contains succinct description of the change:
@@ -261,16 +227,14 @@ The subject contains succinct description of the change:
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
###Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
###Footer
The footer should contain any information about **Breaking Changes** and is also the place to
[reference GitHub issues that this commit closes][closing-issues].
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
@@ -291,7 +255,6 @@ You can find out more detailed information about contributing in the
[Google Closure I18N library]: https://github.com/google/closure-library/tree/master/closure/goog/i18n
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
[closing-issues]: https://help.github.com/articles/closing-issues-via-commit-messages/
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[contribute]: http://docs.angularjs.org/misc/contribute
@@ -299,18 +262,15 @@ You can find out more detailed information about contributing in the
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://docs.angularjs.org/guide
[github]: https://github.com/angular/angular.js
[gitter]: https://gitter.im/angular/angular.js
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[js-style-guide]: https://google.github.io/styleguide/javascriptguide.xml
[js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
[jsfiddle]: http://jsfiddle.net/
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[ngDocs]: https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation
[plunker]: http://plnkr.co/edit
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[unit-testing]: https://docs.angularjs.org/guide/unit-testing
[Common Locale Data Repository (CLDR)]: http://cldr.unicode.org
[Closure guide to i18n changes]: https://github.com/google/closure-library/wiki/Internationalization-%28i18n%29-changes-in-Closure-Library
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/CONTRIBUTING.md?pixel)](https://github.com/igrigorik/ga-beacon)
+83 -142
View File
@@ -1,73 +1,25 @@
'use strict';
var serveFavicon = require('serve-favicon');
var serveStatic = require('serve-static');
var serveIndex = require('serve-index');
var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
var versionInfo = require('./lib/versions/version-info');
var path = require('path');
var e2e = require('./test/e2e/tools');
var semver = require('semver');
var exec = require('shelljs').exec;
var pkg = require(__dirname + '/package.json');
// Node.js version checks
if (!semver.satisfies(process.version, pkg.engines.node)) {
reportOrFail('Invalid node version (' + process.version + '). ' +
'Please use a version that satisfies ' + pkg.engines.node);
}
// Yarn version checks
var expectedYarnVersion = pkg.engines.yarn;
var currentYarnVersion = exec('yarn --version', {silent: true}).stdout.trim();
if (!semver.satisfies(currentYarnVersion, expectedYarnVersion)) {
reportOrFail('Invalid yarn version (' + currentYarnVersion + '). ' +
'Please use a version that satisfies ' + expectedYarnVersion);
}
// Grunt CLI version checks
var expectedGruntVersion = pkg.engines.grunt;
var currentGruntVersions = exec('grunt --version', {silent: true}).stdout;
var match = /^grunt-cli v(.+)$/m.exec(currentGruntVersions);
if (!match) {
reportOrFail('Unable to compute the current grunt-cli version. We found:\n' +
currentGruntVersions);
} else {
if (!semver.satisfies(match[1], expectedGruntVersion)) {
reportOrFail('Invalid grunt-cli version (' + match[1] + '). ' +
'Please use a version that satisfies ' + expectedGruntVersion);
}
}
// Ensure Node.js dependencies have been installed
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);
}
}
module.exports = function(grunt) {
// this loads all the node_modules that start with `grunt-` as plugins
//grunt plugins
require('load-grunt-tasks')(grunt);
// load additional grunt tasks
grunt.loadTasks('lib/grunt');
grunt.loadNpmTasks('angular-benchpress');
// compute version related info for this build
var NG_VERSION = versionInfo.currentVersion;
NG_VERSION.cdn = versionInfo.cdnVersion;
var dist = 'angular-' + NG_VERSION.full;
var dist = 'angular-'+ NG_VERSION.full;
//global beforeEach
util.init();
if (versionInfo.cdnVersion == null) {
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?\n' +
'Perhaps you want to set the NG1_BUILD_NO_REMOTE_VERSION_REQUESTS environment variable?');
}
//config
grunt.initConfig({
@@ -86,15 +38,15 @@ module.exports = function(grunt) {
hostname: '0.0.0.0',
base: '.',
keepalive: true,
middleware: function(connect, options) {
middleware: function(connect, options){
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
return [
util.conditionalCsp(),
util.rewrite(),
e2e.middleware(),
serveFavicon('images/favicon.ico'),
serveStatic(base),
serveIndex(base)
connect.favicon('images/favicon.ico'),
connect.static(base),
connect.directory(base)
];
}
}
@@ -106,7 +58,7 @@ module.exports = function(grunt) {
// to avoid https://github.com/joyent/libuv/issues/826
port: 8000,
hostname: '0.0.0.0',
middleware: function(connect, options) {
middleware: function(connect, options){
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
return [
function(req, resp, next) {
@@ -119,8 +71,8 @@ module.exports = function(grunt) {
},
util.conditionalCsp(),
e2e.middleware(),
serveFavicon('images/favicon.ico'),
serveStatic(base)
connect.favicon('images/favicon.ico'),
connect.static(base)
];
}
}
@@ -131,8 +83,6 @@ module.exports = function(grunt) {
tests: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js',
'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'
},
@@ -141,8 +91,6 @@ module.exports = function(grunt) {
autotest: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js',
'jquery-2.2': 'karma-jquery-2.2.conf.js',
'jquery-2.1': 'karma-jquery-2.1.conf.js',
modules: 'karma-modules.conf.js',
docs: 'karma-docs.conf.js'
},
@@ -160,24 +108,58 @@ module.exports = function(grunt) {
tmp: ['tmp']
},
eslint: {
all: {
src: [
'*.js',
'benchmarks/**/*.js',
'docs/**/*.js',
'lib/**/*.js',
'scripts/**/*.js',
'src/**/*.js',
'test/**/*.js',
'i18n/**/*.js',
'!docs/app/assets/js/angular-bootstrap/**',
'!docs/bower_components/**',
'!docs/config/templates/**',
'!src/angular.bind.js',
'!i18n/closure/**',
'!src/ngParseExt/ucd.js'
]
jshint: {
options: {
jshintrc: true,
},
node: {
files: { src: ['*.js', 'lib/**/*.js'] },
},
tests: {
files: { src: 'test/**/*.js' },
},
ng: {
files: { src: files['angularSrc'] },
},
ngAnimate: {
files: { src: 'src/ngAnimate/**/*.js' },
},
ngCookies: {
files: { src: 'src/ngCookies/**/*.js' },
},
ngLocale: {
files: { src: 'src/ngLocale/**/*.js' },
},
ngMessages: {
files: { src: 'src/ngMessages/**/*.js' },
},
ngMock: {
files: { src: 'src/ngMock/**/*.js' },
},
ngResource: {
files: { src: 'src/ngResource/**/*.js' },
},
ngRoute: {
files: { src: 'src/ngRoute/**/*.js' },
},
ngSanitize: {
files: { src: 'src/ngSanitize/**/*.js' },
},
ngScenario: {
files: { src: 'src/ngScenario/**/*.js' },
},
ngTouch: {
files: { src: 'src/ngTouch/**/*.js' },
},
ngAria: {
files: {src: 'src/ngAria/**/*.js'},
}
},
jscs: {
src: ['src/**/*.js', 'test/**/*.js'],
options: {
config: ".jscs.json"
}
},
@@ -222,10 +204,6 @@ module.exports = function(grunt) {
dest: 'build/angular-resource.js',
src: util.wrap(files['angularModules']['ngResource'], 'module')
},
messageformat: {
dest: 'build/angular-message-format.js',
src: util.wrap(files['angularModules']['ngMessageFormat'], 'module')
},
messages: {
dest: 'build/angular-messages.js',
src: util.wrap(files['angularModules']['ngMessages'], 'module')
@@ -246,13 +224,9 @@ module.exports = function(grunt) {
dest: 'build/angular-aria.js',
src: util.wrap(files['angularModules']['ngAria'], 'module')
},
parseext: {
dest: 'build/angular-parse-ext.js',
src: util.wrap(files['angularModules']['ngParseExt'], 'module')
},
'promises-aplus-adapter': {
"promises-aplus-adapter": {
dest:'tmp/promises-aplus-adapter++.js',
src:['src/ng/q.js', 'lib/promises-aplus/promises-aplus-test-adapter.js']
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
}
},
@@ -262,44 +236,26 @@ module.exports = function(grunt) {
animate: 'build/angular-animate.js',
cookies: 'build/angular-cookies.js',
loader: 'build/angular-loader.js',
messageformat: 'build/angular-message-format.js',
messages: 'build/angular-messages.js',
touch: 'build/angular-touch.js',
resource: 'build/angular-resource.js',
route: 'build/angular-route.js',
sanitize: 'build/angular-sanitize.js',
aria: 'build/angular-aria.js',
parseext: 'build/angular-parse-ext.js'
aria: 'build/angular-aria.js'
},
'ddescribe-iit': {
"ddescribe-iit": {
files: [
'src/**/*.js',
'test/**/*.js',
'!test/ngScenario/DescribeSpec.js',
'!src/ng/directive/attrs.js', // legitimate xit here
'!src/ngScenario/**/*.js',
'!test/helpers/privateMocks*.js'
],
options: {
disallowed: [
'fit',
'iit',
'xit',
'fthey',
'tthey',
'xthey',
'fdescribe',
'ddescribe',
'xdescribe',
'it.only',
'describe.only'
]
}
'!src/ngScenario/**/*.js'
]
},
'merge-conflict': {
"merge-conflict": {
files: [
'src/**/*',
'test/**/*',
@@ -319,7 +275,7 @@ module.exports = function(grunt) {
compress: {
build: {
options: {archive: 'build/' + dist + '.zip', mode: 'zip'},
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
src: ['**'],
cwd: 'build',
expand: true,
@@ -329,16 +285,13 @@ module.exports = function(grunt) {
},
shell: {
'install-node-dependencies': {
command: 'yarn'
},
'promises-aplus-tests': {
"promises-aplus-tests": {
options: {
stdout: false,
stderr: true,
failOnError: true
},
command: path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js --timeout 2000')
command: path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
}
},
@@ -358,35 +311,23 @@ module.exports = function(grunt) {
}
});
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['eslint', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery (latest) unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:jquery-2.2', 'Run the jQuery 2.2 unit tests with Karma', ['tests:jquery-2.2']);
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']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['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', ['test:jqlite', 'test:jquery', 'test:jquery-2.2', 'test:jquery-2.1', 'test:modules']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', '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',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
grunt.registerTask('minify', ['bower','clean', 'build', 'minall']);
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['bower', 'validate-angular-files', 'clean', 'buildall', 'minall', 'collect-errors', 'write', 'docs', 'copy', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'eslint']);
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'jscs']);
grunt.registerTask('default', ['package']);
};
function reportOrFail(message) {
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
throw new Error(message);
} else {
console.log('===============================================================================');
console.log(message);
console.log('===============================================================================');
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2017 Google, Inc. http://angularjs.org
Copyright (c) 2010-2014 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
+2 -2
View File
@@ -1,8 +1,8 @@
Using AngularJS with the Closure Compiler
=========================================
The Closure Compiler project contains definitions for the AngularJS JavaScript
in its `contrib/externs` directory.
The Closure Compiler project contains externs definitions for AngularJS
JavaScript in its `contrib/externs` directory.
The definitions contain externs for use with the Closure compiler (aka
JSCompiler). Passing these files to the --externs parameter of a compiler
+13 -75
View File
@@ -2,33 +2,31 @@ AngularJS [![Build Status](https://travis-ci.org/angular/angular.js.svg?branch=m
=========
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
use good old HTML (or HAML, Jade/Pug and friends!) as your template language and lets you extend HTMLs
use good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTMLs
syntax to express your applications components clearly and succinctly. It automatically
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
binding. To help you structure your application better and make it easy to test, AngularJS teaches
the browser how to do dependency injection and inversion of control.
It also helps with server-side communication, taming async callbacks with promises and deferreds,
and it makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
piece of cake. Best of all? It makes development fun!
Oh yeah and it helps with server-side communication, taming async callbacks with promises and
deferreds. It also makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
piece of cake. The best of all: it makes development fun!
* Web site: https://angularjs.org
* Tutorial: https://docs.angularjs.org/tutorial
* API Docs: https://docs.angularjs.org/api
* Developer Guide: https://docs.angularjs.org/guide
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: [CONTRIBUTING.md](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
* Dashboard: https://dashboard.angularjs.org
##### Looking for Angular 2? Go here: https://github.com/angular/angular
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
---------
[Once you have set up your environment](https://docs.angularjs.org/misc/contribute), just run:
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
grunt package
Running tests
Running Tests
-------------
To execute all unit tests, use:
@@ -39,69 +37,9 @@ To execute end-to-end (e2e) tests, use:
grunt package
grunt test:e2e
To learn more about the grunt tasks, run `grunt --help`
Contribute & Develop
--------------------
We've set up a separate document for our [contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
To learn more about the grunt tasks, run `grunt --help` and also read our
[contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
What to use AngularJS for and when to use it
---------
AngularJS is the next generation framework where each component is designed to work with every other
component in an interconnected way like a well-oiled machine. AngularJS is JavaScript MVC made easy
and done right. (Well it is not really MVC, read on, to understand what this means.)
#### MVC, no, MV* done the right way!
MVC, short for Model-View-Controller, is a design pattern, i.e. how the code should be organized and
how the different parts of an application separated for proper readability and debugging. Model is
the data and the database. View is the user interface and what the user sees. Controller is the main
link between Model and View. These are the three pillars of major programming frameworks present on
the market today. On the other hand AngularJS works on MV*, short for Model-View-_Whatever_. The
_Whatever_ is AngularJS's way of telling that you may create any kind of linking between the Model
and the View here.
Unlike other frameworks in any programming language, where MVC, the three separate components, each
one has to be written and then connected by the programmer, AngularJS helps the programmer by asking
him/her to just create these and everything else will be taken care of by AngularJS.
#### Interconnection with HTML at the root level
AngularJS uses HTML to define the user's interface. AngularJS also enables the programmer to write
new HTML tags (AngularJS Directives) and increase the readability and understandability of the HTML
code. Directives are AngularJSs way of bringing additional functionality to HTML. Directives
achieve this by enabling us to invent our own HTML elements. This also helps in making the code DRY
(Don't Repeat Yourself), which means once created, a new directive can be used anywhere within the
application.
HTML is also used to determine the wiring of the app. Special attributes in the HTML determine where
to load the app, which components or controllers to use for each element, etc. We specify "what"
gets loaded, but not "how". This declarative approach greatly simplifies app development in a sort
of WYSIWYG way. Rather than spending time on how the program flows and orchestrating the various
moving parts, we simply define what we want and Angular will take care of the dependencies.
#### Data Handling made simple
Data and Data Models in AngularJS are plain JavaScript objects and one can add and change properties
directly on it and loop over objects and arrays at will.
#### Two-way Data Binding
One of AngularJS's strongest features. Two-way Data Binding means that if something changes in the
Model, the change gets reflected in the View instantaneously, and the same happens the other way
around. This is also referred to as Reactive Programming, i.e. suppose `a = b + c` is being
programmed and after this, if the value of `b` and/or `c` is changed then the value of `a` will be
automatically updated to reflect the change. AngularJS uses its "scopes" as a glue between the Model
and View and makes these updates in one available for the other.
#### Less Written Code and Easily Maintainable Code
Everything in AngularJS is created to enable the programmer to end up writing less code that is
easily maintainable and readable by any other new person on the team. Believe it or not, one can
write a complete working two-way data binded application in less than 10 lines of code. Try and see
for yourself!
#### Testing Ready
AngularJS has Dependency Injection, i.e. it takes care of providing all the necessary dependencies
to its controllers and services whenever required. This helps in making the AngularJS code ready for
unit testing by making use of mock dependencies created and injected. This makes AngularJS more
modular and easily testable thus in turn helping a team create more robust applications.
+3 -7
View File
@@ -20,7 +20,7 @@ The following is done automatically so you don't have to worry about it:
This process based on the idea of minimizing user pain
[from this blog post](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html).
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?q=is%3Aopen+sort%3Acreated-desc+no%3Amilestone)
1. Open the list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
* Sort by submit date, with the newest issues first
* You don't have to do issues in order; feel free to pick and choose issues as you please.
* You can triage older issues as well
@@ -55,11 +55,7 @@ This process based on the idea of minimizing user pain
* inconvenience - causes ugly/boilerplate code in apps
1. Label `component: *`
* In rare cases, it's ok to have multiple components.
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. In addition to applying this label, you must:
* Leave a comment explaining the problem and solution so someone can easily finish it.
* Assign the issue to yourself.
* Give feedback on PRs addressing this issue.
* You are responsible for mentoring contributors helping with this issue.
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. Apply to issues where the problem and solution are well defined in the comments, and it's not too complex.
1. Label `origin: google` for issues from Google
1. Assign a milestone:
* Backlog - triaged fixes and features, should be the default choice
@@ -95,7 +91,7 @@ You can mention him in the relevant thread like this: `@btford`.
> Thanks for submitting this issue!
> Unfortunately, we don't think this functionality belongs in core.
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or to the npm repository.
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or npm.
## Assigning Work
Vendored Regular → Executable
+17 -67
View File
@@ -5,7 +5,6 @@ var angularFiles = {
'src/minErr.js',
'src/Angular.js',
'src/loader.js',
'src/shallowCopy.js',
'src/stringify.js',
'src/AngularPublic.js',
'src/jqLite.js',
@@ -15,20 +14,17 @@ var angularFiles = {
'src/ng/anchorScroll.js',
'src/ng/animate.js',
'src/ng/animateRunner.js',
'src/ng/animateCss.js',
'src/ng/asyncCallback.js',
'src/ng/browser.js',
'src/ng/cacheFactory.js',
'src/ng/compile.js',
'src/ng/controller.js',
'src/ng/document.js',
'src/ng/exceptionHandler.js',
'src/ng/forceReflow.js',
'src/ng/http.js',
'src/ng/httpBackend.js',
'src/ng/interpolate.js',
'src/ng/interval.js',
'src/ng/jsonpCallbacks.js',
'src/ng/locale.js',
'src/ng/location.js',
'src/ng/log.js',
@@ -36,7 +32,6 @@ var angularFiles = {
'src/ng/q.js',
'src/ng/raf.js',
'src/ng/rootScope.js',
'src/ng/rootElement.js',
'src/ng/sanitizeUri.js',
'src/ng/sce.js',
'src/ng/sniffer.js',
@@ -45,7 +40,6 @@ var angularFiles = {
'src/ng/timeout.js',
'src/ng/urlUtils.js',
'src/ng/window.js',
'src/ng/cookieReader.js',
'src/ng/filter.js',
'src/ng/filter/filter.js',
@@ -70,9 +64,7 @@ var angularFiles = {
'src/ng/directive/ngInit.js',
'src/ng/directive/ngList.js',
'src/ng/directive/ngModel.js',
'src/ng/directive/ngModelOptions.js',
'src/ng/directive/ngNonBindable.js',
'src/ng/directive/ngOptions.js',
'src/ng/directive/ngPluralize.js',
'src/ng/directive/ngRepeat.js',
'src/ng/directive/ngShowHide.js',
@@ -81,56 +73,30 @@ var angularFiles = {
'src/ng/directive/ngTransclude.js',
'src/ng/directive/script.js',
'src/ng/directive/select.js',
'src/ng/directive/validators.js',
'src/angular.bind.js',
'src/publishExternalApis.js',
'src/ngLocale/angular-locale_en-us.js'
'src/ng/directive/style.js',
'src/ng/directive/validators.js'
],
'angularLoader': [
'src/stringify.js',
'stringify.js',
'src/minErr.js',
'src/loader.js'
],
'angularModules': {
'ngAnimate': [
'src/ngAnimate/shared.js',
'src/ngAnimate/rafScheduler.js',
'src/ngAnimate/animateChildrenDirective.js',
'src/ngAnimate/animateCss.js',
'src/ngAnimate/animateCssDriver.js',
'src/ngAnimate/animateJs.js',
'src/ngAnimate/animateJsDriver.js',
'src/ngAnimate/animateQueue.js',
'src/ngAnimate/animation.js',
'src/ngAnimate/ngAnimateSwap.js',
'src/ngAnimate/module.js'
'src/ngAnimate/animate.js'
],
'ngCookies': [
'src/ngCookies/cookies.js',
'src/ngCookies/cookieStore.js',
'src/ngCookies/cookieWriter.js'
],
'ngMessageFormat': [
'src/ngMessageFormat/messageFormatCommon.js',
'src/ngMessageFormat/messageFormatSelector.js',
'src/ngMessageFormat/messageFormatInterpolationParts.js',
'src/ngMessageFormat/messageFormatParser.js',
'src/ngMessageFormat/messageFormatService.js'
'src/ngCookies/cookies.js'
],
'ngMessages': [
'src/ngMessages/messages.js'
],
'ngParseExt': [
'src/ngParseExt/ucd.js',
'src/ngParseExt/module.js'
],
'ngResource': [
'src/ngResource/resource.js'
],
'ngRoute': [
'src/shallowCopy.js',
'src/ngRoute/route.js',
'src/ngRoute/routeParams.js',
'src/ngRoute/directive/ngView.js'
@@ -140,8 +106,7 @@ var angularFiles = {
'src/ngSanitize/filter/linky.js'
],
'ngMock': [
'src/ngMock/angular-mocks.js',
'src/ngMock/browserTrigger.js'
'src/ngMock/angular-mocks.js'
],
'ngTouch': [
'src/ngTouch/touch.js',
@@ -156,6 +121,7 @@ var angularFiles = {
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/browserTrigger.js',
'src/ngScenario/Application.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Future.js',
@@ -178,7 +144,6 @@ var angularFiles = {
'test/auto/*.js',
'test/ng/**/*.js',
'test/ngAnimate/*.js',
'test/ngMessageFormat/*.js',
'test/ngMessages/*.js',
'test/ngCookies/*.js',
'test/ngResource/*.js',
@@ -193,16 +158,16 @@ var angularFiles = {
'bower_components/jquery/dist/jquery.js',
'test/jquery_remove.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'@angularTest'
'@angularTest',
],
'karmaExclude': [
'test/jquery_alias.js',
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js',
'src/angular.bind.js'
'src/ngScenario/angular-bootstrap.js'
],
'karmaScenario': [
@@ -210,14 +175,11 @@ var angularFiles = {
'build/docs/docs-scenario.js'
],
'karmaModules': [
"karmaModules": [
'build/angular.js',
'@angularSrcModules',
'test/modules/no_bootstrap.js',
'src/ngScenario/browserTrigger.js',
'test/helpers/*.js',
'test/ngAnimate/*.js',
'test/ngMessageFormat/*.js',
'test/ngMessages/*.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngRoute/**/*.js',
@@ -231,33 +193,21 @@ var angularFiles = {
'bower_components/jquery/dist/jquery.js',
'test/jquery_alias.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'@angularTest'
'@angularTest',
],
'karmaJqueryExclude': [
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js',
'test/jquery_remove.js',
'src/angular.bind.js'
'test/jquery_remove.js'
]
};
['2.1', '2.2'].forEach(function(jQueryVersion) {
angularFiles['karmaJquery' + jQueryVersion] = []
.concat(angularFiles.karmaJquery)
.map(function(path) {
if (path.startsWith('bower_components/jquery')) {
return path.replace(/^bower_components\/jquery/, 'bower_components/jquery-' + jQueryVersion);
}
return path;
});
});
angularFiles['angularSrcModules'] = [].concat(
angularFiles['angularModules']['ngAnimate'],
angularFiles['angularModules']['ngMessageFormat'],
angularFiles['angularModules']['ngMessages'],
angularFiles['angularModules']['ngCookies'],
angularFiles['angularModules']['ngResource'],
@@ -276,7 +226,7 @@ if (exports) {
Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {
angularFiles[filegroup].forEach(function(file) {
// replace @ref
var match = file.match(/^@(.*)/);
var match = file.match(/^\@(.*)/);
if (match) {
files = files.concat(angularFiles[match[1]]);
} else {
-11
View File
@@ -1,11 +0,0 @@
{
"root": true,
"extends": "../.eslintrc-browser.json",
"globals": {
"benchmarkSteps": false,
// Benchmarks are not run in IE 9 so we're fine.
"console": false
}
}
-44
View File
@@ -1,44 +0,0 @@
'use strict';
angular
.module('animationBenchmark', ['ngAnimate'], config)
.controller('BenchmarkController', BenchmarkController);
// Functions - Definitions
function config($compileProvider) {
$compileProvider
.commentDirectivesEnabled(false)
.cssClassDirectivesEnabled(false)
.debugInfoEnabled(false);
}
function BenchmarkController($scope) {
var self = this;
var itemCount = 1000;
var items = (new Array(itemCount + 1)).join('.').split('');
benchmarkSteps.push({
name: 'create',
fn: function() {
$scope.$apply(function() {
self.items = items;
});
}
});
benchmarkSteps.push({
name: '$digest',
fn: function() {
$scope.$root.$digest();
}
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
$scope.$apply(function() {
self.items = [];
});
}
});
}
-22
View File
@@ -1,22 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [
{
id: 'jquery',
src: 'jquery-noop.js'
}, {
id: 'angular',
src: '/build/angular.js'
}, {
id: 'angular-animate',
src: '/build/angular-animate.js'
}, {
src: 'app.js'
}
]
});
};
-1
View File
@@ -1 +0,0 @@
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
-28
View File
@@ -1,28 +0,0 @@
<style>
[ng-cloak] { display: none !important; }
.animation-container .ng-enter,
.animation-container .ng-leave {
transition: all 0.1s;
}
.animation-container .ng-enter,
.animation-container .ng-leave.ng-leave-active {
opacity: 0;
}
.animation-container .ng-enter.ng-enter-active,
.animation-container .ng-leave {
opacity: 1;
}
</style>
<div ng-app="animationBenchmark" ng-cloak ng-controller="BenchmarkController as bm">
<div class="container-fluid">
<h2>Large collection of elements animated in and out with ngAnimate</h2>
<div class="animation-container">
<div ng-repeat="i in bm.items track by $index">
Just a plain ol' element
</div>
</div>
</div>
</div>
-61
View File
@@ -1,61 +0,0 @@
'use strict';
var app = angular.module('boostrapCompileBenchmark', []);
var commentDirectivesEnabled;
var cssClassDirectivesEnabled;
app.config(function($compileProvider) {
$compileProvider.debugInfoEnabled(false);
commentDirectivesEnabled = window.location.toString().indexOf('comment=disabled') === -1;
cssClassDirectivesEnabled = window.location.toString().indexOf('css=disabled') === -1;
$compileProvider
.commentDirectivesEnabled(commentDirectivesEnabled)
.cssClassDirectivesEnabled(cssClassDirectivesEnabled);
})
.controller('DataController', function DataController($compile, $http, $rootScope) {
this.isEA = !commentDirectivesEnabled && !cssClassDirectivesEnabled;
this.isEAC = !commentDirectivesEnabled && cssClassDirectivesEnabled;
this.isEAM = commentDirectivesEnabled && !cssClassDirectivesEnabled;
this.isEACM = commentDirectivesEnabled && cssClassDirectivesEnabled;
this.repeats = 50;
this.templates = [
'bootstrap-carousel.tpl.html',
'bootstrap-theme.tpl.html'
];
this.html = null;
this.loadTemplate = function() {
this.html = null;
$http.get(window.location.pathname + this.selectedTemplate)
.then(function(response) { this.html = response.data; }.bind(this));
};
this.selectedTemplate = this.templates[0];
this.loadTemplate();
var linkers = [];
benchmarkSteps.push({
name: 'create',
fn: function() {
for (var i = 0; i < this.repeats; i++) {
var linker = $compile(this.html);
linkers.push(linker);
}
}.bind(this)
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
linkers.length = 0;
}
});
});
@@ -1,172 +0,0 @@
<!-- code from http://getbootstrap.com/examples/carousel -->
<div class="navbar-wrapper">
<div class="container">
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
</div>
<!-- Carousel
================================================== -->
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img class="first-slide" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="First slide">
<div class="container">
<div class="carousel-caption">
<h1>Example headline.</h1>
<p>Note: If you're viewing this page via a <code>file://</code> URL, the "next" and "previous" Glyphicon buttons on the left and right might not load/display properly due to web browser security rules.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Sign up today</a></p>
</div>
</div>
</div>
<div class="item">
<img class="second-slide" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="Second slide">
<div class="container">
<div class="carousel-caption">
<h1>Another example headline.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Learn more</a></p>
</div>
</div>
</div>
<div class="item">
<img class="third-slide" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="Third slide">
<div class="container">
<div class="carousel-caption">
<h1>One more for good measure.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Browse gallery</a></p>
</div>
</div>
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div><!-- /.carousel -->
<!-- Marketing messaging and featurettes
================================================== -->
<!-- Wrap the rest of the page in another container to center all the content. -->
<div class="container marketing">
<!-- Three columns of text below the carousel -->
<div class="row">
<div class="col-lg-4">
<img class="img-circle" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="Generic placeholder image" width="140" height="140">
<h2>Heading</h2>
<p>Donec sed odio dui. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh ultricies vehicula ut id elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna.</p>
<p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
</div><!-- /.col-lg-4 -->
<div class="col-lg-4">
<img class="img-circle" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="Generic placeholder image" width="140" height="140">
<h2>Heading</h2>
<p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.</p>
<p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
</div><!-- /.col-lg-4 -->
<div class="col-lg-4">
<img class="img-circle" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" alt="Generic placeholder image" width="140" height="140">
<h2>Heading</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
<p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
</div><!-- /.col-lg-4 -->
</div><!-- /.row -->
<!-- START THE FEATURETTES -->
<hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7">
<h2 class="featurette-heading">First featurette heading. <span class="text-muted">It'll blow your mind.</span></h2>
<p class="lead">Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.</p>
</div>
<div class="col-md-5">
<img class="featurette-image img-responsive center-block" data-src="holder.js/500x500/auto" alt="Generic placeholder image">
</div>
</div>
<hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7 col-md-push-5">
<h2 class="featurette-heading">Oh yeah, it's that good. <span class="text-muted">See for yourself.</span></h2>
<p class="lead">Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.</p>
</div>
<div class="col-md-5 col-md-pull-7">
<img class="featurette-image img-responsive center-block" data-src="holder.js/500x500/auto" alt="Generic placeholder image">
</div>
</div>
<hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7">
<h2 class="featurette-heading">And lastly, this one. <span class="text-muted">Checkmate.</span></h2>
<p class="lead">Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.</p>
</div>
<div class="col-md-5">
<img class="featurette-image img-responsive center-block" data-src="holder.js/500x500/auto" alt="Generic placeholder image">
</div>
</div>
<hr class="featurette-divider">
<!-- /END THE FEATURETTES -->
<!-- FOOTER -->
<footer>
<p class="pull-right"><a href="#">Back to top</a></p>
<p>&copy; 2016 Company, Inc. &middot; <a href="#">Privacy</a> &middot; <a href="#">Terms</a></p>
</footer>
</div><!-- /.container -->
@@ -1,595 +0,0 @@
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Bootstrap theme</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container theme-showcase" role="main">
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<h1>Theme example</h1>
<p>This is a template showcasing the optional theme stylesheet included in Bootstrap. Use it as a starting point to create something more unique by building on or modifying it.</p>
</div>
<div class="page-header">
<h1>Buttons</h1>
</div>
<p>
<button type="button" class="btn btn-lg btn-default">Default</button>
<button type="button" class="btn btn-lg btn-primary">Primary</button>
<button type="button" class="btn btn-lg btn-success">Success</button>
<button type="button" class="btn btn-lg btn-info">Info</button>
<button type="button" class="btn btn-lg btn-warning">Warning</button>
<button type="button" class="btn btn-lg btn-danger">Danger</button>
<button type="button" class="btn btn-lg btn-link">Link</button>
</p>
<p>
<button type="button" class="btn btn-default">Default</button>
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-link">Link</button>
</p>
<p>
<button type="button" class="btn btn-sm btn-default">Default</button>
<button type="button" class="btn btn-sm btn-primary">Primary</button>
<button type="button" class="btn btn-sm btn-success">Success</button>
<button type="button" class="btn btn-sm btn-info">Info</button>
<button type="button" class="btn btn-sm btn-warning">Warning</button>
<button type="button" class="btn btn-sm btn-danger">Danger</button>
<button type="button" class="btn btn-sm btn-link">Link</button>
</p>
<p>
<button type="button" class="btn btn-xs btn-default">Default</button>
<button type="button" class="btn btn-xs btn-primary">Primary</button>
<button type="button" class="btn btn-xs btn-success">Success</button>
<button type="button" class="btn btn-xs btn-info">Info</button>
<button type="button" class="btn btn-xs btn-warning">Warning</button>
<button type="button" class="btn btn-xs btn-danger">Danger</button>
<button type="button" class="btn btn-xs btn-link">Link</button>
</p>
<div class="page-header">
<h1>Tables</h1>
</div>
<div class="row">
<div class="col-md-6">
<table class="table">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<td>3</td>
<td>Larry</td>
<td>the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<td>3</td>
<td>Larry</td>
<td>the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<td>Mark</td>
<td>Otto</td>
<td>@TwBootstrap</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<td>3</td>
<td colspan="2">Larry the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<table class="table table-condensed">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<td>3</td>
<td colspan="2">Larry the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="page-header">
<h1>Thumbnails</h1>
</div>
<img data-src="holder.js/200x200" class="img-thumbnail" alt="200x200" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjwhLS0KU291cmNlIFVSTDogaG9sZGVyLmpzLzIwMHgyMDAKQ3JlYXRlZCB3aXRoIEhvbGRlci5qcyAyLjYuMC4KTGVhcm4gbW9yZSBhdCBodHRwOi8vaG9sZGVyanMuY29tCihjKSAyMDEyLTIwMTUgSXZhbiBNYWxvcGluc2t5IC0gaHR0cDovL2ltc2t5LmNvCi0tPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PCFbQ0RBVEFbI2hvbGRlcl8xNTYyY2ExYjA3YiB0ZXh0IHsgZmlsbDojQUFBQUFBO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1mYW1pbHk6QXJpYWwsIEhlbHZldGljYSwgT3BlbiBTYW5zLCBzYW5zLXNlcmlmLCBtb25vc3BhY2U7Zm9udC1zaXplOjEwcHQgfSBdXT48L3N0eWxlPjwvZGVmcz48ZyBpZD0iaG9sZGVyXzE1NjJjYTFiMDdiIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgZmlsbD0iI0VFRUVFRSIvPjxnPjx0ZXh0IHg9Ijc0LjY5NTMxMjUiIHk9IjEwNC41Ij4yMDB4MjAwPC90ZXh0PjwvZz48L2c+PC9zdmc+" data-holder-rendered="true" style="width: 200px; height: 200px;">
<div class="page-header">
<h1>Labels</h1>
</div>
<h1>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h1>
<h2>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h2>
<h3>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h3>
<h4>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h4>
<h5>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h5>
<h6>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</h6>
<p>
<span class="label label-default">Default</span>
<span class="label label-primary">Primary</span>
<span class="label label-success">Success</span>
<span class="label label-info">Info</span>
<span class="label label-warning">Warning</span>
<span class="label label-danger">Danger</span>
</p>
<div class="page-header">
<h1>Badges</h1>
</div>
<p>
<a href="#">Inbox <span class="badge">42</span></a>
</p>
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#">Home <span class="badge">42</span></a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages <span class="badge">3</span></a></li>
</ul>
<div class="page-header">
<h1>Dropdown menus</h1>
</div>
<div class="dropdown theme-dropdown clearfix">
<a id="dropdownMenu1" href="#" class="sr-only dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li class="active"><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>
<div class="page-header">
<h1>Navs</h1>
</div>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages</a></li>
</ul>
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages</a></li>
</ul>
<div class="page-header">
<h1>Navbars</h1>
</div>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="page-header">
<h1>Alerts</h1>
</div>
<div class="alert alert-success" role="alert">
<strong>Well done!</strong> You successfully read this important alert message.
</div>
<div class="alert alert-info" role="alert">
<strong>Heads up!</strong> This alert needs your attention, but it's not super important.
</div>
<div class="alert alert-warning" role="alert">
<strong>Warning!</strong> Best check yo self, you're not looking too good.
</div>
<div class="alert alert-danger" role="alert">
<strong>Oh snap!</strong> Change a few things up and try submitting again.
</div>
<div class="page-header">
<h1>Progress bars</h1>
</div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"><span class="sr-only">60% Complete</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%"><span class="sr-only">40% Complete (success)</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%"><span class="sr-only">20% Complete</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%"><span class="sr-only">60% Complete (warning)</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%"><span class="sr-only">80% Complete (danger)</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%"><span class="sr-only">60% Complete</span></div>
</div>
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 35%"><span class="sr-only">35% Complete (success)</span></div>
<div class="progress-bar progress-bar-warning" style="width: 20%"><span class="sr-only">20% Complete (warning)</span></div>
<div class="progress-bar progress-bar-danger" style="width: 10%"><span class="sr-only">10% Complete (danger)</span></div>
</div>
<div class="page-header">
<h1>List groups</h1>
</div>
<div class="row">
<div class="col-sm-4">
<ul class="list-group">
<li class="list-group-item">Cras justo odio</li>
<li class="list-group-item">Dapibus ac facilisis in</li>
<li class="list-group-item">Morbi leo risus</li>
<li class="list-group-item">Porta ac consectetur ac</li>
<li class="list-group-item">Vestibulum at eros</li>
</ul>
</div><!-- /.col-sm-4 -->
<div class="col-sm-4">
<div class="list-group">
<a href="#" class="list-group-item active">
Cras justo odio
</a>
<a href="#" class="list-group-item">Dapibus ac facilisis in</a>
<a href="#" class="list-group-item">Morbi leo risus</a>
<a href="#" class="list-group-item">Porta ac consectetur ac</a>
<a href="#" class="list-group-item">Vestibulum at eros</a>
</div>
</div><!-- /.col-sm-4 -->
<div class="col-sm-4">
<div class="list-group">
<a href="#" class="list-group-item active">
<h4 class="list-group-item-heading">List group item heading</h4>
<p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
</a>
<a href="#" class="list-group-item">
<h4 class="list-group-item-heading">List group item heading</h4>
<p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
</a>
<a href="#" class="list-group-item">
<h4 class="list-group-item-heading">List group item heading</h4>
<p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
</a>
</div>
</div><!-- /.col-sm-4 -->
</div>
<div class="page-header">
<h1>Panels</h1>
</div>
<div class="row">
<div class="col-sm-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
</div><!-- /.col-sm-4 -->
<div class="col-sm-4">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
</div><!-- /.col-sm-4 -->
<div class="col-sm-4">
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
</div><!-- /.col-sm-4 -->
</div>
<div class="page-header">
<h1>Wells</h1>
</div>
<div class="well">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed diam eget risus varius blandit sit amet non magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Aenean lacinia bibendum nulla sed consectetur.</p>
</div>
<div class="page-header">
<h1>Carousel</h1>
</div>
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0" class=""></li>
<li data-target="#carousel-example-generic" data-slide-to="1" class=""></li>
<li data-target="#carousel-example-generic" data-slide-to="2" class="active"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item">
<img data-src="holder.js/1140x500/auto/#777:#555/text:First slide" alt="First slide [1140x500]" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTE0MCIgaGVpZ2h0PSI1MDAiIHZpZXdCb3g9IjAgMCAxMTQwIDUwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PCEtLQpTb3VyY2UgVVJMOiBob2xkZXIuanMvMTE0MHg1MDAvYXV0by8jNzc3OiM1NTUvdGV4dDpGaXJzdCBzbGlkZQpDcmVhdGVkIHdpdGggSG9sZGVyLmpzIDIuNi4wLgpMZWFybiBtb3JlIGF0IGh0dHA6Ly9ob2xkZXJqcy5jb20KKGMpIDIwMTItMjAxNSBJdmFuIE1hbG9waW5za3kgLSBodHRwOi8vaW1za3kuY28KLS0+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj48IVtDREFUQVsjaG9sZGVyXzE1NjJjYTIxYzRkIHRleHQgeyBmaWxsOiM1NTU7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LWZhbWlseTpBcmlhbCwgSGVsdmV0aWNhLCBPcGVuIFNhbnMsIHNhbnMtc2VyaWYsIG1vbm9zcGFjZTtmb250LXNpemU6NTdwdCB9IF1dPjwvc3R5bGU+PC9kZWZzPjxnIGlkPSJob2xkZXJfMTU2MmNhMjFjNGQiPjxyZWN0IHdpZHRoPSIxMTQwIiBoZWlnaHQ9IjUwMCIgZmlsbD0iIzc3NyIvPjxnPjx0ZXh0IHg9IjM5MC41MDc4MTI1IiB5PSIyNzUuNSI+Rmlyc3Qgc2xpZGU8L3RleHQ+PC9nPjwvZz48L3N2Zz4=" data-holder-rendered="true">
</div>
<div class="item active left">
<img data-src="holder.js/1140x500/auto/#666:#444/text:Second slide" alt="Second slide [1140x500]" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTE0MCIgaGVpZ2h0PSI1MDAiIHZpZXdCb3g9IjAgMCAxMTQwIDUwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PCEtLQpTb3VyY2UgVVJMOiBob2xkZXIuanMvMTE0MHg1MDAvYXV0by8jNjY2OiM0NDQvdGV4dDpTZWNvbmQgc2xpZGUKQ3JlYXRlZCB3aXRoIEhvbGRlci5qcyAyLjYuMC4KTGVhcm4gbW9yZSBhdCBodHRwOi8vaG9sZGVyanMuY29tCihjKSAyMDEyLTIwMTUgSXZhbiBNYWxvcGluc2t5IC0gaHR0cDovL2ltc2t5LmNvCi0tPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PCFbQ0RBVEFbI2hvbGRlcl8xNTYyY2ExZTY3NCB0ZXh0IHsgZmlsbDojNDQ0O2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1mYW1pbHk6QXJpYWwsIEhlbHZldGljYSwgT3BlbiBTYW5zLCBzYW5zLXNlcmlmLCBtb25vc3BhY2U7Zm9udC1zaXplOjU3cHQgfSBdXT48L3N0eWxlPjwvZGVmcz48ZyBpZD0iaG9sZGVyXzE1NjJjYTFlNjc0Ij48cmVjdCB3aWR0aD0iMTE0MCIgaGVpZ2h0PSI1MDAiIGZpbGw9IiM2NjYiLz48Zz48dGV4dCB4PSIzMzUuNjAxNTYyNSIgeT0iMjc1LjUiPlNlY29uZCBzbGlkZTwvdGV4dD48L2c+PC9nPjwvc3ZnPg==" data-holder-rendered="true">
</div>
<div class="item next left">
<img data-src="holder.js/1140x500/auto/#555:#333/text:Third slide" alt="Third slide [1140x500]" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTE0MCIgaGVpZ2h0PSI1MDAiIHZpZXdCb3g9IjAgMCAxMTQwIDUwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PCEtLQpTb3VyY2UgVVJMOiBob2xkZXIuanMvMTE0MHg1MDAvYXV0by8jNTU1OiMzMzMvdGV4dDpUaGlyZCBzbGlkZQpDcmVhdGVkIHdpdGggSG9sZGVyLmpzIDIuNi4wLgpMZWFybiBtb3JlIGF0IGh0dHA6Ly9ob2xkZXJqcy5jb20KKGMpIDIwMTItMjAxNSBJdmFuIE1hbG9waW5za3kgLSBodHRwOi8vaW1za3kuY28KLS0+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj48IVtDREFUQVsjaG9sZGVyXzE1NjJjYTFiNTg5IHRleHQgeyBmaWxsOiMzMzM7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LWZhbWlseTpBcmlhbCwgSGVsdmV0aWNhLCBPcGVuIFNhbnMsIHNhbnMtc2VyaWYsIG1vbm9zcGFjZTtmb250LXNpemU6NTdwdCB9IF1dPjwvc3R5bGU+PC9kZWZzPjxnIGlkPSJob2xkZXJfMTU2MmNhMWI1ODkiPjxyZWN0IHdpZHRoPSIxMTQwIiBoZWlnaHQ9IjUwMCIgZmlsbD0iIzU1NSIvPjxnPjx0ZXh0IHg9IjM3Ny44NjcxODc1IiB5PSIyNzUuNSI+VGhpcmQgc2xpZGU8L3RleHQ+PC9nPjwvZz48L3N2Zz4=" data-holder-rendered="true">
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div> <!-- /container -->
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-40
View File
@@ -1,40 +0,0 @@
<div ng-app="boostrapCompileBenchmark" ng-cloak>
<div ng-controller="DataController as config">
<p>Please, select which configuration you want to use:</p>
<ul>
<li>
<a href="?comment=disabled&css=disabled">Only EA</a>
<span ng-show="config.isEA">(active)</span>
</li>
<li>
<a href="?comment=disabled">Active EA and classes directives</a>
<span ng-show="config.isEAC">(active)</span>
</li>
<li>
<a href="?css=disabled">Active EA and comment directives</a>
<span ng-show="config.isEAM">(active)</span>
</li>
<li>
<a href="?">Active all directives</a>
<span ng-show="config.isEACM">(active)</span>
</li>
</ul>
<hr>
<p>How many repetitions do you want to do?</p>
<input type="number" ng-model="config.repeats">
<hr>
<p>Template to $compile:</p>
<select
ng-options="template for template in config.templates"
ng-model="config.selectedTemplate"
ng-change="config.loadTemplate()"></select>
<p>The benchmark is
<span ng-show="config.html">Ready!</span>
<span ng-hide="config.html">LOADING!</span>
</p>
</div>
</div>
+7 -8
View File
@@ -1,5 +1,3 @@
'use strict';
var app = angular.module('eventDelegationBenchmark', []);
app.directive('noopDir', function() {
@@ -7,7 +5,7 @@ app.directive('noopDir', function() {
compile: function($element, $attrs) {
return function($scope, $element) {
return 1;
};
}
}
};
});
@@ -15,12 +13,12 @@ app.directive('noopDir', function() {
app.directive('nativeClick', ['$parse', function($parse) {
return {
compile: function($element, $attrs) {
$parse($attrs.tstEvent);
var expr = $parse($attrs.tstEvent);
return function($scope, $element) {
$element[0].addEventListener('click', function() {
console.log('clicked');
}, false);
};
}
}
};
}]);
@@ -28,12 +26,13 @@ app.directive('nativeClick', ['$parse', function($parse) {
app.directive('dlgtClick', function() {
return {
compile: function($element, $attrs) {
var evt = $attrs.dlgtClick;
// We don't setup the global event listeners as the costs are small and one time only...
}
};
});
app.controller('DataController', function DataController($rootScope) {
app.controller('DataController', function($rootScope) {
this.ngRepeatCount = 1000;
this.rows = [];
var self = this;
@@ -48,8 +47,8 @@ app.controller('DataController', function DataController($rootScope) {
self.rows = oldRows;
if (self.rows.length !== self.ngRepeatCount) {
self.rows = [];
for (var i = 0; i < self.ngRepeatCount; i++) {
self.rows.push('row' + i);
for (var i=0; i<self.ngRepeatCount; i++) {
self.rows.push('row'+i);
}
}
$rootScope.$apply();
+2 -6
View File
@@ -1,14 +1,10 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
}, {
src: 'app.js'
},{
src: 'app.js',
}]
});
};
+9 -13
View File
@@ -1,5 +1,3 @@
'use strict';
var app = angular.module('largetableBenchmark', []);
app.config(function($compileProvider) {
@@ -14,23 +12,21 @@ app.filter('noop', function() {
};
});
app.controller('DataController', function DataController($scope, $rootScope) {
app.controller('DataController', function($scope, $rootScope) {
var totalRows = 1000;
var totalColumns = 20;
var data = $scope.data = [];
$scope.digestDuration = '?';
$scope.numberOfBindings = totalRows * totalColumns * 2 + totalRows + 1;
$scope.numberOfBindings = totalRows*totalColumns*2 + totalRows + 1;
$scope.numberOfWatches = '?';
/** @this */
function iGetter() { return this.i; }
/** @this */
function jGetter() { return this.j; }
for (var i = 0; i < totalRows; i++) {
for (var i=0; i<totalRows; i++) {
data[i] = [];
for (var j = 0; j < totalColumns; j++) {
for (var j=0; j<totalColumns; j++) {
data[i][j] = {
i: i, j: j,
iFn: iGetter,
@@ -68,13 +64,14 @@ app.controller('DataController', function DataController($scope, $rootScope) {
});
});
var fn = function() { return 'x'};
app.directive('baselineBindingTable', function() {
return {
restrict: 'E',
link: function($scope, $element) {
link: function ($scope, $element) {
var i, j, row, cell, comment;
var document = window.document;
var template = document.createElement('span');
template.setAttribute('ng-repeat', 'foo in foos');
template.classList.add('ng-scope');
@@ -107,9 +104,8 @@ app.directive('baselineBindingTable', function() {
app.directive('baselineInterpolationTable', function() {
return {
restrict: 'E',
link: function($scope, $element) {
link: function ($scope, $element) {
var i, j, row, cell, comment;
var document = window.document;
var template = document.createElement('span');
template.setAttribute('ng-repeat', 'foo in foos');
template.classList.add('ng-scope');
@@ -184,4 +180,4 @@ app.directive('baselineTable', function() {
};
});
*/
*/
+1 -5
View File
@@ -1,7 +1,3 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
@@ -13,7 +9,7 @@ module.exports = function(config) {
src: '/build/angular.js'
},
{
src: 'app.js'
src: 'app.js',
}]
});
};
+1 -1
View File
@@ -1 +1 @@
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
//Override me with ?jquery=/bower_components/jquery/dist/jquery.js
+12 -35
View File
@@ -8,20 +8,17 @@
Large table rendered with AngularJS
</p>
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineBinding">baseline binding: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="baselineInterpolation">baseline interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBind">ngBind: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindOnce">ngBindOnce: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolation">interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation">interpolation + bind-once: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationAttr">attribute interpolation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFn">ngBind + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFn">interpolation + fnInvocation: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFilter">ngBind + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFilter">interpolation + filter: </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelConstName">ngModel (const name): </label></div>
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelInterpName">ngModel (interp name): </label></div>
<div>none: <input type="radio" ng-model="benchmarkType" value="none"></div>
<div>baseline binding: <input type="radio" ng-model="benchmarkType" value="baselineBinding"></div>
<div>baseline interpolation: <input type="radio" ng-model="benchmarkType" value="baselineInterpolation"></div>
<div>ngBind: <input type="radio" ng-model="benchmarkType" value="ngBind"></div>
<div>ngBindOnce: <input type="radio" ng-model="benchmarkType" value="ngBindOnce"></div>
<div>interpolation: <input type="radio" ng-model="benchmarkType" value="interpolation"></div>
<div>attribute interpolation: <input type="radio" ng-model="benchmarkType" value="interpolationAttr"></div>
<div>ngBind + fnInvocation: <input type="radio" ng-model="benchmarkType" value="ngBindFn"></div>
<div>interpolation + fnInvocation: <input type="radio" ng-model="benchmarkType" value="interpolationFn"></div>
<div>ngBind + filter: <input type="radio" ng-model="benchmarkType" value="ngBindFilter"></div>
<div>interpolation + filter: <input type="radio" ng-model="benchmarkType" value="interpolationFilter"></div>
<ng-switch on="benchmarkType">
<baseline-binding-table ng-switch-when="baselineBinding">
@@ -38,7 +35,7 @@
</div>
<div ng-switch-when="ngBindOnce">
<h2>baseline binding once</h2>
<div ng-repeat="row in ::data">
<div ng-repeat="row in data">
<span ng-repeat="column in ::row">
<span ng-bind="::column.i"></span>:<span ng-bind="::column.j"></span>|
</span>
@@ -50,12 +47,6 @@
<span ng-repeat="column in row">{{column.i}}:{{column.j}}|</span>
</div>
</div>
<div ng-switch-when="bindOnceInterpolation">
<h2>baseline one-time interpolation</h2>
<div ng-repeat="row in ::data">
<span ng-repeat="column in ::row">{{::column.i}}:{{::column.j}}|</span>
</div>
</div>
<div ng-switch-when="interpolationAttr">
<h2>attribute interpolation</h2>
<div ng-repeat="row in data">
@@ -86,20 +77,6 @@
<span ng-repeat="column in row">{{column.i | noop}}:{{column.j | noop}}|</span>
</div>
</div>
<div ng-switch-when="ngModelConstName">
<h2>ngModel (const name)</h2>
<div ng-repeat="row in data">
<input type="text" ng-model="row.i" name="constName" />
<input type="text" ng-model="row.j" />
</div>
</div>
<div ng-switch-when="ngModelInterpName">
<h2>ngModel (interp name)</h2>
<div ng-repeat="(rowIdx, row) in data">
<input type="text" ng-model="row.i" name="input-{{rowIdx}}" />
<input type="text" ng-model="row.j" name="input2-{{rowIdx}}" />
</div>
</div>
</ng-switch>
</div>
</div>
-108
View File
@@ -1,108 +0,0 @@
'use strict';
var app = angular.module('ngClassBenchmark', []);
app.controller('DataController', function DataController($scope) {
this.init = function() {
this.numberOfTodos = 1000;
this.implementation = 'tableOptimized';
this.completedPeriodicity = 3;
this.importantPeriodicity = 13;
this.urgentPeriodicity = 29;
this.createTodos(100);
this.setTodosValuesWithSeed(0);
};
this.clearTodos = function() {
this.todos = null;
};
this.createTodos = function(count) {
var i;
this.todos = [];
for (i = 0; i < count; i++) {
this.todos.push({
id: i + 1,
completed: false,
important: false,
urgent: false
});
}
};
this.setTodosValuesWithSeed = function(offset) {
var i, todo;
for (i = 0; i < this.todos.length; i++) {
todo = this.todos[i];
todo.completed = 0 === (i + offset) % this.completedPeriodicity;
todo.important = 0 === (i + offset) % this.importantPeriodicity;
todo.urgent = 0 === (i + offset) % this.urgentPeriodicity;
}
};
this.init();
benchmarkSteps.push({
name: 'setup',
fn: function() {
$scope.$apply();
this.clearTodos();
this.createTodos(this.numberOfTodos);
}.bind(this)
});
benchmarkSteps.push({
name: 'create',
fn: function() {
// initialize data for first time that will construct the DOM
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: '$apply',
fn: function() {
$scope.$apply();
}
});
benchmarkSteps.push({
name: 'update',
fn: function() {
// move everything but completed
this.setTodosValuesWithSeed(3);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'unclass',
fn: function() {
// remove all classes
this.setTodosValuesWithSeed(NaN);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'class',
fn: function() {
// add all classes as the initial state
this.setTodosValuesWithSeed(0);
$scope.$apply();
}.bind(this)
});
benchmarkSteps.push({
name: 'destroy',
fn: function() {
this.clearTodos();
$scope.$apply();
}.bind(this)
});
});
-15
View File
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-177
View File
@@ -1,177 +0,0 @@
<style>
.gold {
background: gold;
}
.silver {
background: silver;
}
.table tbody tr > td.success {
background-color: #dff0d8;
}
.table tbody tr > td.error {
background-color: #f2dede;
}
.table tbody tr > td.warning {
background-color: #fcf8e3;
}
.table tbody tr > td.info {
background-color: #d9edf7;
}
.completed {
text-decoration: line-through;
}
.important {
font-weight: bold;
}
.urgent {
color: red;
}
</style>
<div ng-app="ngClassBenchmark" ng-cloak class="container-fluid">
<div ng-controller="DataController as benchmark" class="row">
<div class="col-lg-12">
<div class="well">
<h3>Parameters</h3>
<br>
<p>
<label>Number of todos</label><br>
<input type="number" ng-model="benchmark.numberOfTodos">
</p>
<br>
<p>
<label>Implementation</label><br>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="tableOptimized"
type="radio" name="implementation">
Table optimized <br>
<code>ng-class="todo.completed && 'success'"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="table"
type="radio" name="implementation">
Table <br>
<code>ng-class="{success: todo.completed}"</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="list"
type="radio" name="implementation">
List <br>
<code>ng-class="{completed: todo.completed, urgent: todo.urgent, important: todo.important"}</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="singleOptimized"
type="radio" name="implementation">
Single ngClass optimized <br>
<code>
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
<div class="radio">
<label>
<input ng-model="benchmark.implementation" value="single"
type="radio" name="implementation">
Single ngClass <br>
<code>
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}"
</code>
</label>
</div>
</p>
</div>
<br>
<h3>Example</h3>
<div ng-switch="benchmark.implementation">
<table ng-switch-when="tableOptimized" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="todo.completed && 'active'"
ng-class-even="todo.completed && todo.important && 'gold'"
ng-class-odd="todo.completed && todo.important && 'silver'"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="todo.urgent && 'danger'">{{todo.urgent}}</td>
<td ng-class="todo.important && 'success'">{{todo.important}}</td>
</tr>
</tbody>
</table>
<table ng-switch-when="table" class="table">
<thead>
<tr>
<th>todo #id</th>
<th>completed?</th>
<th>urgent?</th>
<th>important?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{active: todo.completed}"
ng-class-even="{gold: todo.completed && todo.important}"
ng-class-odd="{silver: todo.completed && todo.important}"
>
<td>#{{todo.id}}</td>
<td>{{todo.completed}}</td>
<td ng-class="{danger: todo.urgent}">{{todo.urgent}}</td>
<td ng-class="{success: todo.important}">{{todo.important}}</td>
</tr>
</tbody>
</table>
<ul ng-switch-when="list">
<li ng-repeat="todo in benchmark.todos track by todo.id"
ng-class="{
completed: todo.completed,
urgent: todo.urgent,
important: todo.important
}">#{{todo.id}}</li>
</ul>
<div ng-switch-when="singleOptimized"
class="panel"
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
<div ng-switch-when="single"
class="panel"
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}">
<div class="panel-heading">
<h3 class="panel-title">Information</h3>
</div>
<div class="panel-body"> The title is green because there are todos... </div>
</div>
</div>
</div>
</div>
</div>
<br><br><br>
-95
View File
@@ -1,95 +0,0 @@
'use strict';
/* globals angular, benchmarkSteps */
var app = angular.module('ngOptionsBenchmark', []);
app.config(function($compileProvider) {
if ($compileProvider.debugInfoEnabled) {
$compileProvider.debugInfoEnabled(false);
}
});
app.controller('DataController', function($scope, $element) {
$scope.items = [];
$scope.count = 10000;
function changeOptions() {
$scope.items = [];
for (var i = 0; i < $scope.count; ++i) {
$scope.items.push({
id: i,
label: 'item-' + i,
group: 'group-' + i % 100
});
}
}
var selectElement = $element.find('select');
console.log(selectElement);
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-model-1',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.items[1000];
});
}
});
benchmarkSteps.push({
name: 'set-model-2',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.items[10];
});
}
});
benchmarkSteps.push({
name: 'remove-options',
fn: function() {
$scope.count = 100;
changeOptions();
}
});
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-view-1',
fn: function() {
selectElement.val('2000');
selectElement.triggerHandler('change');
}
});
benchmarkSteps.push({
name: 'set-view-2',
fn: function() {
selectElement.val('1000');
selectElement.triggerHandler('change');
}
});
});
-15
View File
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-10
View File
@@ -1,10 +0,0 @@
<div ng-app="ngOptionsBenchmark" ng-cloak>
<div ng-controller="DataController">
<div class="container-fluid">
<p>
Tests the execution of ng-options for rendering during model and option updates.
</p>
<select ng-model="x" ng-options="a as a.label group by a.group for a in items track by a.id"></select>
</div>
</div>
</div>
+3 -5
View File
@@ -1,13 +1,11 @@
'use strict';
var app = angular.module('orderByBenchmark', []);
app.controller('DataController', function DataController($rootScope, $scope) {
app.controller('DataController', function($rootScope, $scope) {
this.ngRepeatCount = 5000;
this.rows = [];
var self = this;
$scope.benchmarkType = 'baseline';
$scope.benchmarkType = 'basic';
$scope.rawProperty = function(key) {
return function(item) {
@@ -39,7 +37,7 @@ app.controller('DataController', function DataController($rootScope, $scope) {
}
}
}
});
})
benchmarkSteps.push({
name: '$apply',
+5 -9
View File
@@ -1,18 +1,14 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [
{
'id': 'jquery',
'src': 'jquery-noop.js'
}, {
"id": "jquery",
"src": "jquery-noop.js"
},{
id: 'angular',
src: '/build/angular.js'
}, {
src: 'app.js'
},{
src: 'app.js',
}]
});
};
-1
View File
@@ -1 +0,0 @@
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
+22 -23
View File
@@ -1,5 +1,3 @@
'use strict';
var app = angular.module('parsedExpressionBenchmark', []);
app.config(function($compileProvider) {
@@ -19,10 +17,11 @@ app.directive('bmPeWatch', function() {
return {
restrict: 'A',
compile: function($element, $attrs) {
$element.text($attrs.bmPeWatch);
$element.text( $attrs.bmPeWatch );
return function($scope, $element, $attrs) {
$scope.$watch($attrs.bmPeWatch, function(val) {
$element.text(val);
});
};
}
@@ -39,9 +38,9 @@ app.directive('bmPeWatchLiteral', function($parse) {
return {
restrict: 'A',
compile: function($element, $attrs) {
$element.text($attrs.bmPeWatchLiteral);
$element.text( $attrs.bmPeWatchLiteral );
return function($scope, $element, $attrs) {
$scope.$watch($parse($attrs.bmPeWatchLiteral, retZero));
$scope.$watch( $parse($attrs.bmPeWatchLiteral, retZero) );
};
}
};
@@ -54,33 +53,33 @@ app.controller('DataController', function($scope, $rootScope) {
var star = '*';
$scope.func = function() { return star; };
$scope.func = function() { return star;};
for (var i = 0; i < totalRows; i++) {
for (var i=0; i<totalRows; i++) {
data.push({
index: i,
odd: i % 2 === 0,
even: i % 2 === 1,
str0: 'foo-' + Math.random() * Date.now(),
str1: 'bar-' + Math.random() * Date.now(),
str2: 'baz-' + Math.random() * Date.now(),
num0: Math.random() * Date.now(),
num1: Math.random() * Date.now(),
num2: Math.random() * Date.now(),
date0: new Date(Math.random() * Date.now()),
date1: new Date(Math.random() * Date.now()),
date2: new Date(Math.random() * Date.now()),
func: function() { return star; },
obj: data[i - 1],
keys: data[i - 1] && (data[i - 1].keys || Object.keys(data[i - 1])),
constructor: data[i - 1]
odd: i%2 === 0,
even: i%2 === 1,
str0: "foo-" + Math.random()*Date.now(),
str1: "bar-" + Math.random()*Date.now(),
str2: "baz-" + Math.random()*Date.now(),
num0: Math.random()*Date.now(),
num1: Math.random()*Date.now(),
num2: Math.random()*Date.now(),
date0: new Date(Math.random()*Date.now()),
date1: new Date(Math.random()*Date.now()),
date2: new Date(Math.random()*Date.now()),
func: function(){ return star; },
obj: data[i-1],
keys: data[i-1] && (data[i-1].keys || Object.keys(data[i-1])),
constructor: data[i-1]
});
}
benchmarkSteps.push({
name: '$apply',
fn: function() {
for (var i = 0; i < 50; i++) {
for (var i=0; i<50; i++) {
$rootScope.$digest();
}
}
+2 -6
View File
@@ -1,15 +1,11 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
scripts: [ {
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
src: 'app.js',
}]
});
};
-17
View File
@@ -52,11 +52,6 @@
<label for="functionCalls">Function calls</label>
</li>
<li>
<input type="radio" ng-model="expressionType" value="assignment" id="assignment">
<label for="assignment">Assignment</label>
</li>
<li>
<input type="radio" ng-model="expressionType" value="objectLiterals" id="objectLiterals">
<label for="objectLiterals">Object Literals</label>
@@ -202,18 +197,6 @@
<span bm-pe-watch="row.func(row.func(), row.func())"></span>
</li>
<li ng-switch-when="assignment" ng-repeat="(rowIdx, row) in ::data">
<span bm-pe-watch="row.foo = row.str0"></span>
<span bm-pe-watch="row.obj.foo = row.str1"></span>
<span bm-pe-watch="row.obj.obj.foo = row.str2"></span>
<span bm-pe-watch="row['bar'] = row.num0"></span>
<span bm-pe-watch="row.obj['bar'] = row.num1"></span>
<span bm-pe-watch="row.obj.obj['bar'] = row.num2"></span>
<span bm-pe-watch="row[0] = row.date0"></span>
<span bm-pe-watch="row.obj[0] = row.date1"></span>
<span bm-pe-watch="row.obj.obj[0] = row.date2"></span>
</li>
<li ng-switch-when="objectLiterals" ng-repeat="(rowIdx, row) in ::data">
<span bm-pe-watch-literal="{foo: rowIdx}"></span>
<span bm-pe-watch-literal="{foo: row, bar: rowIdx}"></span>
-104
View File
@@ -1,104 +0,0 @@
'use strict';
/* globals angular, benchmarkSteps */
var app = angular.module('selectBenchmark', []);
app.config(function($compileProvider) {
if ($compileProvider.debugInfoEnabled) {
$compileProvider.debugInfoEnabled(false);
}
});
app.controller('DataController', function($scope, $element) {
$scope.groups = [];
$scope.count = 10000;
function changeOptions() {
$scope.groups = [];
var i = 0;
var group;
while (i < $scope.count) {
if (i % 100 === 0) {
group = {
name: 'group-' + $scope.groups.length,
items: []
};
$scope.groups.push(group);
}
group.items.push({
id: i,
label: 'item-' + i
});
i++;
}
}
var selectElement = $element.find('select');
console.log(selectElement);
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-model-1',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.groups[10].items[0];
});
}
});
benchmarkSteps.push({
name: 'set-model-2',
fn: function() {
$scope.$apply(function() {
$scope.x = $scope.groups[0].items[10];
});
}
});
benchmarkSteps.push({
name: 'remove-options',
fn: function() {
$scope.count = 100;
changeOptions();
}
});
benchmarkSteps.push({
name: 'add-options',
fn: function() {
$scope.$apply(function() {
$scope.count = 10000;
changeOptions();
});
}
});
benchmarkSteps.push({
name: 'set-view-1',
fn: function() {
selectElement.val('2000');
selectElement.triggerHandler('change');
}
});
benchmarkSteps.push({
name: 'set-view-2',
fn: function() {
selectElement.val('1000');
selectElement.triggerHandler('change');
}
});
});
-15
View File
@@ -1,15 +0,0 @@
/* eslint-env node */
'use strict';
module.exports = function(config) {
config.set({
scripts: [{
id: 'angular',
src: '/build/angular.js'
},
{
src: 'app.js'
}]
});
};
-15
View File
@@ -1,15 +0,0 @@
<div ng-app="selectBenchmark" ng-cloak>
<div ng-controller="DataController">
<div class="container-fluid">
<p>
Tests the execution of a select with ngRepeat'ed options with ngValue for rendering during model
and option updates.
</p>
<select ng-model="x">
<optgroup ng-repeat="g in groups track by g.name" label="{{g.name}}">
<option ng-repeat="a in g.items track by a.id" ng-value="a">{{a.label}}</option>
</optgroup>
</select>
</div>
</div>
</div>
+3 -6
View File
@@ -1,11 +1,8 @@
{
"name": "angularjs",
"license": "MIT",
"name": "AngularJS",
"devDependencies": {
"jquery": "3.1.0",
"jquery-2.2": "jquery#2.2.4",
"jquery-2.1": "jquery#2.1.4",
"jquery": "2.1.1",
"closure-compiler": "https://dl.google.com/closure-compiler/compiler-20140814.zip",
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.4/assets/ng-closure-runner.zip"
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip"
}
}
Executable
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env node
// TODO(vojta): pre-commit hook for validating messages
// TODO(vojta): report errors, currently Q silence everything which really sucks
'use strict';
var child = require('child_process');
var fs = require('fs');
var util = require('util');
var q = require('qq');
var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD';
var GIT_TAG_CMD = 'git describe --tags --abbrev=0';
var HEADER_TPL = '<a name="%s"></a>\n# %s (%s)\n\n';
var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
var EMPTY_COMPONENT = '$$';
var warn = function() {
console.log('WARNING:', util.format.apply(null, arguments));
};
var parseRawCommit = function(raw) {
if (!raw) return null;
var lines = raw.split('\n');
var msg = {}, match;
msg.hash = lines.shift();
msg.subject = lines.shift();
msg.closes = [];
msg.breaks = [];
lines.forEach(function(line) {
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
if (match) msg.closes.push(parseInt(match[1]));
});
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
if (match) {
msg.breaking = match[1];
}
msg.body = lines.join('\n');
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
if (!match || !match[1] || !match[3]) {
warn('Incorrect message: %s %s', msg.hash, msg.subject);
return null;
}
msg.type = match[1];
msg.component = match[2];
msg.subject = match[3];
return msg;
};
var linkToIssue = function(issue) {
return util.format(LINK_ISSUE, issue, issue);
};
var linkToCommit = function(hash) {
return util.format(LINK_COMMIT, hash.substr(0, 8), hash);
};
var currentDate = function() {
var now = new Date();
var pad = function(i) {
return ('0' + i).substr(-2);
};
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()));
};
var printSection = function(stream, title, section, printCommitLinks) {
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
var components = Object.getOwnPropertyNames(section).sort();
if (!components.length) return;
stream.write(util.format('\n## %s\n\n', title));
components.forEach(function(name) {
var prefix = '-';
var nested = section[name].length > 1;
if (name !== EMPTY_COMPONENT) {
if (nested) {
stream.write(util.format('- **%s:**\n', name));
prefix = ' -';
} else {
prefix = util.format('- **%s:**', name);
}
}
section[name].forEach(function(commit) {
if (printCommitLinks) {
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
if (commit.closes.length) {
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
}
stream.write(')\n');
} else {
stream.write(util.format('%s %s\n', prefix, commit.subject));
}
});
});
stream.write('\n');
};
var readGitLog = function(grep, from) {
var deferred = q.defer();
// TODO(vojta): if it's slow, use spawn and stream it instead
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
var commits = [];
stdout.split('\n==END==\n').forEach(function(rawCommit) {
var commit = parseRawCommit(rawCommit);
if (commit) commits.push(commit);
});
deferred.resolve(commits);
});
return deferred.promise;
};
var writeChangelog = function(stream, commits, version) {
var sections = {
fix: {},
feat: {},
perf: {},
breaks: {}
};
sections.breaks[EMPTY_COMPONENT] = [];
commits.forEach(function(commit) {
var section = sections[commit.type];
var component = commit.component || EMPTY_COMPONENT;
if (section) {
section[component] = section[component] || [];
section[component].push(commit);
}
if (commit.breaking) {
sections.breaks[component] = sections.breaks[component] || [];
sections.breaks[component].push({
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
hash: commit.hash,
closes: []
});
}
});
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
printSection(stream, 'Bug Fixes', sections.fix);
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Performance Improvements', sections.perf);
printSection(stream, 'Breaking Changes', sections.breaks, false);
};
var getPreviousTag = function() {
var deferred = q.defer();
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
if (code) deferred.reject('Cannot get the previous tag.');
else deferred.resolve(stdout.replace('\n', ''));
});
return deferred.promise;
};
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
});
});
};
// publish for testing
exports.parseRawCommit = parseRawCommit;
exports.printSection = printSection;
// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
generate(process.argv[2], process.argv[3]);
}
+108
View File
@@ -0,0 +1,108 @@
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
'use strict';
describe('changelog.js', function() {
var ch = require('./changelog');
describe('parseRawCommit', function() {
it('should parse raw commit', function() {
var msg = ch.parseRawCommit(
'9b1aff905b638aa274a5fc8f88662df446d374bd\n' +
'feat(scope): broadcast $destroy event on scope destruction\n' +
'perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.type).toBe('feat');
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.component).toBe('scope');
});
it('should parse closed issues', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'Closes #123\nCloses #25\n');
expect(msg.closes).toEqual([123, 25]);
});
it('should parse breaking changes', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'BREAKING CHANGE: first breaking change\nsomething else\n' +
'another line with more info\n');
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
describe('printSection', function() {
var output;
var streamMock = {
write: function(str) {
output += str;
}
};
beforeEach(function() {
output = '';
});
it('should add a new line at the end of each breaking change list item ' +
'when there is 1 item per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [{subject: 'breaking change 1'}],
module2: [{subject: 'breaking change 2'}]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:** breaking change 1\n' +
'- **module2:** breaking change 2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
it('should add a new line at the end of each breaking change list item ' +
'when there are multiple items per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [
{subject: 'breaking change 1.1'},
{subject: 'breaking change 1.2'}
],
module2: [
{subject: 'breaking change 2.1'},
{subject: 'breaking change 2.2'}
]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:**\n' +
' - breaking change 1.1\n' +
' - breaking change 1.2\n' +
'- **module2:**\n' +
' - breaking change 2.1\n' +
' - breaking change 2.2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
});
});
@@ -9,72 +9,72 @@ var Q = require('q');
var _ = require('lodash');
var semver = require('semver');
var exec = function(cmd) {
return function() {
var exec = function (cmd) {
return function () {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift(cmd);
var fullCmd = util.format.apply(util, args);
return Q.nfcall(cp.exec, fullCmd).then(function(out) {
return Q.nfcall(cp.exec, fullCmd).then(function (out) {
return out[0].split('\n');
});
};
};
var andThen = function(fn, after) {
return /** @this */ function() {
var andThen = function (fn, after) {
return function () {
return fn.apply(this, arguments).then(after);
};
};
var oneArg = function(fn) {
return function(arg) {
var oneArg = function (fn) {
return function (arg) {
return fn(arg);
};
};
var oneLine = function(lines) {
var oneLine = function (lines) {
return lines[0].trim();
};
var noArgs = function(fn) {
return function() {
var noArgs = function (fn) {
return function () {
return fn();
};
};
var identity = function(i) { return i; };
var identity = function (i) { return i; };
// like Q.all, but runs the commands in series
// like Q.all, but runs the comands in series
// useful for ensuring env state (like which branch is checked out)
var allInSeries = function(fn) {
return function(args) {
var allInSeries = function (fn) {
return function (args) {
var results = [];
var def;
while (args.length > 0) {
(function(arg) {
(function (arg) {
if (def) {
def = def.then(function() {
def = def.then(function () {
return fn(arg);
});
} else {
def = fn(arg);
}
def = def.then(function(res) {
def = def.then(function (res) {
results.push(res);
});
})(args.pop());
}(args.pop()));
}
return def.then(function() {
return def.then(function () {
return results;
});
};
};
var compareBranches = function(left, right) {
var compareBranches = function (left, right) {
console.log('# These commits are in ' + left.name + ' but not in ' + right.name + '\n');
console.log(_(left.log).
difference(right.log).
map(function(line) {
map(function (line) {
return left.full[left.log.indexOf(line)]; // lol O(n^2)
}).
value().
@@ -85,43 +85,44 @@ var checkout = oneArg(exec('git checkout %s'));
var getCurrentBranch = andThen(noArgs(exec('git rev-parse --abbrev-ref HEAD')), oneLine);
var getTags = noArgs(exec('git tag'));
var getShaOfTag = oneArg(exec('git rev-list %s | head -n 1'));
var getTheLog = oneArg(exec('git log --pretty=oneline %s..HEAD | cat'));
// remember this so we can restore state
var currentBranch;
getCurrentBranch().
then(function(branch) {
then(function (branch) {
currentBranch = branch;
}).
then(getTags).
then(function(tags) {
then(function (tags) {
return tags.
filter(semver.valid).
map(semver.clean).
sort(semver.rcompare);
}).
then(function(tags) {
var major = semver(tags[0]).major;
then(function (tags) {
var major = tags[0].split('.')[0] + '.x';
return tags.
filter(function(ver) {
return semver(ver).major === major;
filter(function (ver) {
return semver.satisfies(ver, major);
});
}).
then(function(tags) {
then(function (tags) {
return _(tags).
groupBy(function(tag) {
groupBy(function (tag) {
return tag.split('.')[1];
}).
map(function(group) {
map(function (group) {
return _.first(group);
}).
map(function(tag) {
map(function (tag) {
return 'v' + tag;
}).
value();
}).
then(function(tags) {
then(function (tags) {
var master = tags.pop();
var stable = tags.pop();
@@ -130,38 +131,38 @@ then(function(tags) {
{ name: 'master', tag: master}
];
}).
then(allInSeries(function(branch) {
then(allInSeries(function (branch) {
return checkout(branch.name).
then(function() {
then(function () {
return getTheLog(branch.tag);
}).
then(function(log) {
then(function (log) {
return log.
filter(identity);
}).
then(function(log) {
branch.full = log.map(function(line) {
then(function (log) {
branch.full = log.map(function (line) {
line = line.split(' ');
var sha = line.shift();
var msg = line.join(' ');
return sha + ((/fix\([^)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
return sha + ((/fix\([^\)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
});
branch.log = log.map(function(line) {
branch.log = log.map(function (line) {
return line.substr(41);
});
return branch;
});
})).
then(function(pairs) {
then(function (pairs) {
compareBranches(pairs[0], pairs[1]);
console.log('\n');
compareBranches(pairs[1], pairs[0]);
return pairs;
}).
then(function() {
then(function () {
return checkout(currentBranch);
}).
catch(function(e) {
catch(function (e) {
console.log(e.stack);
});
-8
View File
@@ -9,11 +9,3 @@
ng\:form {
display: block;
}
.ng-animate-shim {
visibility:hidden;
}
.ng-anchor {
position:absolute;
}
+3 -3
View File
@@ -22,7 +22,7 @@ ul.doc-example > li.doc-example-heading {
span.nojsfiddle {
float: right;
font-size: 14px;
margin-right: 10px;
margin-right:10px;
margin-top: 10px;
}
@@ -42,7 +42,7 @@ form.jsfiddle button {
color: #7989D6;
border-color: #7989D6;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
-webkit-border-radius:8px;
border-radius: 8px;
}
@@ -56,7 +56,7 @@ li.doc-example-live {
}
div.syntaxhighlighter {
padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars */
padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars http://is.gd/gSMgC */
}
/* TABS - tutorial environment navigation */
+215 -348
View File
@@ -1,21 +1,21 @@
html, body {
position: relative;
height: 100%;
position:relative;
height:100%;
}
#wrapper {
min-height: 100%;
position: relative;
padding-bottom: 120px;
min-height:100%;
position:relative;
padding-bottom:120px;
}
.footer {
border-top: 20px solid white;
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
border-top:20px solid white;
position:absolute;
bottom:0;
left:0;
right:0;
z-index:100;
padding-top: 2em;
background-color: #333;
color: white;
@@ -23,20 +23,20 @@ html, body {
}
.header-fixed {
position: fixed;
z-index: 1000;
top: 0;
left: 0;
right: 0;
position:fixed;
z-index:1000;
top:0;
left:0;
right:0;
}
.header-branding {
min-height: 41px !important;
min-height:41px!important;
}
.docs-navbar-primary {
border-radius: 0 !important;
margin-bottom: 0 !important;
border-radius:0!important;
margin-bottom:0!important;
}
/* Logo */
@@ -49,7 +49,7 @@ h1,h2,h3,h4,h5,h6 {
}
.subnav-body {
margin: 70px 0 20px;
margin:70px 0 20px;
}
.header .brand {
@@ -58,32 +58,32 @@ h1,h2,h3,h4,h5,h6 {
}
.header .brand img {
margin-top: 5px;
margin-top:5px;
height: 30px;
}
.docs-search {
margin: 10px 0;
padding: 4px 0 4px 20px;
background: white;
border-radius: 20px;
vertical-align: middle;
margin:10px 0;
padding:4px 0 4px 20px;
background:white;
border-radius:20px;
vertical-align:middle;
}
.docs-search > .search-query {
font-size: 14px;
border: 0;
width: 80%;
color: #555;
font-size:14px;
border:0;
width:80%;
color:#555;
}
.docs-search > .search-icon {
font-size: 15px;
margin-right: 10px;
font-size:15px;
margin-right:10px;
}
.docs-search > .search-query:focus {
outline: 0;
outline:0;
}
/* end: Logo */
@@ -101,31 +101,31 @@ h1,h2,h3,h4,h5,h6 {
.naked-list,
.naked-list ul,
.naked-list li {
list-style: none;
margin: 0;
padding: 0;
list-style:none;
margin:0;
padding:0;
}
.nav-index-section a {
font-weight: bold;
font-weight:bold;
font-family: "Open Sans";
color: black !important;
margin-top: 10px;
display: block;
color:black!important;
margin-top:10px;
display:block;
}
.nav-index-group {
margin-bottom: 20px !important;
margin-bottom:20px!important;
}
.nav-index-group-heading {
color: #6F0101;
font-weight: bold;
font-size: 1.2em;
padding: 0;
margin: 0;
border-bottom: 1px soild #aaa;
margin-bottom: 5px;
color:#6F0101;
font-weight:bold;
font-size:1.2em;
padding:0;
margin:0;
border-bottom:1px soild #aaa;
margin-bottom:5px;
}
.nav-index-group .nav-index-listing.current a {
@@ -133,58 +133,58 @@ h1,h2,h3,h4,h5,h6 {
}
.nav-breadcrumb {
margin: 4px 0;
padding: 0;
margin:4px 0;
padding:0;
}
.nav-breadcrumb-entry {
font-family: "Open Sans";
padding: 0;
margin: 0;
font-size: 18px;
display: inline-block;
vertical-align: middle;
padding:0;
margin:0;
font-size:18px;
display:inline-block;
vertical-align:middle;
}
.nav-breadcrumb-entry > .divider {
color: #555;
display: inline-block;
padding-left: 8px;
color:#555;
display:inline-block;
padding-left:8px;
}
.nav-breadcrumb-entry > span,
.nav-breadcrumb-entry > a {
color: #6F0101;
color:#6F0101;
}
.step-list > li:nth-child(1) {
padding-left: 20px;
padding-left:20px;
}
.step-list > li:nth-child(2) {
padding-left: 40px;
padding-left:40px;
}
.step-list > li:nth-child(3) {
padding-left: 60px;
padding-left:60px;
}
.api-profile-header-heading {
margin: 0;
padding: 0;
margin:0;
padding:0;
}
.api-profile-header-structure,
.api-profile-header-structure a {
font-family: "Open Sans";
font-weight: bold;
color: #999;
font-weight:bold;
color:#999;
}
.api-profile-section {
margin-top: 30px;
padding-top: 30px;
border-top: 1px solid #aaa;
margin-top:30px;
padding-top:30px;
border-top:1px solid #aaa;
}
pre {
@@ -196,23 +196,23 @@ pre {
.aside-nav a:link,
.aside-nav a:visited,
.aside-nav a:active {
color: #999;
color:#999;
}
.aside-nav a:hover {
color: black;
color:black;
}
.api-profile-description > p:first-child {
margin: 15px 0;
font-size: 18px;
margin:15px 0;
font-size:18px;
}
p > code,
code.highlighted {
background: #f4f4f4;
border-radius: 5px;
padding: 2px 5px;
color: maroon;
background:#f4f4f4;
border-radius:5px;
padding:2px 5px;
color:maroon;
}
ul + p {
@@ -220,8 +220,8 @@ ul + p {
}
.docs-version-jump {
min-width: 100%;
max-width: 100%;
min-width:100%;
max-width:100%;
}
.picker {
@@ -267,14 +267,14 @@ ul + p {
}
.picker:after {
content: "";
content:"";
position: absolute;
right: 8%;
top: 50%;
z-index: 0;
color: #999;
width: 0;
margin-top: -2px;
margin-top:-2px;
height: 0;
border-top: 6px solid;
border-right: 6px solid transparent;
@@ -287,109 +287,48 @@ iframe.example {
}
.search-results-frame {
clear: both;
display: table;
width: 100%;
clear:both;
display:table;
width:100%;
}
.search-results.ng-hide {
display: none;
display:none;
}
.search-results-container {
padding-bottom: 1em;
border-top: 1px solid #111;
background: #181818;
box-shadow: inset 0 0 10px #111;
padding-bottom:1em;
border-top:1px solid #111;
background:#181818;
box-shadow:inset 0 0 10px #111;
}
.search-results-container .search-results-group {
vertical-align: top;
padding: 10px 10px;
display: inline-block;
vertical-align:top;
padding:10px 10px;
display:inline-block;
}
.search-results-group-heading {
font-family: "Open Sans";
padding-left: 10px;
color: white;
}
.search-results-group .search-results {
padding: 0 5px 0;
list-style-type: none;
padding-left:10px;
color:white;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right: 1px solid #222;
}
.search-results-group.col-group-api {
width: 30%;
border-right:1px solid #050505;
}
.search-results-group.col-group-api { width:30%; }
.search-results-group.col-group-guide,
.search-results-group.col-group-tutorial {
width: 20%;
}
.search-results-group.col-group-tutorial { width:20%; }
.search-results-group.col-group-misc,
.search-results-group.col-group-error {
width: 15%;
float: right;
}
.search-results-group.col-group-error { width:15%; float: right; }
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
/* Prevent bullets in the second column from being hidden in Chrome and IE */
-webkit-column-gap: 2em;
-ms-column-gap: 2em;
column-gap: 2em;
}
}
.search-results-group .search-result {
word-wrap: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
-ms-column-break-inside: avoid;
-webkit-column-break-inside: avoid;
-moz-column-break-inside: avoid; /* Unsupported */
column-break-inside: avoid;
text-indent: -0.65em; /* Make sure line wrapped words are aligned vertically */
}
@supports (-moz-column-count: 2) {
.search-results-group .search-result {
/* Prevents column breaks inside words in FF, but has adverse effects in IE11 and Chrome */
overflow: hidden;
padding-left: 1em; /* In FF the list item bullet is otherwise hidden */
margin-left: -1em; /* offset the padding left */
}
}
.search-result:before {
content: "\002D\00A0"; /* Dash and non-breaking space as List item type */
position: relative;
}
.search-results-group.col-group-api .search-result {
width: 48%;
display: inline-block;
padding-left: 12px;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group.col-group-api .search-result {
width: auto;
display: list-item;
}
width:48%;
display:inline-block;
}
.search-close {
@@ -404,135 +343,135 @@ iframe.example {
border-top-right-radius: 5px;
border-top-left-radius: 5px;
width: 200px;
box-shadow: 0 0 10px #111;
box-shadow:0 0 10px #111;
}
.variables-matrix {
border: 1px solid #ddd;
width: 100%;
margin: 10px 0;
border:1px solid #ddd;
width:100%;
margin:10px 0;
}
.variables-matrix td,
.variables-matrix th {
padding: 10px;
padding:10px;
}
.variables-matrix td {
border-top: 1px solid #eee;
border-top:1px solid #eee;
}
.variables-matrix td + td,
.variables-matrix th + th {
border-left: 1px solid #eee;
border-left:1px solid #eee;
}
.variables-matrix tr:nth-child(even) td {
background: #f5f5f5;
background:#f5f5f5;
}
.variables-matrix th {
background: #f1f1f1;
background:#f1f1f1;
}
.sup-header {
padding-top: 10px;
padding-bottom: 5px;
background: rgba(245,245,245,0.88);
box-shadow: 0 0 2px #999;
padding-top:10px;
padding-bottom:5px;
background:rgba(245,245,245,0.88);
box-shadow:0 0 2px #999;
}
.main-body-grid {
margin-top: 120px;
position: relative;
margin-top:120px;
position:relative;
}
.main-body-grid > .grid-left,
.main-body-grid > .grid-right {
padding: 20px 0;
padding:20px 0;
}
.main-body-grid > .grid-left {
position: fixed;
top: 120px;
bottom: 0;
overflow: auto;
position:fixed;
top:120px;
bottom:0;
overflow:auto;
}
.main-header-grid > .grid-left,
.main-body-grid > .grid-left {
width: 260px;
width:260px;
}
.main-header-grid > .grid-right,
.main-body-grid > .grid-right {
margin-left: 270px;
position: relative;
margin-left:270px;
position:relative;
}
.main-header-grid > .grid-left {
float: left;
float:left;
}
.main-body-grid .side-navigation {
position: relative;
padding-bottom: 120px;
position:relative;
padding-bottom:120px;
}
.main-body-grid .side-navigation.ng-hide {
display: block!important;
display:block!important;
}
.variables-matrix td {
vertical-align: top;
padding: 5px;
vertical-align:top;
padding:5px;
}
.type-hint {
display: inline-block;
display:inline-block;
background: gray;
}
.variables-matrix .type-hint {
text-align: center;
min-width: 60px;
margin: 1px 5px;
text-align:center;
min-width:60px;
margin:1px 5px;
}
.type-hint + .type-hint {
margin-top: 5px;
margin-top:5px;
}
.type-hint-expression {
background: purple;
background:purple;
}
.type-hint-date {
background: pink;
background:pink;
}
.type-hint-string {
background: #3a87ad;
background:#3a87ad;
}
.type-hint-function {
background: green;
background:green;
}
.type-hint-object {
background: #999;
background:#999;
}
.type-hint-array {
background: #F90;;
background:#F90;;
}
.type-hint-boolean {
background: rgb(18, 131, 39);
background:rgb(18, 131, 39);
}
.type-hint-number {
background: rgb(189, 63, 66);
background:rgb(189, 63, 66);
}
.type-hint-regexp {
@@ -544,19 +483,19 @@ iframe.example {
}
.runnable-example-frame {
width: 100%;
height: 300px;
width:100%;
height:300px;
border: 1px solid #ddd;
border-radius: 5px;
border-radius:5px;
}
.runnable-example-tabs {
margin-top: 10px;
margin-bottom: 20px;
margin-top:10px;
margin-bottom:20px;
}
.tutorial-nav {
display: block;
display:block;
}
h1 + ul, h1 + ul > li,
@@ -565,23 +504,23 @@ ul.tutorial-nav, ul.tutorial-nav > li,
.usage > ul, .usage > ul > li,
ul.methods, ul.methods > li,
ul.events, ul.events > li {
list-style: none;
padding: 0;
list-style:none;
padding:0;
}
h2 {
border-top: 1px solid #eee;
margin-top: 30px;
padding-top: 30px;
border-top:1px solid #eee;
margin-top:30px;
padding-top:30px;
}
h4 {
margin-top: 20px;
padding-top: 20px;
margin-top:20px;
padding-top:20px;
}
.btn {
color: #428bca;
color:#428bca;
position: relative;
width: auto;
display: inline-block;
@@ -604,26 +543,26 @@ h4 {
}
.btn + .btn {
margin-left: 10px;
margin-left:10px;
}
.btn:hover, .btn:focus {
color: black !important;
border: 1px solid #ddd !important;
background: white !important;
.btn:hover {
color:black!important;
border: 1px solid #ddd!important;
background:white!important;
}
.view-source, .improve-docs {
position: relative;
z-index: 100;
position:relative;
z-index:100;
}
.view-source {
margin-right: 10px;
margin-right:10px;
}
.improve-docs {
float: right;
float:right;
}
.return-arguments,
@@ -631,51 +570,17 @@ h4 {
.return-arguments th + th,
.return-arguments td,
.return-arguments td + td {
border-radius: 0;
border: 0;
border-radius:0;
border:0;
}
.return-arguments td:first-child {
width: 100px;
width:100px;
}
ul.methods > li,
ul.events > li {
margin-bottom: 40px;
}
.definition-table td {
padding: 8px;
border: 1px solid #eee;
vertical-align: top;
}
.table > tbody > tr.head > td,
.table > tbody > tr.head > th {
border-bottom: 2px solid #ddd;
padding-top: 50px;
}
.diagram {
margin-bottom: 10px;
margin-top: 30px;
max-width: 100%;
}
.deprecation {
margin-top: 15px;
}
.deprecation .title {
float: left;
margin-right: 5px;
}
@media only screen and (min-width: 769px) {
[ng-include="partialPath"].ng-hide {
display: block !important;
visibility: hidden;
}
margin-bottom:40px;
}
@media only screen and (min-width: 769px) and (max-width: 991px) {
@@ -689,141 +594,103 @@ ul.events > li {
@media only screen and (max-width : 768px) {
.picker, .picker select {
width: auto;
display: block;
margin-bottom: 10px;
width:auto;
display:block;
margin-bottom:10px;
}
.docs-navbar-primary {
text-align: center;
text-align:center;
}
.main-body-grid {
margin-top: 0;
margin-top:0;
}
.main-header-grid > .grid-left,
.main-body-grid > .grid-left,
.main-header-grid > .grid-right,
.main-body-grid > .grid-right {
display: block;
float: none;
width: auto !important;
margin-left: 0;
display:block;
float:none;
width:auto!important;
margin-left:0;
}
.main-body-grid > .grid-left,
.header-fixed, .footer {
position: static !important;
position:static!important;
}
.main-body-grid > .grid-left {
background: #efefef;
margin-left: -1em;
margin-right: -1em;
padding: 1em;
width: auto !important;
overflow: visible;
background:#efefef;
margin-left:-1em;
margin-right:-1em;
padding:1em;
width:auto!important;
overflow:visible;
}
.main-header-grid > .grid-right,
.main-body-grid > .grid-right {
margin-left: 0;
margin-left:0;
}
.main-body-grid .side-navigation {
display: block !important;
padding-bottom: 50px;
display:block!important;
}
.main-body-grid .side-navigation.ng-hide {
display: none !important;
display:none!important;
}
.nav-index-group .nav-index-listing {
display: inline-block;
padding: 3px 0;
display:inline-block;
padding:3px 0;
}
.nav-index-group .nav-index-listing:not(.nav-index-section):after {
padding-right: 5px;
margin-left: -3px;
content: ", ";
padding-right:5px;
margin-left:-3px;
content:", ";
}
.nav-index-group .nav-index-listing:last-child:after {
content: "";
display: inline-block;
content:"";
display:inline-block;
}
.nav-index-group .nav-index-section {
display: block;
display:block;
}
.toc-toggle {
margin-bottom: 20px;
margin-bottom:20px;
}
.toc-close {
position: absolute;
bottom: 5px;
bottom: -50px;
left: 50%;
margin-left: -50%;
text-align: center;
padding: 5px;
background: #eee;
border-radius: 5px;
width: 100%;
border: 1px solid #ddd;
box-shadow: 0 0 10px #bbb;
width: 90%;
border:1px solid #ddd;
box-shadow:0 0 10px #bbb;
}
.navbar-brand {
float: none;
text-align: center;
float:none;
text-align:center;
}
.search-results-container {
padding-bottom: 60px;
text-align: left;
padding-bottom:60px;
text-align:left;
}
.search-results-frame > .search-results-group:first-child > .search-results {
border-right: none;
}
.search-results-group {
float: none !important;
display: block !important;
width: auto !important;
border: 0! important;
padding: 0! important;
float:none!important;
display:block!important;
width:auto!important;
border:0!important;
padding:0!important;
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-results {
-moz-column-count: 2;
-ms-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
}
}
.search-results-group .search-result {
display: inline-block !important;
padding: 0 5px;
width: auto !important;
text-indent: initial;
margin-left: 0;
display:inline-block!important;
padding:0 5px;
width:auto!important;
}
.search-results-group .search-result:after {
content: ", ";
content:", ";
}
.search-results-group .search-result:before {
content: "";
}
@supports ((column-count: 2) or (-moz-column-count: 2) or (-ms-column-count: 2) or (-webkit-column-count: 2)) {
.search-results-group .search-result {
display: list-item !important;
}
.search-results-group .search-result:after {
content: "";
}
}
#wrapper {
padding-bottom: 0px;
padding-bottom:0px;
}
}
iframe[name="example-anchoringExample"] {
height: 400px;
}
Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 212 B

+442
View File
@@ -0,0 +1,442 @@
'use strict';
var directive = {};
directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) {
var exampleClassNameSelector = '.runnable-example-file';
var doc = $document[0];
var tpl =
'<nav class="runnable-example-tabs" ng-if="tabs">' +
' <a ng-class="{active:$index==activeTabIndex}"' +
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
return {
restrict: 'C',
scope : true,
controller : ['$scope', function($scope) {
$scope.setTab = function(index) {
var tab = $scope.tabs[index];
$scope.activeTabIndex = index;
$scope.$broadcast('tabChange', index, tab);
};
}],
compile : function(element) {
element.html(tpl + element.html());
return function(scope, element) {
var node = element[0];
var examples = node.querySelectorAll(exampleClassNameSelector);
var tabs = [], now = Date.now();
angular.forEach(examples, function(child, index) {
tabs.push(child.getAttribute('name'));
});
if(tabs.length > 0) {
scope.tabs = tabs;
scope.$on('tabChange', function(e, index, title) {
angular.forEach(examples, function(child) {
child.style.display = 'none';
});
var selected = examples[index];
selected.style.display = 'block';
});
scope.setTab(0);
}
}
}
};
}];
directive.dropdownToggle =
['$document', '$location', '$window',
function ($document, $location, $window) {
var openElement = null, close;
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
close && close();
});
element.parent().on('click', function(event) {
close && close();
});
element.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
var iWasOpen = false;
if (openElement) {
iWasOpen = openElement === element;
close();
}
if (!iWasOpen){
element.parent().addClass('open');
openElement = element;
close = function (event) {
event && event.preventDefault();
event && event.stopPropagation();
$document.off('click', close);
element.parent().removeClass('open');
close = null;
openElement = null;
}
$document.on('click', close);
}
});
}
};
}];
directive.syntax = function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
function makeLink(type, text, link, icon) {
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
var html = '';
var types = {
'github' : {
text : 'View on Github',
key : 'syntaxGithub',
icon : 'icon-github'
},
'plunkr' : {
text : 'View on Plunkr',
key : 'syntaxPlunkr',
icon : 'icon-arrow-down'
},
'jsfiddle' : {
text : 'View on JSFiddle',
key : 'syntaxFiddle',
icon : 'icon-cloud'
}
};
for(var type in types) {
var data = types[type];
var link = attrs[data.key];
if(link) {
html += makeLink(type, data.text, link, data.icon);
}
};
var nav = document.createElement('nav');
nav.className = 'syntax-links';
nav.innerHTML = html;
var node = element[0];
var par = node.parentNode;
par.insertBefore(nav, node);
}
}
}
directive.tabbable = function() {
return {
restrict: 'C',
compile: function(element) {
var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
tabContent = angular.element('<div class="tab-content"></div>');
tabContent.append(element.contents());
element.append(navTabs).append(tabContent);
},
controller: ['$scope', '$element', function($scope, $element) {
var navTabs = $element.contents().eq(0),
ngModel = $element.controller('ngModel') || {},
tabs = [],
selectedTab;
ngModel.$render = function() {
var $viewValue = this.$viewValue;
if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
if(selectedTab) {
selectedTab.paneElement.removeClass('active');
selectedTab.tabElement.removeClass('active');
selectedTab = null;
}
if($viewValue) {
for(var i = 0, ii = tabs.length; i < ii; i++) {
if ($viewValue == tabs[i].value) {
selectedTab = tabs[i];
break;
}
}
if (selectedTab) {
selectedTab.paneElement.addClass('active');
selectedTab.tabElement.addClass('active');
}
}
}
};
this.addPane = function(element, attr) {
var li = angular.element('<li><a href></a></li>'),
a = li.find('a'),
tab = {
paneElement: element,
paneAttrs: attr,
tabElement: li
};
tabs.push(tab);
attr.$observe('value', update)();
attr.$observe('title', function(){ update(); a.text(tab.title); })();
function update() {
tab.title = attr.title;
tab.value = attr.value || attr.title;
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
// we are not part of angular
ngModel.$viewValue = tab.value;
}
ngModel.$render();
}
navTabs.append(li);
li.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
if (ngModel.$setViewValue) {
$scope.$apply(function() {
ngModel.$setViewValue(tab.value);
ngModel.$render();
});
} else {
// we are not part of angular
ngModel.$viewValue = tab.value;
ngModel.$render();
}
});
return function() {
tab.tabElement.remove();
for(var i = 0, ii = tabs.length; i < ii; i++ ) {
if (tab == tabs[i]) {
tabs.splice(i, 1);
}
}
};
}
}]
};
};
directive.table = function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
};
var popoverElement = function() {
var object = {
init : function() {
this.element = angular.element(
'<div class="popover popover-incode top">' +
'<div class="arrow"></div>' +
'<div class="popover-inner">' +
'<div class="popover-title"><code></code></div>' +
'<div class="popover-content"></div>' +
'</div>' +
'</div>'
);
this.node = this.element[0];
this.element.css({
'display':'block',
'position':'absolute'
});
angular.element(document.body).append(this.element);
var inner = this.element.children()[1];
this.titleElement = angular.element(inner.childNodes[0].firstChild);
this.contentElement = angular.element(inner.childNodes[1]);
//stop the click on the tooltip
this.element.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
var self = this;
angular.element(document.body).on('click',function(event) {
if(self.visible()) self.hide();
});
},
show : function(x,y) {
this.element.addClass('visible');
this.position(x || 0, y || 0);
},
hide : function() {
this.element.removeClass('visible');
this.position(-9999,-9999);
},
visible : function() {
return this.position().y >= 0;
},
isSituatedAt : function(element) {
return this.besideElement ? element[0] == this.besideElement[0] : false;
},
title : function(value) {
return this.titleElement.html(value);
},
content : function(value) {
if(value && value.length > 0) {
value = marked(value);
}
return this.contentElement.html(value);
},
positionArrow : function(position) {
this.node.className = 'popover ' + position;
},
positionAway : function() {
this.besideElement = null;
this.hide();
},
positionBeside : function(element) {
this.besideElement = element;
var elm = element[0];
var x = elm.offsetLeft;
var y = elm.offsetTop;
x -= 30;
y -= this.node.offsetHeight + 10;
this.show(x,y);
},
position : function(x,y) {
if(x != null && y != null) {
this.element.css('left',x + 'px');
this.element.css('top', y + 'px');
}
else {
return {
x : this.node.offsetLeft,
y : this.node.offsetTop
};
}
}
};
object.init();
object.hide();
return object;
};
directive.popover = ['popoverElement', function(popover) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
element.on('click',function(event) {
event.preventDefault();
event.stopPropagation();
if(popover.isSituatedAt(element) && popover.visible()) {
popover.title('');
popover.content('');
popover.positionAway();
}
else {
popover.title(attrs.title);
popover.content(attrs.content);
popover.positionBeside(element);
}
});
}
}
}];
directive.tabPane = function() {
return {
require: '^tabbable',
restrict: 'C',
link: function(scope, element, attrs, tabsCtrl) {
element.on('$remove', tabsCtrl.addPane(element, attrs));
}
};
};
directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
var container, loading, url = attrs.url;
if(/\/build\//.test($window.location.href)) {
url = '/build/docs' + url;
}
element.on('click',function() {
scope.$apply(function() {
if(!container) {
if(loading) return;
loading = true;
var par = element.parent();
container = angular.element('<div class="foldout">loading...</div>');
$animate.enter(container, null, par);
$http.get(url, { cache : true }).success(function(html) {
loading = false;
html = '<div class="foldout-inner">' +
'<div calss="foldout-arrow"></div>' +
html +
'</div>';
container.html(html);
//avoid showing the element if the user has already closed it
if(container.css('display') == 'block') {
container.css('display','none');
$animate.addClass(container, 'ng-hide');
}
});
}
else {
container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
}
});
});
}
}
}];
angular.module('bootstrap', [])
.directive(directive)
.factory('popoverElement', popoverElement)
.run(function() {
marked.setOptions({
gfm: true,
tables: true
});
});
+1 -3
View File
@@ -54,9 +54,7 @@ angular.module('ui.bootstrap.dropdown', [])
}
};
var closeDropdown = function(evt) {
if (evt && evt.which === 3) return;
var closeDropdown = function() {
openScope.$apply(function() {
openScope.isOpen = false;
});
+11 -12
View File
@@ -1,18 +1,17 @@
'use strict';
/* eslint-env worker */
/* global importScripts, lunr */
"use strict";
/* jshint browser: true */
/* global importScripts, onmessage: true, postMessage, lunr */
// Load up the lunr library
importScripts('../components/lunr-0.7.2/lunr.min.js');
importScripts('../components/lunr.js-0.4.2/lunr.min.js');
// Create the lunr index - the docs should be an array of object, each object containing
// the path and search terms for a page
var index = lunr(/** @this */function() {
var index = lunr(function() {
this.ref('path');
this.field('titleWords', {boost: 50});
this.field('members', {boost: 40});
this.field('keywords', {boost: 20});
this.field('members', { boost: 40});
this.field('keywords', { boost : 20 });
});
// Retrieve the searchData which contains the information about each page to be indexed
@@ -26,13 +25,13 @@ searchDataRequest.onload = function() {
searchData.forEach(function(page) {
index.add(page);
});
self.postMessage({e: 'index-ready'});
postMessage({ e: 'index-ready' });
};
searchDataRequest.open('GET', 'search-data.json');
searchDataRequest.send();
// The worker receives a message everytime the web app wants to query the index
self.onmessage = function(oEvent) {
onmessage = function(oEvent) {
var q = oEvent.data.q;
var hits = index.search(q);
var results = [];
@@ -41,5 +40,5 @@ self.onmessage = function(oEvent) {
results.push(hit.ref);
});
// The results of the query are sent back to the web app via a new message
self.postMessage({e: 'query-ready', q: q, d: results});
};
postMessage({ e: 'query-ready', q: q, d: results });
};
@@ -1,14 +1,28 @@
{
"root": true,
"extends": "../../../.eslintrc-node.json",
"env": {
"jasmine": true,
"protractor": true
},
"extends": "../../../.jshintrc-base",
"globals": {
/* jasmine / karma */
"it": false,
"iit": false,
"describe": false,
"ddescribe": false,
"beforeEach": false,
"afterEach": false,
"expect": false,
"jasmine": false,
"spyOn": false,
"waits": false,
"waitsFor": false,
"runs": false,
"dump": false,
/* e2e */
"browser": false,
"element": false,
"by": false,
/* testabilityPatch / matchers */
"inject": false,
"module": false,
@@ -25,4 +39,4 @@
"browserTrigger": false,
"jqLiteCacheSize": false
}
}
}
+7 -7
View File
@@ -1,10 +1,10 @@
'use strict';
describe('doc.angularjs.org', function() {
describe("doc.angularjs.org", function() {
describe('API pages', function() {
describe("API pages", function() {
it('should display links to code on GitHub', function() {
it("should display links to code on GitHub", function() {
browser.get('build/docs/index.html#!/api/ng/service/$http');
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
@@ -12,7 +12,7 @@ describe('doc.angularjs.org', function() {
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
});
it('should change the page content when clicking a link to a service', function() {
it('should change the page content when clicking a link to a service', function () {
browser.get('build/docs/index.html');
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
@@ -23,7 +23,7 @@ describe('doc.angularjs.org', function() {
});
it('should show the functioning input directive example', function() {
it('should show the functioning input directive example', function () {
browser.get('build/docs/index.html#!/api/ng/directive/input');
// Ensure that the page is loaded before trying to switch frames.
@@ -38,7 +38,7 @@ describe('doc.angularjs.org', function() {
expect(code.getText()).toContain('guest!!!');
});
it('should trim indentation from code blocks', function() {
it("should trim indentation from code blocks", function() {
browser.get('build/docs/index.html#!/api/ng/type/$rootScope.Scope');
var codeBlocks = element.all(by.css('pre > code.lang-js'));
@@ -48,4 +48,4 @@ describe('doc.angularjs.org', function() {
});
});
});
});
});
@@ -1,12 +1,12 @@
'use strict';
describe('provider pages', function() {
describe("provider pages", function() {
it('should show the related service', function() {
it("should show the related service", function() {
browser.get('build/docs/index.html#!/api/ng/provider/$compileProvider');
var serviceLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(serviceLink.getText()).toEqual('- $compile');
expect(serviceLink.getAttribute('href')).toMatch(/api\/ng\/service\/\$compile/);
});
});
});
@@ -1,8 +1,8 @@
'use strict';
describe('service pages', function() {
describe("service pages", function() {
it('should show the related provider if there is one', function() {
it("should show the related provider if there is one", function() {
browser.get('build/docs/index.html#!/api/ng/service/$compile');
var providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(providerLink.getText()).toEqual('- $compileProvider');
@@ -10,13 +10,13 @@ describe('service pages', function() {
browser.get('build/docs/index.html#!/api/ng/service/$q');
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
expect(providerLink.getText()).not.toEqual('- $compileProvider');
expect(providerLink.getText()).not.toEqual('- $qProvider');
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
});
it('should show parameter defaults', function() {
it("should show parameter defaults", function() {
browser.get('build/docs/index.html#!/api/ng/service/$timeout');
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
});
});
});
+13 -13
View File
@@ -1,8 +1,8 @@
'use strict';
var webdriver = require('selenium-webdriver');
var webdriver = require('protractor/node_modules/selenium-webdriver');
describe('docs.angularjs.org', function() {
describe('docs.angularjs.org', function () {
beforeEach(function() {
// read and clear logs from previous tests
@@ -24,7 +24,7 @@ describe('docs.angularjs.org', function() {
});
describe('App', function() {
describe('App', function () {
// it('should filter the module list when searching', function () {
// browser.get();
// browser.waitForAngular();
@@ -38,8 +38,8 @@ describe('docs.angularjs.org', function() {
// });
it('should change the page content when clicking a link to a service', function() {
browser.get('build/docs/index-production.html');
it('should change the page content when clicking a link to a service', function () {
browser.get('build/docs/index.html');
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
ngBindLink.click();
@@ -51,36 +51,36 @@ describe('docs.angularjs.org', function() {
it('should be resilient to trailing slashes', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/');
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
});
it('should be resilient to trailing "index"', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index');
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
});
it('should be resilient to trailing "index/"', function() {
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index/');
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index/');
var pageBody = element(by.css('h1'));
expect(pageBody.getText()).toEqual('angular.noop');
});
it('should display formatted error messages on error doc pages', function() {
browser.get('build/docs/index-production.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
expect(element(by.css('.minerr-errmsg')).getText()).toEqual('Argument \'Missing\' is not a function, got undefined');
browser.get('build/docs/index.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
expect(element(by.css('.minerr-errmsg')).getText()).toEqual("Argument 'Missing' is not a function, got undefined");
});
it('should display an error if the page does not exist', function() {
browser.get('build/docs/index-production.html#!/api/does/not/exist');
it("should display an error if the page does not exist", function() {
browser.get('build/docs/index.html#!/api/does/not/exist');
expect(element(by.css('h1')).getText()).toBe('Oops!');
});
});
});
});
-8
View File
@@ -1,8 +0,0 @@
{
"root": true,
"extends": "../../../.eslintrc-browser.json",
"globals": {
"lunr": false
}
}
+2 -2
View File
@@ -1,11 +1,10 @@
'use strict';
angular.module('docsApp', [
'ngRoute',
'ngCookies',
'ngSanitize',
'ngAnimate',
'DocsController',
'versionsData',
'pagesData',
'navData',
'directives',
@@ -14,6 +13,7 @@ angular.module('docsApp', [
'search',
'tutorials',
'versions',
'bootstrap',
'ui.bootstrap.dropdown'
])
+1 -14
View File
@@ -1,5 +1,3 @@
'use strict';
angular.module('directives', [])
/**
@@ -36,15 +34,4 @@ angular.module('directives', [])
return function(scope, element) {
$anchorScroll.yOffset = element;
};
}])
.directive('table', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
});
}]);
+15 -20
View File
@@ -1,12 +1,14 @@
'use strict';
angular.module('DocsController', ['currentVersionData'])
angular.module('DocsController', [])
.controller('DocsController', [
'$scope', '$rootScope', '$location', '$window', '$cookies',
'NG_PAGES', 'NG_NAVIGATION', 'CURRENT_NG_VERSION',
function($scope, $rootScope, $location, $window, $cookies,
NG_PAGES, NG_NAVIGATION, CURRENT_NG_VERSION) {
'$scope', '$rootScope', '$location', '$window', '$cookies', 'openPlunkr',
'NG_PAGES', 'NG_NAVIGATION', 'NG_VERSION',
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
$scope.openPlunkr = openPlunkr;
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
$scope.navClass = function(navItem) {
return {
@@ -21,22 +23,15 @@ angular.module('DocsController', ['currentVersionData'])
$scope.$on('$includeContentLoaded', function() {
var pagePath = $scope.currentPage ? $scope.currentPage.path : $location.path();
$window._gaq.push(['_trackPageview', pagePath]);
$scope.loading = false;
});
$scope.$on('$includeContentError', function() {
$scope.loading = false;
});
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
path = path.replace(/^\/?(.+?)(\/index)?\/?$/, '$1');
var currentPage = $scope.currentPage = NG_PAGES[path];
currentPage = $scope.currentPage = NG_PAGES[path];
$scope.loading = true;
if (currentPage) {
if ( currentPage ) {
$scope.partialPath = 'partials/' + path + '.html';
$scope.currentArea = NG_NAVIGATION[currentPage.area];
var pathParts = currentPage.path.split('/');
@@ -44,7 +39,7 @@ angular.module('DocsController', ['currentVersionData'])
var breadcrumbPath = '';
angular.forEach(pathParts, function(part) {
breadcrumbPath += part;
breadcrumb.push({ name: (NG_PAGES[breadcrumbPath] && NG_PAGES[breadcrumbPath].name) || part, url: breadcrumbPath });
breadcrumb.push({ name: (NG_PAGES[breadcrumbPath]&&NG_PAGES[breadcrumbPath].name) || part, url: breadcrumbPath });
breadcrumbPath += '/';
});
} else {
@@ -58,12 +53,12 @@ angular.module('DocsController', ['currentVersionData'])
Initialize
***********************************/
$scope.versionNumber = CURRENT_NG_VERSION.full;
$scope.version = CURRENT_NG_VERSION.full + ' ' + CURRENT_NG_VERSION.codeName;
$scope.versionNumber = angular.version.full;
$scope.version = angular.version.full + " " + angular.version.codeName;
$scope.loading = 0;
var INDEX_PATH = /^(\/|\/index[^.]*.html)$/;
var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
if (!$location.path() || INDEX_PATH.test($location.path())) {
$location.path('/api').replace();
}
+16 -25
View File
@@ -1,25 +1,23 @@
'use strict';
angular.module('errors', ['ngSanitize'])
.filter('errorLink', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/g,
.filter('errorLink', ['$sanitize', function ($sanitize) {
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}<>]/g,
MAILTO_REGEXP = /^mailto:/,
STACK_TRACE_REGEXP = /:\d+:\d+$/;
var truncate = function(text, nchars) {
var truncate = function (text, nchars) {
if (text.length > nchars) {
return text.substr(0, nchars - 3) + '...';
}
return text;
};
return function(text, target) {
if (!text) return text;
return function (text, target) {
var targetHtml = target ? ' target="' + target + '"' : '';
return $sanitize(text.replace(LINKY_URL_REGEXP, function(url) {
if (!text) return text;
return $sanitize(text.replace(LINKY_URL_REGEXP, function (url) {
if (STACK_TRACE_REGEXP.test(url)) {
return url;
}
@@ -27,7 +25,7 @@ angular.module('errors', ['ngSanitize'])
// if we did not match ftp/http/mailto then assume mailto
if (!/^((ftp|https?):\/\/|mailto:)/.test(url)) url = 'mailto:' + url;
return '<a' + targetHtml + ' href="' + url + '">' +
return '<a' + targetHtml + ' href="' + url +'">' +
truncate(url.replace(MAILTO_REGEXP, ''), 60) +
'</a>';
}));
@@ -35,37 +33,30 @@ angular.module('errors', ['ngSanitize'])
}])
.directive('errorDisplay', ['$location', 'errorLinkFilter', function($location, errorLinkFilter) {
var encodeAngleBrackets = function(text) {
return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
};
var interpolate = function(formatString) {
.directive('errorDisplay', ['$location', 'errorLinkFilter', function ($location, errorLinkFilter) {
var interpolate = function (formatString) {
var formatArgs = arguments;
return formatString.replace(/\{\d+\}/g, function(match) {
return formatString.replace(/\{\d+\}/g, function (match) {
// Drop the braces and use the unary plus to convert to an integer.
// The index will be off by one because of the formatString.
var index = +match.slice(1, -1);
if (index + 1 >= formatArgs.length) {
return match;
}
return formatArgs[index + 1];
return formatArgs[index+1];
});
};
return {
link: function(scope, element, attrs) {
link: function (scope, element, attrs) {
var search = $location.search(),
formatArgs = [attrs.errorDisplay],
formattedText,
i;
for (i = 0; angular.isDefined(search['p' + i]); i++) {
formatArgs.push(search['p' + i]);
for (i = 0; angular.isDefined(search['p'+i]); i++) {
formatArgs.push(search['p'+i]);
}
formattedText = encodeAngleBrackets(interpolate.apply(null, formatArgs));
element.html(errorLinkFilter(formattedText, '_blank'));
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
}
};
}]);
+33 -160
View File
@@ -1,67 +1,13 @@
'use strict';
angular.module('examples', [])
.directive('runnableExample', [function() {
var exampleClassNameSelector = '.runnable-example-file';
var tpl =
'<nav class="runnable-example-tabs" ng-if="tabs">' +
' <a ng-class="{active:$index==activeTabIndex}"' +
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
return {
restrict: 'C',
scope : true,
controller : ['$scope', function($scope) {
$scope.setTab = function(index) {
var tab = $scope.tabs[index];
$scope.activeTabIndex = index;
$scope.$broadcast('tabChange', index, tab);
};
}],
compile : function(element) {
element.html(tpl + element.html());
return function(scope, element) {
var node = element[0];
var examples = node.querySelectorAll(exampleClassNameSelector);
var tabs = [];
angular.forEach(examples, function(child, index) {
tabs.push(child.getAttribute('name'));
});
if (tabs.length > 0) {
scope.tabs = tabs;
scope.$on('tabChange', function(e, index, title) {
angular.forEach(examples, function(child) {
child.style.display = 'none';
});
var selected = examples[index];
selected.style.display = 'block';
});
scope.setTab(0);
}
};
}
};
}])
.factory('formPostData', ['$document', function($document) {
return function(url, newWindow, fields) {
return function(url, fields) {
/**
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
* 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.
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
* a new default plnkr, not a plnkr with the desired template.
*/
var target = newWindow ? '_blank' : '_self';
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
angular.forEach(fields, function(value, name) {
var input = angular.element('<input type="hidden" name="' + name + '">');
input.attr('value', value);
@@ -73,119 +19,36 @@ angular.module('examples', [])
};
}])
.factory('createCopyrightNotice', function() {
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*/';
var COPYRIGHT_HTML = '\n\n<!-- \n' + COPYRIGHT + '\n-->';
return function getCopyright(filename) {
switch (filename.substr(filename.lastIndexOf('.'))) {
case '.html':
return COPYRIGHT_HTML;
case '.js':
case '.css':
return COPYRIGHT_JS_CSS;
case '.md':
return COPYRIGHT;
}
return '';
};
})
.directive('plnkrOpener', ['$q', 'getExampleData', 'formPostData', 'createCopyrightNotice', function($q, getExampleData, formPostData, createCopyrightNotice) {
return {
scope: {},
bindToController: {
'examplePath': '@'
},
controllerAs: 'plnkr',
template: '<button ng-click="plnkr.open($event)" class="btn pull-right"> <i class="glyphicon glyphicon-edit">&nbsp;</i> Edit in Plunker</button> ',
controller: [function PlnkrOpenerCtrl() {
var ctrl = this;
ctrl.example = {
path: ctrl.examplePath,
manifest: undefined,
files: undefined,
name: 'AngularJS Example'
};
ctrl.prepareExampleData = function() {
if (ctrl.example.manifest) {
return $q.resolve(ctrl.example);
}
return getExampleData(ctrl.examplePath).then(function(data) {
ctrl.example.files = data.files;
ctrl.example.manifest = data.manifest;
// Build a pretty title for the Plunkr
var exampleNameParts = data.manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
ctrl.example.name = exampleNameParts.join(' - ');
return ctrl.example;
});
};
ctrl.open = function(clickEvent) {
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
var postData = {
'tags[0]': 'angularjs',
'tags[1]': 'example',
'private': true
};
// Make sure the example data is available.
// If an XHR must be made, this might break some pop-up blockers when
// new window is requested
ctrl.prepareExampleData()
.then(function() {
angular.forEach(ctrl.example.files, function(file) {
postData['files[' + file.name + ']'] = file.content + createCopyrightNotice(file.name);
});
postData.description = ctrl.example.name;
formPostData('https://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
ctrl.$onInit = function() {
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.example.path);
};
}]
};
}])
.factory('getExampleData', ['$http', '$q', function($http, $q) {
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder) {
var exampleName = 'AngularJS Example';
// Load the manifest for the example
return $http.get(exampleFolder + '/manifest.json')
$http.get(exampleFolder + '/manifest.json')
.then(function(response) {
return response.data;
})
.then(function(manifest) {
var filePromises = [];
// Build a pretty title for the Plunkr
var exampleNameParts = manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
exampleName = exampleNameParts.join(' - ');
angular.forEach(manifest.files, function(filename) {
filePromises.push($http.get(exampleFolder + '/' + filename, { transformResponse: [] })
.then(function(response) {
// The manifests provide the production index file but Plunkr wants
// a straight index.html
if (filename === 'index-production.html') {
filename = 'index.html';
if (filename === "index-production.html") {
filename = "index.html"
}
return {
@@ -194,11 +57,21 @@ angular.module('examples', [])
};
}));
});
return $q.all(filePromises);
})
.then(function(files) {
var postData = {};
return $q.all({
manifest: manifest,
files: $q.all(filePromises)
angular.forEach(files, function(file) {
postData['files[' + file.name + ']'] = file.content;
});
postData['tags[0]'] = "angularjs";
postData['tags[1]'] = "example";
postData.private = true;
postData.description = exampleName;
formPostData('http://plnkr.co/edit/?p=preview', postData);
});
};
}]);
+24 -34
View File
@@ -1,5 +1,3 @@
'use strict';
angular.module('search', [])
.controller('DocsSearchCtrl', ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
@@ -11,38 +9,34 @@ angular.module('search', [])
$scope.search = function(q) {
var MIN_SEARCH_LENGTH = 2;
if (q.length >= MIN_SEARCH_LENGTH) {
if(q.length >= MIN_SEARCH_LENGTH) {
docsSearch(q).then(function(hits) {
// Make sure the areas are always in the same order
var results = {
api: [],
guide: [],
tutorial: [],
error: [],
misc: []
};
var results = {};
angular.forEach(hits, function(hit) {
var area = hit.area;
var limit = (area === 'api') ? 40 : 14;
var limit = (area == 'api') ? 40 : 14;
results[area] = results[area] || [];
if (results[area].length < limit) {
if(results[area].length < limit) {
results[area].push(hit);
}
});
var totalAreas = Object.keys(results).length;
if (totalAreas > 0) {
var totalAreas = 0;
for(var i in results) {
++totalAreas;
}
if(totalAreas > 0) {
$scope.colClassName = 'cols-' + totalAreas;
}
$scope.hasResults = totalAreas > 0;
$scope.results = results;
});
} else {
}
else {
clearResults();
}
if (!$scope.$$phase) $scope.$apply();
if(!$scope.$$phase) $scope.$apply();
};
$scope.submit = function() {
@@ -50,14 +44,14 @@ angular.module('search', [])
if ($scope.results.api) {
result = $scope.results.api[0];
} else {
for (var i in $scope.results) {
for(var i in $scope.results) {
result = $scope.results[i][0];
if (result) {
if(result) {
break;
}
}
}
if (result) {
if(result) {
$location.path(result.path);
$scope.hideResults();
}
@@ -72,7 +66,7 @@ angular.module('search', [])
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
function($scope, $location, docsSearch) {
docsSearch($location.path().split(/[/.:]/).pop()).then(function(results) {
docsSearch($location.path().split(/[\/\.:]/).pop()).then(function(results) {
$scope.results = {};
angular.forEach(results, function(result) {
var area = $scope.results[result.area] || [];
@@ -90,12 +84,10 @@ angular.module('search', [])
// It should only be used where the browser does not support WebWorkers
function localSearchFactory($http, $timeout, NG_PAGES) {
if (window.console && window.console.log) {
window.console.log('Using Local Search Index');
}
console.log('Using Local Search Index');
// Create the lunr index
var index = lunr(/** @this */ function() {
var index = lunr(function() {
this.ref('path');
this.field('titleWords', {boost: 50});
this.field('members', { boost: 40});
@@ -136,14 +128,12 @@ angular.module('search', [])
// It should only be used where the browser does support WebWorkers
function webWorkerSearchFactory($q, $rootScope, NG_PAGES) {
if (window.console && window.console.log) {
window.console.log('Using WebWorker Search Index');
}
console.log('Using WebWorker Search Index')
var searchIndex = $q.defer();
var results;
var worker = new window.Worker('js/search-worker.js');
var worker = new Worker('js/search-worker.js');
// The worker will send us a message in two situations:
// - when the index has been built, ready to run a query
@@ -151,7 +141,7 @@ angular.module('search', [])
worker.onmessage = function(oEvent) {
$rootScope.$apply(function() {
switch (oEvent.data.e) {
switch(oEvent.data.e) {
case 'index-ready':
searchIndex.resolve();
break;
@@ -202,13 +192,13 @@ angular.module('search', [])
};
})
.directive('docsSearchInput', ['$document', function($document) {
.directive('docsSearchInput', ['$document',function($document) {
return function(scope, element, attrs) {
var ESCAPE_KEY_KEYCODE = 27,
FORWARD_SLASH_KEYCODE = 191;
angular.element($document[0].body).on('keydown', function(event) {
var input = element[0];
if (event.keyCode === FORWARD_SLASH_KEYCODE && $document[0].activeElement !== input) {
if(event.keyCode == FORWARD_SLASH_KEYCODE && document.activeElement != input) {
event.stopPropagation();
event.preventDefault();
input.focus();
@@ -216,7 +206,7 @@ angular.module('search', [])
});
element.on('keydown', function(event) {
if (event.keyCode === ESCAPE_KEY_KEYCODE) {
if(event.keyCode == ESCAPE_KEY_KEYCODE) {
event.stopPropagation();
event.preventDefault();
scope.$apply(function() {
+6 -9
View File
@@ -1,5 +1,3 @@
'use strict';
angular.module('tutorials', [])
.directive('docTutorialNav', function() {
@@ -7,8 +5,7 @@ angular.module('tutorials', [])
'',
'step_00', 'step_01', 'step_02', 'step_03', 'step_04',
'step_05', 'step_06', 'step_07', 'step_08', 'step_09',
'step_10', 'step_11', 'step_12', 'step_13', 'step_14',
'the_end'
'step_10', 'step_11', 'step_12', 'the_end'
];
return {
scope: {},
@@ -22,7 +19,7 @@ angular.module('tutorials', [])
scope.seq = seq;
scope.prev = pages[seq];
scope.next = pages[2 + seq];
scope.diffLo = seq ? (seq - 1) : '0~1';
scope.diffLo = seq ? (seq - 1): '0~1';
scope.diffHi = seq;
element.addClass('btn-group');
@@ -38,15 +35,15 @@ angular.module('tutorials', [])
'step': '@docTutorialReset'
},
template:
'<p><button class="btn" ng-click="show=!show">Workspace Reset Instructions ➤</button></p>\n' +
'<p><a href="" ng-click="show=!show;$event.stopPropagation()">Workspace Reset Instructions ➤</a></p>\n' +
'<div class="alert alert-info" ng-show="show">\n' +
' <p>Reset the workspace to step {{step}}.</p>' +
' <p><pre>git checkout -f step-{{step}}</pre></p>\n' +
' <p>Refresh your browser or check out this step online: ' +
' <p>Refresh your browser or check out this step online: '+
'<a href="http://angular.github.io/angular-phonecat/step-{{step}}/app">Step {{step}} Live Demo</a>.</p>\n' +
'</div>\n' +
'<p>The most important changes are listed below. You can see the full diff on ' +
'<a ng-href="https://github.com/angular/angular-phonecat/compare/step-{{step ? (step - 1): \'0~1\'}}...step-{{step}}" title="See diff on Github">GitHub</a>.\n' +
'<a ng-href="https://github.com/angular/angular-phonecat/compare/step-{{step ? (step - 1): \'0~1\'}}...step-{{step}}">GitHub</a>\n' +
'</p>'
};
});
});
+25 -36
View File
@@ -1,42 +1,31 @@
'use strict';
/* global console */
"use strict";
angular.module('versions', ['currentVersionData', 'allVersionsData'])
angular.module('versions', [])
.directive('versionPicker', function() {
return {
restrict: 'E',
scope: true,
controllerAs: '$ctrl',
controller: ['$location', '$window', 'CURRENT_NG_VERSION', 'ALL_NG_VERSIONS',
/** @this VersionPickerController */
function VersionPickerController($location, $window, CURRENT_NG_VERSION, ALL_NG_VERSIONS) {
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
$scope.docs_version = NG_VERSIONS[0];
$scope.docs_versions = NG_VERSIONS;
var versionStr = CURRENT_NG_VERSION.isSnapshot ? 'snapshot' : CURRENT_NG_VERSION.version;
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
var version = NG_VERSIONS[i];
// NaN will give false here
if (minor <= version.minor) {
continue;
}
version.isLatest = true;
minor = version.minor;
}
this.versions = ALL_NG_VERSIONS;
this.selectedVersion = find(ALL_NG_VERSIONS, function(value) { return value.version.version === versionStr; });
this.jumpToDocsVersion = function(value) {
var currentPagePath = $location.path().replace(/\/$/, '');
$window.location = value.docsUrl + currentPagePath;
};
}],
template:
'<div class="picker version-picker">' +
' <select ng-options="v as v.label group by v.group for v in $ctrl.versions"' +
' ng-model="$ctrl.selectedVersion"' +
' ng-change="$ctrl.jumpToDocsVersion($ctrl.selectedVersion)"' +
' class="docs-version-jump">' +
' </select>' +
'</div>'
$scope.getGroupName = function(v) {
return v.isLatest ? 'Latest' : ('v' + v.major + '.' + v.minor + '.x');
};
function find(collection, matcherFn) {
for (var i = 0, ii = collection.length; i < ii; ++i) {
if (matcherFn(collection[i])) {
return collection[i];
}
}
}
});
$scope.jumpToDocsVersion = function(version) {
var currentPagePath = $location.path().replace(/\/$/, '');
// TODO: We need to do some munging of the path for different versions of the API...
$window.location = version.docsUrl + currentPagePath;
};
}]);
-23
View File
@@ -1,23 +0,0 @@
{
"root": true,
"extends": "../../../.eslintrc-browser.json",
"env": {
"jasmine": true
},
"rules": {
// Some rules are not that important in tests and conflict with
// Jasmine or would make it easier to write some tests; we disable
// those ones here.
"no-invalid-this": "off",
"no-throw-literal": "off",
"no-unused-vars": "off"
},
"globals": {
// ngMocks
"module": false,
"inject": true
}
}
+1 -3
View File
@@ -1,6 +1,4 @@
'use strict';
describe('code', function() {
describe("code", function() {
var prettyPrintOne, oldPP;
var compile, scope;
+7 -13
View File
@@ -1,18 +1,12 @@
'use strict';
describe('DocsController', function() {
describe("DocsController", function() {
var $scope;
angular.module('fake', [])
.value('$cookies', {})
.value('openPlunkr', function() {})
.value('NG_PAGES', {})
.value('NG_NAVIGATION', {});
angular.module('currentVersionData', [])
.value('CURRENT_NG_VERSION', {});
angular.module('allVersionsData', [])
.value('ALL_NG_VERSIONS', {});
.value('NG_NAVIGATION', {})
.value('NG_VERSION', {});
beforeEach(module('fake', 'DocsController'));
beforeEach(inject(function($rootScope, $controller) {
@@ -22,7 +16,7 @@ describe('DocsController', function() {
describe('afterPartialLoaded', function() {
it('should update the Google Analytics with currentPage path if currentPage exists', inject(function($window) {
it("should update the Google Analytics with currentPage path if currentPage exists", inject(function($window) {
$window._gaq = [];
$scope.currentPage = { path: 'a/b/c' };
$scope.$broadcast('$includeContentLoaded');
@@ -30,9 +24,9 @@ describe('DocsController', function() {
}));
it('should update the Google Analytics with $location.path if currentPage is missing', inject(function($window, $location) {
it("should update the Google Analytics with $location.path if currentPage is missing", inject(function($window, $location) {
$window._gaq = [];
spyOn($location, 'path').and.returnValue('x/y/z');
spyOn($location, 'path').andReturn('x/y/z');
$scope.$broadcast('$includeContentLoaded');
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
-166
View File
@@ -1,166 +0,0 @@
'use strict';
describe('errors', function() {
// Mock `ngSanitize` module
angular.
module('ngSanitize', []).
value('$sanitize', jasmine.createSpy('$sanitize').and.callFake(angular.identity));
beforeEach(module('errors'));
describe('errorDisplay', function() {
var $sanitize;
var errorLinkFilter;
beforeEach(inject(function(_$sanitize_, _errorLinkFilter_) {
$sanitize = _$sanitize_;
errorLinkFilter = _errorLinkFilter_;
}));
it('should return empty input unchanged', function() {
var inputs = [undefined, null, false, 0, ''];
var remaining = inputs.length;
inputs.forEach(function(falsyValue) {
expect(errorLinkFilter(falsyValue)).toBe(falsyValue);
remaining--;
});
expect(remaining).toBe(0);
});
it('should recognize URLs and convert them to `<a>`', function() {
var urls = [
['ftp://foo/bar?baz#qux'],
['http://foo/bar?baz#qux'],
['https://foo/bar?baz#qux'],
['mailto:foo_bar@baz.qux', null, 'foo_bar@baz.qux'],
['foo_bar@baz.qux', 'mailto:foo_bar@baz.qux', 'foo_bar@baz.qux']
];
var remaining = urls.length;
urls.forEach(function(values) {
var actualUrl = values[0];
var expectedUrl = values[1] || actualUrl;
var expectedText = values[2] || expectedUrl;
var anchor = '<a href="' + expectedUrl + '">' + expectedText + '</a>';
var input = 'start ' + actualUrl + ' end';
var output = 'start ' + anchor + ' end';
expect(errorLinkFilter(input)).toBe(output);
remaining--;
});
expect(remaining).toBe(0);
});
it('should not recognize stack-traces as URLs', function() {
var urls = [
'ftp://foo/bar?baz#qux:4:2',
'http://foo/bar?baz#qux:4:2',
'https://foo/bar?baz#qux:4:2',
'mailto:foo_bar@baz.qux:4:2',
'foo_bar@baz.qux:4:2'
];
var remaining = urls.length;
urls.forEach(function(url) {
var input = 'start ' + url + ' end';
expect(errorLinkFilter(input)).toBe(input);
remaining--;
});
expect(remaining).toBe(0);
});
it('should should set `[target]` if specified', function() {
var url = 'https://foo/bar?baz#qux';
var target = '_blank';
var outputWithoutTarget = '<a href="' + url + '">' + url + '</a>';
var outputWithTarget = '<a target="' + target + '" href="' + url + '">' + url + '</a>';
expect(errorLinkFilter(url)).toBe(outputWithoutTarget);
expect(errorLinkFilter(url, target)).toBe(outputWithTarget);
});
it('should truncate the contents of the generated `<a>` to 60 characters', function() {
var looongUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo';
var truncatedUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooo...';
var output = '<a href="' + looongUrl + '">' + truncatedUrl + '</a>';
expect(looongUrl.length).toBeGreaterThan(60);
expect(truncatedUrl.length).toBe(60);
expect(errorLinkFilter(looongUrl)).toBe(output);
});
it('should pass the final string through `$sanitize`', function() {
$sanitize.calls.reset();
var input = 'start https://foo/bar?baz#qux end';
var output = errorLinkFilter(input);
expect($sanitize).toHaveBeenCalledTimes(1);
expect($sanitize).toHaveBeenCalledWith(output);
});
});
describe('errorDisplay', function() {
var $compile;
var $location;
var $rootScope;
var errorLinkFilter;
beforeEach(module(function($provide) {
$provide.decorator('errorLinkFilter', function() {
errorLinkFilter = jasmine.createSpy('errorLinkFilter');
errorLinkFilter.and.callFake(angular.identity);
return errorLinkFilter;
});
}));
beforeEach(inject(function(_$compile_, _$location_, _$rootScope_) {
$compile = _$compile_;
$location = _$location_;
$rootScope = _$rootScope_;
}));
it('should set the element\'s HTML', function() {
var elem = $compile('<span error-display="bar">foo</span>')($rootScope);
expect(elem.html()).toBe('bar');
});
it('should interpolate the contents against `$location.search()`', function() {
spyOn($location, 'search').and.returnValue({p0: 'foo', p1: 'bar'});
var elem = $compile('<span error-display="foo = {0}, bar = {1}"></span>')($rootScope);
expect(elem.html()).toBe('foo = foo, bar = bar');
});
it('should pass the interpolated text through `errorLinkFilter`', function() {
$location.search = jasmine.createSpy('search').and.returnValue({p0: 'foo'});
$compile('<span error-display="foo = {0}"></span>')($rootScope);
expect(errorLinkFilter).toHaveBeenCalledTimes(1);
expect(errorLinkFilter).toHaveBeenCalledWith('foo = foo', '_blank');
});
it('should encode `<` and `>`', function() {
var elem = $compile('<span error-display="&lt;xyz&gt;"></span>')($rootScope);
expect(elem.text()).toBe('<xyz>');
});
});
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.1.1",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
}
}
+12 -29
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
var path = require('canonical-path');
var packagePath = __dirname;
@@ -6,18 +6,18 @@ var packagePath = __dirname;
var Package = require('dgeni').Package;
// Create and export a new Dgeni package called angularjs. This package depends upon
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages node module.
// the ngdoc,nunjucks and examples packages defined in the dgeni-packages npm module.
module.exports = new Package('angularjs', [
require('dgeni-packages/ngdoc'),
require('dgeni-packages/nunjucks'),
require('dgeni-packages/examples'),
require('dgeni-packages/git')
require('dgeni-packages/examples')
])
.factory(require('./services/errorNamespaceMap'))
.factory(require('./services/getMinerrInfo'))
.factory(require('./services/getVersion'))
.factory(require('./services/gitData'))
.factory(require('./services/deployments/debug'))
.factory(require('./services/deployments/default'))
@@ -26,6 +26,7 @@ module.exports = new Package('angularjs', [
.factory(require('./inline-tag-defs/type'))
.processor(require('./processors/error-docs'))
.processor(require('./processors/index-page'))
.processor(require('./processors/keywords'))
@@ -42,7 +43,7 @@ module.exports = new Package('angularjs', [
readFilesProcessor.basePath = path.resolve(__dirname,'../..');
readFilesProcessor.sourceFiles = [
{ include: 'src/**/*.js', exclude: 'src/angular.bind.js', basePath: 'src' },
{ include: 'src/**/*.js', basePath: 'src' },
{ include: 'docs/content/**/*.ngdoc', basePath: 'docs/content' }
];
@@ -52,12 +53,8 @@ module.exports = new Package('angularjs', [
.config(function(parseTagsProcessor) {
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/deprecated')); // this will override the jsdoc version
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/tutorial-step'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/sortOrder'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/installation'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/this'));
})
@@ -67,11 +64,7 @@ module.exports = new Package('angularjs', [
.config(function(templateFinder, renderDocsProcessor, gitData) {
// We are completely overwriting the folders
templateFinder.templateFolders.length = 0;
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates/examples'));
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates/ngdoc'));
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates/app'));
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates'));
renderDocsProcessor.extraData.git = gitData;
})
@@ -94,7 +87,7 @@ module.exports = new Package('angularjs', [
docTypes: ['overview', 'tutorial'],
getPath: function(doc) {
var docPath = path.dirname(doc.fileInfo.relativePath);
if (doc.fileInfo.baseName !== 'index') {
if ( doc.fileInfo.baseName !== 'index' ) {
docPath = path.join(docPath, doc.fileInfo.baseName);
}
return docPath;
@@ -115,12 +108,12 @@ module.exports = new Package('angularjs', [
});
computePathsProcessor.pathTemplates.push({
docTypes: ['module'],
docTypes: ['module' ],
pathTemplate: '${area}/${name}',
outputPathTemplate: 'partials/${area}/${name}.html'
});
computePathsProcessor.pathTemplates.push({
docTypes: ['componentGroup'],
docTypes: ['componentGroup' ],
pathTemplate: '${area}/${moduleName}/${groupType}',
outputPathTemplate: 'partials/${area}/${moduleName}/${groupType}.html'
});
@@ -132,16 +125,10 @@ module.exports = new Package('angularjs', [
});
computeIdsProcessor.idTemplates.push({
docTypes: ['error'],
getId: function(doc) { return 'error:' + doc.namespace + ':' + doc.name; },
getAliases: function(doc) { return [doc.name, doc.namespace + ':' + doc.name, doc.id]; }
},
{
docTypes: ['errorNamespace'],
docTypes: ['error', 'errorNamespace'],
getId: function(doc) { return 'error:' + doc.name; },
getAliases: function(doc) { return [doc.id]; }
}
);
});
})
.config(function(checkAnchorLinksProcessor) {
@@ -178,8 +165,4 @@ module.exports = new Package('angularjs', [
jqueryDeployment,
productionDeployment
];
})
.config(function(generateKeywordsProcessor) {
generateKeywordsProcessor.docTypesToIgnore = ['componentGroup'];
});
+3 -4
View File
@@ -1,6 +1,5 @@
'use strict';
"use strict";
// eslint-disable-next-line new-cap
var encoder = new require('node-html-encoder').Encoder();
/**
@@ -12,7 +11,7 @@ module.exports = function typeInlineTagDef(getTypeClass) {
return {
name: 'type',
handler: function(doc, tagName, tagDescription) {
return '<a href="" class="' + getTypeClass(tagDescription) + '">' + encoder.htmlEncode(tagDescription) + '</a>';
return '<a href="" class="' + getTypeClass(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
}
};
};
};
+7 -4
View File
@@ -1,4 +1,7 @@
'use strict';
"use strict";
var _ = require('lodash');
var path = require('canonical-path');
/**
* @dgProcessor errorDocsProcessor
@@ -15,7 +18,7 @@ module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
docs.forEach(function(doc) {
var parts, namespaceDoc;
if (doc.docType === 'error') {
if ( doc.docType === 'error' ) {
// Parse out the error info from the id
parts = doc.name.split(':');
@@ -24,7 +27,7 @@ module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
// Get or create the relevant errorNamespace doc
namespaceDoc = errorNamespaceMap.get(doc.namespace);
if (!namespaceDoc) {
if ( !namespaceDoc ) {
namespaceDoc = {
area: 'error',
name: doc.namespace,
@@ -46,4 +49,4 @@ module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
});
}
};
};
};
+4 -3
View File
@@ -1,6 +1,7 @@
'use strict';
"use strict";
var _ = require('lodash');
var path = require('canonical-path');
/**
* @dgProcessor generateIndexPagesProcessor
@@ -20,7 +21,7 @@ module.exports = function generateIndexPagesProcessor() {
// Collect up all the areas in the docs
var areas = {};
docs.forEach(function(doc) {
if (doc.area) {
if ( doc.area ) {
areas[doc.area] = doc.area;
}
});
@@ -39,4 +40,4 @@ module.exports = function generateIndexPagesProcessor() {
});
}
};
};
};
+28 -35
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
var _ = require('lodash');
var fs = require('fs');
@@ -16,11 +16,9 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
ignoreWordsFile: undefined,
areasToSearch: ['api', 'guide', 'misc', 'error', 'tutorial'],
propertiesToIgnore: [],
docTypesToIgnore: [],
$validate: {
ignoreWordsFile: { },
areasToSearch: { presence: true },
docTypesToIgnore: { },
propertiesToIgnore: { }
},
$runAfter: ['memberDocsProcessor'],
@@ -30,14 +28,13 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
// Keywords to ignore
var wordsToIgnore = [];
var propertiesToIgnore;
var docTypesToIgnore;
var areasToSearch;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[$_a-z])[\w\-_]+)/;
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
// Load up the keywords to ignore, if specified in the config
if (this.ignoreWordsFile) {
if ( this.ignoreWordsFile ) {
var ignoreWordsPath = path.resolve(readFilesProcessor.basePath, this.ignoreWordsFile);
wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm);
@@ -50,8 +47,6 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
areasToSearch = _.indexBy(this.areasToSearch);
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
log.debug('Properties to ignore', propertiesToIgnore);
docTypesToIgnore = _.indexBy(this.docTypesToIgnore);
log.debug('Doc types to ignore', docTypesToIgnore);
var ignoreWordsMap = _.indexBy(wordsToIgnore);
@@ -59,7 +54,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
// without the ng to the title text, e.g. "controller".
function extractTitleWords(title) {
var match = /ng([A-Z]\w*)/.exec(title);
if (match) {
if ( match ) {
title = title + ' ' + match[1].toLowerCase();
}
return title;
@@ -67,12 +62,12 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
function extractWords(text, words, keywordMap) {
var tokens = text.toLowerCase().split(/[.\s,`'"#]+/mg);
_.forEach(tokens, function(token) {
var tokens = text.toLowerCase().split(/[\.\s,`'"#]+/mg);
_.forEach(tokens, function(token){
var match = token.match(KEYWORD_REGEX);
if (match) {
if (match){
var key = match[1];
if (!keywordMap[key]) {
if ( !keywordMap[key]) {
keywordMap[key] = true;
words.push(key);
}
@@ -83,36 +78,34 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
// We are only interested in docs that live in the right area
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
docs = _.filter(docs, function(doc) { return !docTypesToIgnore[doc.docType]; });
_.forEach(docs, function(doc) {
var words = [];
var keywordMap = _.clone(ignoreWordsMap);
var members = [];
var membersMap = {};
var words = [];
var keywordMap = _.clone(ignoreWordsMap);
var members = [];
var membersMap = {};
// Search each top level property of the document for search terms
_.forEach(doc, function(value, key) {
// Search each top level property of the document for search terms
_.forEach(doc, function(value, key) {
if ( _.isString(value) && !propertiesToIgnore[key] ) {
extractWords(value, words, keywordMap);
}
if (_.isString(value) && !propertiesToIgnore[key]) {
extractWords(value, words, keywordMap);
}
if (key === 'methods' || key === 'properties' || key === 'events') {
_.forEach(value, function(member) {
extractWords(member.name, members, membersMap);
});
}
});
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
_.forEach(value, function(member) {
extractWords(member.name, members, membersMap);
});
}
});
doc.searchTerms = {
titleWords: extractTitleWords(doc.name),
keywords: _.sortBy(words).join(' '),
members: _.sortBy(members).join(' ')
};
doc.searchTerms = {
titleWords: extractTitleWords(doc.name),
keywords: _.sortBy(words).join(' '),
members: _.sortBy(members).join(' ')
};
});
+4 -4
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
var _ = require('lodash');
var path = require('canonical-path');
@@ -67,7 +67,7 @@ module.exports = function generatePagesDataProcessor(log) {
})
.tap(function(docTypes) {
if (docTypes.input) {
if ( docTypes.input ) {
docTypes.directive = docTypes.directive || [];
// Combine input docTypes into directive docTypes
docTypes.directive = docTypes.directive.concat(docTypes.input);
@@ -79,7 +79,7 @@ module.exports = function generatePagesDataProcessor(log) {
sectionPages = _.sortBy(sectionPages, 'name');
if (sectionPages.length > 0) {
if ( sectionPages.length > 0 ) {
// Push a navItem for this section
navItems.push({
name: sectionName,
@@ -158,7 +158,7 @@ module.exports = function generatePagesDataProcessor(log) {
// We are only interested in pages that are not landing pages
var navPages = _.filter(pages, function(page) {
return page.docType !== 'componentGroup';
return page.docType != 'componentGroup';
});
// Generate an object collection of pages that is grouped by area e.g.
+16 -90
View File
@@ -1,7 +1,6 @@
'use strict';
"use strict";
var exec = require('shelljs').exec;
var semver = require('semver');
var _ = require('lodash');
/**
* @dgProcessor generateVersionDocProcessor
@@ -13,96 +12,23 @@ module.exports = function generateVersionDocProcessor(gitData) {
return {
$runAfter: ['generatePagesDataProcessor'],
$runBefore: ['rendering-docs'],
// 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 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);
var versionDoc = {
docType: 'versions-data',
id: 'versions-data',
template: 'versions-data.template.js',
outputPath: 'js/versions-data.js',
currentVersion: gitData.version
};
docs.push({
docType: 'current-version-data',
id: 'current-version-data',
template: 'angular-service.template.js',
outputPath: 'js/current-version-data.js',
ngModuleName: 'currentVersionData',
serviceName: 'CURRENT_NG_VERSION',
serviceValue: currentVersion
});
versionDoc.versions = _(gitData.versions)
.filter(function(version) { return version.major > 0; })
.push(gitData.version)
.reverse()
.value();
docs.push({
docType: 'allversions-data',
id: 'allversions-data',
template: 'angular-service.template.js',
outputPath: 'js/all-versions-data.js',
ngModuleName: 'allVersionsData',
serviceName: 'ALL_NG_VERSIONS',
serviceValue: allVersions
});
function processAllVersionsResponse(versions) {
var latestMap = {};
versions = versions
.filter(function(versionStr) {
return blacklist.indexOf(versionStr) === -1;
})
.map(function(versionStr) {
return semver.parse(versionStr);
})
.filter(function(version) {
return version && version.major > 0;
})
.map(function(version) {
var key = version.major + '.' + version.minor;
var latest = latestMap[key];
if (!latest || version.compare(latest) > 0) {
latestMap[key] = version;
}
return version;
})
.map(function(version) {
return makeOption(version);
})
.reverse();
var latest = sortObject(latestMap, reverse(semver.compare))
.map(function(version) { return makeOption(version, 'Latest'); });
return [makeOption({version: 'snapshot'}, 'Latest', 'master')]
.concat(latest)
.concat(versions);
}
function makeOption(version, group, label) {
return {
version: version,
label: label || 'v' + version.raw,
group: group || 'v' + version.major + '.' + version.minor,
docsUrl: createDocsUrl(version)
};
}
function createDocsUrl(version) {
var url = 'https://code.angularjs.org/' + version.version + '/docs';
// Versions before 1.0.2 had a different docs folder name
if (version.major === 1 && version.minor === 0 && version.patch < 2) {
url += '-' + version.version;
}
return url;
}
function reverse(fn) {
return function(left, right) { return -fn(left, right); };
}
function sortObject(obj, cmp) {
return Object.keys(obj).map(function(key) { return obj[key]; }).sort(cmp);
}
docs.push(versionDoc);
}
};
};
};
+7 -7
View File
@@ -1,11 +1,11 @@
'use strict';
"use strict";
module.exports = function debugDeployment(getVersion) {
return {
name: 'debug',
examples: {
commonFiles: {
scripts: ['../../../angular.js']
scripts: [ '../../../angular.js' ]
},
dependencyPath: '../../../'
},
@@ -17,13 +17,13 @@ module.exports = function debugDeployment(getVersion) {
'../angular-sanitize.js',
'../angular-touch.js',
'../angular-animate.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.js',
'js/angular-bootstrap/dropdown-toggle.js',
'components/lunr-' + getVersion('lunr') + '/lunr.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
'js/all-versions-data.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.js'
@@ -36,4 +36,4 @@ module.exports = function debugDeployment(getVersion) {
'css/animations.css'
]
};
};
};
+7 -7
View File
@@ -1,11 +1,11 @@
'use strict';
"use strict";
module.exports = function defaultDeployment(getVersion) {
return {
name: 'default',
examples: {
commonFiles: {
scripts: ['../../../angular.min.js']
scripts: [ '../../../angular.min.js' ]
},
dependencyPath: '../../../'
},
@@ -17,13 +17,13 @@ module.exports = function defaultDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
'js/all-versions-data.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
@@ -36,4 +36,4 @@ module.exports = function defaultDeployment(getVersion) {
'css/animations.css'
]
};
};
};
+6 -6
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
module.exports = function jqueryDeployment(getVersion) {
return {
@@ -21,13 +21,13 @@ module.exports = function jqueryDeployment(getVersion) {
'../angular-sanitize.min.js',
'../angular-touch.min.js',
'../angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
'js/all-versions-data.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
@@ -40,4 +40,4 @@ module.exports = function jqueryDeployment(getVersion) {
'css/animations.css'
]
};
};
};
+9 -23
View File
@@ -1,30 +1,16 @@
'use strict';
"use strict";
var versionInfo = require('../../../../lib/versions/version-info');
var googleCdnUrl = '//ajax.googleapis.com/ajax/libs/angularjs/';
var angularCodeUrl = '//code.angularjs.org/';
var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
// The plnkr examples must use the code.angularjs.org repo for the snapshot,
// and the cdn for the tagged version and, if the build is not tagged, the currentVersion.
//
// The currentVersion may not be available on the cdn (e.g. if built locally, or hasn't been pushed
// yet). This will lead to a 404, but this is preferable to loading a version with which the example
// might not work (possibly in subtle ways).
var examplesCdnUrl = versionInfo.currentVersion.isSnapshot ?
(angularCodeUrl + 'snapshot') :
(googleCdnUrl + (versionInfo.currentVersion.version || versionInfo.currentVersion));
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.cdnVersion;
module.exports = function productionDeployment(getVersion) {
return {
name: 'production',
examples: {
commonFiles: {
scripts: [examplesCdnUrl + '/angular.min.js']
scripts: [ cdnUrl + '/angular.min.js' ]
},
dependencyPath: examplesCdnUrl + '/'
dependencyPath: cdnUrl + '/'
},
scripts: [
cdnUrl + '/angular.min.js',
@@ -34,13 +20,13 @@ module.exports = function productionDeployment(getVersion) {
cdnUrl + '/angular-sanitize.min.js',
cdnUrl + '/angular-touch.min.js',
cdnUrl + '/angular-animate.min.js',
'components/marked-' + getVersion('marked') + '/lib/marked.js',
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
'js/angular-bootstrap/bootstrap.min.js',
'js/angular-bootstrap/dropdown-toggle.min.js',
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
'js/current-version-data.js',
'https://code.angularjs.org/snapshot/docs/js/all-versions-data.js',
'js/versions-data.js',
'js/pages-data.js',
'js/nav-data.js',
'js/docs.min.js'
@@ -53,4 +39,4 @@ module.exports = function productionDeployment(getVersion) {
'css/animations.css'
]
};
};
};
+2 -2
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
var StringMap = require('stringmap');
/**
@@ -7,4 +7,4 @@ var StringMap = require('stringmap');
*/
module.exports = function errorNamespaceMap() {
return new StringMap();
};
};
+1 -1
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
var path = require('canonical-path');

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