Compare commits
208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a84393eadb | |||
| c429ad82f5 | |||
| 900c7cd923 | |||
| 2d3303ddda | |||
| a985adfdab | |||
| ca41996ef7 | |||
| 9a60408c80 | |||
| 09f6061a8e | |||
| 2d1ee4bffd | |||
| a412622f69 | |||
| 63ffe5c360 | |||
| 2fc954d33a | |||
| 512c081187 | |||
| 2563ff7ba9 | |||
| 0a641c0181 | |||
| da04571dbc | |||
| 7f1cd3e6a2 | |||
| 6d85f24e20 | |||
| 0afd775433 | |||
| 8eb01216b4 | |||
| 323f9ab736 | |||
| 5ba4419e26 | |||
| 529b2507bd | |||
| 6d19aa2e7c | |||
| bf35d53855 | |||
| 6c4581fcb6 | |||
| 620a20d1b3 | |||
| 1f8431bfaa | |||
| b8773a71b5 | |||
| 8a63071ab0 | |||
| e2a0368726 | |||
| d9157849df | |||
| d558dc5f95 | |||
| 616695eb05 | |||
| 9ac4e5a64b | |||
| fcb6e1e96b | |||
| cf972fd0bd | |||
| ffc3115705 | |||
| 9590bcf062 | |||
| 689c01f599 | |||
| 2334a5101d | |||
| ed7777d3e1 | |||
| a1648737bd | |||
| 420586bd09 | |||
| d89afc488f | |||
| 0a8a6fa36b | |||
| e1a182b105 | |||
| 214f6822c3 | |||
| 9c5a1cd43c | |||
| 8120ab2f77 | |||
| 2f08eae48f | |||
| 6610ae816f | |||
| fa56f8eadb | |||
| 7882c1c6ae | |||
| 84a6ef4d21 | |||
| 4d680c3fad | |||
| bab3069dff | |||
| 4cb8ac61c7 | |||
| 9d28a79219 | |||
| c4489eb3cb | |||
| 7caf91300f | |||
| 0c1b54f04c | |||
| 85e392f354 | |||
| c98e08fd87 | |||
| 33cc75e6fc | |||
| 474865242c | |||
| 0292e6a1a8 | |||
| de193422a3 | |||
| ff228fb524 | |||
| 8709539d4c | |||
| 2995b54afd | |||
| e26256fb70 | |||
| e45f9b66fa | |||
| 158f1aec86 | |||
| f53a7f62bb | |||
| d2b08a0465 | |||
| 43c4029c8a | |||
| 55ac985373 | |||
| 37b6ed3225 | |||
| c5bf9daef6 | |||
| be01cebfae | |||
| 7a81e6fe2d | |||
| 9c49eb131a | |||
| 374a302b90 | |||
| b3da88077f | |||
| 6454f51741 | |||
| e509ab5be6 | |||
| 592bf516e5 | |||
| 8cdafe46e3 | |||
| 45c5688d42 | |||
| 7bb2414bf6 | |||
| da11c1bcee | |||
| a80697938e | |||
| 1d9ad76f1f | |||
| 01387ba3c3 | |||
| f163c90555 | |||
| 4e94864e54 | |||
| 54c4041ebc | |||
| f780aba434 | |||
| 057f78de8b | |||
| 7a36128efc | |||
| d2cd8b9bb6 | |||
| 937942f5ad | |||
| 75e876424d | |||
| 19fab4a1d7 | |||
| d1293540e1 | |||
| 22f66025db | |||
| 6f8ddb6d43 | |||
| 34590e15d4 | |||
| 83098b9add | |||
| 5d8861fb2f | |||
| b9f7c453e0 | |||
| 750344129e | |||
| 74da034077 | |||
| 91ef94d284 | |||
| ab9b021572 | |||
| b268c0b7b4 | |||
| b0c19f8b06 | |||
| bbc2a0ae48 | |||
| ca53dfcc18 | |||
| ce6a96b0d7 | |||
| d4b359f4b2 | |||
| 8d841c3405 | |||
| 2b285c75f4 | |||
| 6e4464331d | |||
| 2f8db1bf01 | |||
| 838cf4be3c | |||
| de2a56bbc8 | |||
| 55ad192e4a | |||
| 5b4713e43e | |||
| 3fa9aba0cc | |||
| 1bba358a75 | |||
| 7a4124c298 | |||
| 2512a81e09 | |||
| 44c9d1616a | |||
| 5758d73964 | |||
| 6bd6dbff49 | |||
| 7170f9d9ca | |||
| 1c0f721368 | |||
| 2a5a52a76c | |||
| c690946469 | |||
| 87b0055c80 | |||
| 2116857a2a | |||
| 0f58334b7b | |||
| bcc257b459 | |||
| 980fb395e4 | |||
| 62ed26a84f | |||
| 59f1f4e19a | |||
| cb51116dbd | |||
| c1f34e8eeb | |||
| 7bf5429e3b | |||
| d3da55c40f | |||
| 70edec947c | |||
| fe17c0e066 | |||
| e403682444 | |||
| 27d441b0d6 | |||
| 8a944b0872 | |||
| 786a1a4429 | |||
| 8e5c4e92f7 | |||
| 46d24ae4c8 | |||
| 9dd33c09b1 | |||
| fea8240c81 | |||
| 3d2b1be211 | |||
| f08a0c5ad1 | |||
| 6f1e0ba563 | |||
| 540338f9a5 | |||
| 0e6a700807 | |||
| 4fc40bc932 | |||
| 216724b4cb | |||
| 9bd1645970 | |||
| 3397a031a1 | |||
| 5ec5aa7751 | |||
| bf5ac5261d | |||
| 91b7cd9b74 | |||
| 7b2ecf42c6 | |||
| 256d9a948c | |||
| 99fc6cda98 | |||
| 690b69b9cd | |||
| 4262f15e16 | |||
| 3a8d1354ce | |||
| f9387c6890 | |||
| 48d0ffcbc4 | |||
| 3485ba1e2b | |||
| 2f61145475 | |||
| 8c618d896b | |||
| 68d4dc5b71 | |||
| 03a4a96cf9 | |||
| 655c52a621 | |||
| fa3ddba5f2 | |||
| c4a1b6124e | |||
| e52d731bfd | |||
| 9b72843018 | |||
| 9c1f8ea70b | |||
| 9fde5648e4 | |||
| ea829620b2 | |||
| 1731d091f8 | |||
| 9d3704ca46 | |||
| 215dff34dd | |||
| fa8c399fad | |||
| 7295c60ffb | |||
| fa01571036 | |||
| dbc698517f | |||
| a7f3761eda | |||
| 5a98e806ef | |||
| 808f984ec0 | |||
| 698af191de | |||
| 7a413df5e4 | |||
| 4994acd26e |
+1
-1
@@ -1,4 +1,4 @@
|
||||
# https://editorconfig.org
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
build/**
|
||||
docs/app/assets/js/angular-bootstrap/**
|
||||
docs/config/templates/**
|
||||
node_modules/**
|
||||
lib/htmlparser/**
|
||||
src/angular.bind.js
|
||||
src/ngParseExt/ucd.js
|
||||
i18n/closure/**
|
||||
tmp/**
|
||||
vendor/**
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "./.eslintrc-base.json",
|
||||
"env": {
|
||||
"browser": false,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"plugins": [
|
||||
"promise"
|
||||
]
|
||||
}
|
||||
@@ -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" }}]
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "./.eslintrc-node.json"
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<!--
|
||||
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATION
|
||||
-->
|
||||
|
||||
<!--
|
||||
- For *SUPPORT QUESTIONS*, use one of the
|
||||
[support channels](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question).
|
||||
- Before submitting, please **SEARCH GITHUB** for a similar issue or PR. -->
|
||||
|
||||
**I'm submitting a ...**
|
||||
<!-- (check one with "x") -->
|
||||
- [ ] bug report
|
||||
- [ ] feature request
|
||||
- [ ] other <!--(Please do not submit support requests here - see above)-->
|
||||
|
||||
**Current behavior:**
|
||||
<!-- Describe how the bug manifests / how the current features are insufficient. -->
|
||||
|
||||
**Expected / new behavior:**
|
||||
<!-- Describe what the behavior would be without the bug / how the feature would improve AngularJS -->
|
||||
|
||||
**Minimal reproduction of the problem with instructions:**
|
||||
<!--
|
||||
If the current behavior is a bug or you can illustrate your feature request better with an example,
|
||||
please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
|
||||
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:yBpEi4).
|
||||
-->
|
||||
|
||||
**AngularJS version:** 1.x.y
|
||||
<!-- Check whether this is still an issue in the most recent stable or in the snapshot AngularJS
|
||||
version (https://code.angularjs.org/snapshot/) -->
|
||||
|
||||
**Browser:** [all | Chrome XX | Firefox XX | Edge XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView | Opera XX ]
|
||||
<!-- All browsers where this could be reproduced (and Operating System if relevant) -->
|
||||
|
||||
**Anything else:**
|
||||
<!-- e.g. stacktraces, related issues, suggestions how to fix -->
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- General PR submission guidelines https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#submit-pr -->
|
||||
**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/DEVELOPERS.md#commits)
|
||||
- [ ] Fix/Feature: [Docs](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#documentation) have been added/updated
|
||||
- [ ] Fix/Feature: Tests have been added; existing tests pass
|
||||
|
||||
**Other information**:
|
||||
|
||||
+3
-5
@@ -1,5 +1,4 @@
|
||||
/build/
|
||||
/deploy/
|
||||
/benchpress-build/
|
||||
.DS_Store
|
||||
gen_docs.disable
|
||||
@@ -10,7 +9,8 @@ performance/temp*.html
|
||||
*~
|
||||
*.swp
|
||||
angular.js.tmproj
|
||||
node_modules/
|
||||
/node_modules/
|
||||
bower_components/
|
||||
angular.xcodeproj
|
||||
.idea
|
||||
*.iml
|
||||
@@ -19,6 +19,4 @@ angular.xcodeproj
|
||||
libpeerconnection.log
|
||||
npm-debug.log
|
||||
/tmp/
|
||||
.vscode
|
||||
*.log
|
||||
*.stackdump
|
||||
/scripts/bower/bower-*
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"excludeFiles": ["src/ngLocale/**"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
|
||||
"disallowSpaceBeforeBinaryOperators": [","],
|
||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInNamedFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"requireSpaceBeforeKeywords": [
|
||||
"else",
|
||||
"while",
|
||||
"catch"
|
||||
],
|
||||
"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
|
||||
},
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"validateLineBreaks": "LF"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules/**
|
||||
lib/htmlparser/**
|
||||
@@ -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,29 +0,0 @@
|
||||
Andres Ornelas <aornelas@google.com>
|
||||
Caitlin Potter <caitpotter88@gmail.com>
|
||||
Caitlin Potter <caitpotter88@gmail.com> <snowball@defpixel.com>
|
||||
Di Peng <pengdi@google.com>
|
||||
Di Peng <pengdi@google.com> <pengdi@go.wustl.edu>
|
||||
Georgios Kalpakas <kalpakas.g@gmail.com>
|
||||
Georgios Kalpakas <kalpakas.g@gmail.com> <g.kalpakas@hotmail.com>
|
||||
Julie Ralph <ju.ralph@gmail.com>
|
||||
Lucas Galfaso <lgalfaso@gmail.com>
|
||||
Martin Staffa <mjstaffa@gmail.com>
|
||||
Martin Staffa <mjstaffa@gmail.com> <mjstaffa@googlemail.com>
|
||||
Matias Niemelä <matias@yearofmoo.com>
|
||||
Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
|
||||
Misko Hevery <misko@hevery.com>
|
||||
Misko Hevery <misko@hevery.com> <misko@google.com>
|
||||
Igor Minar <igor@angularjs.org>
|
||||
Igor Minar <igor@angularjs.org> <iiminar@gmail.com>
|
||||
Igor Minar <igor@angularjs.org> <iminar@google.com>
|
||||
Igor Minar <igor@angularjs.org> <iminar@dhcp-172-19-37-154.mtv.corp.google.com>
|
||||
Pawel Kozlowski <pkozlowski.opensource@gmail.com>
|
||||
Peter Bacon Darwin <pete@bacondarwin.com>
|
||||
Rodric Haddad <rody@rodyhaddad.com>
|
||||
Shahar Talmi <shahar.talmi@gmail.com>
|
||||
Shahar Talmi <shahar.talmi@gmail.com> <shahart@wix.com>
|
||||
Shyam Seshadri <shyamseshadri@google.com>
|
||||
Shyam Seshadri <shyamseshadri@google.com> <shyamseshadri@gmail.com>
|
||||
Vojta Jina <vojta.jina@gmail.com>
|
||||
Vojta Jina <vojta.jina@gmail.com> <vojta@gemin-i.org>
|
||||
Vojta Jina <vojta.jina@gmail.com> <vojta@google.com>
|
||||
+37
-74
@@ -1,104 +1,67 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '8'
|
||||
- '4.2'
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
- bower_components
|
||||
- docs/bower_components
|
||||
|
||||
branches:
|
||||
except:
|
||||
- "/^g3_.*$/"
|
||||
- /^g3_.*$/
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- JOB=ci-checks
|
||||
- JOB=unit-core BROWSER_PROVIDER=saucelabs
|
||||
- JOB=unit-jquery BROWSER_PROVIDER=saucelabs
|
||||
- JOB=unit-modules BROWSER_PROVIDER=saucelabs
|
||||
- JOB=docs-app BROWSER_PROVIDER=saucelabs
|
||||
- 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
|
||||
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
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
|
||||
- secure: oTBjhnOKhs0qDSKTf7fE4f6DYiNDPycvB7qfSF5QRIbJK/LK/J4UtFwetXuXj79HhUZG9qnoT+5e7lPaiaMlpsIKn9ann7ffqFWN1E8TMtpJF+AGigx3djYElwfgf5nEnFUFhwjFzvbfpZNnxVGgX5YbIZpe/WUbHkP4ffU0Wks=
|
||||
|
||||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
|
||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||
# 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
|
||||
|
||||
install:
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
|
||||
# - 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
|
||||
#- npm install -g npm@2.5
|
||||
# Install npm dependencies and ensure that npm cache is not stale
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- du -sh ./node_modules || true
|
||||
- "./scripts/travis/before_build.sh"
|
||||
- ./scripts/travis/before_build.sh
|
||||
|
||||
script:
|
||||
- "./scripts/travis/build.sh"
|
||||
- ./scripts/travis/build.sh
|
||||
|
||||
after_script:
|
||||
- "./scripts/travis/tear_down_browser_provider.sh"
|
||||
- "./scripts/travis/print_logs.sh"
|
||||
- ./scripts/travis/tear_down_browser_provider.sh
|
||||
- ./scripts/travis/print_logs.sh
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
|
||||
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: always # default: false
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
# Don't deploy from PRs. Only deploy from our default branches, or if commit is tagged.
|
||||
# This is a Travis-specific boolean language: https://docs.travis-ci.com/user/conditional-builds-stages-jobs#Specifying-conditions
|
||||
# The deployment logic for pushed branches is further defined in scripts\travis\build.sh
|
||||
if: type != pull_request and (branch =~ ^(v1\.\d+\.x|master)$ or tag IS present)
|
||||
env:
|
||||
- JOB=deploy
|
||||
before_script: skip
|
||||
script:
|
||||
# Export the variables into the current process
|
||||
- . ./scripts/travis/build.sh
|
||||
- "echo DEPLOY_DOCS: $DEPLOY_DOCS, DEPLOY_CODE: $DEPLOY_CODE"
|
||||
after_script: skip
|
||||
# Work around the 10min Travis timeout so the code.angularjs firebase+gcs code deploy can complete
|
||||
# Only run the keep_alive once (before_deploy is run for each provider)
|
||||
before_deploy: |
|
||||
if ! [ "$BEFORE_DEPLOY_RUN" ]; then
|
||||
export BEFORE_DEPLOY_RUN=1;
|
||||
|
||||
function keep_alive() {
|
||||
while true; do
|
||||
echo -en "\a"
|
||||
sleep 10
|
||||
done
|
||||
}
|
||||
keep_alive &
|
||||
fi
|
||||
deploy:
|
||||
- provider: firebase
|
||||
# the upload folder for firebase is configured in /firebase.json
|
||||
skip_cleanup: true
|
||||
project: docs-angularjs-org-9p2
|
||||
token:
|
||||
secure: $FIREBASE_TOKEN
|
||||
on:
|
||||
repo: angular/angular.js
|
||||
all_branches: true
|
||||
condition: "$DEPLOY_DOCS == true"
|
||||
- provider: gcs
|
||||
skip_cleanup: true
|
||||
access_key_id: GOOGLDB7W2J3LFHICF3R
|
||||
secret_access_key:
|
||||
secure: tHIFdSq55qkyZf9zT/3+VkhUrTvOTMuswxXU3KyWaBrSieZqG0UnUDyNm+n3lSfX95zEl/+rJAWbfvhVSxZi13ndOtvRF+MdI1cvow2JynP0aDSiPffEvVrZOmihD6mt2SlMfhskr5FTduQ69kZG6DfLcve1PPDaIwnbOv3phb8=
|
||||
bucket: code-angularjs-org-338b8.appspot.com
|
||||
local-dir: deploy/code
|
||||
detect_encoding: true # detects gzip compression
|
||||
on:
|
||||
repo: angular/angular.js
|
||||
all_branches: true
|
||||
condition: "$DEPLOY_CODE == true"
|
||||
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
|
||||
+85
-7206
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
The AngularJS project follows the Code of Conduct defined in [the angular/code-of-conduct repository](https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md). Please read it.
|
||||
+172
-129
@@ -3,145 +3,114 @@
|
||||
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:
|
||||
|
||||
* [Code of Conduct](#coc)
|
||||
* [Questions and Problems](#question)
|
||||
* [Issues and Bugs](#issue)
|
||||
* [Feature Requests](#feature)
|
||||
* [Improving Documentation](#docs)
|
||||
* [Issue Submission Guidelines](#submit)
|
||||
* [Pull Request Submission Guidelines](#submit-pr)
|
||||
* [Signing the CLA](#cla)
|
||||
- [Code of Conduct](#coc)
|
||||
- [Question or Problem?](#question)
|
||||
- [Issues and Bugs](#issue)
|
||||
- [Feature Requests](#feature)
|
||||
- [Submission Guidelines](#submit)
|
||||
- [Coding Rules](#rules)
|
||||
- [Commit Message Guidelines](#commit)
|
||||
- [Signing the CLA](#cla)
|
||||
- [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].
|
||||
|
||||
Help us keep AngularJS open and inclusive. Please read and follow our [Code of Conduct][coc].
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
## <a name="requests"></a> Questions, Bugs, Features
|
||||
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].
|
||||
|
||||
### <a name="question"></a> Got a Question or Problem?
|
||||
## <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.
|
||||
|
||||
Do not open issues for general support questions as we want to keep GitHub issues for bug reports
|
||||
and feature requests. You've got much better chances of getting your question answered on dedicated
|
||||
support platforms, the best being [Stack Overflow][stackoverflow].
|
||||
***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.*
|
||||
|
||||
Stack Overflow is a much better place to ask questions since:
|
||||
**Please see the Submission Guidelines below**.
|
||||
|
||||
- there are thousands of people willing to help on Stack Overflow
|
||||
- questions and answers stay available for public viewing so your question / answer might help
|
||||
someone else
|
||||
- Stack Overflow's voting system assures that the best answers are prominently visible.
|
||||
## <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:
|
||||
|
||||
To save your and our time, we will systematically close all issues that are requests for general
|
||||
support and redirect people to the section you are reading right now.
|
||||
* **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.
|
||||
|
||||
Other channels for support are:
|
||||
- the [Google Group][groups] discussion list
|
||||
- the [AngularJS IRC][irc]
|
||||
- the [AngularJS Gitter][gitter]
|
||||
|
||||
### <a name="issue"></a> Found an Issue or Bug?
|
||||
|
||||
If you find a bug in the source code, you can help us by submitting an issue to our
|
||||
[GitHub Repository][github]. Even better, you can submit a Pull Request with a fix.
|
||||
|
||||
**Please see the [Submission Guidelines](#submit) below.**
|
||||
|
||||
**Special Note for Localization Issues:** AngularJS 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].
|
||||
|
||||
### <a name="feature"></a> Missing a Feature?
|
||||
|
||||
You can request a new feature by submitting an issue to our [GitHub Repository][github-issues].
|
||||
|
||||
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 in an
|
||||
[GitHub issue][github-issues] that clearly outlines the changes and benefits of the feature.
|
||||
* **Small Changes** can directly be crafted and submitted to the [GitHub Repository][github]
|
||||
as a Pull Request. See the section about [Pull Request Submission Guidelines](#submit-pr), and
|
||||
for detailed information the [core development documentation][developers].
|
||||
|
||||
### <a name="docs"></a> Want a Doc Fix?
|
||||
|
||||
Should you have a suggestion for the documentation, you can open an issue and outline the problem
|
||||
or improvement you have - however, creating the doc fix yourself is much better!
|
||||
|
||||
## <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.
|
||||
|
||||
If you're making a small change (typo, phrasing) 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. The commit message is preformatted to the right type
|
||||
and scope, so you only have to add the description.
|
||||
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.
|
||||
|
||||
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 follows the **[Commit Message Guidelines][developers.commits]**.
|
||||
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> Issue Submission Guidelines
|
||||
## <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.
|
||||
|
||||
The "[new issue][github-new-issue]" form contains a number of prompts that you should fill out to
|
||||
make it easier to understand and categorize the issue.
|
||||
|
||||
In general, 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
|
||||
* **AngularJS Version(s)** - is it a regression?
|
||||
* **Browsers and Operating System** - is this a problem with all browsers or only specific ones?
|
||||
* **Angular Version(s)** - is it a regression?
|
||||
* **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.
|
||||
* **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)
|
||||
|
||||
Here is a great example of a well defined issue: https://github.com/angular/angular.js/issues/5069.
|
||||
Here is a great example of a well defined issue: https://github.com/angular/angular.js/issues/5069
|
||||
|
||||
**If you get help, help others. Good karma rulez!**
|
||||
|
||||
## <a name="submit-pr"></a> Pull Request Submission Guidelines
|
||||
### Submitting a Pull Request
|
||||
Before you submit your pull request consider the following guidelines:
|
||||
|
||||
* Search [GitHub](https://github.com/angular/angular.js/pulls) for an open or closed Pull Request
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Create the [development environment][developers.setup]
|
||||
* 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:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
* Create your patch commit, **including appropriate test cases**.
|
||||
* Follow our [Coding Rules][developers.rules].
|
||||
* If the changes affect public APIs, change or add relevant [documentation][developers.documentation].
|
||||
* Run the AngularJS [unit][developers.tests-unit] and [E2E test][developers.tests-e2e] suites, and ensure that all tests
|
||||
pass. It is generally sufficient to run the tests only on Chrome, as our Travis integration will
|
||||
run the tests on all supported browsers.
|
||||
* Run `yarn grunt eslint` to check that you have followed the automatically enforced coding rules
|
||||
* 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][developers.commits]. Adherence to the
|
||||
[commit message conventions][developers.commits] 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.
|
||||
|
||||
* Before creating the Pull Request, package and run all tests a last time:
|
||||
* Build your changes locally to ensure all the tests pass:
|
||||
|
||||
```shell
|
||||
yarn grunt test
|
||||
grunt test
|
||||
```
|
||||
|
||||
* Push your branch to GitHub:
|
||||
@@ -150,30 +119,22 @@ Before you submit your pull request consider the following guidelines:
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `angular.js:master`. This will trigger the check of the
|
||||
[Contributor License Agreement](#cla) and the Travis integration.
|
||||
|
||||
* If you find that the Travis integration has failed, look into the logs on Travis to find out
|
||||
if your changes caused test failures, the commit message was malformed etc. If you find that the
|
||||
tests failed or times out for unrelated reasons, you can ping a team member so that the build can be
|
||||
restarted.
|
||||
|
||||
* 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 AngularJS test suite to ensure tests are still passing.
|
||||
* 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).
|
||||
|
||||
You can also amend the initial commits and force push them to the branch.
|
||||
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
|
||||
```
|
||||
|
||||
This is generally easier to follow, but seperate commits are useful if the Pull Request contains
|
||||
iterations that might be interesting to see side-by-side.
|
||||
*WARNING. Squashing or reverting commits and forced push thereafter may remove GitHub comments
|
||||
on code that were previously made by you and others in your commits.*
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
@@ -206,41 +167,123 @@ from the main (upstream) repository:
|
||||
git pull --ff upstream master
|
||||
```
|
||||
|
||||
## <a name="cla"></a> Signing the Contributor License Agreement (CLA)
|
||||
## <a name="rules"></a> Coding Rules
|
||||
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
||||
|
||||
Upon submmitting a Pull Request, a friendly bot will ask you to sign our CLA if you haven't done
|
||||
so before. Unfortunately, this is necessary for documentation changes, too.
|
||||
It's a quick process, we promise!
|
||||
* All features or bug fixes **must be tested** by one or more [specs][unit-testing].
|
||||
* All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
|
||||
support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
|
||||
out the existing ngdocs and see [this wiki page][ngDocs].
|
||||
* With the exceptions listed below, we follow the rules contained in
|
||||
[Google's JavaScript Style Guide][js-style-guide]:
|
||||
* **Do not use namespaces**: Instead, wrap the entire angular code base in an anonymous closure and
|
||||
export our API explicitly rather than implicitly.
|
||||
* Wrap all code at **100 characters**.
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypal
|
||||
inheritance only when absolutely necessary.
|
||||
* We **love functions and closures** and, whenever possible, prefer them over objects.
|
||||
* To write concise code that can be better minified, we **use aliases internally** that map to the
|
||||
external API. See our existing code to see what we mean.
|
||||
* We **don't go crazy with type annotations** for private internal APIs unless it's an internal API
|
||||
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
|
||||
|
||||
## <a name="commit"></a> Git Commit Guidelines
|
||||
|
||||
We have very precise rules over how our git commit messages can be formatted. This leads to **more
|
||||
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**.
|
||||
|
||||
### 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**:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<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.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
|
||||
* **feat**: A new feature
|
||||
* **fix**: A bug fix
|
||||
* **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
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
|
||||
### Scope
|
||||
The scope could be anything specifying place of the commit change. For example `$location`,
|
||||
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
|
||||
|
||||
### Subject
|
||||
The subject contains succinct description of the change:
|
||||
|
||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
* 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".
|
||||
The body should include the motivation for the change and contrast this with previous behavior.
|
||||
|
||||
### Footer
|
||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
||||
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].
|
||||
|
||||
## <a name="cla"></a> Signing the CLA
|
||||
|
||||
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
|
||||
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
|
||||
|
||||
* For individuals we have a [simple click-through form][individual-cla].
|
||||
* For corporations we'll need you to
|
||||
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
|
||||
|
||||
## <a name="info"></a> Further Information
|
||||
You can find out more detailed information about contributing in the
|
||||
[AngularJS documentation][contributing].
|
||||
|
||||
|
||||
[Closure guide to i18n changes]: https://github.com/google/closure-library/wiki/Internationalization-%28i18n%29-changes-in-Closure-Library
|
||||
|
||||
[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
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
||||
[Common Locale Data Repository (CLDR)]: http://cldr.unicode.org
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[contribute]: http://docs.angularjs.org/misc/contribute
|
||||
[contributing]: http://docs.angularjs.org/misc/contribute
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[developers]: DEVELOPERS.md
|
||||
[developers.commits]: DEVELOPERS.md#commits
|
||||
[developers.documentation]: DEVELOPERS.md#documentation
|
||||
[developers.rules]: DEVELOPERS.md#rules
|
||||
[developers.setup]: DEVELOPERS.md#setup
|
||||
[developers.tests-e2e]: DEVELOPERS.md#e2e-tests
|
||||
[developers.tests-unit]: DEVELOPERS.md#unit-tests
|
||||
[github-issues]: https://github.com/angular/angular.js/issues
|
||||
[github-new-issue]: https://github.com/angular/angular.js/issues/new
|
||||
[dev-doc]: https://docs.angularjs.org/guide
|
||||
[github]: https://github.com/angular/angular.js
|
||||
[gitter]: https://gitter.im/angular/angular.js
|
||||
[Google Closure I18N library]: https://github.com/google/closure-library/tree/master/closure/goog/i18n
|
||||
[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]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
|
||||
[jsfiddle]: http://jsfiddle.net/
|
||||
[karma-browserstack]: https://github.com/karma-runner/karma-browserstack-launcher
|
||||
[karma-saucelabs]: https://github.com/karma-runner/karma-sauce-launcher
|
||||
[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
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
-489
@@ -1,489 +0,0 @@
|
||||
# Developing AngularJS
|
||||
|
||||
* [Development Setup](#setup)
|
||||
* [Running Tests](#tests)
|
||||
* [Coding Rules](#rules)
|
||||
* [Commit Message Guidelines](#commits)
|
||||
* [Writing Documentation](#documentation)
|
||||
|
||||
## <a name="setup"> Development Setup
|
||||
|
||||
This document describes how to set up your development environment to build and test AngularJS, and
|
||||
explains the basic mechanics of using `git`, `node`, `yarn` and `grunt`.
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
Before you can build AngularJS, you must install and configure the following dependencies on your
|
||||
machine:
|
||||
|
||||
* [Git](http://git-scm.com/): The [Github Guide to
|
||||
Installing Git][git-setup] is a good source of information.
|
||||
|
||||
* [Node.js v8.x (LTS)](http://nodejs.org): We use Node to generate the documentation, run a
|
||||
development web server, run tests, and generate distributable files. Depending on your system,
|
||||
you can install Node either from source or as a pre-packaged bundle.
|
||||
|
||||
We recommend using [nvm](https://github.com/creationix/nvm) (or
|
||||
[nvm-windows](https://github.com/coreybutler/nvm-windows))
|
||||
to manage and install Node.js, which makes it easy to change the version of Node.js per project.
|
||||
|
||||
* [Yarn](https://yarnpkg.com): We use Yarn to install our Node.js module dependencies
|
||||
(rather than using npm). See the detailed [installation instructions][yarn-install].
|
||||
|
||||
* [Java](http://www.java.com): We minify JavaScript using
|
||||
[Closure Tools](https://developers.google.com/closure/), which require Java (version 7 or higher)
|
||||
to be installed and included in your
|
||||
[PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
|
||||
|
||||
* [Grunt](http://gruntjs.com): We use Grunt as our build system. We're using it as a local dependency,
|
||||
but you can also add the grunt command-line tool globally (with `yarn global add grunt-cli`), which allows
|
||||
you to leave out the `yarn` prefix for all our grunt commands.
|
||||
|
||||
### Forking AngularJS on Github
|
||||
|
||||
To contribute code to AngularJS, you must have a GitHub account so you can push code to your own
|
||||
fork of AngularJS and open Pull Requests in the [GitHub Repository][github].
|
||||
|
||||
To create a Github account, follow the instructions [here](https://github.com/signup/free).
|
||||
Afterwards, go ahead and [fork](http://help.github.com/forking) the
|
||||
[main AngularJS repository][github].
|
||||
|
||||
|
||||
### Building AngularJS
|
||||
|
||||
To build AngularJS, you clone the source code repository and use Grunt to generate the non-minified
|
||||
and minified AngularJS files:
|
||||
|
||||
```shell
|
||||
# Clone your Github repository:
|
||||
git clone https://github.com/<github username>/angular.js.git
|
||||
|
||||
# Go to the AngularJS directory:
|
||||
cd angular.js
|
||||
|
||||
# Add the main AngularJS repository as an upstream remote to your repository:
|
||||
git remote add upstream "https://github.com/angular/angular.js.git"
|
||||
|
||||
# Install JavaScript dependencies:
|
||||
yarn install
|
||||
|
||||
# Build AngularJS:
|
||||
yarn grunt package
|
||||
```
|
||||
|
||||
**Note:** If you're using Windows, you must use an elevated command prompt (right click, run as
|
||||
Administrator). This is because `yarn grunt package` creates some symbolic links.
|
||||
|
||||
The build output is in the `build` directory. It consists of the following files and
|
||||
directories:
|
||||
|
||||
* `angular-<version>.zip` — The complete zip file, containing all of the release build
|
||||
artifacts.
|
||||
|
||||
* `angular.js` / `angular.min.js` — The regular and minified core AngularJS script file.
|
||||
|
||||
* `angular-*.js` / `angular-*.min.js` — All other AngularJS module script files.
|
||||
|
||||
* `docs/` — A directory that contains a standalone version of the docs
|
||||
(same as served in `docs.angularjs.org`).
|
||||
|
||||
### <a name="local-server"></a> Running a Local Development Web Server
|
||||
|
||||
To debug code, run end-to-end tests, and serve the docs, it is often useful to have a local
|
||||
HTTP server. For this purpose, we have made available a local web server based on Node.js.
|
||||
|
||||
1. To start the web server, run:
|
||||
```shell
|
||||
yarn grunt webserver
|
||||
```
|
||||
|
||||
2. To access the local server, enter the following URL into your web browser:
|
||||
```text
|
||||
http://localhost:8000/
|
||||
```
|
||||
By default, it serves the contents of the AngularJS project directory.
|
||||
|
||||
3. To access the locally served docs, visit this URL:
|
||||
```text
|
||||
http://localhost:8000/build/docs/
|
||||
```
|
||||
|
||||
## <a name="tests"> Running Tests
|
||||
|
||||
### <a name="unit-tests"></a> Running the Unit Test Suite
|
||||
|
||||
We write unit and integration tests with Jasmine and execute them with Karma. To run all of the
|
||||
tests once on Chrome run:
|
||||
|
||||
```shell
|
||||
yarn grunt test:unit
|
||||
```
|
||||
|
||||
To run the tests on other browsers use the command line flag:
|
||||
|
||||
```shell
|
||||
yarn grunt test:unit --browsers=Chrome,Firefox
|
||||
```
|
||||
|
||||
**Note:** there should be _no spaces between browsers_. `Chrome, Firefox` is INVALID.
|
||||
|
||||
If you have a Saucelabs or Browserstack account, you can also run the unit tests on these services
|
||||
via our pre-defined customLaunchers. See the [karma config file](/karma-shared.conf.js) for all pre-configured browsers.
|
||||
|
||||
For example, to run the whole unit test suite on selected browsers:
|
||||
|
||||
```shell
|
||||
# Browserstack
|
||||
yarn grunt test:unit --browsers=BS_Chrome,BS_Firefox,BS_Safari,BS_IE_9,BS_IE_10,BS_IE_11,BS_EDGE,BS_iOS_10
|
||||
# Saucelabs
|
||||
yarn grunt test:unit --browsers=SL_Chrome,SL_Firefox,SL_Safari,SL_IE_9,SL_IE_10,SL_IE_11,SL_EDGE,SL_iOS_10
|
||||
```
|
||||
|
||||
Running these commands requires you to set up [Karma Browserstack][karma-browserstack] or
|
||||
[Karma-Saucelabs][karma-saucelabs], respectively.
|
||||
|
||||
During development, however, it's more productive to continuously run unit tests every time the
|
||||
source or test files change. To execute tests in this mode run:
|
||||
|
||||
1. To start the Karma server, capture Chrome browser and run unit tests, run:
|
||||
|
||||
```shell
|
||||
yarn grunt autotest
|
||||
```
|
||||
|
||||
2. To capture more browsers, open this URL in the desired browser (URL might be different if you
|
||||
have multiple instance of Karma running, read Karma's console output for the correct URL):
|
||||
|
||||
```text
|
||||
http://localhost:9876/
|
||||
```
|
||||
|
||||
3. To re-run tests just change any source or test file.
|
||||
|
||||
|
||||
To learn more about all of the preconfigured Grunt tasks run:
|
||||
|
||||
```shell
|
||||
yarn grunt --help
|
||||
```
|
||||
|
||||
|
||||
### <a name="e2e-tests"></a> Running the End-to-end Test Suite
|
||||
|
||||
AngularJS's end to end tests are run with Protractor. Simply run:
|
||||
|
||||
```shell
|
||||
yarn grunt test:e2e
|
||||
```
|
||||
|
||||
This will start the webserver and run the tests on Chrome.
|
||||
|
||||
## <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].
|
||||
* All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
|
||||
support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
|
||||
out the existing source code and see the section about [writing documentation](#documentation)
|
||||
* With the exceptions listed below, we follow the rules contained in
|
||||
[Google's JavaScript Style Guide][js-style-guide]:
|
||||
* **Do not use namespaces**: Instead, wrap the entire AngularJS code base in an anonymous
|
||||
closure and export our API explicitly rather than implicitly.
|
||||
* Wrap all code at **100 characters**.
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypal
|
||||
inheritance only when absolutely necessary.
|
||||
* We **love functions and closures** and, whenever possible, prefer them over objects.
|
||||
* To write concise code that can be better minified, we **use aliases internally** that map to
|
||||
the external API. See our existing code to see what we mean.
|
||||
* We **don't go crazy with type annotations** for private internal APIs unless it's an internal
|
||||
API that is used throughout AngularJS. The best guidance is to do what makes the most sense.
|
||||
|
||||
### Specific topics
|
||||
|
||||
#### Provider configuration
|
||||
|
||||
When adding configuration (options) to [providers][docs.provider], we follow a special pattern.
|
||||
|
||||
- for each option, add a `method` that ...
|
||||
- works as a getter and returns the current value when called without argument
|
||||
- works as a setter and returns itself for chaining when called with argument
|
||||
- for boolean options, uses the naming scheme `<option>Enabled([enabled])`
|
||||
- non-primitive options (e.g. objects) should be copied or the properties assigned explicitly to a
|
||||
new object so that the configuration cannot be changed during runtime.
|
||||
|
||||
For a boolean config example, see [`$compileProvider#debugInfoEnabled`][code.debugInfoEnabled]
|
||||
|
||||
For an object config example, see [`$location.html5Mode`][code.html5Mode]
|
||||
|
||||
#### Throwing errors
|
||||
|
||||
User-facing errors should be thrown with [`minErr`][code.minErr], a special error function that provides
|
||||
errors ids, templated error messages, and adds a link to a detailed error description.
|
||||
|
||||
The `$compile:badrestrict` error is a good example for a well-defined `minErr`:
|
||||
[code][code.badrestrict] and [description][docs.badrestrict].
|
||||
|
||||
|
||||
## <a name="commits"></a> Git Commit Guidelines
|
||||
|
||||
We have very precise rules over how our git commit messages can be formatted. This leads to **more
|
||||
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**:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<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.
|
||||
A commit with this format is automatically created by the [`git revert`][git-revert] command.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
|
||||
* **feat**: A new feature
|
||||
* **fix**: A bug fix
|
||||
* **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
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing or correcting existing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
|
||||
### Scope
|
||||
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:
|
||||
|
||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
* 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".
|
||||
The body should include the motivation for the change and contrast this with previous behavior.
|
||||
|
||||
### 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].
|
||||
|
||||
**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].
|
||||
|
||||
## <a name="documentation"></a> Writing Documentation
|
||||
|
||||
The AngularJS project uses a form of [jsdoc](http://usejsdoc.org/) called ngdoc for all of its code
|
||||
documentation.
|
||||
|
||||
This means that all the docs are stored inline in the source code and so are kept in sync as it
|
||||
changes.
|
||||
|
||||
There is also extra content (the developer guide, error pages, the tutorial,
|
||||
and misceallenous pages) that live inside the AngularJS repository as markdown files.
|
||||
|
||||
This means that since we generate the documentation from the source code, we can easily provide
|
||||
version-specific documentation by simply checking out a version of AngularJS and running the build.
|
||||
|
||||
Extracting the source code documentation, processing and building the docs is handled by the
|
||||
documentation generation tool [Dgeni][dgeni].
|
||||
|
||||
### Building and viewing the docs locally
|
||||
The docs can be built from scratch using grunt:
|
||||
|
||||
```shell
|
||||
yarn grunt docs
|
||||
```
|
||||
|
||||
This defers the doc-building task to `gulp`.
|
||||
|
||||
Note that the docs app is using the local build files to run. This means you might first have to run
|
||||
the build:
|
||||
|
||||
```shell
|
||||
yarn grunt build
|
||||
```
|
||||
|
||||
(This is also necessary if you are making changes to minErrors).
|
||||
|
||||
To view the docs, see [Running a Local Development Web Server](#local-server).
|
||||
|
||||
### Writing jsdoc
|
||||
The ngdoc utility has basic support for many of the standard jsdoc directives. But in particular it
|
||||
is interested in the following block tags:
|
||||
|
||||
* `@name name` - the name of the ngdoc document
|
||||
* `@param {type} name description` - describes a parameter of a function
|
||||
* `@returns {type} description` - describes what a function returns
|
||||
* `@requires` - normally indicates that a JavaScript module is required; in an Angular service it is
|
||||
used to describe what other services this service relies on
|
||||
* `@property` - describes a property of an object
|
||||
* `@description` - used to provide a description of a component in markdown
|
||||
* `@link` - specifies a link to a URL or a type in the API reference.
|
||||
Links to the API have the following structure:
|
||||
|
||||
* the module namespace, followed by `.` (optional, default `ng`)
|
||||
* the `@ngdoc` type (see below), followed by `:` (optional, automatically inferred)
|
||||
* the name
|
||||
* the method, property, or anchor (optional)
|
||||
* the display name
|
||||
|
||||
For example: `{@link ng.type:$rootScope.Scope#$new Scope.$new()}`.
|
||||
|
||||
* `@example` - specifies an example. This can be a simple code block, or a
|
||||
[runnable example](#the-example-tag).
|
||||
* `@deprecated` - specifies that the following code is deprecated and should not be used.
|
||||
In The AngularJS docs, there are two specific patterns which can be used to further describe
|
||||
the deprecation: `sinceVersion="<version>"` and `removeVersion="<version>"`
|
||||
|
||||
The `type` in `@param` and `@returns` must be wrapped in `{}` curly braces, e.g. `{Object|Array}`.
|
||||
Parameters can be made optional by *either* appending a `=` to the type, e.g. `{Object=}`, *or* by
|
||||
putting the `[name]` in square brackets.
|
||||
Default values are only possible with the second syntax by appending `=<value>` to the parameter
|
||||
name, e.g. `@param {boolean} [ownPropsOnly=false]`.
|
||||
|
||||
Descriptions can contain markdown formatting.
|
||||
|
||||
#### AngularJS-specific jsdoc directives
|
||||
|
||||
In addition to the standard jsdoc tags, there are a number that are specific to the Angular
|
||||
code-base:
|
||||
|
||||
* `@ngdoc` - specifies the type of thing being documented. See below for more detail.
|
||||
* `@eventType emit|broadcast` - specifies whether the event is emitted or broadcast
|
||||
* `@usage` - shows how to use a `function` or `directive`. Is usually automatically generated.
|
||||
* `@knownIssue` - adds info about known quirks, problems, or limitations with the API, and possibly,
|
||||
workarounds. This section is not for bugs.
|
||||
|
||||
The following are specific to directives:
|
||||
|
||||
* `@animations` - specifies the animations a directive supports
|
||||
* `@multiElement` - specifies if a directive can span over multiple elements
|
||||
* `@priority` - specifies a directive's priority
|
||||
* `@restrict` - is extracted to show the usage of a directive. For example, for [E]lement,
|
||||
[A]ttribute, and [C]lass, use `@restrict ECA`
|
||||
* `@scope` - specifies that a directive will create a new scope
|
||||
|
||||
### The `@ngdoc` Directive
|
||||
This directive helps to specify the template used to render the item being documented. For instance,
|
||||
a directive would have different properties to a filter and so would be documented differently. The
|
||||
commonly used types are:
|
||||
|
||||
* `overview` - a general page (guide, api index)
|
||||
* `provider` - AngularJS provider, such as `$compileProvider` or `$httpProvider`.
|
||||
* `service` - injectable AngularJS service, such as `$compile` or `$http`.
|
||||
* `object` - well defined object (often exposed as a service)
|
||||
* `function` - function that will be available to other methods (such as a helper function within
|
||||
the ng module)
|
||||
* `method` - method on an object/service/controller
|
||||
* `property` - property on an object/service/controller
|
||||
* `event` - AngularJS event that will propagate through the `$scope` tree.
|
||||
* `directive` - AngularJS directive
|
||||
* `filter` - AngularJS filter
|
||||
* `error` - minErr error description
|
||||
|
||||
### General documentation with Markdown
|
||||
|
||||
Any text in tags can contain markdown syntax for formatting. Generally, you can use any markdown
|
||||
feature.
|
||||
|
||||
#### Headings
|
||||
|
||||
Only use *h2* headings and lower, as the page title is set in *h1*. Also make sure you follow the
|
||||
heading hierarchy. This ensures correct table of contents are created.
|
||||
|
||||
#### Code blocks
|
||||
In line code can be specified by enclosing the code in back-ticks (\`).
|
||||
A block of multi-line code can be enclosed in triple back-ticks (\`\`\`) but it is formatted better
|
||||
if it is enclosed in <pre>...</pre> tags and the code lines themselves are indented.
|
||||
|
||||
### Writing runnable (live) examples and e2e tests
|
||||
It is possible to embed examples in the documentation along with appropriate e2e tests. These
|
||||
examples and scenarios will be converted to runnable code within the documentation. So it is
|
||||
important that they work correctly. To ensure this, all these e2e scenarios are run as part of the
|
||||
automated Travis tests.
|
||||
|
||||
If you are adding an example with an e2e test, you should [run the test locally](#e2e-tests) first
|
||||
to ensure it passes. You can change `it(...)` to `fit(...)` to run only your test,
|
||||
but make sure you change it back to `it(...)` before committing.
|
||||
|
||||
#### The `<example>` tag
|
||||
This tag identifies a block of HTML that will define a runnable example. It can take the following
|
||||
attributes:
|
||||
|
||||
* `animations` - if set to `true` then this example uses ngAnimate.
|
||||
* `deps` - Semicolon-separated list of additional angular module files to be loaded,
|
||||
e.g. `angular-animate.js`
|
||||
* `name` - every example should have a name. It should start with the component, e.g directive name,
|
||||
and not contain whitespace
|
||||
* `module` - the name of the app module as defined in the example's JavaScript
|
||||
|
||||
Within this tag we provide `<file>` tags that specify what files contain the example code.
|
||||
|
||||
```
|
||||
<example
|
||||
module="angularAppModule"
|
||||
name="exampleName"
|
||||
deps="angular-animate.js;angular-route.js"
|
||||
animations="true">
|
||||
...
|
||||
<file name="index.html">...</file>
|
||||
<file name="script.js">...</file>
|
||||
<file name="animations.css">...</file>
|
||||
<file name="protractor.js">...</file>
|
||||
...
|
||||
</example>
|
||||
```
|
||||
|
||||
You can see an example of a well-defined example [in the `ngRepeat` documentation][code.ngRepeat-example].
|
||||
|
||||
[closing-issues]: https://help.github.com/articles/closing-issues-via-commit-messages/
|
||||
[Closure guide to i18n changes]: https://github.com/google/closure-library/wiki/Internationalization-%28i18n%29-changes-in-Closure-Library
|
||||
[code.badrestrict]: https://github.com/angular/angular.js/blob/202f1809ad14827a6ac6a125157c605d65e0b551/src/ng/compile.js#L1107-L1110
|
||||
[code.debugInfoEnabled]: https://github.com/angular/angular.js/blob/32fbb2e78f53d765fbb170f7cf99e42e072d363b/src/ng/compile.js#L1378-L1413
|
||||
[code.html5Mode]: https://github.com/angular/angular.js/blob/202f1809ad14827a6ac6a125157c605d65e0b551/src/ng/location.js#L752-L797
|
||||
[code.minErr]: https://github.com/angular/angular.js/blob/202f1809ad14827a6ac6a125157c605d65e0b551/src/minErr.js#L53-L113
|
||||
[code.ngRepeat-example]: https://github.com/angular/angular.js/blob/0822d34b10ea0371c260c80a1486a4d508ea5a91/src/ng/directive/ngRepeat.js#L249-L340
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[Common Locale Data Repository (CLDR)]: http://cldr.unicode.org
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[dgeni]: https://github.com/angular/dgeni
|
||||
[docs.badrestrict]: docs/content/error/$compile/badrestrict.ngdoc
|
||||
[docs.provider]: https://code.angularjs.org/snapshot/docs/api/auto/service/$provide#provider
|
||||
[git-revert]: https://git-scm.com/docs/git-revert
|
||||
[git-setup]: https://help.github.com/articles/set-up-git
|
||||
[github-issues]: https://github.com/angular/angular.js/issues
|
||||
[github]: https://github.com/angular/angular.js
|
||||
[js-style-guide]: https://google.github.io/styleguide/javascriptguide.xml
|
||||
[karma-browserstack]: https://github.com/karma-runner/karma-browserstack-launcher
|
||||
[karma-saucelabs]: https://github.com/karma-runner/karma-sauce-launcher
|
||||
[unit-testing]: https://docs.angularjs.org/guide/unit-testing
|
||||
[yarn-install]: https://yarnpkg.com/en/docs/install
|
||||
+109
-303
@@ -1,81 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
var serveFavicon = require('serve-favicon');
|
||||
var serveStatic = require('serve-static');
|
||||
var serveIndex = require('serve-index');
|
||||
var files = require('./angularFiles').files;
|
||||
var mergeFilesFor = require('./angularFiles').mergeFilesFor;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
var path = require('path');
|
||||
var e2e = require('./test/e2e/tools');
|
||||
|
||||
var semver = require('semver');
|
||||
var exec = require('shelljs').exec;
|
||||
var pkg = require(__dirname + '/package.json');
|
||||
|
||||
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
|
||||
|
||||
// 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-cli'];
|
||||
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 deployVersion = NG_VERSION.full;
|
||||
|
||||
if (NG_VERSION.isSnapshot) {
|
||||
deployVersion = NG_VERSION.distTag === 'latest' ? 'snapshot-stable' : 'snapshot';
|
||||
}
|
||||
|
||||
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?');
|
||||
}
|
||||
var dist = 'angular-'+ NG_VERSION.full;
|
||||
|
||||
//config
|
||||
grunt.initConfig({
|
||||
@@ -94,15 +34,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)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -114,7 +54,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) {
|
||||
@@ -127,8 +67,8 @@ module.exports = function(grunt) {
|
||||
},
|
||||
util.conditionalCsp(),
|
||||
e2e.middleware(),
|
||||
serveFavicon('images/favicon.ico'),
|
||||
serveStatic(base)
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(base)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -139,20 +79,14 @@ 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',
|
||||
'modules-ngAnimate': 'karma-modules-ngAnimate.conf.js',
|
||||
'modules-ngMock': 'karma-modules-ngMock.conf.js'
|
||||
modules: 'karma-modules.conf.js'
|
||||
},
|
||||
|
||||
|
||||
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'
|
||||
},
|
||||
@@ -167,36 +101,82 @@ module.exports = function(grunt) {
|
||||
|
||||
clean: {
|
||||
build: ['build'],
|
||||
tmp: ['tmp'],
|
||||
deploy: [
|
||||
'deploy/docs',
|
||||
'deploy/code',
|
||||
docsScriptFolder + '/functions/html'
|
||||
]
|
||||
tmp: ['tmp']
|
||||
},
|
||||
|
||||
eslint: {
|
||||
all: {
|
||||
src: [
|
||||
'*.js',
|
||||
'benchmarks/**/*.js',
|
||||
'docs/**/*.js',
|
||||
'lib/**/*.js',
|
||||
'scripts/**/*.js',
|
||||
'!scripts/*/*/node_modules/**',
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
'i18n/**/*.js',
|
||||
'!docs/app/assets/js/angular-bootstrap/**',
|
||||
'!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'].concat('!src/angular.bind.js') },
|
||||
},
|
||||
ngAnimate: {
|
||||
files: { src: 'src/ngAnimate/**/*.js' },
|
||||
},
|
||||
ngCookies: {
|
||||
files: { src: 'src/ngCookies/**/*.js' },
|
||||
},
|
||||
ngLocale: {
|
||||
files: { src: 'src/ngLocale/**/*.js' },
|
||||
},
|
||||
ngMessageFormat: {
|
||||
files: { src: 'src/ngMessageFormat/**/*.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',
|
||||
'!src/angular.bind.js' // we ignore this file since contains an early return statement
|
||||
],
|
||||
options: {
|
||||
config: '.jscsrc'
|
||||
}
|
||||
},
|
||||
|
||||
build: {
|
||||
scenario: {
|
||||
dest: 'build/angular-scenario.js',
|
||||
src: [
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
|
||||
],
|
||||
styles: {
|
||||
css: ['css/angular.css', 'css/angular-scenario.css']
|
||||
}
|
||||
},
|
||||
angular: {
|
||||
dest: 'build/angular.js',
|
||||
src: util.wrap([files['angularSrc']], 'angular'),
|
||||
@@ -214,12 +194,6 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-touch.js',
|
||||
src: util.wrap(files['angularModules']['ngTouch'], 'module')
|
||||
},
|
||||
touchModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-touch.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngTouch'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
mocks: {
|
||||
dest: 'build/angular-mocks.js',
|
||||
src: util.wrap(files['angularModules']['ngMock'], 'module'),
|
||||
@@ -229,42 +203,18 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-sanitize.js',
|
||||
src: util.wrap(files['angularModules']['ngSanitize'], 'module')
|
||||
},
|
||||
sanitizeModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-sanitize.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngSanitize'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
resource: {
|
||||
dest: 'build/angular-resource.js',
|
||||
src: util.wrap(files['angularModules']['ngResource'], 'module')
|
||||
},
|
||||
resourceModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-resource.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngResource'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
messageformat: {
|
||||
dest: 'build/angular-message-format.js',
|
||||
src: util.wrap(files['angularModules']['ngMessageFormat'], 'module')
|
||||
},
|
||||
messageformatModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-message-format.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngMessageFormat'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
messages: {
|
||||
dest: 'build/angular-messages.js',
|
||||
src: util.wrap(files['angularModules']['ngMessages'], 'module')
|
||||
},
|
||||
messagesModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-messages.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngMessages'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
animate: {
|
||||
dest: 'build/angular-animate.js',
|
||||
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
|
||||
@@ -273,36 +223,14 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-route.js',
|
||||
src: util.wrap(files['angularModules']['ngRoute'], 'module')
|
||||
},
|
||||
routeModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-route.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngRoute'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
cookies: {
|
||||
dest: 'build/angular-cookies.js',
|
||||
src: util.wrap(files['angularModules']['ngCookies'], 'module')
|
||||
},
|
||||
cookiesModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-cookies.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngCookies'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
aria: {
|
||||
dest: 'build/angular-aria.js',
|
||||
src: util.wrap(files['angularModules']['ngAria'], 'module')
|
||||
},
|
||||
ariaModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-aria.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngAria'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
parseext: {
|
||||
dest: 'build/angular-parse-ext.js',
|
||||
src: util.wrap(files['angularModules']['ngParseExt'], 'module')
|
||||
},
|
||||
'promises-aplus-adapter': {
|
||||
dest:'tmp/promises-aplus-adapter++.js',
|
||||
src:['src/ng/q.js', 'lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
@@ -321,8 +249,7 @@ module.exports = function(grunt) {
|
||||
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'
|
||||
},
|
||||
|
||||
|
||||
@@ -330,22 +257,19 @@ module.exports = function(grunt) {
|
||||
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'
|
||||
'xdescribe'
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -362,54 +286,7 @@ module.exports = function(grunt) {
|
||||
copy: {
|
||||
i18n: {
|
||||
files: [
|
||||
{
|
||||
src: 'src/ngLocale/**',
|
||||
dest: 'build/i18n/',
|
||||
expand: true,
|
||||
flatten: true
|
||||
}
|
||||
]
|
||||
},
|
||||
deployFirebaseCode: {
|
||||
files: [
|
||||
// copy files that are not handled by compress
|
||||
{
|
||||
cwd: 'build',
|
||||
src: '**/*.{zip,jpg,jpeg,png}',
|
||||
dest: 'deploy/code/' + deployVersion + '/',
|
||||
expand: true
|
||||
}
|
||||
]
|
||||
},
|
||||
deployFirebaseDocs: {
|
||||
files: [
|
||||
// The source files are needed by the embedded examples in the docs app.
|
||||
{
|
||||
src: ['build/angular*.{js,js.map,min.js}', 'build/sitemap.xml'],
|
||||
dest: 'deploy/docs/',
|
||||
expand: true,
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: ['**', '!ptore2e/**', '!index*.html'],
|
||||
dest: 'deploy/docs/',
|
||||
expand: true
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
dest: 'deploy/docs/index.html'
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
dest: docsScriptFolder + '/functions/content/index.html'
|
||||
},
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: 'partials/**',
|
||||
dest: docsScriptFolder + '/functions/content',
|
||||
expand: true
|
||||
}
|
||||
{ src: 'src/ngLocale/**', dest: 'build/i18n/', expand: true, flatten: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -417,36 +294,27 @@ 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,
|
||||
dot: true,
|
||||
dest: dist + '/'
|
||||
},
|
||||
deployFirebaseCode: {
|
||||
options: {
|
||||
mode: 'gzip'
|
||||
},
|
||||
// Already compressed files should not be compressed again
|
||||
src: ['**', '!**/*.{zip,png,jpeg,jpg}'],
|
||||
cwd: 'build',
|
||||
expand: true,
|
||||
dest: 'deploy/code/' + deployVersion + '/'
|
||||
}
|
||||
},
|
||||
|
||||
shell: {
|
||||
'install-node-dependencies': {
|
||||
command: 'yarn'
|
||||
'npm-install': {
|
||||
command: 'node scripts/npm/check-node-modules.js'
|
||||
},
|
||||
|
||||
'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')
|
||||
}
|
||||
},
|
||||
|
||||
@@ -466,91 +334,29 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
// global beforeEach task
|
||||
if (!process.env.TRAVIS) {
|
||||
grunt.task.run('shell:npm-install');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//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',
|
||||
'tests:modules-ngAnimate',
|
||||
'tests:modules-ngMock'
|
||||
]);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', '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: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:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test: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('minify', [
|
||||
'clean',
|
||||
'build',
|
||||
'minall'
|
||||
]);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
|
||||
|
||||
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', [
|
||||
'validate-angular-files',
|
||||
'clean',
|
||||
'buildall',
|
||||
'minall',
|
||||
'collect-errors',
|
||||
'write',
|
||||
'docs',
|
||||
'copy:i18n',
|
||||
'compress:build'
|
||||
]);
|
||||
grunt.registerTask('ci-checks', [
|
||||
'ddescribe-iit',
|
||||
'merge-conflict',
|
||||
'eslint'
|
||||
]);
|
||||
grunt.registerTask('prepareDeploy', [
|
||||
'package',
|
||||
'compress:deployFirebaseCode',
|
||||
'copy:deployFirebaseCode',
|
||||
'firebaseDocsJsonForTravis',
|
||||
'copy:deployFirebaseDocs'
|
||||
]);
|
||||
grunt.registerTask('package', ['bower', 'validate-angular-files', '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,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
Copyright (c) 2010-2015 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
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ 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
|
||||
pass allows using type annotations for AngularJS objects. For example,
|
||||
AngularJS's $scope objects can be annotated as:
|
||||
Angular's $scope objects can be annotated as:
|
||||
```js
|
||||
/** @type {angular.Scope} */
|
||||
var scope = $scope;
|
||||
|
||||
@@ -2,105 +2,44 @@ AngularJS [ as your template language and lets you extend HTML’s
|
||||
use good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
||||
syntax to express your application’s 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 deferred objects,
|
||||
and it makes client-side navigation and deep linking 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. Best of all?? It makes development fun!
|
||||
|
||||
--------------------
|
||||
* 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: http://dashboard.angularjs.org
|
||||
|
||||
**On July 1, 2018 AngularJS entered a 3 year Long Term Support period:** [Find out more](https://docs.angularjs.org/misc/version-support-status)
|
||||
Building AngularJS
|
||||
---------
|
||||
[Once you have your environment set up](http://docs.angularjs.org/misc/contribute) just run:
|
||||
|
||||
**Looking for the new Angular? Go here:** https://github.com/angular/angular
|
||||
|
||||
--------------------
|
||||
|
||||
* 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
|
||||
* Contribution guidelines: [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
* Core Development: [DEVELOPERS.md](DEVELOPERS.md)
|
||||
* Dashboard: https://dashboard.angularjs.org
|
||||
grunt package
|
||||
|
||||
|
||||
Documentation
|
||||
--------------------
|
||||
Go to https://docs.angularjs.org
|
||||
Running Tests
|
||||
-------------
|
||||
To execute all unit tests, use:
|
||||
|
||||
Contribute
|
||||
--------------------
|
||||
grunt test:unit
|
||||
|
||||
We've set up a separate document for our
|
||||
To execute end-to-end (e2e) tests, use:
|
||||
|
||||
grunt package
|
||||
grunt test:e2e
|
||||
|
||||
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).
|
||||
|
||||
Develop
|
||||
--------------------
|
||||
|
||||
We've set up a separate document for
|
||||
[developers](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md).
|
||||
|
||||
|
||||
[](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 AngularJS’s 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 AngularJS 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.
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
# AngularJS Release instructions
|
||||
|
||||
|
||||
## Compare the list of commits between stable and unstable
|
||||
|
||||
There is a script - compare-master-to-stable.js - that helps with this.
|
||||
We just want to make sure that good commits (low risk fixes + docs fixes) got cherry-picked into stable branch and nothing interesting got merged only into stable branch.
|
||||
|
||||
|
||||
## Pick a release name (for this version)
|
||||
|
||||
A super-heroic power (adverb-verb phrase).
|
||||
|
||||
|
||||
## Generate release notes
|
||||
|
||||
Example Commit: https://github.com/angular/angular.js/commit/7ab5098c14ee4f195dbfe2681e402fe2dfeacd78
|
||||
|
||||
1) Run
|
||||
|
||||
```bash
|
||||
node_modules/.bin/changez -o changes.md -v <new version> <base branch>
|
||||
```
|
||||
|
||||
2) Review the generated file and manually fix typos, group and reorder stuff if needed.
|
||||
3) Move the content into CHANGELOG.md add release code-names to headers.
|
||||
4) Push the changes to your private github repo and review.
|
||||
5) cherry-pick the release notes commit to the appropriate branches.
|
||||
|
||||
|
||||
## Pick a commit to release (for this version)
|
||||
|
||||
Usually this will be the commit containing the release notes, but it may also be in the past.
|
||||
|
||||
|
||||
## Run "release" script
|
||||
|
||||
```bash
|
||||
scripts/jenkins/release.sh --git-push-dryrun=false --commit-sha=8822a4f --version-number=1.7.6 --version-name=gravity-manipulation
|
||||
```
|
||||
|
||||
1) The SHA is of the commit to release (could be in the past).
|
||||
|
||||
2) The version number and code-name that should be released, not the next version number (e.g. to release 1.2.12 you enter 1.2.12 as release version and the code-name that was picked for 1.2.12, cauliflower-eradication).
|
||||
|
||||
3) You will need to have write access to all the AngularJS github dist repositories and publish rights for the AngularJS packages on npm.
|
||||
|
||||
|
||||
## Update GitHub milestones
|
||||
|
||||
1) Create the next milestone if it doesn't exist yet-giving ita due date.
|
||||
2) Move all open issues and PRs for the current milestone to the next milestone<br>
|
||||
You can do this by filtering the current milestone, selecting via checklist, and moving to the next milestone within the GH issues page.
|
||||
|
||||
3) Close the current milestone click the milestones tab and close from there.
|
||||
4) Create a new holding milestone for the release after next-but don't give it a due date otherwise that will mess up the dashboard.
|
||||
|
||||
|
||||
## Push build artifacts to CDN
|
||||
|
||||
Google CDNs are fed with data from google3 every day at 11:15am PT it takes only few minutes for the import to propagate).
|
||||
If we want to make our files available, we need submit our CLs before this time on the day of the release.
|
||||
|
||||
|
||||
## Don't update the package.json (branchVersion) until the CDN has updated
|
||||
|
||||
This is the version used to compute what version to link to in the CDN. If you update this too early then the CDN lookup fails and you end up with 'null, for the version, which breaks the docs.
|
||||
|
||||
|
||||
## Verify angularjs.org download modal has latest version (updates via Travis job)
|
||||
|
||||
The versions in the modal are updated (based on the versions available on CDN) as part of the Travis deploy stage: https://github.com/angular/angularjs.org/blob/a4d25c5abcd39e8ce19d31cb1c78073d13c4c974/.travis.yml#L26
|
||||
(You may need to explicitly trigger the Travis job. e.g. re-running the last job.)
|
||||
|
||||
|
||||
## Announce the release (via official Google accounts)
|
||||
|
||||
Double check that angularjs.org is up to date with the new release version before sharing.
|
||||
|
||||
1) Collect a list of contributors
|
||||
|
||||
use: `git log --format='%aN' v1.2.12..v1.2.13 | sort -u`
|
||||
|
||||
2) Write a blog post (for minor releases, not patch releases) and publish it with the "release" tag
|
||||
3) Post on twitter as yourself (tweet from your heart; there is no template for this), retweet as @AngularJS
|
||||
|
||||
|
||||
## Party!
|
||||
|
||||
|
||||
## Major Release Tasks
|
||||
|
||||
1) Update angularjs.org to use the latest branch.
|
||||
2) Write up a migration document.
|
||||
3) Create a new git branch for the version that has been released (e.g. 1.8.x).
|
||||
4) Check that the build and release scripts still work.
|
||||
5) Update the dist-tag of the old branch, see https://github.com/angular/angular.js/pull/12722.
|
||||
6) Write a blog post.
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
# Triage new issues/PRs on github
|
||||
|
||||
This document shows the steps the AngularJS team is using to triage issues.
|
||||
This document shows the steps the Angular team is using to triage issues.
|
||||
The labels are used later on for [planning releases](#assigning-work).
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -45,12 +45,12 @@ This process based on the idea of minimizing user pain
|
||||
1. Label `frequency: *` – How often does this issue come up? How many developers does this affect? Chose just one of the following:
|
||||
* low - obscure issue affecting a handful of developers
|
||||
* moderate - impacts a common usage pattern
|
||||
* high - impacts most or all AngularJS apps
|
||||
* high - impacts most or all Angular apps
|
||||
1. Label `severity: *` - How bad is the issue? Chose just one of the following:
|
||||
* security issue
|
||||
* regression
|
||||
* memory leak
|
||||
* broken expected use - it's hard or impossible for a developer using AngularJS to accomplish something that AngularJS should be able to do
|
||||
* broken expected use - it's hard or impossible for a developer using Angular to accomplish something that Angular should be able to do
|
||||
* confusing - unexpected or inconsistent behavior; hard-to-debug
|
||||
* inconvenience - causes ugly/boilerplate code in apps
|
||||
1. Label `component: *`
|
||||
@@ -95,7 +95,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 to the npm registry.
|
||||
> 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
|
||||
|
||||
+47
-107
@@ -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',
|
||||
@@ -28,8 +27,6 @@ var angularFiles = {
|
||||
'src/ng/httpBackend.js',
|
||||
'src/ng/interpolate.js',
|
||||
'src/ng/interval.js',
|
||||
'src/ng/intervalFactory.js',
|
||||
'src/ng/jsonpCallbacks.js',
|
||||
'src/ng/locale.js',
|
||||
'src/ng/location.js',
|
||||
'src/ng/log.js',
|
||||
@@ -41,7 +38,6 @@ var angularFiles = {
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
'src/ng/taskTrackerFactory.js',
|
||||
'src/ng/templateRequest.js',
|
||||
'src/ng/testability.js',
|
||||
'src/ng/timeout.js',
|
||||
@@ -72,11 +68,9 @@ 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/ngRef.js',
|
||||
'src/ng/directive/ngRepeat.js',
|
||||
'src/ng/directive/ngShowHide.js',
|
||||
'src/ng/directive/ngStyle.js',
|
||||
@@ -84,6 +78,7 @@ var angularFiles = {
|
||||
'src/ng/directive/ngTransclude.js',
|
||||
'src/ng/directive/script.js',
|
||||
'src/ng/directive/select.js',
|
||||
'src/ng/directive/style.js',
|
||||
'src/ng/directive/validators.js',
|
||||
'src/angular.bind.js',
|
||||
'src/publishExternalApis.js',
|
||||
@@ -106,13 +101,12 @@ var angularFiles = {
|
||||
'src/ngAnimate/animateJs.js',
|
||||
'src/ngAnimate/animateJsDriver.js',
|
||||
'src/ngAnimate/animateQueue.js',
|
||||
'src/ngAnimate/animateCache.js',
|
||||
'src/ngAnimate/animation.js',
|
||||
'src/ngAnimate/ngAnimateSwap.js',
|
||||
'src/ngAnimate/module.js'
|
||||
],
|
||||
'ngCookies': [
|
||||
'src/ngCookies/cookies.js',
|
||||
'src/ngCookies/cookieStore.js',
|
||||
'src/ngCookies/cookieWriter.js'
|
||||
],
|
||||
'ngMessageFormat': [
|
||||
@@ -125,16 +119,10 @@ var angularFiles = {
|
||||
'ngMessages': [
|
||||
'src/ngMessages/messages.js'
|
||||
],
|
||||
'ngParseExt': [
|
||||
'src/ngParseExt/ucd.js',
|
||||
'src/ngParseExt/module.js'
|
||||
],
|
||||
'ngResource': [
|
||||
'src/ngResource/resource.js'
|
||||
],
|
||||
'ngRoute': [
|
||||
'src/shallowCopy.js',
|
||||
'src/routeToRegExp.js',
|
||||
'src/ngRoute/route.js',
|
||||
'src/ngRoute/routeParams.js',
|
||||
'src/ngRoute/directive/ngView.js'
|
||||
@@ -144,13 +132,12 @@ var angularFiles = {
|
||||
'src/ngSanitize/filter/linky.js'
|
||||
],
|
||||
'ngMock': [
|
||||
'src/routeToRegExp.js',
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'src/ngMock/browserTrigger.js'
|
||||
'src/ngMock/angular-mocks.js'
|
||||
],
|
||||
'ngTouch': [
|
||||
'src/ngTouch/touch.js',
|
||||
'src/ngTouch/swipe.js',
|
||||
'src/ngTouch/directive/ngClick.js',
|
||||
'src/ngTouch/directive/ngSwipe.js'
|
||||
],
|
||||
'ngAria': [
|
||||
@@ -158,13 +145,31 @@ var angularFiles = {
|
||||
]
|
||||
},
|
||||
|
||||
'angularScenario': [
|
||||
'src/ngScenario/Scenario.js',
|
||||
'src/ngScenario/browserTrigger.js',
|
||||
'src/ngScenario/Application.js',
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Future.js',
|
||||
'src/ngScenario/ObjectModel.js',
|
||||
'src/ngScenario/Runner.js',
|
||||
'src/ngScenario/SpecRunner.js',
|
||||
'src/ngScenario/dsl.js',
|
||||
'src/ngScenario/matchers.js',
|
||||
'src/ngScenario/output/Html.js',
|
||||
'src/ngScenario/output/Json.js',
|
||||
'src/ngScenario/output/Xml.js',
|
||||
'src/ngScenario/output/Object.js'
|
||||
],
|
||||
|
||||
'angularTest': [
|
||||
'test/helpers/*.js',
|
||||
'test/ngScenario/*.js',
|
||||
'test/ngScenario/output/*.js',
|
||||
'test/*.js',
|
||||
'test/auto/*.js',
|
||||
'test/ng/**/*.js',
|
||||
'test/ngAnimate/*.js',
|
||||
'test/ngMessageFormat/*.js',
|
||||
'test/ngMessages/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngResource/*.js',
|
||||
@@ -176,123 +181,58 @@ var angularFiles = {
|
||||
],
|
||||
|
||||
'karma': [
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'test/jquery_remove.js',
|
||||
'@angularSrc',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'@angularTest'
|
||||
],
|
||||
|
||||
'karmaExclude': [
|
||||
'test/jquery_alias.js',
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js',
|
||||
'src/angular.bind.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngAnimate': [
|
||||
'karmaScenario': [
|
||||
'build/angular-scenario.js',
|
||||
'build/docs/docs-scenario.js'
|
||||
],
|
||||
|
||||
"karmaModules": [
|
||||
'build/angular.js',
|
||||
'build/angular-mocks.js',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'test/helpers/matchers.js',
|
||||
'test/helpers/privateMocks.js',
|
||||
'test/helpers/support.js',
|
||||
'test/helpers/testabilityPatch.js',
|
||||
'@angularSrcModuleNgAnimate',
|
||||
'test/ngAnimate/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngAria': [
|
||||
'@angularSrcModuleNgAria',
|
||||
'test/ngAria/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngCookies': [
|
||||
'@angularSrcModuleNgCookies',
|
||||
'test/ngCookies/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngMessageFormat': [
|
||||
'@angularSrcModuleNgMessageFormat',
|
||||
'test/ngMessageFormat/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngMessages': [
|
||||
'build/angular-animate.js',
|
||||
'@angularSrcModuleNgMessages',
|
||||
'test/ngMessages/**/*.js'
|
||||
],
|
||||
|
||||
// ngMock doesn't include the base because it must use the ngMock src files
|
||||
'karmaModules-ngMock': [
|
||||
'build/angular.js',
|
||||
'src/ngMock/*.js',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'test/helpers/matchers.js',
|
||||
'test/helpers/privateMocks.js',
|
||||
'test/helpers/support.js',
|
||||
'test/helpers/testabilityPatch.js',
|
||||
'src/routeToRegExp.js',
|
||||
'build/angular-animate.js',
|
||||
'test/ngMock/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngResource': [
|
||||
'@angularSrcModuleNgResource',
|
||||
'test/ngResource/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngRoute': [
|
||||
'build/angular-animate.js',
|
||||
'@angularSrcModuleNgRoute',
|
||||
'test/ngRoute/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngSanitize': [
|
||||
'@angularSrcModuleNgSanitize',
|
||||
'test/ngSanitize/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngTouch': [
|
||||
'@angularSrcModuleNgTouch',
|
||||
'test/ngTouch/**/*.js'
|
||||
'@angularSrcModules',
|
||||
'src/ngScenario/browserTrigger.js',
|
||||
'test/helpers/*.js',
|
||||
'test/ngMessageFormat/*.js',
|
||||
'test/ngMock/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngRoute/**/*.js',
|
||||
'test/ngResource/*.js',
|
||||
'test/ngSanitize/**/*.js',
|
||||
'test/ngTouch/**/*.js',
|
||||
'test/ngAria/*.js'
|
||||
],
|
||||
|
||||
'karmaJquery': [
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'test/jquery_alias.js',
|
||||
'@angularSrc',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'@angularTest'
|
||||
],
|
||||
|
||||
'karmaJqueryExclude': [
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js',
|
||||
'test/jquery_remove.js',
|
||||
'src/angular.bind.js'
|
||||
]
|
||||
};
|
||||
|
||||
['2.1', '2.2'].forEach(function(jQueryVersion) {
|
||||
angularFiles['karmaJquery' + jQueryVersion] = []
|
||||
.concat(angularFiles.karmaJquery)
|
||||
.map(function(path) {
|
||||
if (path.startsWith('node_modules/jquery')) {
|
||||
return path.replace(/^node_modules\/jquery/, 'node_modules/jquery-' + jQueryVersion);
|
||||
}
|
||||
return path;
|
||||
});
|
||||
});
|
||||
|
||||
angularFiles['angularSrcModuleNgAnimate'] = angularFiles['angularModules']['ngAnimate'];
|
||||
angularFiles['angularSrcModuleNgAria'] = angularFiles['angularModules']['ngAria'];
|
||||
angularFiles['angularSrcModuleNgCookies'] = angularFiles['angularModules']['ngCookies'];
|
||||
angularFiles['angularSrcModuleNgMessageFormat'] = angularFiles['angularModules']['ngMessageFormat'];
|
||||
angularFiles['angularSrcModuleNgMessages'] = angularFiles['angularModules']['ngMessages'];
|
||||
angularFiles['angularSrcModuleNgResource'] = angularFiles['angularModules']['ngResource'];
|
||||
angularFiles['angularSrcModuleNgRoute'] = angularFiles['angularModules']['ngRoute'];
|
||||
angularFiles['angularSrcModuleNgSanitize'] = angularFiles['angularModules']['ngSanitize'];
|
||||
angularFiles['angularSrcModuleNgTouch'] = angularFiles['angularModules']['ngTouch'];
|
||||
|
||||
angularFiles['angularSrcModules'] = [].concat(
|
||||
angularFiles['angularModules']['ngAnimate'],
|
||||
angularFiles['angularModules']['ngMessageFormat'],
|
||||
@@ -314,7 +254,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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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
@@ -1 +0,0 @@
|
||||
// Override me with ?jquery=/node_modules/jquery/dist/jquery.js
|
||||
@@ -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>
|
||||
@@ -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 »</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 »</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 »</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>© 2016 Company, Inc. · <a href="#">Privacy</a> · <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'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
|
||||
@@ -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',
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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,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
@@ -1 +1 @@
|
||||
// Override me with ?jquery=/node_modules/jquery/dist/jquery.js
|
||||
//Override me with ?jquery=/bower_components/jquery/dist/jquery.js
|
||||
|
||||
@@ -8,20 +8,20 @@
|
||||
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>interpolation + bind-once: <input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation"></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>
|
||||
<div>ngModel (const name): <input type="radio" ng-model="benchmarkType" value="ngModelConstName"></div>
|
||||
<div>ngModel (interp name): <input type="radio" ng-model="benchmarkType" value="ngModelInterpName"></div>
|
||||
|
||||
<ng-switch on="benchmarkType">
|
||||
<baseline-binding-table ng-switch-when="baselineBinding">
|
||||
|
||||
@@ -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)
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
Regular → Executable
+1
-1
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
/* globals angular, benchmarkSteps */
|
||||
|
||||
|
||||
Regular → Executable
+2
-6
@@ -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',
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
Regular → Executable
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
// Override me with ?jquery=/node_modules/jquery/dist/jquery.js
|
||||
Regular → Executable
+29
-26
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
var app = angular.module('parsedExpressionBenchmark', []);
|
||||
|
||||
app.config(function($compileProvider) {
|
||||
@@ -19,26 +17,30 @@ 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);
|
||||
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
//Executes the specified expression as a collection watcher
|
||||
app.directive('bmPeWatchCollection', function() {
|
||||
//Executes the specified expression as a watcher
|
||||
//Adds a simple wrapper method to allow use of $watch instead of $watchCollection
|
||||
app.directive('bmPeWatchLiteral', function($parse) {
|
||||
function retZero() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, $attrs) {
|
||||
$element.text($attrs.bmPeWatchCollection);
|
||||
$element.text( $attrs.bmPeWatchLiteral );
|
||||
return function($scope, $element, $attrs) {
|
||||
$scope.$watchCollection($attrs.bmPeWatchCollection, function(val) {
|
||||
$element.text(val);
|
||||
});
|
||||
$scope.$watch( $parse($attrs.bmPeWatchLiteral, retZero) );
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -51,32 +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]))
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
Regular → Executable
+2
-6
@@ -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',
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
Regular → Executable
+35
-62
@@ -16,6 +16,12 @@
|
||||
<label for="complexPath">Complex Paths</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="constructorPath" id="constructorPath">
|
||||
<label for="constructorPath">Constructor Paths</label>
|
||||
($parse special cases "constructor" for security)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="fieldAccess" id="fieldAccess">
|
||||
<label for="fieldAccess">Field Accessors</label>
|
||||
@@ -46,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>
|
||||
@@ -60,16 +61,6 @@
|
||||
<input type="radio" ng-model="expressionType" value="arrayLiterals" id="arrayLiterals">
|
||||
<label for="arrayLiterals">Array Literals</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="watchCollection" id="watchCollection">
|
||||
<label for="watchCollection">$watchCollection</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="watchCollectionLiterals" id="watchCollectionLiterals">
|
||||
<label for="watchCollectionLiterals">$watchCollection Literals</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!--
|
||||
@@ -92,6 +83,17 @@
|
||||
<span bm-pe-watch="row.keys"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="constructorPath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.constructor.index"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="complexPath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.num0"></span>
|
||||
@@ -195,57 +197,28 @@
|
||||
<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="{foo: rowIdx}"></span>
|
||||
<span bm-pe-watch="{foo: row, bar: rowIdx}"></span>
|
||||
<span bm-pe-watch="{0: row, 1: rowIdx, 2: 3}"></span>
|
||||
<span bm-pe-watch="{str: 'foo', num: rowIdx, b: true}"></span>
|
||||
<span bm-pe-watch="{a: {b: {c: {d: {e: {f: rowIdx}}}}}}"></span>
|
||||
<span bm-pe-watch="{a: rowIdx, b: 1, c: 2, d: 3, e: 4, f: 5, g: rowIdx, h: 6, i: 7, j: 8, k: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{foo: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{foo: row, bar: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{0: row, 1: rowIdx, 2: 3}"></span>
|
||||
<span bm-pe-watch-literal="{str: 'foo', num: rowIdx, b: true}"></span>
|
||||
<span bm-pe-watch-literal="{a: {b: {c: {d: {e: {f: rowIdx}}}}}}"></span>
|
||||
<span bm-pe-watch-literal="{a: rowIdx, b: 1, c: 2, d: 3, e: 4, f: 5, g: rowIdx, h: 6, i: 7, j: 8, k: rowIdx}"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="arrayLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="[rowIdx]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1, 2]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1, 2, 3]"></span>
|
||||
<span bm-pe-watch="[[], [rowIdx], [], [], [3], [[[]]]]"></span>
|
||||
<span bm-pe-watch="[rowIdx, undefined, null, true, false]"></span>
|
||||
<span bm-pe-watch="[[][0], [0][0], [][rowIdx]]"></span>
|
||||
<span bm-pe-watch="[0, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, 2, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, 2, 3, rowIdx]"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="watchCollection" ng-repeat="(rowIdx, row) in data">
|
||||
<span bm-pe-watch-collection="data"></span>
|
||||
<span bm-pe-watch-collection="row.keys"></span>
|
||||
<span bm-pe-watch-collection="thisProbablyDoesntHaveAValue"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="watchCollectionLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch-collection="[rowIdx, row]"></span>
|
||||
<span bm-pe-watch-collection="[rowIdx, row, num0, str0, date0, obj, g, h, i, j, k, l, m, n, o, p]"></span>
|
||||
<span bm-pe-watch-collection="{a: rowIdx, b: row, c: num0, d: str0, e: date0, f: obj, g: g, h: h, i: i, j: j, k: k, l: l, m: m, n: n, o: o, p: p}"></span>
|
||||
|
||||
<!-- primitive/valueOf-compatible -->
|
||||
<span bm-pe-watch-collection="[rowIdx, row]"></span>
|
||||
<span bm-pe-watch-collection="[rowIdx, num0, str0, date0, date1, h, i, j, k, l, m, n, o, p]"></span>
|
||||
<span bm-pe-watch-collection="{a: rowIdx, c: num0, d: str0, e: date0, g: date1, h: h, i: i, j: j, k: k, l: l, m: m, n: n, o: o, p: p}"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2, 3]"></span>
|
||||
<span bm-pe-watch-literal="[[], [rowIdx], [], [], [3], [[[]]]]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, undefined, null, true, false]"></span>
|
||||
<span bm-pe-watch-literal="[[][0], [0][0], [][rowIdx]]"></span>
|
||||
<span bm-pe-watch-literal="[0, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, 3, rowIdx]"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', ['ngAnimate'])
|
||||
.config(function($animateProvider) {
|
||||
$animateProvider.classNameFilter(/animate-/);
|
||||
})
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'classfilter';
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', [])
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'noanimate';
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', ['ngAnimate'])
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'default';
|
||||
});
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [
|
||||
{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
id: 'angular-animate',
|
||||
src: '/build/angular-animate.js'
|
||||
},
|
||||
{
|
||||
id: 'app',
|
||||
src: 'app.js'
|
||||
},
|
||||
{
|
||||
src: 'common.js'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -1,120 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
var app = angular.module('repeatAnimateBenchmark');
|
||||
|
||||
app.config(function($compileProvider, $animateProvider) {
|
||||
if ($compileProvider.debugInfoEnabled) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
app.run(function($animate) {
|
||||
if ($animate.enabled) {
|
||||
$animate.enabled(true);
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('DataController', function($scope, $rootScope, $animate) {
|
||||
var totalRows = 500;
|
||||
var totalColumns = 20;
|
||||
|
||||
var data = $scope.data = [];
|
||||
|
||||
function fillData() {
|
||||
if ($animate.enabled) {
|
||||
$animate.enabled($scope.benchmarkType !== 'globallyDisabled');
|
||||
}
|
||||
|
||||
for (var i = 0; i < totalRows; i++) {
|
||||
data[i] = [];
|
||||
for (var j = 0; j < totalColumns; j++) {
|
||||
data[i][j] = {
|
||||
i: i
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'enter',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
fillData();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'leave',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
data = $scope.data = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.directive('disableAnimations', function($animate) {
|
||||
return {
|
||||
link: {
|
||||
pre: function(s, e) {
|
||||
$animate.enabled(e, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.directive('noop', function($animate) {
|
||||
return {
|
||||
link: {
|
||||
pre: angular.noop
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.directive('baseline', function($document) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function($scope, $element) {
|
||||
var document = $document[0];
|
||||
|
||||
var i, j, row, cell, comment;
|
||||
var template = document.createElement('span');
|
||||
template.setAttribute('ng-repeat', 'foo in foos');
|
||||
template.classList.add('ng-scope');
|
||||
template.appendChild(document.createElement('span'));
|
||||
template.appendChild(document.createTextNode(':'));
|
||||
|
||||
function createList() {
|
||||
for (i = 0; i < $scope.data.length; i++) {
|
||||
row = document.createElement('div');
|
||||
$element[0].appendChild(row);
|
||||
for (j = 0; j < $scope.data[i].length; j++) {
|
||||
cell = template.cloneNode(true);
|
||||
row.appendChild(cell);
|
||||
cell.childNodes[0].textContent = i;
|
||||
cell.ng339 = 'xxx';
|
||||
comment = document.createComment('ngRepeat end: bar in foo');
|
||||
row.appendChild(comment);
|
||||
}
|
||||
|
||||
comment = document.createComment('ngRepeat end: foo in foos');
|
||||
$element[0].appendChild(comment);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch('data.length', function(newVal) {
|
||||
if (newVal === 0) {
|
||||
while ($element[0].firstChild) {
|
||||
$element[0].removeChild($element[0].firstChild);
|
||||
}
|
||||
} else {
|
||||
createList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -1,70 +0,0 @@
|
||||
<div ng-app="repeatAnimateBenchmark" ng-cloak>
|
||||
<div ng-controller="DataController">
|
||||
<div class="container-fluid">
|
||||
<p>
|
||||
Tests rendering of an ngRepeat with 500 elements.<br>
|
||||
Animations can be enabled / disabled in different ways.<br>
|
||||
Two tests require reloading the app with different module / app configurations.
|
||||
</p>
|
||||
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="baseline">baseline (vanilla Javascript): </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default'" value="enabled">enabled : </label> (requires <a href="./">app.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default' && fileType !== 'classfilter'" value="globallyDisabled">globally disabled:</label> (requires <a href="./">app.js</a> or <a href="?app=app-classfilter.js">app-classfilter.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default'" value="disabledParentElement">disabled by $animate.enabled() on parent element: </label> (requires <a href="./">app.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'noanimate'" value="noanimate">Without ngAnimate:</label> (requires <a href="?app=app-noanimate.js">app-noanimate.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'classfilter'" value="disabledClassFilter">disabled by classNameFilter on element:</label> (requires <a href="?app=app-classfilter.js">app-classfilter.js</a>)</div>
|
||||
|
||||
<ng-switch on="benchmarkType">
|
||||
<baseline ng-switch-when="baseline">
|
||||
</baseline>
|
||||
<div ng-switch-when="noanimate">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="enabled">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="globallyDisabled">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="disabledClassFilter">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span class="disable-animations" ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="disabledParentElement">
|
||||
<div disable-animations>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -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'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "AngularJS",
|
||||
"devDependencies": {
|
||||
"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.3/assets/ng-closure-runner.zip"
|
||||
}
|
||||
}
|
||||
Executable
+210
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
// 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];
|
||||
return tags.
|
||||
filter(function(ver) {
|
||||
return semver(ver).major === major;
|
||||
filter(function (ver) {
|
||||
return semver(ver).major == 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);
|
||||
});
|
||||
|
||||
@@ -13,8 +13,7 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#json,
|
||||
#xml {
|
||||
#json, #xml {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -1,11 +1,7 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
[ng\:cloak],
|
||||
[ng-cloak],
|
||||
[data-ng-cloak],
|
||||
[x-ng-cloak],
|
||||
.ng-cloak,
|
||||
.x-ng-cloak,
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
|
||||
.ng-cloak, .x-ng-cloak,
|
||||
.ng-hide:not(.ng-hide-animate) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.visible-phone{display:none}.visible-desktop{display:block}.navbar{display:block}.navbar .container{padding:0 16px;width:auto}.navbar .brand{float:left;margin:8px 80px 0 8px;padding:0}.navbar .brand a{display:block;height:30px;margin:6px 0 5px 0;overflow:hidden;padding:0;width:117px}.navbar .nav{float:right}.navbar .nav .dropdown-toggle{color:rgba(255,255,255,0.87);font-size:16px;font-weight:300;line-height:56px;padding:0 24px;text-transform:uppercase;transition:all .3s}.navbar .nav .dropdown-toggle:hover,.navbar .nav .dropdown-toggle:active,.navbar .nav .dropdown-toggle:focus{background:#37474F;color:#fff}.navbar .nav .dropdown-menu{background:#37474F;border:none;border-radius:0;box-shadow:0 0 16px rgba(0,0,0,0.12),0 16px 16px rgba(0,0,0,0.24);color:#fff;left:auto;margin:0;padding:0;right:0}.navbar .nav .dropdown-menu:after,.navbar .nav .dropdown-menu:before{display:none}.navbar .nav .dropdown-menu li{border-bottom:1px solid rgba(38,50,56,0.56);box-sizing:border-box;line-height:48px}.navbar .nav .dropdown-menu li:last-child{border:none}.navbar .nav .dropdown-menu a{background:#37474F;color:#fff;font-weight:300;line-height:48px;padding:0 16px;transition:all .2s}.navbar .nav .dropdown-menu a:hover,.navbar .nav .dropdown-menu a:focus{background:#455A64}.navbar .navbar-search{left:200px;margin:0;position:absolute;right:440px;top:8px;width:auto}.navbar .navbar-search i{color:#546E7A;font-size:16px;left:12px;position:absolute;top:11px}.navbar .navbar-search .search-query{background:#37474F;border:none;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#546E7A;font-size:14px;height:40px;width:100%;padding:0 16px 0 32px;text-shadow:none;transition:all .3s}.navbar .navbar-search .search-query:-webkit-autofill,.navbar .navbar-search .search-query:-webkit-autofill:hover,.navbar .navbar-search .search-query:-webkit-autofill:focus{background-color:#fff;transition:background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#455A64}.navbar .navbar-search .search-query:hover,.navbar .navbar-search .search-query:active,.navbar .navbar-search .search-query:focus{background:#fff;box-shadow:inset 0 2px 4px rgba(0,0,0,0.24);color:#2196F3}.navbar .navbar-search .search-query::-webkit-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query::-moz-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-ms-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-moz-placeholder{color:#546E7A}#navbar-main .navbar-inner{background:#263238;height:56px}#navbar-notice{z-index:1029;top:56px}#navbar-notice .navbar-inner{background:#ECEFF1;box-shadow:0 0 3px rgba(0,0,0,0.12),0 3px 3px rgba(0,0,0,0.24);height:auto}.site-notice{padding:4px 0;text-align:center;font-size:13px;margin:0}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.visible-phone{display:block}.visible-desktop{display:none}}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.homepage .container{padding:16px;width:auto}.homepage .span1{width:auto}.homepage .span2{width:auto}.homepage .span3{width:auto}.homepage .span4{width:auto}.homepage .span5{width:auto}.homepage .span6{width:auto}.homepage .span7{width:auto}.homepage .span8{width:auto}.homepage .span9{width:auto}.homepage .span10{width:auto}.homepage .navbar .container{padding:0 8px}.homepage #navbar-main .navbar-inner{height:40px}.homepage #navbar-main .brand{margin:6px 0 0 0}.homepage #navbar-main .brand a{margin:0}.homepage #navbar-main .nav{margin:0}.homepage #navbar-main .nav .dropdown-toggle{font-size:12px;line-height:40px;padding:0 8px}.homepage #navbar-main .dropdown-menu a{padding:0 8px}.homepage #navbar-main .navbar-search{background:#263238;border-bottom:1px solid #263238;left:0;right:0;top:100%}.homepage #navbar-main .navbar-search i{left:12px;top:7px}.homepage #navbar-main .navbar-search .search-query{border-radius:0;height:32px}.homepage #navbar-notice{top:40px}.homepage #navbar-notice .site-notice{font-size:11px}.homepage .hero{padding:80px 32px 32px 32px}.homepage .hero h2{background-size:230px 60px;height:60px;width:230px}}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+219
-497
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.1 KiB |
Regular → Executable
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 212 B |
+442
@@ -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
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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,4 +0,0 @@
|
||||
User-agent: *
|
||||
|
||||
# The map files are not required by the app
|
||||
Disallow: /*.map$
|
||||
@@ -1,15 +1,28 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "../../../.eslintrc-node.json",
|
||||
|
||||
|
||||
"env": {
|
||||
"jasmine": true,
|
||||
"protractor": true
|
||||
},
|
||||
"extends": "../../../.jshintrc-base",
|
||||
|
||||
"globals": {
|
||||
"angular": false,
|
||||
|
||||
/* 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,
|
||||
@@ -26,4 +39,4 @@
|
||||
"browserTrigger": false,
|
||||
"jqLiteCacheSize": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
describe('API pages', function() {
|
||||
describe("doc.angularjs.org", 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/);
|
||||
describe("API pages", function() {
|
||||
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
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/);
|
||||
|
||||
it('should change the page content when clicking a link to a service', function() {
|
||||
browser.get('build/docs/index.html');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('build/docs/index.html');
|
||||
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
});
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
it('should show the functioning input directive example', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/input');
|
||||
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.
|
||||
browser.waitForAngular();
|
||||
// Ensure that the page is loaded before trying to switch frames.
|
||||
browser.waitForAngular();
|
||||
|
||||
browser.switchTo().frame('example-input-directive');
|
||||
browser.switchTo().frame('example-input-directive');
|
||||
|
||||
var nameInput = element(by.model('user.name'));
|
||||
nameInput.sendKeys('!!!');
|
||||
var nameInput = element(by.model('user.name'));
|
||||
nameInput.sendKeys('!!!');
|
||||
|
||||
var code = element.all(by.css('tt')).first();
|
||||
expect(code.getText()).toContain('guest!!!');
|
||||
});
|
||||
var code = element.all(by.css('tt')).first();
|
||||
expect(code.getText()).toContain('guest!!!');
|
||||
});
|
||||
|
||||
it('should trim indentation from code blocks', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/type/$rootScope.Scope');
|
||||
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'));
|
||||
codeBlocks.each(function(codeBlock) {
|
||||
var firstSpan = codeBlock.all(by.css('span')).first();
|
||||
expect(firstSpan.getText()).not.toMatch(/^\W+$/);
|
||||
var codeBlocks = element.all(by.css('pre > code.lang-js'));
|
||||
codeBlocks.each(function(codeBlock) {
|
||||
var firstSpan = codeBlock.all(by.css('span')).first();
|
||||
expect(firstSpan.getText()).not.toMatch(/^\W+$/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('directives', function() {
|
||||
|
||||
describe('parameter section', function() {
|
||||
|
||||
it('should show the directive name only if it is a param (attribute) with a value', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/ngInclude');
|
||||
expect(getParamNames().getText()).toContain('ngInclude | src');
|
||||
|
||||
browser.get('build/docs/index.html#!/api/ngRoute/directive/ngView');
|
||||
expect(getParamNames().getText()).not.toContain('ngView');
|
||||
});
|
||||
});
|
||||
|
||||
describe('usage section', function() {
|
||||
|
||||
it('should show the directive name if it is a param (attribute) with a value', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/ngInclude');
|
||||
|
||||
expect(getUsageAs('element', 'ng-include').isPresent()).toBe(true);
|
||||
expect(getUsageAs('attribute', 'ng-include').isPresent()).toBe(true);
|
||||
expect(getUsageAs('CSS class', 'ng-include').isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
it('should show the directive name if it is a void param (attribute)', function() {
|
||||
browser.get('build/docs/index.html#!/api/ngRoute/directive/ngView');
|
||||
|
||||
expect(getUsageAs('element', 'ng-view').isPresent()).toBe(true);
|
||||
expect(getUsageAs('attribute', 'ng-view').isPresent()).toBe(true);
|
||||
expect(getUsageAs('CSS class', 'ng-view').isPresent()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getParamNames() {
|
||||
var argsSection = element(by.className('input-arguments'));
|
||||
|
||||
var paramNames = argsSection.all(by.css('tr td:nth-child(1)'));
|
||||
|
||||
return paramNames;
|
||||
}
|
||||
|
||||
// Based on the type of directive usage, the directive name will show up in the code block
|
||||
// with a specific class
|
||||
var typeClassMap = {
|
||||
element: 'tag',
|
||||
attribute: 'atn',
|
||||
'CSS class': 'atv'
|
||||
};
|
||||
|
||||
function getUsageAs(type, directiveName) {
|
||||
var usage = element(by.className('usage'));
|
||||
|
||||
var as = usage.element(by.cssContainingText('li', 'as ' + type));
|
||||
|
||||
return as.element(by.cssContainingText('span.' + typeClassMap[type], directiveName));
|
||||
}
|
||||
@@ -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)');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
+22
-106
@@ -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
|
||||
@@ -21,13 +21,10 @@ describe('docs.angularjs.org', function() {
|
||||
console.log('browser console errors: ' + require('util').inspect(filteredLog));
|
||||
}
|
||||
});
|
||||
|
||||
browser.ignoreSynchronization = false;
|
||||
browser.clearMockModules();
|
||||
});
|
||||
|
||||
|
||||
describe('App', function() {
|
||||
describe('App', function () {
|
||||
// it('should filter the module list when searching', function () {
|
||||
// browser.get();
|
||||
// browser.waitForAngular();
|
||||
@@ -41,130 +38,49 @@ 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();
|
||||
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
it('should include the files for the embedded examples from the same domain', function() {
|
||||
browser.get('build/docs/index-production.html#!api/ng/directive/ngClick');
|
||||
|
||||
var origin = browser.executeScript('return document.location.origin;');
|
||||
|
||||
var exampleIFrame = element(by.name('example-ng-click'));
|
||||
|
||||
// This is technically an implementation detail, but if this changes, then there's a good
|
||||
// chance the deployment process changed
|
||||
expect(exampleIFrame.getAttribute('src')).toContain('examples/example-ng-click/index.html');
|
||||
|
||||
browser.switchTo().frame('example-ng-click');
|
||||
|
||||
var scriptEl = element(by.tagName('script'));
|
||||
|
||||
// Ensure the included file is from the same domain
|
||||
expect(scriptEl.getAttribute('src')).toContain(origin);
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/');
|
||||
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('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');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
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/');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
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');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('Oops!');
|
||||
});
|
||||
|
||||
it('should set "noindex" if the page does not exist', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/does/not/exist');
|
||||
var robots = element(by.css('meta[name="robots"][content="noindex"]'));
|
||||
var googleBot = element(by.css('meta[name="googlebot"][content="noindex"]'));
|
||||
expect(robots.isPresent()).toBe(true);
|
||||
expect(googleBot.isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove "noindex" if the page exists', function() {
|
||||
browser.get('build/docs/index-production.html#!/api');
|
||||
var robots = element(by.css('meta[name="robots"][content="noindex"]'));
|
||||
var googleBot = element(by.css('meta[name="googlebot"][content="noindex"]'));
|
||||
expect(robots.isPresent()).toBe(false);
|
||||
expect(googleBot.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
describe('template request error', function() {
|
||||
beforeEach(function() {
|
||||
browser.addMockModule('httpMocker', function() {
|
||||
angular.module('httpMocker', ['ngMock'])
|
||||
.run(['$httpBackend', function($httpBackend) {
|
||||
$httpBackend.whenGET('localhost:8000/build/docs/partials/api.html').respond(500, '');
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set "noindex" for robots if the request fails', function() {
|
||||
// index-test includes ngMock
|
||||
browser.get('build/docs/index-test.html#!/api');
|
||||
var robots = element(by.css('meta[name="robots"][content="noindex"]'));
|
||||
var googleBot = element(by.css('meta[name="googlebot"][content="noindex"]'));
|
||||
expect(robots.isPresent()).toBe(true);
|
||||
expect(googleBot.isPresent()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('page bootstrap error', function() {
|
||||
beforeEach(function() {
|
||||
browser.addMockModule('httpMocker', function() {
|
||||
// Require a module that does not exist to break the bootstrapping
|
||||
angular.module('httpMocker', ['doesNotExist']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have "noindex" for robots if bootstrapping fails', function() {
|
||||
browser.get('build/docs/index.html#!/api').catch(function() {
|
||||
// get() will fail on AngularJS bootstrap, but if we continue here, protractor
|
||||
// will assume the app is ready
|
||||
browser.ignoreSynchronization = true;
|
||||
var robots = element(by.css('meta[name="robots"][content="noindex"]'));
|
||||
var googleBot = element(by.css('meta[name="googlebot"][content="noindex"]'));
|
||||
expect(robots.isPresent()).toBe(true);
|
||||
expect(googleBot.isPresent()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
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!');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,130 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This scenario checks the presence of the table of contents for a sample of pages - API and guide.
|
||||
* The expectations are kept vague so that they can be easily adjusted when the docs change.
|
||||
*/
|
||||
|
||||
describe('table of contents', function() {
|
||||
|
||||
it('on provider pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$controllerProvider');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Methods');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('on service pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$controller');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(3);
|
||||
|
||||
expect(match[2].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on directive pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/input');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
expect(text.join('')).toContain('Directive Info');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(4);
|
||||
|
||||
expect(match[2].all(by.css('li')).count()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('on function pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.bind');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on type pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/type/ModelOptions');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Methods');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on filter pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/filter/date');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(3);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on guide pages', function() {
|
||||
browser.get('build/docs/index.html#!/guide/services');
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(5);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "../../../.eslintrc-browser.json",
|
||||
|
||||
"globals": {
|
||||
"lunr": false
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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
-147
@@ -1,8 +1,5 @@
|
||||
'use strict';
|
||||
angular.module('directives', [])
|
||||
|
||||
var directivesModule = angular.module('directives', []);
|
||||
|
||||
directivesModule
|
||||
/**
|
||||
* backToTop Directive
|
||||
* @param {Function} $anchorScroll
|
||||
@@ -37,147 +34,4 @@ directivesModule
|
||||
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');
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
.directive('tocCollector', ['$rootScope', function($rootScope) {
|
||||
return {
|
||||
controller: ['$element', function($element) {
|
||||
/* eslint-disable no-invalid-this */
|
||||
var ctrl = this;
|
||||
|
||||
$rootScope.$on('$includeContentRequested', function() {
|
||||
ctrl.hs = [];
|
||||
ctrl.root = [];
|
||||
});
|
||||
|
||||
this.hs = [];
|
||||
this.root = [];
|
||||
this.element = $element;
|
||||
|
||||
this.register = function(h) {
|
||||
var previousLevel;
|
||||
|
||||
for (var i = ctrl.hs.length - 1; i >= 0; i--) {
|
||||
if (ctrl.hs[i].level === (h.level - 1)) {
|
||||
previousLevel = ctrl.hs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousLevel) {
|
||||
previousLevel.children.push(h);
|
||||
} else {
|
||||
this.root.push(h);
|
||||
}
|
||||
|
||||
ctrl.hs.push(h);
|
||||
/* eslint-enable no-invalid-this */
|
||||
};
|
||||
}]
|
||||
};
|
||||
}])
|
||||
|
||||
.component('tocTree', {
|
||||
template: '<ul>' +
|
||||
'<li ng-repeat="item in $ctrl.items">' +
|
||||
'<a ng-href="{{ $ctrl.path }}#{{item.fragment}}">{{item.title}}</a>' +
|
||||
'<toc-tree ng-if="::item.children.length > 0" items="item.children"></toc-tree>' +
|
||||
'</li>' +
|
||||
'</ul>',
|
||||
bindings: {
|
||||
items: '<'
|
||||
},
|
||||
controller: ['$location', /** @this */ function($location) {
|
||||
this.path = $location.path().replace(/^\/?(.+?)(\/index)?\/?$/, '$1');
|
||||
}]
|
||||
})
|
||||
.directive('tocContainer', function() {
|
||||
return {
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
require: {
|
||||
tocContainer: '',
|
||||
tocCollector: '^^'
|
||||
},
|
||||
controller: function() {
|
||||
this.showToc = true;
|
||||
this.items = [];
|
||||
},
|
||||
controllerAs: '$ctrl',
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
ctrls.tocContainer.items = ctrls.tocCollector.root;
|
||||
},
|
||||
template: '<div ng-if="::$ctrl.items.length > 1">' +
|
||||
'<b>Contents</b>' +
|
||||
'<button class="btn" ng-click="$ctrl.showToc = !$ctrl.showToc">{{$ctrl.showToc ? \'Hide\' : \'Show\'}}</button><br>' +
|
||||
'<toc-tree items="$ctrl.items" ng-show="$ctrl.showToc"></toc-tree>' +
|
||||
'</div>'
|
||||
};
|
||||
})
|
||||
.directive('header', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: ['$element', function($element) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.element = $element;
|
||||
}]
|
||||
};
|
||||
})
|
||||
.directive('h1', ['$compile', function($compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: {
|
||||
tocCollector: '^^?',
|
||||
header: '^^?'
|
||||
},
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
if (!ctrls.tocCollector) return;
|
||||
|
||||
var tocContainer = angular.element('<toc-container></toc-container>');
|
||||
var containerElement = ctrls.header ? ctrls.header.element : element;
|
||||
|
||||
containerElement.after(tocContainer);
|
||||
$compile(tocContainer)(scope);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
for (var i = 2; i <= 5; i++) {
|
||||
registerHDirective(i);
|
||||
}
|
||||
|
||||
function registerHDirective(i) {
|
||||
directivesModule.directive('h' + i, function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: {
|
||||
'tocCollector': '^^?'
|
||||
},
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
var toc = ctrls.tocCollector;
|
||||
|
||||
if (!toc || !attrs.id) return;
|
||||
|
||||
toc.register({
|
||||
level: i,
|
||||
fragment: attrs.id,
|
||||
title: element.text(),
|
||||
children: []
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+19
-30
@@ -1,14 +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) {
|
||||
|
||||
var errorPartialPath = 'Error404.html';
|
||||
$scope.openPlunkr = openPlunkr;
|
||||
|
||||
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
|
||||
|
||||
$scope.navClass = function(navItem) {
|
||||
return {
|
||||
@@ -18,27 +18,20 @@ 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.loadingError = true;
|
||||
});
|
||||
|
||||
$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;
|
||||
$scope.loadingError = false;
|
||||
|
||||
if (currentPage) {
|
||||
if ( currentPage ) {
|
||||
$scope.partialPath = 'partials/' + path + '.html';
|
||||
$scope.currentArea = NG_NAVIGATION[currentPage.area];
|
||||
var pathParts = currentPage.path.split('/');
|
||||
@@ -46,30 +39,26 @@ 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 {
|
||||
$scope.currentArea = NG_NAVIGATION['api'];
|
||||
$scope.breadcrumb = [];
|
||||
$scope.partialPath = errorPartialPath;
|
||||
$scope.partialPath = 'Error404.html';
|
||||
}
|
||||
});
|
||||
|
||||
$scope.hasError = function() {
|
||||
return $scope.partialPath === errorPartialPath || $scope.loadingError;
|
||||
};
|
||||
|
||||
/**********************************
|
||||
Initialize
|
||||
***********************************/
|
||||
|
||||
$scope.versionNumber = CURRENT_NG_VERSION.full;
|
||||
$scope.version = CURRENT_NG_VERSION.full + ' ' + CURRENT_NG_VERSION.codeName;
|
||||
$scope.loading = false;
|
||||
$scope.loadingError = false;
|
||||
$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
@@ -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, '<').replace(/>/g, '>');
|
||||
};
|
||||
|
||||
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'));
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
+28
-151
@@ -1,56 +1,5 @@
|
||||
'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) {
|
||||
/**
|
||||
@@ -73,119 +22,37 @@ 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 '';
|
||||
};
|
||||
})
|
||||
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
.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"> </i> Edit in Plunker</button> ',
|
||||
controller: [function PlnkrOpenerCtrl() {
|
||||
var ctrl = this;
|
||||
var exampleName = 'AngularJS Example';
|
||||
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
|
||||
|
||||
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) {
|
||||
return function(exampleFolder) {
|
||||
// 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 +61,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', newWindow, postData);
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
+24
-40
@@ -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();
|
||||
}
|
||||
@@ -67,18 +61,12 @@ angular.module('search', [])
|
||||
clearResults();
|
||||
$scope.q = '';
|
||||
};
|
||||
|
||||
$scope.handleResultClicked = function($event) {
|
||||
if ($event.which === 1 && !$event.ctrlKey && !$event.metaKey) {
|
||||
$scope.hideResults();
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
|
||||
.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] || [];
|
||||
@@ -96,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});
|
||||
@@ -142,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
|
||||
@@ -157,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;
|
||||
@@ -208,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();
|
||||
@@ -222,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() {
|
||||
|
||||
@@ -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');
|
||||
@@ -42,11 +39,11 @@ angular.module('tutorials', [])
|
||||
'<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}}" title="See diff on Github">GitHub</a>\n' +
|
||||
'</p>'
|
||||
};
|
||||
});
|
||||
});
|
||||
+26
-41
@@ -1,48 +1,33 @@
|
||||
'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.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;
|
||||
}
|
||||
|
||||
if (CURRENT_NG_VERSION.isSnapshot) {
|
||||
versionStr = CURRENT_NG_VERSION.distTag === 'latest' ? 'snapshot-stable' : 'snapshot';
|
||||
}
|
||||
|
||||
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(/\/$/, ''),
|
||||
url = '';
|
||||
if (version.isOldDocsUrl) {
|
||||
url = version.docsUrl;
|
||||
}else{
|
||||
url = version.docsUrl + currentPagePath;
|
||||
}
|
||||
}
|
||||
});
|
||||
$window.location = url;
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -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,50 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
describe('directives', function() {
|
||||
describe("code", function() {
|
||||
var prettyPrintOne, oldPP;
|
||||
var compile, scope;
|
||||
|
||||
var any = jasmine.any;
|
||||
|
||||
beforeEach(module('directives'));
|
||||
|
||||
beforeEach(module(function($compileProvider) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($rootScope, $compile) {
|
||||
// Provide stub for pretty print function
|
||||
oldPP = window.prettyPrintOne;
|
||||
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
|
||||
|
||||
scope = $rootScope.$new();
|
||||
compile = $compile;
|
||||
}));
|
||||
|
||||
describe('code', function() {
|
||||
var prettyPrintOne, oldPP;
|
||||
var any = jasmine.any;
|
||||
|
||||
beforeEach(function() {
|
||||
// Provide stub for pretty print function
|
||||
oldPP = window.prettyPrintOne;
|
||||
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
window.prettyPrintOne = oldPP;
|
||||
});
|
||||
|
||||
|
||||
it('should pretty print innerHTML', function() {
|
||||
compile('<code>var x;</code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
|
||||
});
|
||||
|
||||
it('should allow language declaration', function() {
|
||||
compile('<code class="lang-javascript"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
|
||||
});
|
||||
|
||||
it('supports allow line numbers', function() {
|
||||
compile('<code class="linenum"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
|
||||
});
|
||||
afterEach(function() {
|
||||
window.prettyPrintOne = oldPP;
|
||||
});
|
||||
|
||||
|
||||
it('should pretty print innerHTML', function() {
|
||||
compile('<code>var x;</code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
|
||||
});
|
||||
|
||||
it('should allow language declaration', function() {
|
||||
compile('<code class="lang-javascript"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
|
||||
});
|
||||
|
||||
it('supports allow line numbers', function() {
|
||||
compile('<code class="linenum"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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']);
|
||||
}));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user