It seems like your browser is having problems with CSS3
\n" +
- "
\n" +
- "
\n" +
- "
" +
- " Your browser does not seem to understand CSS3 {{ feature }}. " +
- " Please click here " +
- " to see which modern browsers support this feature and consider upgrading." +
- "
\n" +
- "");
-}]);
\ No newline at end of file
diff --git a/build-monitor-plugin/src/main/webapp/styles/angular-slider.css b/build-monitor-plugin/src/main/webapp/styles/angular-slider.css
deleted file mode 100755
index baf418d6f..000000000
--- a/build-monitor-plugin/src/main/webapp/styles/angular-slider.css
+++ /dev/null
@@ -1,86 +0,0 @@
-slider {
- display: inline-block;
- position: relative;
- height: 7px;
- width: 100%;
- margin: 25px 5px 25px 5px;
- vertical-align: middle;
-}
-slider span {
- white-space: nowrap;
- position: absolute;
- display: inline-block;
-}
-slider span.base {
- width: 100%;
- height: 100%;
- padding: 0;
-}
-slider span.bar {
- width: 100%;
- height: 100%;
- z-index: 0;
- -webkit-border-radius: 1em/1em;
- border-radius: 1em/1em;
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #c0c0c0), color-stop(1, #8d8d8d));
- background: -webkit-linear-gradient(top, #c0c0c0 0%, #8d8d8d 100%);
- background: -moz-linear-gradient(top, #c0c0c0 0%, #8d8d8d 100%);
- background: -o-linear-gradient(top, #c0c0c0 0%, #8d8d8d 100%);
- background: -ms-linear-gradient(top, #c0c0c0 0%, #8d8d8d 100%);
- background: linear-gradient(top, #c0c0c0 0%, #8d8d8d 100%);
- -webkit-box-shadow: inset 2px 2px 5px;
- box-shadow: inset 2px 2px 5px;
-}
-slider span.bar.selection {
- width: 0%;
- z-index: 1;
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #13b6ff), color-stop(1, #00a8f3));
- background: -webkit-linear-gradient(top, #13b6ff 0%, #00a8f3 100%);
- background: -moz-linear-gradient(top, #13b6ff 0%, #00a8f3 100%);
- background: -o-linear-gradient(top, #13b6ff 0%, #00a8f3 100%);
- background: -ms-linear-gradient(top, #13b6ff 0%, #00a8f3 100%);
- background: linear-gradient(top, #13b6ff 0%, #00a8f3 100%);
- -webkit-box-shadow: none;
- box-shadow: none;
-}
-slider span.pointer {
- cursor: pointer;
- width: 20px;
- height: 20px;
- top: -8px;
- background-color: #fff;
- border: 1px solid #000;
- z-index: 2;
- -webkit-border-radius: 1em/1em;
- border-radius: 1em/1em;
-}
-slider span.pointer:after {
- content: '';
- background-color: #808080;
- width: 8px;
- height: 8px;
- position: absolute;
- top: 6px;
- left: 6px;
- -webkit-border-radius: 1em/1em;
- border-radius: 1em/1em;
-}
-slider span.pointer:hover:after {
- background-color: #000;
-}
-slider span.pointer.active:after {
- background-color: #f00;
-}
-slider span.bubble {
- cursor: default;
- top: -22px;
- padding: 1px 3px 1px 3px;
- font-size: 0.7em;
- font-family: sans-serif;
-}
-slider span.bubble.selection {
- top: 15px;
-}
-slider span.bubble.limit {
- color: #808080;
-}
diff --git a/build-monitor-plugin/src/main/webapp/styles/bootstrap-combined.2.3.2.min.css b/build-monitor-plugin/src/main/webapp/styles/bootstrap-combined.2.3.2.min.css
deleted file mode 100644
index afcd46221..000000000
--- a/build-monitor-plugin/src/main/webapp/styles/bootstrap-combined.2.3.2.min.css
+++ /dev/null
@@ -1,121 +0,0 @@
-/*!
- * Bootstrap v2.3.2
- *
- * Copyright 2012 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world @twitter by @mdo and @fat.
- */
-.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
-.clearfix:after{clear:both;}
-button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
-button,input{*overflow:visible;line-height:normal;}
-button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
-button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
-label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;}
-.btn .label,.btn .badge{position:relative;top:-1px;}
-.btn-mini .label,.btn-mini .badge{top:0;}
-label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;}
-input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
-.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
-.btn:active,.btn.active{background-color:#cccccc \9;}
-.btn:first-child{*margin-left:0;}
-.btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
-.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
-.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
-.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
-.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
-.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;}
-.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
-.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;}
-.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;}
-.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
-.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
-.btn-block+.btn-block{margin-top:5px;}
-input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;}
-.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
-.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
-.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
-.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
-.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
-.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
-.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
-.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
-.btn-success:active,.btn-success.active{background-color:#408140 \9;}
-.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
-.btn-info:active,.btn-info.active{background-color:#24748c \9;}
-.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
-.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
-button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
-button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
-button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
-button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
-.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
-.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
-.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;}
-.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;}
-.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;}
-.btn-group+.btn-group{margin-left:5px;}
-.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;}
-.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
-.btn-group>.btn+.btn{margin-left:-1px;}
-.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;}
-.btn-group>.btn-mini{font-size:10.5px;}
-.btn-group>.btn-small{font-size:11.9px;}
-.btn-group>.btn-large{font-size:17.5px;}
-.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
-.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
-.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
-.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
-.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
-.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
-.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;}
-.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}
-.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}
-.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}
-.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
-.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
-.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}
-.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
-.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
-.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
-.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
-.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
-.btn .caret{margin-top:8px;margin-left:0;}
-.btn-large .caret{margin-top:6px;}
-.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}
-.btn-mini .caret,.btn-small .caret{margin-top:8px;}
-.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
-.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}
-.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
-.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;}
-.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
-.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
-.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}
-.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
-.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
-.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
-.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
-.modal.fade.in{top:10%;}
-.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
-.modal-header h3{margin:0;line-height:30px;}
-.modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;}
-.modal-form{margin-bottom:0;}
-.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;}
-.modal-footer:after{clear:both;}
-.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
-.modal-footer .btn-group .btn+.btn{margin-left:-1px;}
-.modal-footer .btn-block+.btn-block{margin-left:0;}
-.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
-button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
-.hide{display:none;}
-.show{display:block;}
-.invisible{visibility:hidden;}
-.affix{position:fixed;}
-.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}
-.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}
-.visible-phone{display:none !important;}
-.visible-tablet{display:none !important;}
-.hidden-desktop{display:none !important;}
-.visible-desktop{display:inherit !important;}
\ No newline at end of file
diff --git a/build-monitor-plugin/src/main/webapp/styles/normalize.css b/build-monitor-plugin/src/main/webapp/styles/normalize.css
deleted file mode 100644
index 74ec031d4..000000000
--- a/build-monitor-plugin/src/main/webapp/styles/normalize.css
+++ /dev/null
@@ -1,533 +0,0 @@
-/*! normalize.css v1.1.1 | MIT License | git.io/normalize */
-
-/* ==========================================================================
- HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
- */
-
-audio,
-canvas,
-video {
- display: inline-block;
- *display: inline;
- *zoom: 1;
-}
-
-/**
- * Prevent modern browsers ofA displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
- * Known issue: no IE 6 support.
- */
-
-[hidden] {
- display: none;
-}
-
-/* ==========================================================================
- Base
- ========================================================================== */
-
-/**
- * 1. Prevent system color scheme's background color being used in Firefox, IE,
- * and Opera.
- * 2. Prevent system color scheme's text color being used in Firefox, IE, and
- * Opera.
- * 3. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
- * `em` units.
- * 4. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- background: #fff; /* 1 */
- color: #000; /* 2 */
- font-size: 100%; /* 3 */
- -webkit-text-size-adjust: 100%; /* 4 */
- -ms-text-size-adjust: 100%; /* 4 */
-}
-
-/**
- * Address `font-family` inconsistency between `textarea` and other form
- * elements.
- */
-
-html,
-button,
-input,
-select,
-textarea {
- font-family: sans-serif;
-}
-
-/**
- * Address margins handled incorrectly in IE 6/7.
- */
-
-body {
- margin: 0;
-}
-
-/* ==========================================================================
- Links
- ========================================================================== */
-
-/**
- * Address `outline` inconsistency between Chrome and other browsers.
- */
-
-a:focus {
- outline: thin dotted;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* ==========================================================================
- Typography
- ========================================================================== */
-
-/**
- * Address font sizes and margins set differently in IE 6/7.
- * Address font sizes within `section` and `article` in Firefox 4+, Safari 5,
- * and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-h2 {
- font-size: 1.5em;
- margin: 0.83em 0;
-}
-
-h3 {
- font-size: 1.17em;
- margin: 1em 0;
-}
-
-h4 {
- font-size: 1em;
- margin: 1.33em 0;
-}
-
-h5 {
- font-size: 0.83em;
- margin: 1.67em 0;
-}
-
-h6 {
- font-size: 0.67em;
- margin: 2.33em 0;
-}
-
-/**
- * Address styling not present in IE 7/8/9, Safari 5, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-blockquote {
- margin: 1em 40px;
-}
-
-/**
- * Address styling not present in Safari 5 and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- * Known issue: no IE 6/7 normalization.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Address styling not present in IE 6/7/8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Address margins set differently in IE 6/7.
- */
-
-p,
-pre {
- margin: 1em 0;
-}
-
-/**
- * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, serif;
- _font-family: 'courier new', monospace;
- font-size: 1em;
-}
-
-/**
- * Improve readability of pre-formatted text in all browsers.
- */
-
-pre {
- white-space: pre;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-/**
- * Address CSS quotes not supported in IE 6/7.
- */
-
-q {
- quotes: none;
-}
-
-/**
- * Address `quotes` property not supported in Safari 4.
- */
-
-q:before,
-q:after {
- content: '';
- content: none;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* ==========================================================================
- Lists
- ========================================================================== */
-
-/**
- * Address margins set differently in IE 6/7.
- */
-
-dl,
-menu,
-ol,
-ul {
- margin: 1em 0;
-}
-
-dd {
- margin: 0 0 0 40px;
-}
-
-/**
- * Address paddings set differently in IE 6/7.
- */
-
-menu,
-ol,
-ul {
- padding: 0 0 0 40px;
-}
-
-/**
- * Correct list images handled incorrectly in IE 7.
- */
-
-nav ul,
-nav ol {
- list-style: none;
- list-style-image: none;
-}
-
-/* ==========================================================================
- Embedded content
- ========================================================================== */
-
-/**
- * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
- * 2. Improve image quality when scaled in IE 7.
- */
-
-img {
- border: 0; /* 1 */
- -ms-interpolation-mode: bicubic; /* 2 */
-}
-
-/**
- * Correct overflow displayed oddly in IE 9.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* ==========================================================================
- Figures
- ========================================================================== */
-
-/**
- * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
- */
-
-figure {
- margin: 0;
-}
-
-/* ==========================================================================
- Forms
- ========================================================================== */
-
-/**
- * Correct margin displayed oddly in IE 6/7.
- */
-
-form {
- margin: 0;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct color not being inherited in IE 6/7/8/9.
- * 2. Correct text not wrapping in Firefox 3.
- * 3. Correct alignment displayed oddly in IE 6/7.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0;
- white-space: normal; /* 2 */
- *margin-left: -7px; /* 3 */
-}
-
-/**
- * 1. Correct font size not being inherited in all browsers.
- * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
- * and Chrome.
- * 3. Improve appearance and consistency in all browsers.
- */
-
-button,
-input,
-select,
-textarea {
- font-size: 100%; /* 1 */
- margin: 0; /* 2 */
- vertical-align: baseline; /* 3 */
- *vertical-align: middle; /* 3 */
-}
-
-/**
- * Address Firefox 3+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-button,
-input {
- line-height: normal;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
- * Correct `select` style inheritance in Firefox 4+ and Opera.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- * 4. Remove inner spacing in IE 7 without affecting normal text inputs.
- * Known issue: inner spacing remains in IE 6.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
- *overflow: visible; /* 4 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * 1. Address box sizing set to content-box in IE 8/9.
- * 2. Remove excess padding in IE 8/9.
- * 3. Remove excess padding in IE 7.
- * Known issue: excess padding remains in IE 6.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
- *height: 13px; /* 3 */
- *width: 13px; /* 3 */
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari 5 and Chrome
- * on OS X.
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Remove inner padding and border in Firefox 3+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * 1. Remove default vertical scrollbar in IE 6/7/8/9.
- * 2. Improve readability and alignment in all browsers.
- */
-
-textarea {
- overflow: auto; /* 1 */
- vertical-align: top; /* 2 */
-}
-
-/* ==========================================================================
- Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
diff --git a/build-monitor-plugin/src/main/webapp/themes/industrial.css b/build-monitor-plugin/src/main/webapp/themes/industrial.css
deleted file mode 100644
index b097b24cd..000000000
--- a/build-monitor-plugin/src/main/webapp/themes/industrial.css
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Industrial Theme for Jenkins Build Monitor Plugin
- */
-
-/*
- * The MIT License
- *
- * Copyright (c) Jan Molak, SmartCode Ltd http://smartcodeltd.co.uk
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-
-
-/* ----------------------------------------------- */
-/* @DEPRECATED: Please use the .less files instead */
-/* ----------------------------------------------- */
-
-
-
-
-/*
- * Colours & Typography
- */
-
-html{color:#fff;}
-h1,h2,h3,h4,h5,h6 {
- text-align:center;
- margin:0; padding:0;
-}
-.build-monitor { color:#fff; }
-.build-monitor header>h1 {
- text-shadow: 2px 2px rgba(0,0,0,0.5);
-}
-h2 {
- text-shadow: 1px 1px rgba(0,0,0,0.5);
-}
-
-.build-monitor a {
- color: #73BFFF;
- text-decoration: none;
-}
-
-.build-monitor #widgets li a,
-.build-monitor #widgets li a:visited,
-.build-monitor header>h1>a{
- color:white;
-}
-.build-monitor a:hover {
- text-decoration: underline;
-}
-
-.build-monitor header h1 {
- margin:10px auto 0 auto;
- display:block;
-}
-
-.build-monitor header a.home-link {
- position: absolute;
- top: 5px;
- left: 8px;
- z-index:2;
- background: url('industrial/jenkins-logo.png') no-repeat;
- background-size: 100%;
- width: 50px; /* 100 */
- height: 69px; /* 138 */
- text-indent: -100%;
- text-decoration: none;
- white-space: nowrap;
- overflow: hidden;
-}
-
-.build-monitor h2 {
- margin-bottom: 0.1em;
-}
-
-.build-monitor p {
- margin: 0 0 0.5em 0;
-}
-
-.build-monitor .unknown { background-color:#474747; }
-.build-monitor .successful { background-color:darkgreen; }
-.build-monitor .unstable { background-color:#f59400; }
-.build-monitor .failing { background-color:darkred; }
-/* same grey background because in each case there's no visibility of what's wrong with the build */
-.build-monitor .aborted,
-.build-monitor .disabled { background-color:grey; }
-.build-monitor .disabled h2 { text-decoration: line-through; }
-
-/*
- * Striped background patterns inspired by Lea Verou
- * http://lea.verou.me/2010/12/checkered-stripes-other-background-patterns-with-css3-gradients/
- */
-.build-monitor .disabled,
-.build-monitor .successful,
-.build-monitor .unstable,
-.build-monitor .aborted,
-.build-monitor .failing {
- -webkit-background-size: 50px 50px;
- -moz-background-size: 50px 50px;
- background-size: 50px 50px; /* Controls the size of the stripes */
-}
-
-
-.build-monitor.colour-blind-mode .unstable {
- /* diamonds */
- background-image: -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.25, rgba(255, 255, 255, .2)), color-stop(.25, transparent), to(transparent)),
- -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255, 255, 255, .2)), color-stop(.25, transparent), to(transparent)),
- -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.75, transparent), color-stop(.75, rgba(255, 255, 255, .2))),
- -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.75, transparent), color-stop(.75, rgba(255, 255, 255, .2)));
- background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -webkit-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -webkit-linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .2) 75%),
- -webkit-linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .2) 75%);
- background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -moz-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -moz-linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .2) 75%),
- -moz-linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .2) 75%);
- background-image: -ms-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -ms-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -ms-linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .2) 75%),
- -ms-linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .2) 75%);
- background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -o-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- -o-linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .2) 75%),
- -o-linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .2) 75%);
- background-image: linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%, transparent),
- linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .2) 75%),
- linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .2) 75%);
-}
-
-.build-monitor.colour-blind-mode .aborted,
-.build-monitor.colour-blind-mode .failing {
- background-image: -webkit-gradient(linear, 0 100%, 100% 0,
- color-stop(.25, rgba(255, 255, 255, .2)), color-stop(.25, transparent),
- color-stop(.5, transparent), color-stop(.5, rgba(255, 255, 255, .2)),
- color-stop(.75, rgba(255, 255, 255, .2)), color-stop(.75, transparent),
- to(transparent));
- background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -ms-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: linear-gradient(45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
-}
-
-.build-monitor .unstable.claimed,
-.build-monitor .aborted.claimed,
-.build-monitor .failing.claimed {
- background-image: -webkit-gradient(linear, 0 0, 100% 100%,
- color-stop(.25, rgba(255, 255, 255, .2)), color-stop(.25, transparent),
- color-stop(.5, transparent), color-stop(.5, rgba(255, 255, 255, .2)),
- color-stop(.75, rgba(255, 255, 255, .2)), color-stop(.75, transparent),
- to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, .2) 25%, transparent 25%,
- transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
- transparent 75%, transparent);
-}
-
-.build-monitor .latest-results ul,
-.build-monitor .latest-results ol {
- list-style-type: none;
- margin: 0 0 0.25em 1em; padding: 0;
-}
-
-/*
- * Layout
- */
-.no-flexbox .build-monitor.dashboard * {
- display:none;
-}
-
-.dashboard { background: url('industrial/background.png'); }
-
-.build-monitor #widgets.empty em {
- padding:5em 0 0 0;
-}
-
-/*
- * Modal
- */
-.modal {
- width: 60%;
- margin-left: -30%;
- color: #000;
- background: #fff;
-}
-.modal-header h1 {
- text-align: left;
-}
-
-.modal textarea {
- width: 100%;
-}
-
-
-/*
- * Config nav
- */
-
-.build-monitor nav {
- z-index: 100;
- position:absolute;
- top:10px;
- right:8px;
-}
-
-.build-monitor nav section {
- border:1px solid white;
- width:32px;
- overflow: hidden;
- margin: 0; padding: 5px;
- background: rgba(57, 57, 57, 0.9);
- border-radius: 5px;
-
- -webkit-transition: all 0.25 ease-in;
- transition: all 0.25s ease-in;
-}
-.build-monitor nav section {
- opacity:0.5;
-}
-
-.build-monitor nav:hover section {
- opacity:1.0;
-}
-.build-monitor nav section.showSettings {
- opacity: 1.0;
- width:200px !important;
-}
-.build-monitor nav section.showSettings ul {
- height:auto;
-}
-
-.build-monitor nav ul {
- height:0;
- width:200px !important;
- overflow: hidden;
-
- list-style-type: none;
- margin:0; padding:0;
-}
-.build-monitor nav li {
- display: block;
- margin:0 0.5em;
- border-radius: 5px;
-}
-
-.build-monitor nav label {
- width:100%;
-}
-.build-monitor nav li.settings-option {
- margin-top:2em;
-}
-.build-monitor nav li.buttons {
- margin-top:2em;
-}
-
-.build-monitor nav li:last-child {
- padding:1em 0 1em 0;
-}
-
-.build-monitor nav li .slider-label {
- width:100px;
- margin-right:10px;
-}
-
-.build-monitor nav li a.btn {
- width: 86%;
- color: #000 !important;
- text-decoration: none;
-}
-.build-monitor nav li button.btn {
- width: 100%;
-}
-
-.build-monitor nav .notifications {
- position: absolute;
- top:-5px;
- right:-5px;
- z-index: 110;
- opacity: 1;
- border:1px solid red;
- background: red;
- color:white;
- padding:1px 5px 1px 5px;
- border-radius: 10px;
- font-weight: bold;
- box-shadow:1px 1px 1px black;
-}
-
-.build-monitor nav li.new-version-available {
- margin-top:1em;
- margin-bottom:2em;
- padding-bottom:1em;
- border-bottom: 1px solid white;
- border-radius: 0;
-}
-
-/*
- * Inspired by WittySparks - (c) Sravan Kumar, WittySparks.com
- */
-.build-monitor nav input[type='checkbox']#settings-toggle{opacity:0;position:absolute;filter:alpha(opacity=0);margin:5px 0 0 5px}
-.build-monitor nav input[type='checkbox']#settings-toggle+label {
- background:url("industrial/glyphs.png") left top no-repeat;
- background-size:32px 32px;
- position:relative;
- margin:0; padding:0 0 0 40px;
- cursor:pointer;
- line-height:32px;
- min-height:32px;
- display:inline-block;
- z-index:0;
- font-weight:bold;
-}
-
-.build-monitor nav input[type='checkbox']#settings-toggle+label { background-position:0 0}
-.build-monitor nav input[type='checkbox']#settings-toggle:checked+label { }
-.build-monitor nav input[type='checkbox']#settings-toggle:disabled+label { }
-.build-monitor nav input[type='checkbox']#settings-toggle:disabled:checked+label{ }
-
-.build-monitor nav li input[type='checkbox'] { margin-right:0.5em; }
-
-
-/*
- * Animations
- */
-.fade-hide, .fade-show {
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.75s;
- -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.75s;
- -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.75s;
- transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.75s;
-}
-
-.fade-hide { opacity:1; }
-.fade-hide.fade-hide-active { opacity:0; }
-
-.fade-show { opacity:0; }
-.fade-show.fade-show-active { opacity:1; }
diff --git a/build-monitor-plugin/src/main/webapp/themes/industrial/background.png b/build-monitor-plugin/src/main/webapp/themes/industrial/background.png
deleted file mode 100644
index afe3d84be..000000000
Binary files a/build-monitor-plugin/src/main/webapp/themes/industrial/background.png and /dev/null differ
diff --git a/build-monitor-plugin/src/main/webapp/themes/industrial/glyphs.png b/build-monitor-plugin/src/main/webapp/themes/industrial/glyphs.png
deleted file mode 100644
index caaded3cb..000000000
Binary files a/build-monitor-plugin/src/main/webapp/themes/industrial/glyphs.png and /dev/null differ
diff --git a/build-monitor-plugin/src/main/webapp/themes/industrial/jenkins-logo.png b/build-monitor-plugin/src/main/webapp/themes/industrial/jenkins-logo.png
deleted file mode 100644
index c0641d16a..000000000
Binary files a/build-monitor-plugin/src/main/webapp/themes/industrial/jenkins-logo.png and /dev/null differ
diff --git a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.js b/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.js
deleted file mode 100644
index b18b828eb..000000000
--- a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.js
+++ /dev/null
@@ -1,4139 +0,0 @@
-/**
- * @license AngularJS v1.5.8
- * (c) 2010-2016 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window, angular) {'use strict';
-
-var ELEMENT_NODE = 1;
-var COMMENT_NODE = 8;
-
-var ADD_CLASS_SUFFIX = '-add';
-var REMOVE_CLASS_SUFFIX = '-remove';
-var EVENT_CLASS_PREFIX = 'ng-';
-var ACTIVE_CLASS_SUFFIX = '-active';
-var PREPARE_CLASS_SUFFIX = '-prepare';
-
-var NG_ANIMATE_CLASSNAME = 'ng-animate';
-var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
-
-// Detect proper transitionend/animationend event names.
-var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
-
-// If unprefixed events are not supported but webkit-prefixed are, use the latter.
-// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
-// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
-// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
-// Register both events in case `window.onanimationend` is not supported because of that,
-// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
-// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
-// therefore there is no reason to test anymore for other vendor prefixes:
-// http://caniuse.com/#search=transition
-if ((window.ontransitionend === void 0) && (window.onwebkittransitionend !== void 0)) {
- CSS_PREFIX = '-webkit-';
- TRANSITION_PROP = 'WebkitTransition';
- TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
-} else {
- TRANSITION_PROP = 'transition';
- TRANSITIONEND_EVENT = 'transitionend';
-}
-
-if ((window.onanimationend === void 0) && (window.onwebkitanimationend !== void 0)) {
- CSS_PREFIX = '-webkit-';
- ANIMATION_PROP = 'WebkitAnimation';
- ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
-} else {
- ANIMATION_PROP = 'animation';
- ANIMATIONEND_EVENT = 'animationend';
-}
-
-var DURATION_KEY = 'Duration';
-var PROPERTY_KEY = 'Property';
-var DELAY_KEY = 'Delay';
-var TIMING_KEY = 'TimingFunction';
-var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
-var ANIMATION_PLAYSTATE_KEY = 'PlayState';
-var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
-
-var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
-var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
-var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
-var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
-
-var ngMinErr = angular.$$minErr('ng');
-function assertArg(arg, name, reason) {
- if (!arg) {
- throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
- }
- return arg;
-}
-
-function mergeClasses(a,b) {
- if (!a && !b) return '';
- if (!a) return b;
- if (!b) return a;
- if (isArray(a)) a = a.join(' ');
- if (isArray(b)) b = b.join(' ');
- return a + ' ' + b;
-}
-
-function packageStyles(options) {
- var styles = {};
- if (options && (options.to || options.from)) {
- styles.to = options.to;
- styles.from = options.from;
- }
- return styles;
-}
-
-function pendClasses(classes, fix, isPrefix) {
- var className = '';
- classes = isArray(classes)
- ? classes
- : classes && isString(classes) && classes.length
- ? classes.split(/\s+/)
- : [];
- forEach(classes, function(klass, i) {
- if (klass && klass.length > 0) {
- className += (i > 0) ? ' ' : '';
- className += isPrefix ? fix + klass
- : klass + fix;
- }
- });
- return className;
-}
-
-function removeFromArray(arr, val) {
- var index = arr.indexOf(val);
- if (val >= 0) {
- arr.splice(index, 1);
- }
-}
-
-function stripCommentsFromElement(element) {
- if (element instanceof jqLite) {
- switch (element.length) {
- case 0:
- return element;
-
- case 1:
- // there is no point of stripping anything if the element
- // is the only element within the jqLite wrapper.
- // (it's important that we retain the element instance.)
- if (element[0].nodeType === ELEMENT_NODE) {
- return element;
- }
- break;
-
- default:
- return jqLite(extractElementNode(element));
- }
- }
-
- if (element.nodeType === ELEMENT_NODE) {
- return jqLite(element);
- }
-}
-
-function extractElementNode(element) {
- if (!element[0]) return element;
- for (var i = 0; i < element.length; i++) {
- var elm = element[i];
- if (elm.nodeType == ELEMENT_NODE) {
- return elm;
- }
- }
-}
-
-function $$addClass($$jqLite, element, className) {
- forEach(element, function(elm) {
- $$jqLite.addClass(elm, className);
- });
-}
-
-function $$removeClass($$jqLite, element, className) {
- forEach(element, function(elm) {
- $$jqLite.removeClass(elm, className);
- });
-}
-
-function applyAnimationClassesFactory($$jqLite) {
- return function(element, options) {
- if (options.addClass) {
- $$addClass($$jqLite, element, options.addClass);
- options.addClass = null;
- }
- if (options.removeClass) {
- $$removeClass($$jqLite, element, options.removeClass);
- options.removeClass = null;
- }
- };
-}
-
-function prepareAnimationOptions(options) {
- options = options || {};
- if (!options.$$prepared) {
- var domOperation = options.domOperation || noop;
- options.domOperation = function() {
- options.$$domOperationFired = true;
- domOperation();
- domOperation = noop;
- };
- options.$$prepared = true;
- }
- return options;
-}
-
-function applyAnimationStyles(element, options) {
- applyAnimationFromStyles(element, options);
- applyAnimationToStyles(element, options);
-}
-
-function applyAnimationFromStyles(element, options) {
- if (options.from) {
- element.css(options.from);
- options.from = null;
- }
-}
-
-function applyAnimationToStyles(element, options) {
- if (options.to) {
- element.css(options.to);
- options.to = null;
- }
-}
-
-function mergeAnimationDetails(element, oldAnimation, newAnimation) {
- var target = oldAnimation.options || {};
- var newOptions = newAnimation.options || {};
-
- var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
- var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
- var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
-
- if (newOptions.preparationClasses) {
- target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);
- delete newOptions.preparationClasses;
- }
-
- // noop is basically when there is no callback; otherwise something has been set
- var realDomOperation = target.domOperation !== noop ? target.domOperation : null;
-
- extend(target, newOptions);
-
- // TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.
- if (realDomOperation) {
- target.domOperation = realDomOperation;
- }
-
- if (classes.addClass) {
- target.addClass = classes.addClass;
- } else {
- target.addClass = null;
- }
-
- if (classes.removeClass) {
- target.removeClass = classes.removeClass;
- } else {
- target.removeClass = null;
- }
-
- oldAnimation.addClass = target.addClass;
- oldAnimation.removeClass = target.removeClass;
-
- return target;
-}
-
-function resolveElementClasses(existing, toAdd, toRemove) {
- var ADD_CLASS = 1;
- var REMOVE_CLASS = -1;
-
- var flags = {};
- existing = splitClassesToLookup(existing);
-
- toAdd = splitClassesToLookup(toAdd);
- forEach(toAdd, function(value, key) {
- flags[key] = ADD_CLASS;
- });
-
- toRemove = splitClassesToLookup(toRemove);
- forEach(toRemove, function(value, key) {
- flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;
- });
-
- var classes = {
- addClass: '',
- removeClass: ''
- };
-
- forEach(flags, function(val, klass) {
- var prop, allow;
- if (val === ADD_CLASS) {
- prop = 'addClass';
- allow = !existing[klass] || existing[klass + REMOVE_CLASS_SUFFIX];
- } else if (val === REMOVE_CLASS) {
- prop = 'removeClass';
- allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX];
- }
- if (allow) {
- if (classes[prop].length) {
- classes[prop] += ' ';
- }
- classes[prop] += klass;
- }
- });
-
- function splitClassesToLookup(classes) {
- if (isString(classes)) {
- classes = classes.split(' ');
- }
-
- var obj = {};
- forEach(classes, function(klass) {
- // sometimes the split leaves empty string values
- // incase extra spaces were applied to the options
- if (klass.length) {
- obj[klass] = true;
- }
- });
- return obj;
- }
-
- return classes;
-}
-
-function getDomNode(element) {
- return (element instanceof jqLite) ? element[0] : element;
-}
-
-function applyGeneratedPreparationClasses(element, event, options) {
- var classes = '';
- if (event) {
- classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
- }
- if (options.addClass) {
- classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));
- }
- if (options.removeClass) {
- classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));
- }
- if (classes.length) {
- options.preparationClasses = classes;
- element.addClass(classes);
- }
-}
-
-function clearGeneratedClasses(element, options) {
- if (options.preparationClasses) {
- element.removeClass(options.preparationClasses);
- options.preparationClasses = null;
- }
- if (options.activeClasses) {
- element.removeClass(options.activeClasses);
- options.activeClasses = null;
- }
-}
-
-function blockTransitions(node, duration) {
- // we use a negative delay value since it performs blocking
- // yet it doesn't kill any existing transitions running on the
- // same element which makes this safe for class-based animations
- var value = duration ? '-' + duration + 's' : '';
- applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
- return [TRANSITION_DELAY_PROP, value];
-}
-
-function blockKeyframeAnimations(node, applyBlock) {
- var value = applyBlock ? 'paused' : '';
- var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
- applyInlineStyle(node, [key, value]);
- return [key, value];
-}
-
-function applyInlineStyle(node, styleTuple) {
- var prop = styleTuple[0];
- var value = styleTuple[1];
- node.style[prop] = value;
-}
-
-function concatWithSpace(a,b) {
- if (!a) return b;
- if (!b) return a;
- return a + ' ' + b;
-}
-
-var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
- var queue, cancelFn;
-
- function scheduler(tasks) {
- // we make a copy since RAFScheduler mutates the state
- // of the passed in array variable and this would be difficult
- // to track down on the outside code
- queue = queue.concat(tasks);
- nextTick();
- }
-
- queue = scheduler.queue = [];
-
- /* waitUntilQuiet does two things:
- * 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through
- * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
- *
- * The motivation here is that animation code can request more time from the scheduler
- * before the next wave runs. This allows for certain DOM properties such as classes to
- * be resolved in time for the next animation to run.
- */
- scheduler.waitUntilQuiet = function(fn) {
- if (cancelFn) cancelFn();
-
- cancelFn = $$rAF(function() {
- cancelFn = null;
- fn();
- nextTick();
- });
- };
-
- return scheduler;
-
- function nextTick() {
- if (!queue.length) return;
-
- var items = queue.shift();
- for (var i = 0; i < items.length; i++) {
- items[i]();
- }
-
- if (!cancelFn) {
- $$rAF(function() {
- if (!cancelFn) nextTick();
- });
- }
- }
-}];
-
-/**
- * @ngdoc directive
- * @name ngAnimateChildren
- * @restrict AE
- * @element ANY
- *
- * @description
- *
- * ngAnimateChildren allows you to specify that children of this element should animate even if any
- * of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`
- * (structural) animation, child elements that also have an active structural animation are not animated.
- *
- * Note that even if `ngAnimteChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).
- *
- *
- * @param {string} ngAnimateChildren If the value is empty, `true` or `on`,
- * then child animations are allowed. If the value is `false`, child animations are not allowed.
- *
- * @example
- *
-
-
-
-
-
-
-
- List of items:
-
Item {{item}}
-
-
-
-
-
-
- .container.ng-enter,
- .container.ng-leave {
- transition: all ease 1.5s;
- }
-
- .container.ng-enter,
- .container.ng-leave-active {
- opacity: 0;
- }
-
- .container.ng-leave,
- .container.ng-enter-active {
- opacity: 1;
- }
-
- .item {
- background: firebrick;
- color: #FFF;
- margin-bottom: 10px;
- }
-
- .item.ng-enter,
- .item.ng-leave {
- transition: transform 1.5s ease;
- }
-
- .item.ng-enter {
- transform: translateX(50px);
- }
-
- .item.ng-enter-active {
- transform: translateX(0);
- }
-
-
- angular.module('ngAnimateChildren', ['ngAnimate'])
- .controller('mainController', function() {
- this.animateChildren = false;
- this.enterElement = false;
- });
-
-
- */
-var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
- return {
- link: function(scope, element, attrs) {
- var val = attrs.ngAnimateChildren;
- if (isString(val) && val.length === 0) { //empty attribute
- element.data(NG_ANIMATE_CHILDREN_DATA, true);
- } else {
- // Interpolate and set the value, so that it is available to
- // animations that run right after compilation
- setData($interpolate(val)(scope));
- attrs.$observe('ngAnimateChildren', setData);
- }
-
- function setData(value) {
- value = value === 'on' || value === 'true';
- element.data(NG_ANIMATE_CHILDREN_DATA, value);
- }
- }
- };
-}];
-
-var ANIMATE_TIMER_KEY = '$$animateCss';
-
-/**
- * @ngdoc service
- * @name $animateCss
- * @kind object
- *
- * @description
- * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes
- * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT
- * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or
- * directives to create more complex animations that can be purely driven using CSS code.
- *
- * Note that only browsers that support CSS transitions and/or keyframe animations are capable of
- * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).
- *
- * ## Usage
- * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that
- * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,
- * any automatic control over cancelling animations and/or preventing animations from being run on
- * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to
- * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger
- * the CSS animation.
- *
- * The example below shows how we can create a folding animation on an element using `ng-if`:
- *
- * ```html
- *
- *
- * This element will go BOOM
- *
- *
- * ```
- *
- * Now we create the **JavaScript animation** that will trigger the CSS transition:
- *
- * ```js
- * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {
- * return {
- * enter: function(element, doneFn) {
- * var height = element[0].offsetHeight;
- * return $animateCss(element, {
- * from: { height:'0px' },
- * to: { height:height + 'px' },
- * duration: 1 // one second
- * });
- * }
- * }
- * }]);
- * ```
- *
- * ## More Advanced Uses
- *
- * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks
- * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code.
- *
- * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation,
- * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with
- * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order
- * to provide a working animation that will run in CSS.
- *
- * The example below showcases a more advanced version of the `.fold-animation` from the example above:
- *
- * ```js
- * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {
- * return {
- * enter: function(element, doneFn) {
- * var height = element[0].offsetHeight;
- * return $animateCss(element, {
- * addClass: 'red large-text pulse-twice',
- * easing: 'ease-out',
- * from: { height:'0px' },
- * to: { height:height + 'px' },
- * duration: 1 // one second
- * });
- * }
- * }
- * }]);
- * ```
- *
- * Since we're adding/removing CSS classes then the CSS transition will also pick those up:
- *
- * ```css
- * /* since a hardcoded duration value of 1 was provided in the JavaScript animation code,
- * the CSS classes below will be transitioned despite them being defined as regular CSS classes */
- * .red { background:red; }
- * .large-text { font-size:20px; }
- *
- * /* we can also use a keyframe animation and $animateCss will make it work alongside the transition */
- * .pulse-twice {
- * animation: 0.5s pulse linear 2;
- * -webkit-animation: 0.5s pulse linear 2;
- * }
- *
- * @keyframes pulse {
- * from { transform: scale(0.5); }
- * to { transform: scale(1.5); }
- * }
- *
- * @-webkit-keyframes pulse {
- * from { -webkit-transform: scale(0.5); }
- * to { -webkit-transform: scale(1.5); }
- * }
- * ```
- *
- * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.
- *
- * ## How the Options are handled
- *
- * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation
- * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline
- * styles using the `from` and `to` properties.
- *
- * ```js
- * var animator = $animateCss(element, {
- * from: { background:'red' },
- * to: { background:'blue' }
- * });
- * animator.start();
- * ```
- *
- * ```css
- * .rotating-animation {
- * animation:0.5s rotate linear;
- * -webkit-animation:0.5s rotate linear;
- * }
- *
- * @keyframes rotate {
- * from { transform: rotate(0deg); }
- * to { transform: rotate(360deg); }
- * }
- *
- * @-webkit-keyframes rotate {
- * from { -webkit-transform: rotate(0deg); }
- * to { -webkit-transform: rotate(360deg); }
- * }
- * ```
- *
- * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is
- * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition
- * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition
- * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied
- * and spread across the transition and keyframe animation.
- *
- * ## What is returned
- *
- * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually
- * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are
- * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties:
- *
- * ```js
- * var animator = $animateCss(element, { ... });
- * ```
- *
- * Now what do the contents of our `animator` variable look like:
- *
- * ```js
- * {
- * // starts the animation
- * start: Function,
- *
- * // ends (aborts) the animation
- * end: Function
- * }
- * ```
- *
- * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
- * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been
- * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
- * and that changing them will not reconfigure the parameters of the animation.
- *
- * ### runner.done() vs runner.then()
- * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the
- * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.
- * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`
- * unless you really need a digest to kick off afterwards.
- *
- * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss
- * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).
- * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.
- *
- * @param {DOMElement} element the element that will be animated
- * @param {object} options the animation-related options that will be applied during the animation
- *
- * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied
- * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)
- * * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and
- * `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted.
- * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).
- * * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`).
- * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
- * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.
- * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.
- * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.
- * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.
- * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`
- * is provided then the animation will be skipped entirely.
- * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is
- * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value
- * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same
- * CSS delay value.
- * * `stagger` - A numeric time value representing the delay between successively animated elements
- * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
- * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
- * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
- * * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)
- * * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once
- * the animation is closed. This is useful for when the styles are used purely for the sake of
- * the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).
- * By default this value is set to `false`.
- *
- * @return {object} an object with start and end methods and details about the animation.
- *
- * * `start` - The method to start the animation. This will return a `Promise` when called.
- * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
- */
-var ONE_SECOND = 1000;
-var BASE_TEN = 10;
-
-var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
-var CLOSING_TIME_BUFFER = 1.5;
-
-var DETECT_CSS_PROPERTIES = {
- transitionDuration: TRANSITION_DURATION_PROP,
- transitionDelay: TRANSITION_DELAY_PROP,
- transitionProperty: TRANSITION_PROP + PROPERTY_KEY,
- animationDuration: ANIMATION_DURATION_PROP,
- animationDelay: ANIMATION_DELAY_PROP,
- animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY
-};
-
-var DETECT_STAGGER_CSS_PROPERTIES = {
- transitionDuration: TRANSITION_DURATION_PROP,
- transitionDelay: TRANSITION_DELAY_PROP,
- animationDuration: ANIMATION_DURATION_PROP,
- animationDelay: ANIMATION_DELAY_PROP
-};
-
-function getCssKeyframeDurationStyle(duration) {
- return [ANIMATION_DURATION_PROP, duration + 's'];
-}
-
-function getCssDelayStyle(delay, isKeyframeAnimation) {
- var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
- return [prop, delay + 's'];
-}
-
-function computeCssStyles($window, element, properties) {
- var styles = Object.create(null);
- var detectedStyles = $window.getComputedStyle(element) || {};
- forEach(properties, function(formalStyleName, actualStyleName) {
- var val = detectedStyles[formalStyleName];
- if (val) {
- var c = val.charAt(0);
-
- // only numerical-based values have a negative sign or digit as the first value
- if (c === '-' || c === '+' || c >= 0) {
- val = parseMaxTime(val);
- }
-
- // by setting this to null in the event that the delay is not set or is set directly as 0
- // then we can still allow for negative values to be used later on and not mistake this
- // value for being greater than any other negative value.
- if (val === 0) {
- val = null;
- }
- styles[actualStyleName] = val;
- }
- });
-
- return styles;
-}
-
-function parseMaxTime(str) {
- var maxValue = 0;
- var values = str.split(/\s*,\s*/);
- forEach(values, function(value) {
- // it's always safe to consider only second values and omit `ms` values since
- // getComputedStyle will always handle the conversion for us
- if (value.charAt(value.length - 1) == 's') {
- value = value.substring(0, value.length - 1);
- }
- value = parseFloat(value) || 0;
- maxValue = maxValue ? Math.max(value, maxValue) : value;
- });
- return maxValue;
-}
-
-function truthyTimingValue(val) {
- return val === 0 || val != null;
-}
-
-function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
- var style = TRANSITION_PROP;
- var value = duration + 's';
- if (applyOnlyDuration) {
- style += DURATION_KEY;
- } else {
- value += ' linear all';
- }
- return [style, value];
-}
-
-function createLocalCacheLookup() {
- var cache = Object.create(null);
- return {
- flush: function() {
- cache = Object.create(null);
- },
-
- count: function(key) {
- var entry = cache[key];
- return entry ? entry.total : 0;
- },
-
- get: function(key) {
- var entry = cache[key];
- return entry && entry.value;
- },
-
- put: function(key, value) {
- if (!cache[key]) {
- cache[key] = { total: 1, value: value };
- } else {
- cache[key].total++;
- }
- }
- };
-}
-
-// we do not reassign an already present style value since
-// if we detect the style property value again we may be
-// detecting styles that were added via the `from` styles.
-// We make use of `isDefined` here since an empty string
-// or null value (which is what getPropertyValue will return
-// for a non-existing style) will still be marked as a valid
-// value for the style (a falsy value implies that the style
-// is to be removed at the end of the animation). If we had a simple
-// "OR" statement then it would not be enough to catch that.
-function registerRestorableStyles(backup, node, properties) {
- forEach(properties, function(prop) {
- backup[prop] = isDefined(backup[prop])
- ? backup[prop]
- : node.style.getPropertyValue(prop);
- });
-}
-
-var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
- var gcsLookup = createLocalCacheLookup();
- var gcsStaggerLookup = createLocalCacheLookup();
-
- this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
- '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
- function($window, $$jqLite, $$AnimateRunner, $timeout,
- $$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
-
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
-
- var parentCounter = 0;
- function gcsHashFn(node, extraClasses) {
- var KEY = "$$ngAnimateParentKey";
- var parentNode = node.parentNode;
- var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
- return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;
- }
-
- function computeCachedCssStyles(node, className, cacheKey, properties) {
- var timings = gcsLookup.get(cacheKey);
-
- if (!timings) {
- timings = computeCssStyles($window, node, properties);
- if (timings.animationIterationCount === 'infinite') {
- timings.animationIterationCount = 1;
- }
- }
-
- // we keep putting this in multiple times even though the value and the cacheKey are the same
- // because we're keeping an internal tally of how many duplicate animations are detected.
- gcsLookup.put(cacheKey, timings);
- return timings;
- }
-
- function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {
- var stagger;
-
- // if we have one or more existing matches of matching elements
- // containing the same parent + CSS styles (which is how cacheKey works)
- // then staggering is possible
- if (gcsLookup.count(cacheKey) > 0) {
- stagger = gcsStaggerLookup.get(cacheKey);
-
- if (!stagger) {
- var staggerClassName = pendClasses(className, '-stagger');
-
- $$jqLite.addClass(node, staggerClassName);
-
- stagger = computeCssStyles($window, node, properties);
-
- // force the conversion of a null value to zero incase not set
- stagger.animationDuration = Math.max(stagger.animationDuration, 0);
- stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);
-
- $$jqLite.removeClass(node, staggerClassName);
-
- gcsStaggerLookup.put(cacheKey, stagger);
- }
- }
-
- return stagger || {};
- }
-
- var cancelLastRAFRequest;
- var rafWaitQueue = [];
- function waitUntilQuiet(callback) {
- rafWaitQueue.push(callback);
- $$rAFScheduler.waitUntilQuiet(function() {
- gcsLookup.flush();
- gcsStaggerLookup.flush();
-
- // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
- // PLEASE EXAMINE THE `$$forceReflow` service to understand why.
- var pageWidth = $$forceReflow();
-
- // we use a for loop to ensure that if the queue is changed
- // during this looping then it will consider new requests
- for (var i = 0; i < rafWaitQueue.length; i++) {
- rafWaitQueue[i](pageWidth);
- }
- rafWaitQueue.length = 0;
- });
- }
-
- function computeTimings(node, className, cacheKey) {
- var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);
- var aD = timings.animationDelay;
- var tD = timings.transitionDelay;
- timings.maxDelay = aD && tD
- ? Math.max(aD, tD)
- : (aD || tD);
- timings.maxDuration = Math.max(
- timings.animationDuration * timings.animationIterationCount,
- timings.transitionDuration);
-
- return timings;
- }
-
- return function init(element, initialOptions) {
- // all of the animation functions should create
- // a copy of the options data, however, if a
- // parent service has already created a copy then
- // we should stick to using that
- var options = initialOptions || {};
- if (!options.$$prepared) {
- options = prepareAnimationOptions(copy(options));
- }
-
- var restoreStyles = {};
- var node = getDomNode(element);
- if (!node
- || !node.parentNode
- || !$$animateQueue.enabled()) {
- return closeAndReturnNoopAnimator();
- }
-
- var temporaryStyles = [];
- var classes = element.attr('class');
- var styles = packageStyles(options);
- var animationClosed;
- var animationPaused;
- var animationCompleted;
- var runner;
- var runnerHost;
- var maxDelay;
- var maxDelayTime;
- var maxDuration;
- var maxDurationTime;
- var startTime;
- var events = [];
-
- if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {
- return closeAndReturnNoopAnimator();
- }
-
- var method = options.event && isArray(options.event)
- ? options.event.join(' ')
- : options.event;
-
- var isStructural = method && options.structural;
- var structuralClassName = '';
- var addRemoveClassName = '';
-
- if (isStructural) {
- structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);
- } else if (method) {
- structuralClassName = method;
- }
-
- if (options.addClass) {
- addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);
- }
-
- if (options.removeClass) {
- if (addRemoveClassName.length) {
- addRemoveClassName += ' ';
- }
- addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);
- }
-
- // there may be a situation where a structural animation is combined together
- // with CSS classes that need to resolve before the animation is computed.
- // However this means that there is no explicit CSS code to block the animation
- // from happening (by setting 0s none in the class name). If this is the case
- // we need to apply the classes before the first rAF so we know to continue if
- // there actually is a detected transition or keyframe animation
- if (options.applyClassesEarly && addRemoveClassName.length) {
- applyAnimationClasses(element, options);
- }
-
- var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
- var fullClassName = classes + ' ' + preparationClasses;
- var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
- var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
- var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
-
- // there is no way we can trigger an animation if no styles and
- // no classes are being applied which would then trigger a transition,
- // unless there a is raw keyframe value that is applied to the element.
- if (!containsKeyframeAnimation
- && !hasToStyles
- && !preparationClasses) {
- return closeAndReturnNoopAnimator();
- }
-
- var cacheKey, stagger;
- if (options.stagger > 0) {
- var staggerVal = parseFloat(options.stagger);
- stagger = {
- transitionDelay: staggerVal,
- animationDelay: staggerVal,
- transitionDuration: 0,
- animationDuration: 0
- };
- } else {
- cacheKey = gcsHashFn(node, fullClassName);
- stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
- }
-
- if (!options.$$skipPreparationClasses) {
- $$jqLite.addClass(element, preparationClasses);
- }
-
- var applyOnlyDuration;
-
- if (options.transitionStyle) {
- var transitionStyle = [TRANSITION_PROP, options.transitionStyle];
- applyInlineStyle(node, transitionStyle);
- temporaryStyles.push(transitionStyle);
- }
-
- if (options.duration >= 0) {
- applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;
- var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);
-
- // we set the duration so that it will be picked up by getComputedStyle later
- applyInlineStyle(node, durationStyle);
- temporaryStyles.push(durationStyle);
- }
-
- if (options.keyframeStyle) {
- var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];
- applyInlineStyle(node, keyframeStyle);
- temporaryStyles.push(keyframeStyle);
- }
-
- var itemIndex = stagger
- ? options.staggerIndex >= 0
- ? options.staggerIndex
- : gcsLookup.count(cacheKey)
- : 0;
-
- var isFirst = itemIndex === 0;
-
- // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY
- // without causing any combination of transitions to kick in. By adding a negative delay value
- // it forces the setup class' transition to end immediately. We later then remove the negative
- // transition delay to allow for the transition to naturally do it's thing. The beauty here is
- // that if there is no transition defined then nothing will happen and this will also allow
- // other transitions to be stacked on top of each other without any chopping them out.
- if (isFirst && !options.skipBlocking) {
- blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
- }
-
- var timings = computeTimings(node, fullClassName, cacheKey);
- var relativeDelay = timings.maxDelay;
- maxDelay = Math.max(relativeDelay, 0);
- maxDuration = timings.maxDuration;
-
- var flags = {};
- flags.hasTransitions = timings.transitionDuration > 0;
- flags.hasAnimations = timings.animationDuration > 0;
- flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all';
- flags.applyTransitionDuration = hasToStyles && (
- (flags.hasTransitions && !flags.hasTransitionAll)
- || (flags.hasAnimations && !flags.hasTransitions));
- flags.applyAnimationDuration = options.duration && flags.hasAnimations;
- flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);
- flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations;
- flags.recalculateTimingStyles = addRemoveClassName.length > 0;
-
- if (flags.applyTransitionDuration || flags.applyAnimationDuration) {
- maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;
-
- if (flags.applyTransitionDuration) {
- flags.hasTransitions = true;
- timings.transitionDuration = maxDuration;
- applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;
- temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));
- }
-
- if (flags.applyAnimationDuration) {
- flags.hasAnimations = true;
- timings.animationDuration = maxDuration;
- temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));
- }
- }
-
- if (maxDuration === 0 && !flags.recalculateTimingStyles) {
- return closeAndReturnNoopAnimator();
- }
-
- if (options.delay != null) {
- var delayStyle;
- if (typeof options.delay !== "boolean") {
- delayStyle = parseFloat(options.delay);
- // number in options.delay means we have to recalculate the delay for the closing timeout
- maxDelay = Math.max(delayStyle, 0);
- }
-
- if (flags.applyTransitionDelay) {
- temporaryStyles.push(getCssDelayStyle(delayStyle));
- }
-
- if (flags.applyAnimationDelay) {
- temporaryStyles.push(getCssDelayStyle(delayStyle, true));
- }
- }
-
- // we need to recalculate the delay value since we used a pre-emptive negative
- // delay value and the delay value is required for the final event checking. This
- // property will ensure that this will happen after the RAF phase has passed.
- if (options.duration == null && timings.transitionDuration > 0) {
- flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;
- }
-
- maxDelayTime = maxDelay * ONE_SECOND;
- maxDurationTime = maxDuration * ONE_SECOND;
- if (!options.skipBlocking) {
- flags.blockTransition = timings.transitionDuration > 0;
- flags.blockKeyframeAnimation = timings.animationDuration > 0 &&
- stagger.animationDelay > 0 &&
- stagger.animationDuration === 0;
- }
-
- if (options.from) {
- if (options.cleanupStyles) {
- registerRestorableStyles(restoreStyles, node, Object.keys(options.from));
- }
- applyAnimationFromStyles(element, options);
- }
-
- if (flags.blockTransition || flags.blockKeyframeAnimation) {
- applyBlocking(maxDuration);
- } else if (!options.skipBlocking) {
- blockTransitions(node, false);
- }
-
- // TODO(matsko): for 1.5 change this code to have an animator object for better debugging
- return {
- $$willAnimate: true,
- end: endFn,
- start: function() {
- if (animationClosed) return;
-
- runnerHost = {
- end: endFn,
- cancel: cancelFn,
- resume: null, //this will be set during the start() phase
- pause: null
- };
-
- runner = new $$AnimateRunner(runnerHost);
-
- waitUntilQuiet(start);
-
- // we don't have access to pause/resume the animation
- // since it hasn't run yet. AnimateRunner will therefore
- // set noop functions for resume and pause and they will
- // later be overridden once the animation is triggered
- return runner;
- }
- };
-
- function endFn() {
- close();
- }
-
- function cancelFn() {
- close(true);
- }
-
- function close(rejected) { // jshint ignore:line
- // if the promise has been called already then we shouldn't close
- // the animation again
- if (animationClosed || (animationCompleted && animationPaused)) return;
- animationClosed = true;
- animationPaused = false;
-
- if (!options.$$skipPreparationClasses) {
- $$jqLite.removeClass(element, preparationClasses);
- }
- $$jqLite.removeClass(element, activeClasses);
-
- blockKeyframeAnimations(node, false);
- blockTransitions(node, false);
-
- forEach(temporaryStyles, function(entry) {
- // There is only one way to remove inline style properties entirely from elements.
- // By using `removeProperty` this works, but we need to convert camel-cased CSS
- // styles down to hyphenated values.
- node.style[entry[0]] = '';
- });
-
- applyAnimationClasses(element, options);
- applyAnimationStyles(element, options);
-
- if (Object.keys(restoreStyles).length) {
- forEach(restoreStyles, function(value, prop) {
- value ? node.style.setProperty(prop, value)
- : node.style.removeProperty(prop);
- });
- }
-
- // the reason why we have this option is to allow a synchronous closing callback
- // that is fired as SOON as the animation ends (when the CSS is removed) or if
- // the animation never takes off at all. A good example is a leave animation since
- // the element must be removed just after the animation is over or else the element
- // will appear on screen for one animation frame causing an overbearing flicker.
- if (options.onDone) {
- options.onDone();
- }
-
- if (events && events.length) {
- // Remove the transitionend / animationend listener(s)
- element.off(events.join(' '), onAnimationProgress);
- }
-
- //Cancel the fallback closing timeout and remove the timer data
- var animationTimerData = element.data(ANIMATE_TIMER_KEY);
- if (animationTimerData) {
- $timeout.cancel(animationTimerData[0].timer);
- element.removeData(ANIMATE_TIMER_KEY);
- }
-
- // if the preparation function fails then the promise is not setup
- if (runner) {
- runner.complete(!rejected);
- }
- }
-
- function applyBlocking(duration) {
- if (flags.blockTransition) {
- blockTransitions(node, duration);
- }
-
- if (flags.blockKeyframeAnimation) {
- blockKeyframeAnimations(node, !!duration);
- }
- }
-
- function closeAndReturnNoopAnimator() {
- runner = new $$AnimateRunner({
- end: endFn,
- cancel: cancelFn
- });
-
- // should flush the cache animation
- waitUntilQuiet(noop);
- close();
-
- return {
- $$willAnimate: false,
- start: function() {
- return runner;
- },
- end: endFn
- };
- }
-
- function onAnimationProgress(event) {
- event.stopPropagation();
- var ev = event.originalEvent || event;
-
- // we now always use `Date.now()` due to the recent changes with
- // event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)
- var timeStamp = ev.$manualTimeStamp || Date.now();
-
- /* Firefox (or possibly just Gecko) likes to not round values up
- * when a ms measurement is used for the animation */
- var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
-
- /* $manualTimeStamp is a mocked timeStamp value which is set
- * within browserTrigger(). This is only here so that tests can
- * mock animations properly. Real events fallback to event.timeStamp,
- * or, if they don't, then a timeStamp is automatically created for them.
- * We're checking to see if the timeStamp surpasses the expected delay,
- * but we're using elapsedTime instead of the timeStamp on the 2nd
- * pre-condition since animationPauseds sometimes close off early */
- if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
- // we set this flag to ensure that if the transition is paused then, when resumed,
- // the animation will automatically close itself since transitions cannot be paused.
- animationCompleted = true;
- close();
- }
- }
-
- function start() {
- if (animationClosed) return;
- if (!node.parentNode) {
- close();
- return;
- }
-
- // even though we only pause keyframe animations here the pause flag
- // will still happen when transitions are used. Only the transition will
- // not be paused since that is not possible. If the animation ends when
- // paused then it will not complete until unpaused or cancelled.
- var playPause = function(playAnimation) {
- if (!animationCompleted) {
- animationPaused = !playAnimation;
- if (timings.animationDuration) {
- var value = blockKeyframeAnimations(node, animationPaused);
- animationPaused
- ? temporaryStyles.push(value)
- : removeFromArray(temporaryStyles, value);
- }
- } else if (animationPaused && playAnimation) {
- animationPaused = false;
- close();
- }
- };
-
- // checking the stagger duration prevents an accidentally cascade of the CSS delay style
- // being inherited from the parent. If the transition duration is zero then we can safely
- // rely that the delay value is an intentional stagger delay style.
- var maxStagger = itemIndex > 0
- && ((timings.transitionDuration && stagger.transitionDuration === 0) ||
- (timings.animationDuration && stagger.animationDuration === 0))
- && Math.max(stagger.animationDelay, stagger.transitionDelay);
- if (maxStagger) {
- $timeout(triggerAnimationStart,
- Math.floor(maxStagger * itemIndex * ONE_SECOND),
- false);
- } else {
- triggerAnimationStart();
- }
-
- // this will decorate the existing promise runner with pause/resume methods
- runnerHost.resume = function() {
- playPause(true);
- };
-
- runnerHost.pause = function() {
- playPause(false);
- };
-
- function triggerAnimationStart() {
- // just incase a stagger animation kicks in when the animation
- // itself was cancelled entirely
- if (animationClosed) return;
-
- applyBlocking(false);
-
- forEach(temporaryStyles, function(entry) {
- var key = entry[0];
- var value = entry[1];
- node.style[key] = value;
- });
-
- applyAnimationClasses(element, options);
- $$jqLite.addClass(element, activeClasses);
-
- if (flags.recalculateTimingStyles) {
- fullClassName = node.className + ' ' + preparationClasses;
- cacheKey = gcsHashFn(node, fullClassName);
-
- timings = computeTimings(node, fullClassName, cacheKey);
- relativeDelay = timings.maxDelay;
- maxDelay = Math.max(relativeDelay, 0);
- maxDuration = timings.maxDuration;
-
- if (maxDuration === 0) {
- close();
- return;
- }
-
- flags.hasTransitions = timings.transitionDuration > 0;
- flags.hasAnimations = timings.animationDuration > 0;
- }
-
- if (flags.applyAnimationDelay) {
- relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay)
- ? parseFloat(options.delay)
- : relativeDelay;
-
- maxDelay = Math.max(relativeDelay, 0);
- timings.animationDelay = relativeDelay;
- delayStyle = getCssDelayStyle(relativeDelay, true);
- temporaryStyles.push(delayStyle);
- node.style[delayStyle[0]] = delayStyle[1];
- }
-
- maxDelayTime = maxDelay * ONE_SECOND;
- maxDurationTime = maxDuration * ONE_SECOND;
-
- if (options.easing) {
- var easeProp, easeVal = options.easing;
- if (flags.hasTransitions) {
- easeProp = TRANSITION_PROP + TIMING_KEY;
- temporaryStyles.push([easeProp, easeVal]);
- node.style[easeProp] = easeVal;
- }
- if (flags.hasAnimations) {
- easeProp = ANIMATION_PROP + TIMING_KEY;
- temporaryStyles.push([easeProp, easeVal]);
- node.style[easeProp] = easeVal;
- }
- }
-
- if (timings.transitionDuration) {
- events.push(TRANSITIONEND_EVENT);
- }
-
- if (timings.animationDuration) {
- events.push(ANIMATIONEND_EVENT);
- }
-
- startTime = Date.now();
- var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime;
- var endTime = startTime + timerTime;
-
- var animationsData = element.data(ANIMATE_TIMER_KEY) || [];
- var setupFallbackTimer = true;
- if (animationsData.length) {
- var currentTimerData = animationsData[0];
- setupFallbackTimer = endTime > currentTimerData.expectedEndTime;
- if (setupFallbackTimer) {
- $timeout.cancel(currentTimerData.timer);
- } else {
- animationsData.push(close);
- }
- }
-
- if (setupFallbackTimer) {
- var timer = $timeout(onAnimationExpired, timerTime, false);
- animationsData[0] = {
- timer: timer,
- expectedEndTime: endTime
- };
- animationsData.push(close);
- element.data(ANIMATE_TIMER_KEY, animationsData);
- }
-
- if (events.length) {
- element.on(events.join(' '), onAnimationProgress);
- }
-
- if (options.to) {
- if (options.cleanupStyles) {
- registerRestorableStyles(restoreStyles, node, Object.keys(options.to));
- }
- applyAnimationToStyles(element, options);
- }
- }
-
- function onAnimationExpired() {
- var animationsData = element.data(ANIMATE_TIMER_KEY);
-
- // this will be false in the event that the element was
- // removed from the DOM (via a leave animation or something
- // similar)
- if (animationsData) {
- for (var i = 1; i < animationsData.length; i++) {
- animationsData[i]();
- }
- element.removeData(ANIMATE_TIMER_KEY);
- }
- }
- }
- };
- }];
-}];
-
-var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) {
- $$animationProvider.drivers.push('$$animateCssDriver');
-
- var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';
- var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';
-
- var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';
- var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';
-
- function isDocumentFragment(node) {
- return node.parentNode && node.parentNode.nodeType === 11;
- }
-
- this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document',
- function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $sniffer, $$jqLite, $document) {
-
- // only browsers that support these properties can render animations
- if (!$sniffer.animations && !$sniffer.transitions) return noop;
-
- var bodyNode = $document[0].body;
- var rootNode = getDomNode($rootElement);
-
- var rootBodyElement = jqLite(
- // this is to avoid using something that exists outside of the body
- // we also special case the doc fragment case because our unit test code
- // appends the $rootElement to the body after the app has been bootstrapped
- isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
- );
-
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
-
- return function initDriverFn(animationDetails) {
- return animationDetails.from && animationDetails.to
- ? prepareFromToAnchorAnimation(animationDetails.from,
- animationDetails.to,
- animationDetails.classes,
- animationDetails.anchors)
- : prepareRegularAnimation(animationDetails);
- };
-
- function filterCssClasses(classes) {
- //remove all the `ng-` stuff
- return classes.replace(/\bng-\S+\b/g, '');
- }
-
- function getUniqueValues(a, b) {
- if (isString(a)) a = a.split(' ');
- if (isString(b)) b = b.split(' ');
- return a.filter(function(val) {
- return b.indexOf(val) === -1;
- }).join(' ');
- }
-
- function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {
- var clone = jqLite(getDomNode(outAnchor).cloneNode(true));
- var startingClasses = filterCssClasses(getClassVal(clone));
-
- outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
- inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
-
- clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);
-
- rootBodyElement.append(clone);
-
- var animatorIn, animatorOut = prepareOutAnimation();
-
- // the user may not end up using the `out` animation and
- // only making use of the `in` animation or vice-versa.
- // In either case we should allow this and not assume the
- // animation is over unless both animations are not used.
- if (!animatorOut) {
- animatorIn = prepareInAnimation();
- if (!animatorIn) {
- return end();
- }
- }
-
- var startingAnimator = animatorOut || animatorIn;
-
- return {
- start: function() {
- var runner;
-
- var currentAnimation = startingAnimator.start();
- currentAnimation.done(function() {
- currentAnimation = null;
- if (!animatorIn) {
- animatorIn = prepareInAnimation();
- if (animatorIn) {
- currentAnimation = animatorIn.start();
- currentAnimation.done(function() {
- currentAnimation = null;
- end();
- runner.complete();
- });
- return currentAnimation;
- }
- }
- // in the event that there is no `in` animation
- end();
- runner.complete();
- });
-
- runner = new $$AnimateRunner({
- end: endFn,
- cancel: endFn
- });
-
- return runner;
-
- function endFn() {
- if (currentAnimation) {
- currentAnimation.end();
- }
- }
- }
- };
-
- function calculateAnchorStyles(anchor) {
- var styles = {};
-
- var coords = getDomNode(anchor).getBoundingClientRect();
-
- // we iterate directly since safari messes up and doesn't return
- // all the keys for the coords object when iterated
- forEach(['width','height','top','left'], function(key) {
- var value = coords[key];
- switch (key) {
- case 'top':
- value += bodyNode.scrollTop;
- break;
- case 'left':
- value += bodyNode.scrollLeft;
- break;
- }
- styles[key] = Math.floor(value) + 'px';
- });
- return styles;
- }
-
- function prepareOutAnimation() {
- var animator = $animateCss(clone, {
- addClass: NG_OUT_ANCHOR_CLASS_NAME,
- delay: true,
- from: calculateAnchorStyles(outAnchor)
- });
-
- // read the comment within `prepareRegularAnimation` to understand
- // why this check is necessary
- return animator.$$willAnimate ? animator : null;
- }
-
- function getClassVal(element) {
- return element.attr('class') || '';
- }
-
- function prepareInAnimation() {
- var endingClasses = filterCssClasses(getClassVal(inAnchor));
- var toAdd = getUniqueValues(endingClasses, startingClasses);
- var toRemove = getUniqueValues(startingClasses, endingClasses);
-
- var animator = $animateCss(clone, {
- to: calculateAnchorStyles(inAnchor),
- addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,
- removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,
- delay: true
- });
-
- // read the comment within `prepareRegularAnimation` to understand
- // why this check is necessary
- return animator.$$willAnimate ? animator : null;
- }
-
- function end() {
- clone.remove();
- outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
- inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
- }
- }
-
- function prepareFromToAnchorAnimation(from, to, classes, anchors) {
- var fromAnimation = prepareRegularAnimation(from, noop);
- var toAnimation = prepareRegularAnimation(to, noop);
-
- var anchorAnimations = [];
- forEach(anchors, function(anchor) {
- var outElement = anchor['out'];
- var inElement = anchor['in'];
- var animator = prepareAnchoredAnimation(classes, outElement, inElement);
- if (animator) {
- anchorAnimations.push(animator);
- }
- });
-
- // no point in doing anything when there are no elements to animate
- if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;
-
- return {
- start: function() {
- var animationRunners = [];
-
- if (fromAnimation) {
- animationRunners.push(fromAnimation.start());
- }
-
- if (toAnimation) {
- animationRunners.push(toAnimation.start());
- }
-
- forEach(anchorAnimations, function(animation) {
- animationRunners.push(animation.start());
- });
-
- var runner = new $$AnimateRunner({
- end: endFn,
- cancel: endFn // CSS-driven animations cannot be cancelled, only ended
- });
-
- $$AnimateRunner.all(animationRunners, function(status) {
- runner.complete(status);
- });
-
- return runner;
-
- function endFn() {
- forEach(animationRunners, function(runner) {
- runner.end();
- });
- }
- }
- };
- }
-
- function prepareRegularAnimation(animationDetails) {
- var element = animationDetails.element;
- var options = animationDetails.options || {};
-
- if (animationDetails.structural) {
- options.event = animationDetails.event;
- options.structural = true;
- options.applyClassesEarly = true;
-
- // we special case the leave animation since we want to ensure that
- // the element is removed as soon as the animation is over. Otherwise
- // a flicker might appear or the element may not be removed at all
- if (animationDetails.event === 'leave') {
- options.onDone = options.domOperation;
- }
- }
-
- // We assign the preparationClasses as the actual animation event since
- // the internals of $animateCss will just suffix the event token values
- // with `-active` to trigger the animation.
- if (options.preparationClasses) {
- options.event = concatWithSpace(options.event, options.preparationClasses);
- }
-
- var animator = $animateCss(element, options);
-
- // the driver lookup code inside of $$animation attempts to spawn a
- // driver one by one until a driver returns a.$$willAnimate animator object.
- // $animateCss will always return an object, however, it will pass in
- // a flag as a hint as to whether an animation was detected or not
- return animator.$$willAnimate ? animator : null;
- }
- }];
-}];
-
-// TODO(matsko): use caching here to speed things up for detection
-// TODO(matsko): add documentation
-// by the time...
-
-var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
- this.$get = ['$injector', '$$AnimateRunner', '$$jqLite',
- function($injector, $$AnimateRunner, $$jqLite) {
-
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
- // $animateJs(element, 'enter');
- return function(element, event, classes, options) {
- var animationClosed = false;
-
- // the `classes` argument is optional and if it is not used
- // then the classes will be resolved from the element's className
- // property as well as options.addClass/options.removeClass.
- if (arguments.length === 3 && isObject(classes)) {
- options = classes;
- classes = null;
- }
-
- options = prepareAnimationOptions(options);
- if (!classes) {
- classes = element.attr('class') || '';
- if (options.addClass) {
- classes += ' ' + options.addClass;
- }
- if (options.removeClass) {
- classes += ' ' + options.removeClass;
- }
- }
-
- var classesToAdd = options.addClass;
- var classesToRemove = options.removeClass;
-
- // the lookupAnimations function returns a series of animation objects that are
- // matched up with one or more of the CSS classes. These animation objects are
- // defined via the module.animation factory function. If nothing is detected then
- // we don't return anything which then makes $animation query the next driver.
- var animations = lookupAnimations(classes);
- var before, after;
- if (animations.length) {
- var afterFn, beforeFn;
- if (event == 'leave') {
- beforeFn = 'leave';
- afterFn = 'afterLeave'; // TODO(matsko): get rid of this
- } else {
- beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);
- afterFn = event;
- }
-
- if (event !== 'enter' && event !== 'move') {
- before = packageAnimations(element, event, options, animations, beforeFn);
- }
- after = packageAnimations(element, event, options, animations, afterFn);
- }
-
- // no matching animations
- if (!before && !after) return;
-
- function applyOptions() {
- options.domOperation();
- applyAnimationClasses(element, options);
- }
-
- function close() {
- animationClosed = true;
- applyOptions();
- applyAnimationStyles(element, options);
- }
-
- var runner;
-
- return {
- $$willAnimate: true,
- end: function() {
- if (runner) {
- runner.end();
- } else {
- close();
- runner = new $$AnimateRunner();
- runner.complete(true);
- }
- return runner;
- },
- start: function() {
- if (runner) {
- return runner;
- }
-
- runner = new $$AnimateRunner();
- var closeActiveAnimations;
- var chain = [];
-
- if (before) {
- chain.push(function(fn) {
- closeActiveAnimations = before(fn);
- });
- }
-
- if (chain.length) {
- chain.push(function(fn) {
- applyOptions();
- fn(true);
- });
- } else {
- applyOptions();
- }
-
- if (after) {
- chain.push(function(fn) {
- closeActiveAnimations = after(fn);
- });
- }
-
- runner.setHost({
- end: function() {
- endAnimations();
- },
- cancel: function() {
- endAnimations(true);
- }
- });
-
- $$AnimateRunner.chain(chain, onComplete);
- return runner;
-
- function onComplete(success) {
- close(success);
- runner.complete(success);
- }
-
- function endAnimations(cancelled) {
- if (!animationClosed) {
- (closeActiveAnimations || noop)(cancelled);
- onComplete(cancelled);
- }
- }
- }
- };
-
- function executeAnimationFn(fn, element, event, options, onDone) {
- var args;
- switch (event) {
- case 'animate':
- args = [element, options.from, options.to, onDone];
- break;
-
- case 'setClass':
- args = [element, classesToAdd, classesToRemove, onDone];
- break;
-
- case 'addClass':
- args = [element, classesToAdd, onDone];
- break;
-
- case 'removeClass':
- args = [element, classesToRemove, onDone];
- break;
-
- default:
- args = [element, onDone];
- break;
- }
-
- args.push(options);
-
- var value = fn.apply(fn, args);
- if (value) {
- if (isFunction(value.start)) {
- value = value.start();
- }
-
- if (value instanceof $$AnimateRunner) {
- value.done(onDone);
- } else if (isFunction(value)) {
- // optional onEnd / onCancel callback
- return value;
- }
- }
-
- return noop;
- }
-
- function groupEventedAnimations(element, event, options, animations, fnName) {
- var operations = [];
- forEach(animations, function(ani) {
- var animation = ani[fnName];
- if (!animation) return;
-
- // note that all of these animations will run in parallel
- operations.push(function() {
- var runner;
- var endProgressCb;
-
- var resolved = false;
- var onAnimationComplete = function(rejected) {
- if (!resolved) {
- resolved = true;
- (endProgressCb || noop)(rejected);
- runner.complete(!rejected);
- }
- };
-
- runner = new $$AnimateRunner({
- end: function() {
- onAnimationComplete();
- },
- cancel: function() {
- onAnimationComplete(true);
- }
- });
-
- endProgressCb = executeAnimationFn(animation, element, event, options, function(result) {
- var cancelled = result === false;
- onAnimationComplete(cancelled);
- });
-
- return runner;
- });
- });
-
- return operations;
- }
-
- function packageAnimations(element, event, options, animations, fnName) {
- var operations = groupEventedAnimations(element, event, options, animations, fnName);
- if (operations.length === 0) {
- var a,b;
- if (fnName === 'beforeSetClass') {
- a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');
- b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');
- } else if (fnName === 'setClass') {
- a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');
- b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');
- }
-
- if (a) {
- operations = operations.concat(a);
- }
- if (b) {
- operations = operations.concat(b);
- }
- }
-
- if (operations.length === 0) return;
-
- // TODO(matsko): add documentation
- return function startAnimation(callback) {
- var runners = [];
- if (operations.length) {
- forEach(operations, function(animateFn) {
- runners.push(animateFn());
- });
- }
-
- runners.length ? $$AnimateRunner.all(runners, callback) : callback();
-
- return function endFn(reject) {
- forEach(runners, function(runner) {
- reject ? runner.cancel() : runner.end();
- });
- };
- };
- }
- };
-
- function lookupAnimations(classes) {
- classes = isArray(classes) ? classes : classes.split(' ');
- var matches = [], flagMap = {};
- for (var i=0; i < classes.length; i++) {
- var klass = classes[i],
- animationFactory = $animateProvider.$$registeredAnimations[klass];
- if (animationFactory && !flagMap[klass]) {
- matches.push($injector.get(animationFactory));
- flagMap[klass] = true;
- }
- }
- return matches;
- }
- }];
-}];
-
-var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) {
- $$animationProvider.drivers.push('$$animateJsDriver');
- this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {
- return function initDriverFn(animationDetails) {
- if (animationDetails.from && animationDetails.to) {
- var fromAnimation = prepareAnimation(animationDetails.from);
- var toAnimation = prepareAnimation(animationDetails.to);
- if (!fromAnimation && !toAnimation) return;
-
- return {
- start: function() {
- var animationRunners = [];
-
- if (fromAnimation) {
- animationRunners.push(fromAnimation.start());
- }
-
- if (toAnimation) {
- animationRunners.push(toAnimation.start());
- }
-
- $$AnimateRunner.all(animationRunners, done);
-
- var runner = new $$AnimateRunner({
- end: endFnFactory(),
- cancel: endFnFactory()
- });
-
- return runner;
-
- function endFnFactory() {
- return function() {
- forEach(animationRunners, function(runner) {
- // at this point we cannot cancel animations for groups just yet. 1.5+
- runner.end();
- });
- };
- }
-
- function done(status) {
- runner.complete(status);
- }
- }
- };
- } else {
- return prepareAnimation(animationDetails);
- }
- };
-
- function prepareAnimation(animationDetails) {
- // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations
- var element = animationDetails.element;
- var event = animationDetails.event;
- var options = animationDetails.options;
- var classes = animationDetails.classes;
- return $$animateJs(element, event, classes, options);
- }
- }];
-}];
-
-var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';
-var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
-var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
- var PRE_DIGEST_STATE = 1;
- var RUNNING_STATE = 2;
- var ONE_SPACE = ' ';
-
- var rules = this.rules = {
- skip: [],
- cancel: [],
- join: []
- };
-
- function makeTruthyCssClassMap(classString) {
- if (!classString) {
- return null;
- }
-
- var keys = classString.split(ONE_SPACE);
- var map = Object.create(null);
-
- forEach(keys, function(key) {
- map[key] = true;
- });
- return map;
- }
-
- function hasMatchingClasses(newClassString, currentClassString) {
- if (newClassString && currentClassString) {
- var currentClassMap = makeTruthyCssClassMap(currentClassString);
- return newClassString.split(ONE_SPACE).some(function(className) {
- return currentClassMap[className];
- });
- }
- }
-
- function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
- return rules[ruleType].some(function(fn) {
- return fn(element, currentAnimation, previousAnimation);
- });
- }
-
- function hasAnimationClasses(animation, and) {
- var a = (animation.addClass || '').length > 0;
- var b = (animation.removeClass || '').length > 0;
- return and ? a && b : a || b;
- }
-
- rules.join.push(function(element, newAnimation, currentAnimation) {
- // if the new animation is class-based then we can just tack that on
- return !newAnimation.structural && hasAnimationClasses(newAnimation);
- });
-
- rules.skip.push(function(element, newAnimation, currentAnimation) {
- // there is no need to animate anything if no classes are being added and
- // there is no structural animation that will be triggered
- return !newAnimation.structural && !hasAnimationClasses(newAnimation);
- });
-
- rules.skip.push(function(element, newAnimation, currentAnimation) {
- // why should we trigger a new structural animation if the element will
- // be removed from the DOM anyway?
- return currentAnimation.event == 'leave' && newAnimation.structural;
- });
-
- rules.skip.push(function(element, newAnimation, currentAnimation) {
- // if there is an ongoing current animation then don't even bother running the class-based animation
- return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;
- });
-
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
- // there can never be two structural animations running at the same time
- return currentAnimation.structural && newAnimation.structural;
- });
-
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
- // if the previous animation is already running, but the new animation will
- // be triggered, but the new animation is structural
- return currentAnimation.state === RUNNING_STATE && newAnimation.structural;
- });
-
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
- // cancel the animation if classes added / removed in both animation cancel each other out,
- // but only if the current animation isn't structural
-
- if (currentAnimation.structural) return false;
-
- var nA = newAnimation.addClass;
- var nR = newAnimation.removeClass;
- var cA = currentAnimation.addClass;
- var cR = currentAnimation.removeClass;
-
- // early detection to save the global CPU shortage :)
- if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {
- return false;
- }
-
- return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
- });
-
- this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
- '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
- function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
- $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {
-
- var activeAnimationsLookup = new $$HashMap();
- var disabledElementsLookup = new $$HashMap();
- var animationsEnabled = null;
-
- function postDigestTaskFactory() {
- var postDigestCalled = false;
- return function(fn) {
- // we only issue a call to postDigest before
- // it has first passed. This prevents any callbacks
- // from not firing once the animation has completed
- // since it will be out of the digest cycle.
- if (postDigestCalled) {
- fn();
- } else {
- $rootScope.$$postDigest(function() {
- postDigestCalled = true;
- fn();
- });
- }
- };
- }
-
- // Wait until all directive and route-related templates are downloaded and
- // compiled. The $templateRequest.totalPendingRequests variable keeps track of
- // all of the remote templates being currently downloaded. If there are no
- // templates currently downloading then the watcher will still fire anyway.
- var deregisterWatch = $rootScope.$watch(
- function() { return $templateRequest.totalPendingRequests === 0; },
- function(isEmpty) {
- if (!isEmpty) return;
- deregisterWatch();
-
- // Now that all templates have been downloaded, $animate will wait until
- // the post digest queue is empty before enabling animations. By having two
- // calls to $postDigest calls we can ensure that the flag is enabled at the
- // very end of the post digest queue. Since all of the animations in $animate
- // use $postDigest, it's important that the code below executes at the end.
- // This basically means that the page is fully downloaded and compiled before
- // any animations are triggered.
- $rootScope.$$postDigest(function() {
- $rootScope.$$postDigest(function() {
- // we check for null directly in the event that the application already called
- // .enabled() with whatever arguments that it provided it with
- if (animationsEnabled === null) {
- animationsEnabled = true;
- }
- });
- });
- }
- );
-
- var callbackRegistry = Object.create(null);
-
- // remember that the classNameFilter is set during the provider/config
- // stage therefore we can optimize here and setup a helper function
- var classNameFilter = $animateProvider.classNameFilter();
- var isAnimatableClassName = !classNameFilter
- ? function() { return true; }
- : function(className) {
- return classNameFilter.test(className);
- };
-
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
-
- function normalizeAnimationDetails(element, animation) {
- return mergeAnimationDetails(element, animation, {});
- }
-
- // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
- var contains = window.Node.prototype.contains || function(arg) {
- // jshint bitwise: false
- return this === arg || !!(this.compareDocumentPosition(arg) & 16);
- // jshint bitwise: true
- };
-
- function findCallbacks(parent, element, event) {
- var targetNode = getDomNode(element);
- var targetParentNode = getDomNode(parent);
-
- var matches = [];
- var entries = callbackRegistry[event];
- if (entries) {
- forEach(entries, function(entry) {
- if (contains.call(entry.node, targetNode)) {
- matches.push(entry.callback);
- } else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {
- matches.push(entry.callback);
- }
- });
- }
-
- return matches;
- }
-
- function filterFromRegistry(list, matchContainer, matchCallback) {
- var containerNode = extractElementNode(matchContainer);
- return list.filter(function(entry) {
- var isMatch = entry.node === containerNode &&
- (!matchCallback || entry.callback === matchCallback);
- return !isMatch;
- });
- }
-
- function cleanupEventListeners(phase, element) {
- if (phase === 'close' && !element[0].parentNode) {
- // If the element is not attached to a parentNode, it has been removed by
- // the domOperation, and we can safely remove the event callbacks
- $animate.off(element);
- }
- }
-
- var $animate = {
- on: function(event, container, callback) {
- var node = extractElementNode(container);
- callbackRegistry[event] = callbackRegistry[event] || [];
- callbackRegistry[event].push({
- node: node,
- callback: callback
- });
-
- // Remove the callback when the element is removed from the DOM
- jqLite(container).on('$destroy', function() {
- var animationDetails = activeAnimationsLookup.get(node);
-
- if (!animationDetails) {
- // If there's an animation ongoing, the callback calling code will remove
- // the event listeners. If we'd remove here, the callbacks would be removed
- // before the animation ends
- $animate.off(event, container, callback);
- }
- });
- },
-
- off: function(event, container, callback) {
- if (arguments.length === 1 && !isString(arguments[0])) {
- container = arguments[0];
- for (var eventType in callbackRegistry) {
- callbackRegistry[eventType] = filterFromRegistry(callbackRegistry[eventType], container);
- }
-
- return;
- }
-
- var entries = callbackRegistry[event];
- if (!entries) return;
-
- callbackRegistry[event] = arguments.length === 1
- ? null
- : filterFromRegistry(entries, container, callback);
- },
-
- pin: function(element, parentElement) {
- assertArg(isElement(element), 'element', 'not an element');
- assertArg(isElement(parentElement), 'parentElement', 'not an element');
- element.data(NG_ANIMATE_PIN_DATA, parentElement);
- },
-
- push: function(element, event, options, domOperation) {
- options = options || {};
- options.domOperation = domOperation;
- return queueAnimation(element, event, options);
- },
-
- // this method has four signatures:
- // () - global getter
- // (bool) - global setter
- // (element) - element getter
- // (element, bool) - element setter
- enabled: function(element, bool) {
- var argCount = arguments.length;
-
- if (argCount === 0) {
- // () - Global getter
- bool = !!animationsEnabled;
- } else {
- var hasElement = isElement(element);
-
- if (!hasElement) {
- // (bool) - Global setter
- bool = animationsEnabled = !!element;
- } else {
- var node = getDomNode(element);
-
- if (argCount === 1) {
- // (element) - Element getter
- bool = !disabledElementsLookup.get(node);
- } else {
- // (element, bool) - Element setter
- disabledElementsLookup.put(node, !bool);
- }
- }
- }
-
- return bool;
- }
- };
-
- return $animate;
-
- function queueAnimation(element, event, initialOptions) {
- // we always make a copy of the options since
- // there should never be any side effects on
- // the input data when running `$animateCss`.
- var options = copy(initialOptions);
-
- var node, parent;
- element = stripCommentsFromElement(element);
- if (element) {
- node = getDomNode(element);
- parent = element.parent();
- }
-
- options = prepareAnimationOptions(options);
-
- // we create a fake runner with a working promise.
- // These methods will become available after the digest has passed
- var runner = new $$AnimateRunner();
-
- // this is used to trigger callbacks in postDigest mode
- var runInNextPostDigestOrNow = postDigestTaskFactory();
-
- if (isArray(options.addClass)) {
- options.addClass = options.addClass.join(' ');
- }
-
- if (options.addClass && !isString(options.addClass)) {
- options.addClass = null;
- }
-
- if (isArray(options.removeClass)) {
- options.removeClass = options.removeClass.join(' ');
- }
-
- if (options.removeClass && !isString(options.removeClass)) {
- options.removeClass = null;
- }
-
- if (options.from && !isObject(options.from)) {
- options.from = null;
- }
-
- if (options.to && !isObject(options.to)) {
- options.to = null;
- }
-
- // there are situations where a directive issues an animation for
- // a jqLite wrapper that contains only comment nodes... If this
- // happens then there is no way we can perform an animation
- if (!node) {
- close();
- return runner;
- }
-
- var className = [node.className, options.addClass, options.removeClass].join(' ');
- if (!isAnimatableClassName(className)) {
- close();
- return runner;
- }
-
- var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
-
- var documentHidden = $document[0].hidden;
-
- // this is a hard disable of all animations for the application or on
- // the element itself, therefore there is no need to continue further
- // past this point if not enabled
- // Animations are also disabled if the document is currently hidden (page is not visible
- // to the user), because browsers slow down or do not flush calls to requestAnimationFrame
- var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
- var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
- var hasExistingAnimation = !!existingAnimation.state;
-
- // there is no point in traversing the same collection of parent ancestors if a followup
- // animation will be run on the same element that already did all that checking work
- if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) {
- skipAnimations = !areAnimationsAllowed(element, parent, event);
- }
-
- if (skipAnimations) {
- // Callbacks should fire even if the document is hidden (regression fix for issue #14120)
- if (documentHidden) notifyProgress(runner, event, 'start');
- close();
- if (documentHidden) notifyProgress(runner, event, 'close');
- return runner;
- }
-
- if (isStructural) {
- closeChildAnimations(element);
- }
-
- var newAnimation = {
- structural: isStructural,
- element: element,
- event: event,
- addClass: options.addClass,
- removeClass: options.removeClass,
- close: close,
- options: options,
- runner: runner
- };
-
- if (hasExistingAnimation) {
- var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation);
- if (skipAnimationFlag) {
- if (existingAnimation.state === RUNNING_STATE) {
- close();
- return runner;
- } else {
- mergeAnimationDetails(element, existingAnimation, newAnimation);
- return existingAnimation.runner;
- }
- }
- var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
- if (cancelAnimationFlag) {
- if (existingAnimation.state === RUNNING_STATE) {
- // this will end the animation right away and it is safe
- // to do so since the animation is already running and the
- // runner callback code will run in async
- existingAnimation.runner.end();
- } else if (existingAnimation.structural) {
- // this means that the animation is queued into a digest, but
- // hasn't started yet. Therefore it is safe to run the close
- // method which will call the runner methods in async.
- existingAnimation.close();
- } else {
- // this will merge the new animation options into existing animation options
- mergeAnimationDetails(element, existingAnimation, newAnimation);
-
- return existingAnimation.runner;
- }
- } else {
- // a joined animation means that this animation will take over the existing one
- // so an example would involve a leave animation taking over an enter. Then when
- // the postDigest kicks in the enter will be ignored.
- var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);
- if (joinAnimationFlag) {
- if (existingAnimation.state === RUNNING_STATE) {
- normalizeAnimationDetails(element, newAnimation);
- } else {
- applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
-
- event = newAnimation.event = existingAnimation.event;
- options = mergeAnimationDetails(element, existingAnimation, newAnimation);
-
- //we return the same runner since only the option values of this animation will
- //be fed into the `existingAnimation`.
- return existingAnimation.runner;
- }
- }
- }
- } else {
- // normalization in this case means that it removes redundant CSS classes that
- // already exist (addClass) or do not exist (removeClass) on the element
- normalizeAnimationDetails(element, newAnimation);
- }
-
- // when the options are merged and cleaned up we may end up not having to do
- // an animation at all, therefore we should check this before issuing a post
- // digest callback. Structural animations will always run no matter what.
- var isValidAnimation = newAnimation.structural;
- if (!isValidAnimation) {
- // animate (from/to) can be quickly checked first, otherwise we check if any classes are present
- isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)
- || hasAnimationClasses(newAnimation);
- }
-
- if (!isValidAnimation) {
- close();
- clearElementAnimationState(element);
- return runner;
- }
-
- // the counter keeps track of cancelled animations
- var counter = (existingAnimation.counter || 0) + 1;
- newAnimation.counter = counter;
-
- markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation);
-
- $rootScope.$$postDigest(function() {
- var animationDetails = activeAnimationsLookup.get(node);
- var animationCancelled = !animationDetails;
- animationDetails = animationDetails || {};
-
- // if addClass/removeClass is called before something like enter then the
- // registered parent element may not be present. The code below will ensure
- // that a final value for parent element is obtained
- var parentElement = element.parent() || [];
-
- // animate/structural/class-based animations all have requirements. Otherwise there
- // is no point in performing an animation. The parent node must also be set.
- var isValidAnimation = parentElement.length > 0
- && (animationDetails.event === 'animate'
- || animationDetails.structural
- || hasAnimationClasses(animationDetails));
-
- // this means that the previous animation was cancelled
- // even if the follow-up animation is the same event
- if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {
- // if another animation did not take over then we need
- // to make sure that the domOperation and options are
- // handled accordingly
- if (animationCancelled) {
- applyAnimationClasses(element, options);
- applyAnimationStyles(element, options);
- }
-
- // if the event changed from something like enter to leave then we do
- // it, otherwise if it's the same then the end result will be the same too
- if (animationCancelled || (isStructural && animationDetails.event !== event)) {
- options.domOperation();
- runner.end();
- }
-
- // in the event that the element animation was not cancelled or a follow-up animation
- // isn't allowed to animate from here then we need to clear the state of the element
- // so that any future animations won't read the expired animation data.
- if (!isValidAnimation) {
- clearElementAnimationState(element);
- }
-
- return;
- }
-
- // this combined multiple class to addClass / removeClass into a setClass event
- // so long as a structural event did not take over the animation
- event = !animationDetails.structural && hasAnimationClasses(animationDetails, true)
- ? 'setClass'
- : animationDetails.event;
-
- markElementAnimationState(element, RUNNING_STATE);
- var realRunner = $$animation(element, event, animationDetails.options);
-
- // this will update the runner's flow-control events based on
- // the `realRunner` object.
- runner.setHost(realRunner);
- notifyProgress(runner, event, 'start', {});
-
- realRunner.done(function(status) {
- close(!status);
- var animationDetails = activeAnimationsLookup.get(node);
- if (animationDetails && animationDetails.counter === counter) {
- clearElementAnimationState(getDomNode(element));
- }
- notifyProgress(runner, event, 'close', {});
- });
- });
-
- return runner;
-
- function notifyProgress(runner, event, phase, data) {
- runInNextPostDigestOrNow(function() {
- var callbacks = findCallbacks(parent, element, event);
- if (callbacks.length) {
- // do not optimize this call here to RAF because
- // we don't know how heavy the callback code here will
- // be and if this code is buffered then this can
- // lead to a performance regression.
- $$rAF(function() {
- forEach(callbacks, function(callback) {
- callback(element, phase, data);
- });
- cleanupEventListeners(phase, element);
- });
- } else {
- cleanupEventListeners(phase, element);
- }
- });
- runner.progress(event, phase, data);
- }
-
- function close(reject) { // jshint ignore:line
- clearGeneratedClasses(element, options);
- applyAnimationClasses(element, options);
- applyAnimationStyles(element, options);
- options.domOperation();
- runner.complete(!reject);
- }
- }
-
- function closeChildAnimations(element) {
- var node = getDomNode(element);
- var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');
- forEach(children, function(child) {
- var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
- var animationDetails = activeAnimationsLookup.get(child);
- if (animationDetails) {
- switch (state) {
- case RUNNING_STATE:
- animationDetails.runner.end();
- /* falls through */
- case PRE_DIGEST_STATE:
- activeAnimationsLookup.remove(child);
- break;
- }
- }
- });
- }
-
- function clearElementAnimationState(element) {
- var node = getDomNode(element);
- node.removeAttribute(NG_ANIMATE_ATTR_NAME);
- activeAnimationsLookup.remove(node);
- }
-
- function isMatchingElement(nodeOrElmA, nodeOrElmB) {
- return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
- }
-
- /**
- * This fn returns false if any of the following is true:
- * a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed
- * b) a parent element has an ongoing structural animation, and animateChildren is false
- * c) the element is not a child of the body
- * d) the element is not a child of the $rootElement
- */
- function areAnimationsAllowed(element, parentElement, event) {
- var bodyElement = jqLite($document[0].body);
- var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
- var rootElementDetected = isMatchingElement(element, $rootElement);
- var parentAnimationDetected = false;
- var animateChildren;
- var elementDisabled = disabledElementsLookup.get(getDomNode(element));
-
- var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA);
- if (parentHost) {
- parentElement = parentHost;
- }
-
- parentElement = getDomNode(parentElement);
-
- while (parentElement) {
- if (!rootElementDetected) {
- // angular doesn't want to attempt to animate elements outside of the application
- // therefore we need to ensure that the rootElement is an ancestor of the current element
- rootElementDetected = isMatchingElement(parentElement, $rootElement);
- }
-
- if (parentElement.nodeType !== ELEMENT_NODE) {
- // no point in inspecting the #document element
- break;
- }
-
- var details = activeAnimationsLookup.get(parentElement) || {};
- // either an enter, leave or move animation will commence
- // therefore we can't allow any animations to take place
- // but if a parent animation is class-based then that's ok
- if (!parentAnimationDetected) {
- var parentElementDisabled = disabledElementsLookup.get(parentElement);
-
- if (parentElementDisabled === true && elementDisabled !== false) {
- // disable animations if the user hasn't explicitly enabled animations on the
- // current element
- elementDisabled = true;
- // element is disabled via parent element, no need to check anything else
- break;
- } else if (parentElementDisabled === false) {
- elementDisabled = false;
- }
- parentAnimationDetected = details.structural;
- }
-
- if (isUndefined(animateChildren) || animateChildren === true) {
- var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA);
- if (isDefined(value)) {
- animateChildren = value;
- }
- }
-
- // there is no need to continue traversing at this point
- if (parentAnimationDetected && animateChildren === false) break;
-
- if (!bodyElementDetected) {
- // we also need to ensure that the element is or will be a part of the body element
- // otherwise it is pointless to even issue an animation to be rendered
- bodyElementDetected = isMatchingElement(parentElement, bodyElement);
- }
-
- if (bodyElementDetected && rootElementDetected) {
- // If both body and root have been found, any other checks are pointless,
- // as no animation data should live outside the application
- break;
- }
-
- if (!rootElementDetected) {
- // If no rootElement is detected, check if the parentElement is pinned to another element
- parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA);
- if (parentHost) {
- // The pin target element becomes the next parent element
- parentElement = getDomNode(parentHost);
- continue;
- }
- }
-
- parentElement = parentElement.parentNode;
- }
-
- var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
- return allowAnimation && rootElementDetected && bodyElementDetected;
- }
-
- function markElementAnimationState(element, state, details) {
- details = details || {};
- details.state = state;
-
- var node = getDomNode(element);
- node.setAttribute(NG_ANIMATE_ATTR_NAME, state);
-
- var oldValue = activeAnimationsLookup.get(node);
- var newValue = oldValue
- ? extend(oldValue, details)
- : details;
- activeAnimationsLookup.put(node, newValue);
- }
- }];
-}];
-
-var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
- var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
-
- var drivers = this.drivers = [];
-
- var RUNNER_STORAGE_KEY = '$$animationRunner';
-
- function setRunner(element, runner) {
- element.data(RUNNER_STORAGE_KEY, runner);
- }
-
- function removeRunner(element) {
- element.removeData(RUNNER_STORAGE_KEY);
- }
-
- function getRunner(element) {
- return element.data(RUNNER_STORAGE_KEY);
- }
-
- this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler',
- function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) {
-
- var animationQueue = [];
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
-
- function sortAnimations(animations) {
- var tree = { children: [] };
- var i, lookup = new $$HashMap();
-
- // this is done first beforehand so that the hashmap
- // is filled with a list of the elements that will be animated
- for (i = 0; i < animations.length; i++) {
- var animation = animations[i];
- lookup.put(animation.domNode, animations[i] = {
- domNode: animation.domNode,
- fn: animation.fn,
- children: []
- });
- }
-
- for (i = 0; i < animations.length; i++) {
- processNode(animations[i]);
- }
-
- return flatten(tree);
-
- function processNode(entry) {
- if (entry.processed) return entry;
- entry.processed = true;
-
- var elementNode = entry.domNode;
- var parentNode = elementNode.parentNode;
- lookup.put(elementNode, entry);
-
- var parentEntry;
- while (parentNode) {
- parentEntry = lookup.get(parentNode);
- if (parentEntry) {
- if (!parentEntry.processed) {
- parentEntry = processNode(parentEntry);
- }
- break;
- }
- parentNode = parentNode.parentNode;
- }
-
- (parentEntry || tree).children.push(entry);
- return entry;
- }
-
- function flatten(tree) {
- var result = [];
- var queue = [];
- var i;
-
- for (i = 0; i < tree.children.length; i++) {
- queue.push(tree.children[i]);
- }
-
- var remainingLevelEntries = queue.length;
- var nextLevelEntries = 0;
- var row = [];
-
- for (i = 0; i < queue.length; i++) {
- var entry = queue[i];
- if (remainingLevelEntries <= 0) {
- remainingLevelEntries = nextLevelEntries;
- nextLevelEntries = 0;
- result.push(row);
- row = [];
- }
- row.push(entry.fn);
- entry.children.forEach(function(childEntry) {
- nextLevelEntries++;
- queue.push(childEntry);
- });
- remainingLevelEntries--;
- }
-
- if (row.length) {
- result.push(row);
- }
-
- return result;
- }
- }
-
- // TODO(matsko): document the signature in a better way
- return function(element, event, options) {
- options = prepareAnimationOptions(options);
- var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
-
- // there is no animation at the current moment, however
- // these runner methods will get later updated with the
- // methods leading into the driver's end/cancel methods
- // for now they just stop the animation from starting
- var runner = new $$AnimateRunner({
- end: function() { close(); },
- cancel: function() { close(true); }
- });
-
- if (!drivers.length) {
- close();
- return runner;
- }
-
- setRunner(element, runner);
-
- var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));
- var tempClasses = options.tempClasses;
- if (tempClasses) {
- classes += ' ' + tempClasses;
- options.tempClasses = null;
- }
-
- var prepareClassName;
- if (isStructural) {
- prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;
- $$jqLite.addClass(element, prepareClassName);
- }
-
- animationQueue.push({
- // this data is used by the postDigest code and passed into
- // the driver step function
- element: element,
- classes: classes,
- event: event,
- structural: isStructural,
- options: options,
- beforeStart: beforeStart,
- close: close
- });
-
- element.on('$destroy', handleDestroyedElement);
-
- // we only want there to be one function called within the post digest
- // block. This way we can group animations for all the animations that
- // were apart of the same postDigest flush call.
- if (animationQueue.length > 1) return runner;
-
- $rootScope.$$postDigest(function() {
- var animations = [];
- forEach(animationQueue, function(entry) {
- // the element was destroyed early on which removed the runner
- // form its storage. This means we can't animate this element
- // at all and it already has been closed due to destruction.
- if (getRunner(entry.element)) {
- animations.push(entry);
- } else {
- entry.close();
- }
- });
-
- // now any future animations will be in another postDigest
- animationQueue.length = 0;
-
- var groupedAnimations = groupAnimations(animations);
- var toBeSortedAnimations = [];
-
- forEach(groupedAnimations, function(animationEntry) {
- toBeSortedAnimations.push({
- domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
- fn: function triggerAnimationStart() {
- // it's important that we apply the `ng-animate` CSS class and the
- // temporary classes before we do any driver invoking since these
- // CSS classes may be required for proper CSS detection.
- animationEntry.beforeStart();
-
- var startAnimationFn, closeFn = animationEntry.close;
-
- // in the event that the element was removed before the digest runs or
- // during the RAF sequencing then we should not trigger the animation.
- var targetElement = animationEntry.anchors
- ? (animationEntry.from.element || animationEntry.to.element)
- : animationEntry.element;
-
- if (getRunner(targetElement)) {
- var operation = invokeFirstDriver(animationEntry);
- if (operation) {
- startAnimationFn = operation.start;
- }
- }
-
- if (!startAnimationFn) {
- closeFn();
- } else {
- var animationRunner = startAnimationFn();
- animationRunner.done(function(status) {
- closeFn(!status);
- });
- updateAnimationRunners(animationEntry, animationRunner);
- }
- }
- });
- });
-
- // we need to sort each of the animations in order of parent to child
- // relationships. This ensures that the child classes are applied at the
- // right time.
- $$rAFScheduler(sortAnimations(toBeSortedAnimations));
- });
-
- return runner;
-
- // TODO(matsko): change to reference nodes
- function getAnchorNodes(node) {
- var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';
- var items = node.hasAttribute(NG_ANIMATE_REF_ATTR)
- ? [node]
- : node.querySelectorAll(SELECTOR);
- var anchors = [];
- forEach(items, function(node) {
- var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);
- if (attr && attr.length) {
- anchors.push(node);
- }
- });
- return anchors;
- }
-
- function groupAnimations(animations) {
- var preparedAnimations = [];
- var refLookup = {};
- forEach(animations, function(animation, index) {
- var element = animation.element;
- var node = getDomNode(element);
- var event = animation.event;
- var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;
- var anchorNodes = animation.structural ? getAnchorNodes(node) : [];
-
- if (anchorNodes.length) {
- var direction = enterOrMove ? 'to' : 'from';
-
- forEach(anchorNodes, function(anchor) {
- var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);
- refLookup[key] = refLookup[key] || {};
- refLookup[key][direction] = {
- animationID: index,
- element: jqLite(anchor)
- };
- });
- } else {
- preparedAnimations.push(animation);
- }
- });
-
- var usedIndicesLookup = {};
- var anchorGroups = {};
- forEach(refLookup, function(operations, key) {
- var from = operations.from;
- var to = operations.to;
-
- if (!from || !to) {
- // only one of these is set therefore we can't have an
- // anchor animation since all three pieces are required
- var index = from ? from.animationID : to.animationID;
- var indexKey = index.toString();
- if (!usedIndicesLookup[indexKey]) {
- usedIndicesLookup[indexKey] = true;
- preparedAnimations.push(animations[index]);
- }
- return;
- }
-
- var fromAnimation = animations[from.animationID];
- var toAnimation = animations[to.animationID];
- var lookupKey = from.animationID.toString();
- if (!anchorGroups[lookupKey]) {
- var group = anchorGroups[lookupKey] = {
- structural: true,
- beforeStart: function() {
- fromAnimation.beforeStart();
- toAnimation.beforeStart();
- },
- close: function() {
- fromAnimation.close();
- toAnimation.close();
- },
- classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),
- from: fromAnimation,
- to: toAnimation,
- anchors: [] // TODO(matsko): change to reference nodes
- };
-
- // the anchor animations require that the from and to elements both have at least
- // one shared CSS class which effectively marries the two elements together to use
- // the same animation driver and to properly sequence the anchor animation.
- if (group.classes.length) {
- preparedAnimations.push(group);
- } else {
- preparedAnimations.push(fromAnimation);
- preparedAnimations.push(toAnimation);
- }
- }
-
- anchorGroups[lookupKey].anchors.push({
- 'out': from.element, 'in': to.element
- });
- });
-
- return preparedAnimations;
- }
-
- function cssClassesIntersection(a,b) {
- a = a.split(' ');
- b = b.split(' ');
- var matches = [];
-
- for (var i = 0; i < a.length; i++) {
- var aa = a[i];
- if (aa.substring(0,3) === 'ng-') continue;
-
- for (var j = 0; j < b.length; j++) {
- if (aa === b[j]) {
- matches.push(aa);
- break;
- }
- }
- }
-
- return matches.join(' ');
- }
-
- function invokeFirstDriver(animationDetails) {
- // we loop in reverse order since the more general drivers (like CSS and JS)
- // may attempt more elements, but custom drivers are more particular
- for (var i = drivers.length - 1; i >= 0; i--) {
- var driverName = drivers[i];
- var factory = $injector.get(driverName);
- var driver = factory(animationDetails);
- if (driver) {
- return driver;
- }
- }
- }
-
- function beforeStart() {
- element.addClass(NG_ANIMATE_CLASSNAME);
- if (tempClasses) {
- $$jqLite.addClass(element, tempClasses);
- }
- if (prepareClassName) {
- $$jqLite.removeClass(element, prepareClassName);
- prepareClassName = null;
- }
- }
-
- function updateAnimationRunners(animation, newRunner) {
- if (animation.from && animation.to) {
- update(animation.from.element);
- update(animation.to.element);
- } else {
- update(animation.element);
- }
-
- function update(element) {
- var runner = getRunner(element);
- if (runner) runner.setHost(newRunner);
- }
- }
-
- function handleDestroyedElement() {
- var runner = getRunner(element);
- if (runner && (event !== 'leave' || !options.$$domOperationFired)) {
- runner.end();
- }
- }
-
- function close(rejected) { // jshint ignore:line
- element.off('$destroy', handleDestroyedElement);
- removeRunner(element);
-
- applyAnimationClasses(element, options);
- applyAnimationStyles(element, options);
- options.domOperation();
-
- if (tempClasses) {
- $$jqLite.removeClass(element, tempClasses);
- }
-
- element.removeClass(NG_ANIMATE_CLASSNAME);
- runner.complete(!rejected);
- }
- };
- }];
-}];
-
-/**
- * @ngdoc directive
- * @name ngAnimateSwap
- * @restrict A
- * @scope
- *
- * @description
- *
- * ngAnimateSwap is a animation-oriented directive that allows for the container to
- * be removed and entered in whenever the associated expression changes. A
- * common usecase for this directive is a rotating banner or slider component which
- * contains one image being present at a time. When the active image changes
- * then the old image will perform a `leave` animation and the new element
- * will be inserted via an `enter` animation.
- *
- * @animations
- * | Animation | Occurs |
- * |----------------------------------|--------------------------------------|
- * | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM |
- * | {@link ng.$animate#leave leave} | when the old element is removed from the DOM |
- *
- * @example
- *
- *
- *
- *
- * {{ number }}
- *
- *
- *
- *
- * angular.module('ngAnimateSwapExample', ['ngAnimate'])
- * .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {
- * $scope.number = 0;
- * $interval(function() {
- * $scope.number++;
- * }, 1000);
- *
- * var colors = ['red','blue','green','yellow','orange'];
- * $scope.colorClass = function(number) {
- * return colors[number % colors.length];
- * };
- * }]);
- *
- *
- * .container {
- * height:250px;
- * width:250px;
- * position:relative;
- * overflow:hidden;
- * border:2px solid black;
- * }
- * .container .cell {
- * font-size:150px;
- * text-align:center;
- * line-height:250px;
- * position:absolute;
- * top:0;
- * left:0;
- * right:0;
- * border-bottom:2px solid black;
- * }
- * .swap-animation.ng-enter, .swap-animation.ng-leave {
- * transition:0.5s linear all;
- * }
- * .swap-animation.ng-enter {
- * top:-250px;
- * }
- * .swap-animation.ng-enter-active {
- * top:0px;
- * }
- * .swap-animation.ng-leave {
- * top:0px;
- * }
- * .swap-animation.ng-leave-active {
- * top:250px;
- * }
- * .red { background:red; }
- * .green { background:green; }
- * .blue { background:blue; }
- * .yellow { background:yellow; }
- * .orange { background:orange; }
- *
- *
- */
-var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
- return {
- restrict: 'A',
- transclude: 'element',
- terminal: true,
- priority: 600, // we use 600 here to ensure that the directive is caught before others
- link: function(scope, $element, attrs, ctrl, $transclude) {
- var previousElement, previousScope;
- scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
- if (previousElement) {
- $animate.leave(previousElement);
- }
- if (previousScope) {
- previousScope.$destroy();
- previousScope = null;
- }
- if (value || value === 0) {
- previousScope = scope.$new();
- $transclude(previousScope, function(element) {
- previousElement = element;
- $animate.enter(element, null, $element);
- });
- }
- });
- }
- };
-}];
-
-/**
- * @ngdoc module
- * @name ngAnimate
- * @description
- *
- * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
- * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app.
- *
- *
- *
- * # Usage
- * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based
- * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For
- * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within
- * the HTML element that the animation will be triggered on.
- *
- * ## Directive Support
- * The following directives are "animation aware":
- *
- * | Directive | Supported Animations |
- * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
- * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
- * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
- * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
- * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
- * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
- * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |
- * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |
- * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
- * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |
- * | {@link module:ngMessages#animations ngMessage} | enter and leave |
- *
- * (More information can be found by visiting each the documentation associated with each directive.)
- *
- * ## CSS-based Animations
- *
- * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML
- * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.
- *
- * The example below shows how an `enter` animation can be made possible on an element using `ng-if`:
- *
- * ```html
- *
- * Fade me in out
- *
- *
- *
- * ```
- *
- * Notice the CSS class **fade**? We can now create the CSS transition code that references this class:
- *
- * ```css
- * /* The starting CSS styles for the enter animation */
- * .fade.ng-enter {
- * transition:0.5s linear all;
- * opacity:0;
- * }
- *
- * /* The finishing CSS styles for the enter animation */
- * .fade.ng-enter.ng-enter-active {
- * opacity:1;
- * }
- * ```
- *
- * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two
- * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition
- * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.
- *
- * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:
- *
- * ```css
- * /* now the element will fade out before it is removed from the DOM */
- * .fade.ng-leave {
- * transition:0.5s linear all;
- * opacity:1;
- * }
- * .fade.ng-leave.ng-leave-active {
- * opacity:0;
- * }
- * ```
- *
- * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:
- *
- * ```css
- * /* there is no need to define anything inside of the destination
- * CSS class since the keyframe will take charge of the animation */
- * .fade.ng-leave {
- * animation: my_fade_animation 0.5s linear;
- * -webkit-animation: my_fade_animation 0.5s linear;
- * }
- *
- * @keyframes my_fade_animation {
- * from { opacity:1; }
- * to { opacity:0; }
- * }
- *
- * @-webkit-keyframes my_fade_animation {
- * from { opacity:1; }
- * to { opacity:0; }
- * }
- * ```
- *
- * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.
- *
- * ### CSS Class-based Animations
- *
- * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different
- * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added
- * and removed.
- *
- * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:
- *
- * ```html
- *
- * Show and hide me
- *
- *
- *
- *
- * ```
- *
- * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since
- * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.
- *
- * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation
- * with CSS styles.
- *
- * ```html
- *
- * Highlight this box
- *
- *
- *
- *
- * ```
- *
- * We can also make use of CSS keyframes by placing them within the CSS classes.
- *
- *
- * ### CSS Staggering Animations
- * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
- * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be
- * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
- * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
- * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
- *
- * ```css
- * .my-animation.ng-enter {
- * /* standard transition code */
- * transition: 1s linear all;
- * opacity:0;
- * }
- * .my-animation.ng-enter-stagger {
- * /* this will have a 100ms delay between each successive leave animation */
- * transition-delay: 0.1s;
- *
- * /* As of 1.4.4, this must always be set: it signals ngAnimate
- * to not accidentally inherit a delay property from another CSS class */
- * transition-duration: 0s;
- * }
- * .my-animation.ng-enter.ng-enter-active {
- * /* standard transition styles */
- * opacity:1;
- * }
- * ```
- *
- * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
- * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
- * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
- * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired.
- *
- * The following code will issue the **ng-leave-stagger** event on the element provided:
- *
- * ```js
- * var kids = parent.children();
- *
- * $animate.leave(kids[0]); //stagger index=0
- * $animate.leave(kids[1]); //stagger index=1
- * $animate.leave(kids[2]); //stagger index=2
- * $animate.leave(kids[3]); //stagger index=3
- * $animate.leave(kids[4]); //stagger index=4
- *
- * window.requestAnimationFrame(function() {
- * //stagger has reset itself
- * $animate.leave(kids[5]); //stagger index=0
- * $animate.leave(kids[6]); //stagger index=1
- *
- * $scope.$digest();
- * });
- * ```
- *
- * Stagger animations are currently only supported within CSS-defined animations.
- *
- * ### The `ng-animate` CSS class
- *
- * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.
- * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).
- *
- * Therefore, animations can be applied to an element using this temporary class directly via CSS.
- *
- * ```css
- * .zipper.ng-animate {
- * transition:0.5s linear all;
- * }
- * .zipper.ng-enter {
- * opacity:0;
- * }
- * .zipper.ng-enter.ng-enter-active {
- * opacity:1;
- * }
- * .zipper.ng-leave {
- * opacity:1;
- * }
- * .zipper.ng-leave.ng-leave-active {
- * opacity:0;
- * }
- * ```
- *
- * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove
- * the CSS class once an animation has completed.)
- *
- *
- * ### The `ng-[event]-prepare` class
- *
- * This is a special class that can be used to prevent unwanted flickering / flash of content before
- * the actual animation starts. The class is added as soon as an animation is initialized, but removed
- * before the actual animation starts (after waiting for a $digest).
- * It is also only added for *structural* animations (`enter`, `move`, and `leave`).
- *
- * In practice, flickering can appear when nesting elements with structural animations such as `ngIf`
- * into elements that have class-based animations such as `ngClass`.
- *
- * ```html
- *
- *
- *
- *
- *
- * ```
- *
- * It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating.
- * In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:
- *
- * ```css
- * .message.ng-enter-prepare {
- * opacity: 0;
- * }
- *
- * ```
- *
- * ## JavaScript-based Animations
- *
- * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
- * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the
- * `module.animation()` module function we can register the animation.
- *
- * Let's see an example of a enter/leave animation using `ngRepeat`:
- *
- * ```html
- *
- * {{ item }}
- *
- * ```
- *
- * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:
- *
- * ```js
- * myModule.animation('.slide', [function() {
- * return {
- * // make note that other events (like addClass/removeClass)
- * // have different function input parameters
- * enter: function(element, doneFn) {
- * jQuery(element).fadeIn(1000, doneFn);
- *
- * // remember to call doneFn so that angular
- * // knows that the animation has concluded
- * },
- *
- * move: function(element, doneFn) {
- * jQuery(element).fadeIn(1000, doneFn);
- * },
- *
- * leave: function(element, doneFn) {
- * jQuery(element).fadeOut(1000, doneFn);
- * }
- * }
- * }]);
- * ```
- *
- * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as
- * greensock.js and velocity.js.
- *
- * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define
- * our animations inside of the same registered animation, however, the function input arguments are a bit different:
- *
- * ```html
- *
- * this box is moody
- *
- *
- *
- *
- * ```
- *
- * ```js
- * myModule.animation('.colorful', [function() {
- * return {
- * addClass: function(element, className, doneFn) {
- * // do some cool animation and call the doneFn
- * },
- * removeClass: function(element, className, doneFn) {
- * // do some cool animation and call the doneFn
- * },
- * setClass: function(element, addedClass, removedClass, doneFn) {
- * // do some cool animation and call the doneFn
- * }
- * }
- * }]);
- * ```
- *
- * ## CSS + JS Animations Together
- *
- * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
- * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
- * charge of the animation**:
- *
- * ```html
- *
- * Slide in and out
- *
- * ```
- *
- * ```js
- * myModule.animation('.slide', [function() {
- * return {
- * enter: function(element, doneFn) {
- * jQuery(element).slideIn(1000, doneFn);
- * }
- * }
- * }]);
- * ```
- *
- * ```css
- * .slide.ng-enter {
- * transition:0.5s linear all;
- * transform:translateY(-100px);
- * }
- * .slide.ng-enter.ng-enter-active {
- * transform:translateY(0);
- * }
- * ```
- *
- * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the
- * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
- * our own JS-based animation code:
- *
- * ```js
- * myModule.animation('.slide', ['$animateCss', function($animateCss) {
- * return {
- * enter: function(element) {
-* // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.
- * return $animateCss(element, {
- * event: 'enter',
- * structural: true
- * });
- * }
- * }
- * }]);
- * ```
- *
- * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.
- *
- * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or
- * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that
- * data into `$animateCss` directly:
- *
- * ```js
- * myModule.animation('.slide', ['$animateCss', function($animateCss) {
- * return {
- * enter: function(element) {
- * return $animateCss(element, {
- * event: 'enter',
- * structural: true,
- * addClass: 'maroon-setting',
- * from: { height:0 },
- * to: { height: 200 }
- * });
- * }
- * }
- * }]);
- * ```
- *
- * Now we can fill in the rest via our transition CSS code:
- *
- * ```css
- * /* the transition tells ngAnimate to make the animation happen */
- * .slide.ng-enter { transition:0.5s linear all; }
- *
- * /* this extra CSS class will be absorbed into the transition
- * since the $animateCss code is adding the class */
- * .maroon-setting { background:red; }
- * ```
- *
- * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.
- *
- * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.
- *
- * ## Animation Anchoring (via `ng-animate-ref`)
- *
- * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between
- * structural areas of an application (like views) by pairing up elements using an attribute
- * called `ng-animate-ref`.
- *
- * Let's say for example we have two views that are managed by `ng-view` and we want to show
- * that there is a relationship between two components situated in within these views. By using the
- * `ng-animate-ref` attribute we can identify that the two components are paired together and we
- * can then attach an animation, which is triggered when the view changes.
- *
- * Say for example we have the following template code:
- *
- * ```html
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * ```
- *
- * Now, when the view changes (once the link is clicked), ngAnimate will examine the
- * HTML contents to see if there is a match reference between any components in the view
- * that is leaving and the view that is entering. It will scan both the view which is being
- * removed (leave) and inserted (enter) to see if there are any paired DOM elements that
- * contain a matching ref value.
- *
- * The two images match since they share the same ref value. ngAnimate will now create a
- * transport element (which is a clone of the first image element) and it will then attempt
- * to animate to the position of the second image element in the next view. For the animation to
- * work a special CSS class called `ng-anchor` will be added to the transported element.
- *
- * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then
- * ngAnimate will handle the entire transition for us as well as the addition and removal of
- * any changes of CSS classes between the elements:
- *
- * ```css
- * .banner.ng-anchor {
- * /* this animation will last for 1 second since there are
- * two phases to the animation (an `in` and an `out` phase) */
- * transition:0.5s linear all;
- * }
- * ```
- *
- * We also **must** include animations for the views that are being entered and removed
- * (otherwise anchoring wouldn't be possible since the new view would be inserted right away).
- *
- * ```css
- * .view-animation.ng-enter, .view-animation.ng-leave {
- * transition:0.5s linear all;
- * position:fixed;
- * left:0;
- * top:0;
- * width:100%;
- * }
- * .view-animation.ng-enter {
- * transform:translateX(100%);
- * }
- * .view-animation.ng-leave,
- * .view-animation.ng-enter.ng-enter-active {
- * transform:translateX(0%);
- * }
- * .view-animation.ng-leave.ng-leave-active {
- * transform:translateX(-100%);
- * }
- * ```
- *
- * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:
- * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away
- * from its origin. Once that animation is over then the `in` stage occurs which animates the
- * element to its destination. The reason why there are two animations is to give enough time
- * for the enter animation on the new element to be ready.
- *
- * The example above sets up a transition for both the in and out phases, but we can also target the out or
- * in phases directly via `ng-anchor-out` and `ng-anchor-in`.
- *
- * ```css
- * .banner.ng-anchor-out {
- * transition: 0.5s linear all;
- *
- * /* the scale will be applied during the out animation,
- * but will be animated away when the in animation runs */
- * transform: scale(1.2);
- * }
- *
- * .banner.ng-anchor-in {
- * transition: 1s linear all;
- * }
- * ```
- *
- *
- *
- *
- * ### Anchoring Demo
- *
-
-
- Home
-
-
-
-
- .record {
- display:block;
- font-size:20px;
- }
- .profile {
- background:black;
- color:white;
- font-size:100px;
- }
- .view-container {
- position:relative;
- }
- .view-container > .view.ng-animate {
- position:absolute;
- top:0;
- left:0;
- width:100%;
- min-height:500px;
- }
- .view.ng-enter, .view.ng-leave,
- .record.ng-anchor {
- transition:0.5s linear all;
- }
- .view.ng-enter {
- transform:translateX(100%);
- }
- .view.ng-enter.ng-enter-active, .view.ng-leave {
- transform:translateX(0%);
- }
- .view.ng-leave.ng-leave-active {
- transform:translateX(-100%);
- }
- .record.ng-anchor-out {
- background:red;
- }
-
-
- *
- * ### How is the element transported?
- *
- * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting
- * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element
- * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The
- * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match
- * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied
- * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class
- * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element
- * will become visible since the shim class will be removed.
- *
- * ### How is the morphing handled?
- *
- * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out
- * what CSS classes differ between the starting element and the destination element. These different CSS classes
- * will be added/removed on the anchor element and a transition will be applied (the transition that is provided
- * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will
- * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that
- * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since
- * the cloned element is placed inside of root element which is likely close to the body element).
- *
- * Note that if the root element is on the `` element then the cloned node will be placed inside of body.
- *
- *
- * ## Using $animate in your directive code
- *
- * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?
- * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's
- * imagine we have a greeting box that shows and hides itself when the data changes
- *
- * ```html
- * Hi there
- * ```
- *
- * ```js
- * ngModule.directive('greetingBox', ['$animate', function($animate) {
- * return function(scope, element, attrs) {
- * attrs.$observe('active', function(value) {
- * value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
- * });
- * });
- * }]);
- * ```
- *
- * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element
- * in our HTML code then we can trigger a CSS or JS animation to happen.
- *
- * ```css
- * /* normally we would create a CSS class to reference on the element */
- * greeting-box.on { transition:0.5s linear all; background:green; color:white; }
- * ```
- *
- * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's
- * possible be sure to visit the {@link ng.$animate $animate service API page}.
- *
- *
- * ## Callbacks and Promises
- *
- * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger
- * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has
- * ended by chaining onto the returned promise that animation method returns.
- *
- * ```js
- * // somewhere within the depths of the directive
- * $animate.enter(element, parent).then(function() {
- * //the animation has completed
- * });
- * ```
- *
- * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case
- * anymore.)
- *
- * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering
- * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view
- * routing controller to hook into that:
- *
- * ```js
- * ngModule.controller('HomePageController', ['$animate', function($animate) {
- * $animate.on('enter', ngViewElement, function(element) {
- * // the animation for this route has completed
- * }]);
- * }])
- * ```
- *
- * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)
- */
-
-var copy;
-var extend;
-var forEach;
-var isArray;
-var isDefined;
-var isElement;
-var isFunction;
-var isObject;
-var isString;
-var isUndefined;
-var jqLite;
-var noop;
-
-/**
- * @ngdoc service
- * @name $animate
- * @kind object
- *
- * @description
- * The ngAnimate `$animate` service documentation is the same for the core `$animate` service.
- *
- * Click here {@link ng.$animate to learn more about animations with `$animate`}.
- */
-angular.module('ngAnimate', [], function initAngularHelpers() {
- // Access helpers from angular core.
- // Do it inside a `config` block to ensure `window.angular` is available.
- noop = angular.noop;
- copy = angular.copy;
- extend = angular.extend;
- jqLite = angular.element;
- forEach = angular.forEach;
- isArray = angular.isArray;
- isString = angular.isString;
- isObject = angular.isObject;
- isUndefined = angular.isUndefined;
- isDefined = angular.isDefined;
- isFunction = angular.isFunction;
- isElement = angular.isElement;
-})
- .directive('ngAnimateSwap', ngAnimateSwapDirective)
-
- .directive('ngAnimateChildren', $$AnimateChildrenDirective)
- .factory('$$rAFScheduler', $$rAFSchedulerFactory)
-
- .provider('$$animateQueue', $$AnimateQueueProvider)
- .provider('$$animation', $$AnimationProvider)
-
- .provider('$animateCss', $AnimateCssProvider)
- .provider('$$animateCssDriver', $$AnimateCssDriverProvider)
-
- .provider('$$animateJs', $$AnimateJsProvider)
- .provider('$$animateJsDriver', $$AnimateJsDriverProvider);
-
-
-})(window, window.angular);
diff --git a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.min.js b/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.min.js
deleted file mode 100644
index b4087ed1b..000000000
--- a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-animate.min.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- AngularJS v1.5.8
- (c) 2010-2016 Google, Inc. http://angularjs.org
- License: MIT
-*/
-(function(R,B){'use strict';function Da(a,b,c){if(!a)throw Ma("areq",b||"?",c||"required");return a}function Ea(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;Y(a)&&(a=a.join(" "));Y(b)&&(b=b.join(" "));return a+" "+b}function Na(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function Z(a,b,c){var d="";a=Y(a)?a:a&&G(a)&&a.length?a.split(/\s+/):[];s(a,function(a,l){a&&0=a&&(a=e,e=0,b.push(k),k=[]);k.push(g.fn);g.children.forEach(function(a){e++;c.push(a)});a--}k.length&&b.push(k);return b}(c)}var u=[],C=V(a);return function(n,Q,t){function H(a){a=
-a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];s(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function T(a){var b=[],c={};s(a,function(a,d){var h=y(a.element),e=0<=["enter","move"].indexOf(a.event),h=a.structural?H(h):[];if(h.length){var k=e?"to":"from";s(h,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][k]={animationID:d,element:F(a)}})}else b.push(a)});var d={},e={};s(c,function(c,k){var r=c.from,
-p=c.to;if(r&&p){var z=a[r.animationID],g=a[p.animationID],A=r.animationID.toString();if(!e[A]){var n=e[A]={structural:!0,beforeStart:function(){z.beforeStart();g.beforeStart()},close:function(){z.close();g.close()},classes:O(z.classes,g.classes),from:z,to:g,anchors:[]};n.classes.length?b.push(n):(b.push(z),b.push(g))}e[A].anchors.push({out:r.element,"in":p.element})}else r=r?r.animationID:p.animationID,p=r.toString(),d[p]||(d[p]=!0,b.push(a[r]))});return b}function O(a,b){a=a.split(" ");b=b.split(" ");
-for(var c=[],d=0;d=R&&b>=m&&(F=!0,k())}function N(){function b(){if(!w){M(!1);s(x,function(a){h.style[a[0]]=a[1]});T(a,f);e.addClass(a,ea);if(q.recalculateTimingStyles){na=
-h.className+" "+ga;ia=B(h,na);D=H(h,na,ia);ca=D.maxDelay;J=Math.max(ca,0);m=D.maxDuration;if(0===m){k();return}q.hasTransitions=0l.expectedEndTime)?n.cancel(l.timer):g.push(k)}N&&(p=n(c,p,!1),g[0]={timer:p,expectedEndTime:d},g.push(k),a.data("$$animateCss",g));if(fa.length)a.on(fa.join(" "),z);f.to&&(f.cleanupStyles&&Ka(A,h,Object.keys(f.to)),Ga(a,f))}}function c(){var b=a.data("$$animateCss");if(b){for(var d=1;d
- *
- * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
- */
-
-/**
- * @ngdoc service
- * @name $sanitize
- * @kind function
- *
- * @description
- * Sanitizes an html string by stripping all potentially dangerous tokens.
- *
- * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
- * then serialized back to properly escaped html string. This means that no unsafe input can make
- * it into the returned string.
- *
- * The whitelist for URL sanitization of attribute values is configured using the functions
- * `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
- * `$compileProvider`}.
- *
- * The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
- *
- * @param {string} html HTML input.
- * @returns {string} Sanitized HTML.
- *
- * @example
-
-
-
-
- Snippet:
-
-
-
Directive
-
How
-
Source
-
Rendered
-
-
-
ng-bind-html
-
Automatically uses $sanitize
-
<div ng-bind-html="snippet"> </div>
-
-
-
-
ng-bind-html
-
Bypass $sanitize by explicitly trusting the dangerous value
By enabling this setting without taking other precautions, you might expose your
- * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned
- * outside of the containing element and be rendered over other elements on the page (e.g. a login
- * link). Such behavior can then result in phishing incidents.
- *
- *
To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
- * tags within the sanitized content:
-
-
- angular.module('linkyExample', ['ngSanitize'])
- .controller('ExampleController', ['$scope', function($scope) {
- $scope.snippet =
- 'Pretty text with some links:\n'+
- 'http://angularjs.org/,\n'+
- 'mailto:us@somewhere.org,\n'+
- 'another@somewhere.org,\n'+
- 'and one more: ftp://127.0.0.1/.';
- $scope.snippetWithSingleURL = 'http://angularjs.org/';
- }]);
-
-
- it('should linkify the snippet with urls', function() {
- expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
- toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
- 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
- expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
- });
-
- it('should not linkify snippet without the linky filter', function() {
- expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
- toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
- 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
- expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
- });
-
- it('should update', function() {
- element(by.model('snippet')).clear();
- element(by.model('snippet')).sendKeys('new http://link.');
- expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
- toBe('new http://link.');
- expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
- expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
- .toBe('new http://link.');
- });
-
- it('should work with the target property', function() {
- expect(element(by.id('linky-target')).
- element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
- toBe('http://angularjs.org/');
- expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
- });
-
- it('should optionally add custom attributes', function() {
- expect(element(by.id('linky-custom-attributes')).
- element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
- toBe('http://angularjs.org/');
- expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
- });
-
-
- */
-angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
- var LINKY_URL_REGEXP =
- /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
- MAILTO_REGEXP = /^mailto:/i;
-
- var linkyMinErr = angular.$$minErr('linky');
- var isDefined = angular.isDefined;
- var isFunction = angular.isFunction;
- var isObject = angular.isObject;
- var isString = angular.isString;
-
- return function(text, target, attributes) {
- if (text == null || text === '') return text;
- if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text);
-
- var attributesFn =
- isFunction(attributes) ? attributes :
- isObject(attributes) ? function getAttributesObject() {return attributes;} :
- function getEmptyAttributesObject() {return {};};
-
- var match;
- var raw = text;
- var html = [];
- var url;
- var i;
- while ((match = raw.match(LINKY_URL_REGEXP))) {
- // We can not end in these as they are sometimes found at the end of the sentence
- url = match[0];
- // if we did not match ftp/http/www/mailto then assume mailto
- if (!match[2] && !match[4]) {
- url = (match[3] ? 'http://' : 'mailto:') + url;
- }
- i = match.index;
- addText(raw.substr(0, i));
- addLink(url, match[0].replace(MAILTO_REGEXP, ''));
- raw = raw.substring(i + match[0].length);
- }
- addText(raw);
- return $sanitize(html.join(''));
-
- function addText(text) {
- if (!text) {
- return;
- }
- html.push(sanitizeText(text));
- }
-
- function addLink(url, text) {
- var key, linkAttributes = attributesFn(url);
- html.push('');
- addText(text);
- html.push('');
- }
- };
-}]);
-
-
-})(window, window.angular);
diff --git a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-sanitize.min.js b/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-sanitize.min.js
deleted file mode 100644
index ca82fd27e..000000000
--- a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular-sanitize.min.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- AngularJS v1.5.8
- (c) 2010-2016 Google, Inc. http://angularjs.org
- License: MIT
-*/
-(function(s,g){'use strict';function H(g){var l=[];t(l,A).chars(g);return l.join("")}var B=g.$$minErr("$sanitize"),C,l,D,E,q,A,F,t;g.module("ngSanitize",[]).provider("$sanitize",function(){function k(a,e){var b={},c=a.split(","),h;for(h=0;h/g,">")}function u(a){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,b=0,c=e.length;b"))},end:function(a){a=
-q(a);b||!0!==w[a]||!0===y[a]||(c(""),c(a),c(">"));a==b&&(b=!1)},chars:function(a){b||c(G(a))}}};var J=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,K=/([^\#-~ |!])/g,y=k("area,br,col,hr,img,wbr"),d=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),r=k("rp,rt"),p=l({},r,d),d=l({},d,k("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),r=l({},r,k("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),
-x=k("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),z=k("script,style"),w=l({},y,d,r,p),n=k("background,cite,href,longdesc,src,xlink:href"),p=k("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"),
-r=k("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
-!0),m=l({},n,r,p),f;(function(a){if(a.document&&a.document.implementation)a=a.document.implementation.createHTMLDocument("inert");else throw B("noinert");var e=(a.documentElement||a.getDocumentElement()).getElementsByTagName("body");1===e.length?f=e[0]:(e=a.createElement("html"),f=a.createElement("body"),e.appendChild(f),a.appendChild(e))})(s)});g.module("ngSanitize").filter("linky",["$sanitize",function(k){var l=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
-q=/^mailto:/i,u=g.$$minErr("linky"),v=g.isDefined,s=g.isFunction,t=g.isObject,y=g.isString;return function(d,g,p){function x(a){a&&m.push(H(a))}function z(a,b){var c,d=w(a);m.push("');x(b);m.push("")}if(null==d||""===d)return d;if(!y(d))throw u("notstring",d);for(var w=s(p)?p:t(p)?function(){return p}:function(){return{}},n=d,m=[],f,a;d=n.match(l);)f=d[0],d[2]||
-d[4]||(f=(d[3]?"http://":"mailto:")+f),a=d.index,x(n.substr(0,a)),z(f,d[0].replace(q,"")),n=n.substring(a+d[0].length);x(n);return k(m.join(""))}}])})(window,window.angular);
-//# sourceMappingURL=angular-sanitize.min.js.map
diff --git a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular.js b/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular.js
deleted file mode 100644
index 54f65588f..000000000
--- a/build-monitor-plugin/src/main/webapp/vendor/angular-1.5.8/angular.js
+++ /dev/null
@@ -1,31768 +0,0 @@
-/**
- * @license AngularJS v1.5.8
- * (c) 2010-2016 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window) {'use strict';
-
-/**
- * @description
- *
- * This object provides a utility for producing rich Error messages within
- * Angular. It can be called as follows:
- *
- * var exampleMinErr = minErr('example');
- * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
- *
- * The above creates an instance of minErr in the example namespace. The
- * resulting error will have a namespaced error code of example.one. The
- * resulting error will replace {0} with the value of foo, and {1} with the
- * value of bar. The object is not restricted in the number of arguments it can
- * take.
- *
- * If fewer arguments are specified than necessary for interpolation, the extra
- * interpolation markers will be preserved in the final string.
- *
- * Since data will be parsed statically during a build step, some restrictions
- * are applied with respect to how minErr instances are created and called.
- * Instances should have names of the form namespaceMinErr for a minErr created
- * using minErr('namespace') . Error codes, namespaces and template strings
- * should all be static strings, not variables or general expressions.
- *
- * @param {string} module The namespace to use for the new minErr instance.
- * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
- * error from returned function, for cases when a particular type of error is useful.
- * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
- */
-
-function minErr(module, ErrorConstructor) {
- ErrorConstructor = ErrorConstructor || Error;
- return function() {
- var SKIP_INDEXES = 2;
-
- var templateArgs = arguments,
- code = templateArgs[0],
- message = '[' + (module ? module + ':' : '') + code + '] ',
- template = templateArgs[1],
- paramPrefix, i;
-
- message += template.replace(/\{\d+\}/g, function(match) {
- var index = +match.slice(1, -1),
- shiftedIndex = index + SKIP_INDEXES;
-
- if (shiftedIndex < templateArgs.length) {
- return toDebugString(templateArgs[shiftedIndex]);
- }
-
- return match;
- });
-
- message += '\nhttp://errors.angularjs.org/1.5.8/' +
- (module ? module + '/' : '') + code;
-
- for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
- message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
- encodeURIComponent(toDebugString(templateArgs[i]));
- }
-
- return new ErrorConstructor(message);
- };
-}
-
-/* We need to tell jshint what variables are being exported */
-/* global angular: true,
- msie: true,
- jqLite: true,
- jQuery: true,
- slice: true,
- splice: true,
- push: true,
- toString: true,
- ngMinErr: true,
- angularModule: true,
- uid: true,
- REGEX_STRING_REGEXP: true,
- VALIDITY_STATE_PROPERTY: true,
-
- lowercase: true,
- uppercase: true,
- manualLowercase: true,
- manualUppercase: true,
- nodeName_: true,
- isArrayLike: true,
- forEach: true,
- forEachSorted: true,
- reverseParams: true,
- nextUid: true,
- setHashKey: true,
- extend: true,
- toInt: true,
- inherit: true,
- merge: true,
- noop: true,
- identity: true,
- valueFn: true,
- isUndefined: true,
- isDefined: true,
- isObject: true,
- isBlankObject: true,
- isString: true,
- isNumber: true,
- isDate: true,
- isArray: true,
- isFunction: true,
- isRegExp: true,
- isWindow: true,
- isScope: true,
- isFile: true,
- isFormData: true,
- isBlob: true,
- isBoolean: true,
- isPromiseLike: true,
- trim: true,
- escapeForRegexp: true,
- isElement: true,
- makeMap: true,
- includes: true,
- arrayRemove: true,
- copy: true,
- equals: true,
- csp: true,
- jq: true,
- concat: true,
- sliceArgs: true,
- bind: true,
- toJsonReplacer: true,
- toJson: true,
- fromJson: true,
- convertTimezoneToLocal: true,
- timezoneToOffset: true,
- startingTag: true,
- tryDecodeURIComponent: true,
- parseKeyValue: true,
- toKeyValue: true,
- encodeUriSegment: true,
- encodeUriQuery: true,
- angularInit: true,
- bootstrap: true,
- getTestability: true,
- snake_case: true,
- bindJQuery: true,
- assertArg: true,
- assertArgFn: true,
- assertNotHasOwnProperty: true,
- getter: true,
- getBlockNodes: true,
- hasOwnProperty: true,
- createMap: true,
-
- NODE_TYPE_ELEMENT: true,
- NODE_TYPE_ATTRIBUTE: true,
- NODE_TYPE_TEXT: true,
- NODE_TYPE_COMMENT: true,
- NODE_TYPE_DOCUMENT: true,
- NODE_TYPE_DOCUMENT_FRAGMENT: true,
-*/
-
-////////////////////////////////////
-
-/**
- * @ngdoc module
- * @name ng
- * @module ng
- * @installation
- * @description
- *
- * # ng (core module)
- * The ng module is loaded by default when an AngularJS application is started. The module itself
- * contains the essential components for an AngularJS application to function. The table below
- * lists a high level breakdown of each of the services/factories, filters, directives and testing
- * components available within this core module.
- *
- *
- */
-
-var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
-
-// The name of a form control's ValidityState property.
-// This is used so that it's possible for internal tests to create mock ValidityStates.
-var VALIDITY_STATE_PROPERTY = 'validity';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
-var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
-
-
-var manualLowercase = function(s) {
- /* jshint bitwise: false */
- return isString(s)
- ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
- : s;
-};
-var manualUppercase = function(s) {
- /* jshint bitwise: false */
- return isString(s)
- ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
- : s;
-};
-
-
-// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
-// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
-// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
-if ('i' !== 'I'.toLowerCase()) {
- lowercase = manualLowercase;
- uppercase = manualUppercase;
-}
-
-
-var
- msie, // holds major version number for IE, or NaN if UA is not IE.
- jqLite, // delay binding since jQuery could be loaded after us.
- jQuery, // delay binding
- slice = [].slice,
- splice = [].splice,
- push = [].push,
- toString = Object.prototype.toString,
- getPrototypeOf = Object.getPrototypeOf,
- ngMinErr = minErr('ng'),
-
- /** @name angular */
- angular = window.angular || (window.angular = {}),
- angularModule,
- uid = 0;
-
-/**
- * documentMode is an IE-only property
- * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
- */
-msie = window.document.documentMode;
-
-
-/**
- * @private
- * @param {*} obj
- * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
- * String ...)
- */
-function isArrayLike(obj) {
-
- // `null`, `undefined` and `window` are not array-like
- if (obj == null || isWindow(obj)) return false;
-
- // arrays, strings and jQuery/jqLite objects are array like
- // * jqLite is either the jQuery or jqLite constructor function
- // * we have to check the existence of jqLite first as this method is called
- // via the forEach method when constructing the jqLite object in the first place
- if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
-
- // Support: iOS 8.2 (not reproducible in simulator)
- // "length" in obj used to prevent JIT error (gh-11508)
- var length = "length" in Object(obj) && obj.length;
-
- // NodeList objects (with `item` method) and
- // other objects with suitable length characteristics are array-like
- return isNumber(length) &&
- (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
-
-}
-
-/**
- * @ngdoc function
- * @name angular.forEach
- * @module ng
- * @kind function
- *
- * @description
- * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
- * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
- * is the value of an object property or an array element, `key` is the object property key or
- * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
- *
- * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
- * using the `hasOwnProperty` method.
- *
- * Unlike ES262's
- * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
- * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
- * return the value provided.
- *
- ```js
- var values = {name: 'misko', gender: 'male'};
- var log = [];
- angular.forEach(values, function(value, key) {
- this.push(key + ': ' + value);
- }, log);
- expect(log).toEqual(['name: misko', 'gender: male']);
- ```
- *
- * @param {Object|Array} obj Object to iterate over.
- * @param {Function} iterator Iterator function.
- * @param {Object=} context Object to become context (`this`) for the iterator function.
- * @returns {Object|Array} Reference to `obj`.
- */
-
-function forEach(obj, iterator, context) {
- var key, length;
- if (obj) {
- if (isFunction(obj)) {
- for (key in obj) {
- // Need to check if hasOwnProperty exists,
- // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
- if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else if (isArray(obj) || isArrayLike(obj)) {
- var isPrimitive = typeof obj !== 'object';
- for (key = 0, length = obj.length; key < length; key++) {
- if (isPrimitive || key in obj) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else if (obj.forEach && obj.forEach !== forEach) {
- obj.forEach(iterator, context, obj);
- } else if (isBlankObject(obj)) {
- // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
- for (key in obj) {
- iterator.call(context, obj[key], key, obj);
- }
- } else if (typeof obj.hasOwnProperty === 'function') {
- // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
- for (key in obj) {
- if (obj.hasOwnProperty(key)) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else {
- // Slow path for objects which do not have a method `hasOwnProperty`
- for (key in obj) {
- if (hasOwnProperty.call(obj, key)) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- }
- }
- return obj;
-}
-
-function forEachSorted(obj, iterator, context) {
- var keys = Object.keys(obj).sort();
- for (var i = 0; i < keys.length; i++) {
- iterator.call(context, obj[keys[i]], keys[i]);
- }
- return keys;
-}
-
-
-/**
- * when using forEach the params are value, key, but it is often useful to have key, value.
- * @param {function(string, *)} iteratorFn
- * @returns {function(*, string)}
- */
-function reverseParams(iteratorFn) {
- return function(value, key) {iteratorFn(key, value);};
-}
-
-/**
- * A consistent way of creating unique IDs in angular.
- *
- * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
- * we hit number precision issues in JavaScript.
- *
- * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
- *
- * @returns {number} an unique alpha-numeric string
- */
-function nextUid() {
- return ++uid;
-}
-
-
-/**
- * Set or clear the hashkey for an object.
- * @param obj object
- * @param h the hashkey (!truthy to delete the hashkey)
- */
-function setHashKey(obj, h) {
- if (h) {
- obj.$$hashKey = h;
- } else {
- delete obj.$$hashKey;
- }
-}
-
-
-function baseExtend(dst, objs, deep) {
- var h = dst.$$hashKey;
-
- for (var i = 0, ii = objs.length; i < ii; ++i) {
- var obj = objs[i];
- if (!isObject(obj) && !isFunction(obj)) continue;
- var keys = Object.keys(obj);
- for (var j = 0, jj = keys.length; j < jj; j++) {
- var key = keys[j];
- var src = obj[key];
-
- if (deep && isObject(src)) {
- if (isDate(src)) {
- dst[key] = new Date(src.valueOf());
- } else if (isRegExp(src)) {
- dst[key] = new RegExp(src);
- } else if (src.nodeName) {
- dst[key] = src.cloneNode(true);
- } else if (isElement(src)) {
- dst[key] = src.clone();
- } else {
- if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
- baseExtend(dst[key], [src], true);
- }
- } else {
- dst[key] = src;
- }
- }
- }
-
- setHashKey(dst, h);
- return dst;
-}
-
-/**
- * @ngdoc function
- * @name angular.extend
- * @module ng
- * @kind function
- *
- * @description
- * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
- * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
- * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
- *
- * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
- * {@link angular.merge} for this.
- *
- * @param {Object} dst Destination object.
- * @param {...Object} src Source object(s).
- * @returns {Object} Reference to `dst`.
- */
-function extend(dst) {
- return baseExtend(dst, slice.call(arguments, 1), false);
-}
-
-
-/**
-* @ngdoc function
-* @name angular.merge
-* @module ng
-* @kind function
-*
-* @description
-* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
-* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
-* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
-*
-* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
-* objects, performing a deep copy.
-*
-* @param {Object} dst Destination object.
-* @param {...Object} src Source object(s).
-* @returns {Object} Reference to `dst`.
-*/
-function merge(dst) {
- return baseExtend(dst, slice.call(arguments, 1), true);
-}
-
-
-
-function toInt(str) {
- return parseInt(str, 10);
-}
-
-
-function inherit(parent, extra) {
- return extend(Object.create(parent), extra);
-}
-
-/**
- * @ngdoc function
- * @name angular.noop
- * @module ng
- * @kind function
- *
- * @description
- * A function that performs no operations. This function can be useful when writing code in the
- * functional style.
- ```js
- function foo(callback) {
- var result = calculateResult();
- (callback || angular.noop)(result);
- }
- ```
- */
-function noop() {}
-noop.$inject = [];
-
-
-/**
- * @ngdoc function
- * @name angular.identity
- * @module ng
- * @kind function
- *
- * @description
- * A function that returns its first argument. This function is useful when writing code in the
- * functional style.
- *
- ```js
- function transformer(transformationFn, value) {
- return (transformationFn || angular.identity)(value);
- };
-
- // E.g.
- function getResult(fn, input) {
- return (fn || angular.identity)(input);
- };
-
- getResult(function(n) { return n * 2; }, 21); // returns 42
- getResult(null, 21); // returns 21
- getResult(undefined, 21); // returns 21
- ```
- *
- * @param {*} value to be returned.
- * @returns {*} the value passed in.
- */
-function identity($) {return $;}
-identity.$inject = [];
-
-
-function valueFn(value) {return function valueRef() {return value;};}
-
-function hasCustomToString(obj) {
- return isFunction(obj.toString) && obj.toString !== toString;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isUndefined
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is undefined.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is undefined.
- */
-function isUndefined(value) {return typeof value === 'undefined';}
-
-
-/**
- * @ngdoc function
- * @name angular.isDefined
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is defined.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is defined.
- */
-function isDefined(value) {return typeof value !== 'undefined';}
-
-
-/**
- * @ngdoc function
- * @name angular.isObject
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
- * considered to be objects. Note that JavaScript arrays are objects.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is an `Object` but not `null`.
- */
-function isObject(value) {
- // http://jsperf.com/isobject4
- return value !== null && typeof value === 'object';
-}
-
-
-/**
- * Determine if a value is an object with a null prototype
- *
- * @returns {boolean} True if `value` is an `Object` with a null prototype
- */
-function isBlankObject(value) {
- return value !== null && typeof value === 'object' && !getPrototypeOf(value);
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isString
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `String`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `String`.
- */
-function isString(value) {return typeof value === 'string';}
-
-
-/**
- * @ngdoc function
- * @name angular.isNumber
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `Number`.
- *
- * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
- *
- * If you wish to exclude these then you can use the native
- * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
- * method.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Number`.
- */
-function isNumber(value) {return typeof value === 'number';}
-
-
-/**
- * @ngdoc function
- * @name angular.isDate
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a value is a date.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Date`.
- */
-function isDate(value) {
- return toString.call(value) === '[object Date]';
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isArray
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is an `Array`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is an `Array`.
- */
-var isArray = Array.isArray;
-
-/**
- * @ngdoc function
- * @name angular.isFunction
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `Function`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Function`.
- */
-function isFunction(value) {return typeof value === 'function';}
-
-
-/**
- * Determines if a value is a regular expression object.
- *
- * @private
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `RegExp`.
- */
-function isRegExp(value) {
- return toString.call(value) === '[object RegExp]';
-}
-
-
-/**
- * Checks if `obj` is a window object.
- *
- * @private
- * @param {*} obj Object to check
- * @returns {boolean} True if `obj` is a window obj.
- */
-function isWindow(obj) {
- return obj && obj.window === obj;
-}
-
-
-function isScope(obj) {
- return obj && obj.$evalAsync && obj.$watch;
-}
-
-
-function isFile(obj) {
- return toString.call(obj) === '[object File]';
-}
-
-
-function isFormData(obj) {
- return toString.call(obj) === '[object FormData]';
-}
-
-
-function isBlob(obj) {
- return toString.call(obj) === '[object Blob]';
-}
-
-
-function isBoolean(value) {
- return typeof value === 'boolean';
-}
-
-
-function isPromiseLike(obj) {
- return obj && isFunction(obj.then);
-}
-
-
-var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
-function isTypedArray(value) {
- return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
-}
-
-function isArrayBuffer(obj) {
- return toString.call(obj) === '[object ArrayBuffer]';
-}
-
-
-var trim = function(value) {
- return isString(value) ? value.trim() : value;
-};
-
-// Copied from:
-// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
-// Prereq: s is a string.
-var escapeForRegexp = function(s) {
- return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0) {
- array.splice(index, 1);
- }
- return index;
-}
-
-/**
- * @ngdoc function
- * @name angular.copy
- * @module ng
- * @kind function
- *
- * @description
- * Creates a deep copy of `source`, which should be an object or an array.
- *
- * * If no destination is supplied, a copy of the object or array is created.
- * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
- * are deleted and then all elements/properties from the source are copied to it.
- * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
- * * If `source` is identical to `destination` an exception will be thrown.
- *
- *
- *
- * Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
- * and on `destination`) will be ignored.
- *
- *
- * @param {*} source The source that will be used to make a copy.
- * Can be any type, including primitives, `null`, and `undefined`.
- * @param {(Object|Array)=} destination Destination into which the source is copied. If
- * provided, must be of the same type as `source`.
- * @returns {*} The copy or updated `destination`, if `destination` was specified.
- *
- * @example
-
-
-
-
-
form = {{user | json}}
-
master = {{master | json}}
-
-
-
- // Module: copyExample
- angular.
- module('copyExample', []).
- controller('ExampleController', ['$scope', function($scope) {
- $scope.master = {};
-
- $scope.reset = function() {
- // Example with 1 argument
- $scope.user = angular.copy($scope.master);
- };
-
- $scope.update = function(user) {
- // Example with 2 arguments
- angular.copy(user, $scope.master);
- };
-
- $scope.reset();
- }]);
-
-
- */
-function copy(source, destination) {
- var stackSource = [];
- var stackDest = [];
-
- if (destination) {
- if (isTypedArray(destination) || isArrayBuffer(destination)) {
- throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
- }
- if (source === destination) {
- throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
- }
-
- // Empty the destination object
- if (isArray(destination)) {
- destination.length = 0;
- } else {
- forEach(destination, function(value, key) {
- if (key !== '$$hashKey') {
- delete destination[key];
- }
- });
- }
-
- stackSource.push(source);
- stackDest.push(destination);
- return copyRecurse(source, destination);
- }
-
- return copyElement(source);
-
- function copyRecurse(source, destination) {
- var h = destination.$$hashKey;
- var key;
- if (isArray(source)) {
- for (var i = 0, ii = source.length; i < ii; i++) {
- destination.push(copyElement(source[i]));
- }
- } else if (isBlankObject(source)) {
- // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
- for (key in source) {
- destination[key] = copyElement(source[key]);
- }
- } else if (source && typeof source.hasOwnProperty === 'function') {
- // Slow path, which must rely on hasOwnProperty
- for (key in source) {
- if (source.hasOwnProperty(key)) {
- destination[key] = copyElement(source[key]);
- }
- }
- } else {
- // Slowest path --- hasOwnProperty can't be called as a method
- for (key in source) {
- if (hasOwnProperty.call(source, key)) {
- destination[key] = copyElement(source[key]);
- }
- }
- }
- setHashKey(destination, h);
- return destination;
- }
-
- function copyElement(source) {
- // Simple values
- if (!isObject(source)) {
- return source;
- }
-
- // Already copied values
- var index = stackSource.indexOf(source);
- if (index !== -1) {
- return stackDest[index];
- }
-
- if (isWindow(source) || isScope(source)) {
- throw ngMinErr('cpws',
- "Can't copy! Making copies of Window or Scope instances is not supported.");
- }
-
- var needsRecurse = false;
- var destination = copyType(source);
-
- if (destination === undefined) {
- destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
- needsRecurse = true;
- }
-
- stackSource.push(source);
- stackDest.push(destination);
-
- return needsRecurse
- ? copyRecurse(source, destination)
- : destination;
- }
-
- function copyType(source) {
- switch (toString.call(source)) {
- case '[object Int8Array]':
- case '[object Int16Array]':
- case '[object Int32Array]':
- case '[object Float32Array]':
- case '[object Float64Array]':
- case '[object Uint8Array]':
- case '[object Uint8ClampedArray]':
- case '[object Uint16Array]':
- case '[object Uint32Array]':
- return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
-
- case '[object ArrayBuffer]':
- //Support: IE10
- if (!source.slice) {
- var copied = new ArrayBuffer(source.byteLength);
- new Uint8Array(copied).set(new Uint8Array(source));
- return copied;
- }
- return source.slice(0);
-
- case '[object Boolean]':
- case '[object Number]':
- case '[object String]':
- case '[object Date]':
- return new source.constructor(source.valueOf());
-
- case '[object RegExp]':
- var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
- re.lastIndex = source.lastIndex;
- return re;
-
- case '[object Blob]':
- return new source.constructor([source], {type: source.type});
- }
-
- if (isFunction(source.cloneNode)) {
- return source.cloneNode(true);
- }
- }
-}
-
-
-/**
- * @ngdoc function
- * @name angular.equals
- * @module ng
- * @kind function
- *
- * @description
- * Determines if two objects or two values are equivalent. Supports value types, regular
- * expressions, arrays and objects.
- *
- * Two objects or values are considered equivalent if at least one of the following is true:
- *
- * * Both objects or values pass `===` comparison.
- * * Both objects or values are of the same type and all of their properties are equal by
- * comparing them with `angular.equals`.
- * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
- * * Both values represent the same regular expression (In JavaScript,
- * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
- * representation matches).
- *
- * During a property comparison, properties of `function` type and properties with names
- * that begin with `$` are ignored.
- *
- * Scope and DOMWindow objects are being compared only by identify (`===`).
- *
- * @param {*} o1 Object or value to compare.
- * @param {*} o2 Object or value to compare.
- * @returns {boolean} True if arguments are equal.
- *
- * @example
-
-
-
-
-
-
-
- angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
- $scope.user1 = {};
- $scope.user2 = {};
- $scope.result;
- $scope.compare = function() {
- $scope.result = angular.equals($scope.user1, $scope.user2);
- };
- }]);
-
-
- */
-function equals(o1, o2) {
- if (o1 === o2) return true;
- if (o1 === null || o2 === null) return false;
- if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
- var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
- if (t1 == t2 && t1 == 'object') {
- if (isArray(o1)) {
- if (!isArray(o2)) return false;
- if ((length = o1.length) == o2.length) {
- for (key = 0; key < length; key++) {
- if (!equals(o1[key], o2[key])) return false;
- }
- return true;
- }
- } else if (isDate(o1)) {
- if (!isDate(o2)) return false;
- return equals(o1.getTime(), o2.getTime());
- } else if (isRegExp(o1)) {
- if (!isRegExp(o2)) return false;
- return o1.toString() == o2.toString();
- } else {
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
- isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
- keySet = createMap();
- for (key in o1) {
- if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
- if (!equals(o1[key], o2[key])) return false;
- keySet[key] = true;
- }
- for (key in o2) {
- if (!(key in keySet) &&
- key.charAt(0) !== '$' &&
- isDefined(o2[key]) &&
- !isFunction(o2[key])) return false;
- }
- return true;
- }
- }
- return false;
-}
-
-var csp = function() {
- if (!isDefined(csp.rules)) {
-
-
- var ngCspElement = (window.document.querySelector('[ng-csp]') ||
- window.document.querySelector('[data-ng-csp]'));
-
- if (ngCspElement) {
- var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
- ngCspElement.getAttribute('data-ng-csp');
- csp.rules = {
- noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
- noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
- };
- } else {
- csp.rules = {
- noUnsafeEval: noUnsafeEval(),
- noInlineStyle: false
- };
- }
- }
-
- return csp.rules;
-
- function noUnsafeEval() {
- try {
- /* jshint -W031, -W054 */
- new Function('');
- /* jshint +W031, +W054 */
- return false;
- } catch (e) {
- return true;
- }
- }
-};
-
-/**
- * @ngdoc directive
- * @module ng
- * @name ngJq
- *
- * @element ANY
- * @param {string=} ngJq the name of the library available under `window`
- * to be used for angular.element
- * @description
- * Use this directive to force the angular.element library. This should be
- * used to force either jqLite by leaving ng-jq blank or setting the name of
- * the jquery variable under window (eg. jQuery).
- *
- * Since angular looks for this directive when it is loaded (doesn't wait for the
- * DOMContentLoaded event), it must be placed on an element that comes before the script
- * which loads angular. Also, only the first instance of `ng-jq` will be used and all
- * others ignored.
- *
- * @example
- * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
- ```html
-
-
- ...
- ...
-
- ```
- * @example
- * This example shows how to use a jQuery based library of a different name.
- * The library name must be available at the top most 'window'.
- ```html
-
-
- ...
- ...
-
- ```
- */
-var jq = function() {
- if (isDefined(jq.name_)) return jq.name_;
- var el;
- var i, ii = ngAttrPrefixes.length, prefix, name;
- for (i = 0; i < ii; ++i) {
- prefix = ngAttrPrefixes[i];
- if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
- name = el.getAttribute(prefix + 'jq');
- break;
- }
- }
-
- return (jq.name_ = name);
-};
-
-function concat(array1, array2, index) {
- return array1.concat(slice.call(array2, index));
-}
-
-function sliceArgs(args, startIndex) {
- return slice.call(args, startIndex || 0);
-}
-
-
-/* jshint -W101 */
-/**
- * @ngdoc function
- * @name angular.bind
- * @module ng
- * @kind function
- *
- * @description
- * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
- * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
- * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
- * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
- *
- * @param {Object} self Context which `fn` should be evaluated in.
- * @param {function()} fn Function to be bound.
- * @param {...*} args Optional arguments to be prebound to the `fn` function call.
- * @returns {function()} Function that wraps the `fn` with all the specified bindings.
- */
-/* jshint +W101 */
-function bind(self, fn) {
- var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
- if (isFunction(fn) && !(fn instanceof RegExp)) {
- return curryArgs.length
- ? function() {
- return arguments.length
- ? fn.apply(self, concat(curryArgs, arguments, 0))
- : fn.apply(self, curryArgs);
- }
- : function() {
- return arguments.length
- ? fn.apply(self, arguments)
- : fn.call(self);
- };
- } else {
- // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
- return fn;
- }
-}
-
-
-function toJsonReplacer(key, value) {
- var val = value;
-
- if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
- val = undefined;
- } else if (isWindow(value)) {
- val = '$WINDOW';
- } else if (value && window.document === value) {
- val = '$DOCUMENT';
- } else if (isScope(value)) {
- val = '$SCOPE';
- }
-
- return val;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.toJson
- * @module ng
- * @kind function
- *
- * @description
- * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
- * stripped since angular uses this notation internally.
- *
- * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
- * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
- * If set to an integer, the JSON output will contain that many spaces per indentation.
- * @returns {string|undefined} JSON-ified string representing `obj`.
- * @knownIssue
- *
- * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
- * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
- * `Date.prototype.toJSON` method as follows:
- *
- * ```
- * var _DatetoJSON = Date.prototype.toJSON;
- * Date.prototype.toJSON = function() {
- * try {
- * return _DatetoJSON.call(this);
- * } catch(e) {
- * if (e instanceof RangeError) {
- * return null;
- * }
- * throw e;
- * }
- * };
- * ```
- *
- * See https://github.com/angular/angular.js/pull/14221 for more information.
- */
-function toJson(obj, pretty) {
- if (isUndefined(obj)) return undefined;
- if (!isNumber(pretty)) {
- pretty = pretty ? 2 : null;
- }
- return JSON.stringify(obj, toJsonReplacer, pretty);
-}
-
-
-/**
- * @ngdoc function
- * @name angular.fromJson
- * @module ng
- * @kind function
- *
- * @description
- * Deserializes a JSON string.
- *
- * @param {string} json JSON string to deserialize.
- * @returns {Object|Array|string|number} Deserialized JSON string.
- */
-function fromJson(json) {
- return isString(json)
- ? JSON.parse(json)
- : json;
-}
-
-
-var ALL_COLONS = /:/g;
-function timezoneToOffset(timezone, fallback) {
- // IE/Edge do not "understand" colon (`:`) in timezone
- timezone = timezone.replace(ALL_COLONS, '');
- var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
- return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
-}
-
-
-function addDateMinutes(date, minutes) {
- date = new Date(date.getTime());
- date.setMinutes(date.getMinutes() + minutes);
- return date;
-}
-
-
-function convertTimezoneToLocal(date, timezone, reverse) {
- reverse = reverse ? -1 : 1;
- var dateTimezoneOffset = date.getTimezoneOffset();
- var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
- return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
-}
-
-
-/**
- * @returns {string} Returns the string representation of the element.
- */
-function startingTag(element) {
- element = jqLite(element).clone();
- try {
- // turns out IE does not let you set .html() on elements which
- // are not allowed to have children. So we just ignore it.
- element.empty();
- } catch (e) {}
- var elemHtml = jqLite('
').append(element).html();
- try {
- return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
- elemHtml.
- match(/^(<[^>]+>)/)[1].
- replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
- } catch (e) {
- return lowercase(elemHtml);
- }
-
-}
-
-
-/////////////////////////////////////////////////
-
-/**
- * Tries to decode the URI component without throwing an exception.
- *
- * @private
- * @param str value potential URI component to check.
- * @returns {boolean} True if `value` can be decoded
- * with the decodeURIComponent function.
- */
-function tryDecodeURIComponent(value) {
- try {
- return decodeURIComponent(value);
- } catch (e) {
- // Ignore any invalid uri component.
- }
-}
-
-
-/**
- * Parses an escaped url query string into key-value pairs.
- * @returns {Object.}
- */
-function parseKeyValue(/**string*/keyValue) {
- var obj = {};
- forEach((keyValue || "").split('&'), function(keyValue) {
- var splitPoint, key, val;
- if (keyValue) {
- key = keyValue = keyValue.replace(/\+/g,'%20');
- splitPoint = keyValue.indexOf('=');
- if (splitPoint !== -1) {
- key = keyValue.substring(0, splitPoint);
- val = keyValue.substring(splitPoint + 1);
- }
- key = tryDecodeURIComponent(key);
- if (isDefined(key)) {
- val = isDefined(val) ? tryDecodeURIComponent(val) : true;
- if (!hasOwnProperty.call(obj, key)) {
- obj[key] = val;
- } else if (isArray(obj[key])) {
- obj[key].push(val);
- } else {
- obj[key] = [obj[key],val];
- }
- }
- }
- });
- return obj;
-}
-
-function toKeyValue(obj) {
- var parts = [];
- forEach(obj, function(value, key) {
- if (isArray(value)) {
- forEach(value, function(arrayValue) {
- parts.push(encodeUriQuery(key, true) +
- (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
- });
- } else {
- parts.push(encodeUriQuery(key, true) +
- (value === true ? '' : '=' + encodeUriQuery(value, true)));
- }
- });
- return parts.length ? parts.join('&') : '';
-}
-
-
-/**
- * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
- * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
- * segments:
- * segment = *pchar
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * pct-encoded = "%" HEXDIG HEXDIG
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
-function encodeUriSegment(val) {
- return encodeUriQuery(val, true).
- replace(/%26/gi, '&').
- replace(/%3D/gi, '=').
- replace(/%2B/gi, '+');
-}
-
-
-/**
- * This method is intended for encoding *key* or *value* parts of query component. We need a custom
- * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
- * encoded per http://tools.ietf.org/html/rfc3986:
- * query = *( pchar / "/" / "?" )
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * pct-encoded = "%" HEXDIG HEXDIG
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
-function encodeUriQuery(val, pctEncodeSpaces) {
- return encodeURIComponent(val).
- replace(/%40/gi, '@').
- replace(/%3A/gi, ':').
- replace(/%24/g, '$').
- replace(/%2C/gi, ',').
- replace(/%3B/gi, ';').
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
-}
-
-var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
-
-function getNgAttribute(element, ngAttr) {
- var attr, i, ii = ngAttrPrefixes.length;
- for (i = 0; i < ii; ++i) {
- attr = ngAttrPrefixes[i] + ngAttr;
- if (isString(attr = element.getAttribute(attr))) {
- return attr;
- }
- }
- return null;
-}
-
-/**
- * @ngdoc directive
- * @name ngApp
- * @module ng
- *
- * @element ANY
- * @param {angular.Module} ngApp an optional application
- * {@link angular.module module} name to load.
- * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
- * created in "strict-di" mode. This means that the application will fail to invoke functions which
- * do not use explicit function annotation (and are thus unsuitable for minification), as described
- * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
- * tracking down the root of these bugs.
- *
- * @description
- *
- * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
- * designates the **root element** of the application and is typically placed near the root element
- * of the page - e.g. on the `` or `` tags.
- *
- * There are a few things to keep in mind when using `ngApp`:
- * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
- * found in the document will be used to define the root element to auto-bootstrap as an
- * application. To run multiple applications in an HTML document you must manually bootstrap them using
- * {@link angular.bootstrap} instead.
- * - AngularJS applications cannot be nested within each other.
- * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
- * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
- * {@link ngRoute.ngView `ngView`}.
- * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
- * causing animations to stop working and making the injector inaccessible from outside the app.
- *
- * You can specify an **AngularJS module** to be used as the root module for the application. This
- * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
- * should contain the application code needed or have dependencies on other modules that will
- * contain the code. See {@link angular.module} for more information.
- *
- * In the example below if the `ngApp` directive were not placed on the `html` element then the
- * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
- * would not be resolved to `3`.
- *
- * `ngApp` is the easiest, and most common way to bootstrap an application.
- *
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
-
- angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- });
-
-
- *
- * Using `ngStrictDi`, you would see something like this:
- *
-
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
This renders because the controller does not fail to
- instantiate, by using explicit annotation style (see
- script.js for details)
-
-
-
-
- Name:
- Hello, {{name}}!
-
-
This renders because the controller does not fail to
- instantiate, by using explicit annotation style
- (see script.js for details)
-
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
The controller could not be instantiated, due to relying
- on automatic function annotations (which are disabled in
- strict mode). As such, the content of this section is not
- interpolated, and there should be an error in your web console.
-
-
-
-
-
- angular.module('ngAppStrictDemo', [])
- // BadController will fail to instantiate, due to relying on automatic function annotation,
- // rather than an explicit annotation
- .controller('BadController', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- })
- // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
- // due to using explicit annotations using the array style and $inject property, respectively.
- .controller('GoodController1', ['$scope', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- }])
- .controller('GoodController2', GoodController2);
- function GoodController2($scope) {
- $scope.name = "World";
- }
- GoodController2.$inject = ['$scope'];
-
-
- div[ng-controller] {
- margin-bottom: 1em;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- border: 1px solid;
- padding: .5em;
- }
- div[ng-controller^=Good] {
- border-color: #d6e9c6;
- background-color: #dff0d8;
- color: #3c763d;
- }
- div[ng-controller^=Bad] {
- border-color: #ebccd1;
- background-color: #f2dede;
- color: #a94442;
- margin-bottom: 0;
- }
-
-
- */
-function angularInit(element, bootstrap) {
- var appElement,
- module,
- config = {};
-
- // The element `element` has priority over any other element.
- forEach(ngAttrPrefixes, function(prefix) {
- var name = prefix + 'app';
-
- if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
- appElement = element;
- module = element.getAttribute(name);
- }
- });
- forEach(ngAttrPrefixes, function(prefix) {
- var name = prefix + 'app';
- var candidate;
-
- if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
- appElement = candidate;
- module = candidate.getAttribute(name);
- }
- });
- if (appElement) {
- config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
- bootstrap(appElement, module ? [module] : [], config);
- }
-}
-
-/**
- * @ngdoc function
- * @name angular.bootstrap
- * @module ng
- * @description
- * Use this function to manually start up angular application.
- *
- * For more information, see the {@link guide/bootstrap Bootstrap guide}.
- *
- * Angular will detect if it has been loaded into the browser more than once and only allow the
- * first loaded script to be bootstrapped and will report a warning to the browser console for
- * each of the subsequent scripts. This prevents strange results in applications, where otherwise
- * multiple instances of Angular try to work on the DOM.
- *
- *
- * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
- * They must use {@link ng.directive:ngApp ngApp}.
- *
- *
- *
- * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
- * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
- * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
- * causing animations to stop working and making the injector inaccessible from outside the app.
- *
- *
- * ```html
- *
- *
- *
- *
- * {{greeting}}
- *
- *
- *
- *
- *
- *
- * ```
- *
- * @param {DOMElement} element DOM element which is the root of angular application.
- * @param {Array=} modules an array of modules to load into the application.
- * Each item in the array should be the name of a predefined module or a (DI annotated)
- * function that will be invoked by the injector as a `config` block.
- * See: {@link angular.module modules}
- * @param {Object=} config an object for defining configuration options for the application. The
- * following keys are supported:
- *
- * * `strictDi` - disable automatic function annotation for the application. This is meant to
- * assist in finding bugs which break minified code. Defaults to `false`.
- *
- * @returns {auto.$injector} Returns the newly created injector for this app.
- */
-function bootstrap(element, modules, config) {
- if (!isObject(config)) config = {};
- var defaultConfig = {
- strictDi: false
- };
- config = extend(defaultConfig, config);
- var doBootstrap = function() {
- element = jqLite(element);
-
- if (element.injector()) {
- var tag = (element[0] === window.document) ? 'document' : startingTag(element);
- // Encode angle brackets to prevent input from being sanitized to empty string #8683.
- throw ngMinErr(
- 'btstrpd',
- "App already bootstrapped with this element '{0}'",
- tag.replace(/,'<').replace(/>/,'>'));
- }
-
- modules = modules || [];
- modules.unshift(['$provide', function($provide) {
- $provide.value('$rootElement', element);
- }]);
-
- if (config.debugInfoEnabled) {
- // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
- modules.push(['$compileProvider', function($compileProvider) {
- $compileProvider.debugInfoEnabled(true);
- }]);
- }
-
- modules.unshift('ng');
- var injector = createInjector(modules, config.strictDi);
- injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
- function bootstrapApply(scope, element, compile, injector) {
- scope.$apply(function() {
- element.data('$injector', injector);
- compile(element)(scope);
- });
- }]
- );
- return injector;
- };
-
- var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
- var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
-
- if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
- config.debugInfoEnabled = true;
- window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
- }
-
- if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
- return doBootstrap();
- }
-
- window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
- angular.resumeBootstrap = function(extraModules) {
- forEach(extraModules, function(module) {
- modules.push(module);
- });
- return doBootstrap();
- };
-
- if (isFunction(angular.resumeDeferredBootstrap)) {
- angular.resumeDeferredBootstrap();
- }
-}
-
-/**
- * @ngdoc function
- * @name angular.reloadWithDebugInfo
- * @module ng
- * @description
- * Use this function to reload the current application with debug information turned on.
- * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
- *
- * See {@link ng.$compileProvider#debugInfoEnabled} for more.
- */
-function reloadWithDebugInfo() {
- window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
- window.location.reload();
-}
-
-/**
- * @name angular.getTestability
- * @module ng
- * @description
- * Get the testability service for the instance of Angular on the given
- * element.
- * @param {DOMElement} element DOM element which is the root of angular application.
- */
-function getTestability(rootElement) {
- var injector = angular.element(rootElement).injector();
- if (!injector) {
- throw ngMinErr('test',
- 'no injector found for element argument to getTestability');
- }
- return injector.get('$$testability');
-}
-
-var SNAKE_CASE_REGEXP = /[A-Z]/g;
-function snake_case(name, separator) {
- separator = separator || '_';
- return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
- return (pos ? separator : '') + letter.toLowerCase();
- });
-}
-
-var bindJQueryFired = false;
-function bindJQuery() {
- var originalCleanData;
-
- if (bindJQueryFired) {
- return;
- }
-
- // bind to jQuery if present;
- var jqName = jq();
- jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)
- !jqName ? undefined : // use jqLite
- window[jqName]; // use jQuery specified by `ngJq`
-
- // Use jQuery if it exists with proper functionality, otherwise default to us.
- // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
- // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
- // versions. It will not work for sure with jQuery <1.7, though.
- if (jQuery && jQuery.fn.on) {
- jqLite = jQuery;
- extend(jQuery.fn, {
- scope: JQLitePrototype.scope,
- isolateScope: JQLitePrototype.isolateScope,
- controller: JQLitePrototype.controller,
- injector: JQLitePrototype.injector,
- inheritedData: JQLitePrototype.inheritedData
- });
-
- // All nodes removed from the DOM via various jQuery APIs like .remove()
- // are passed through jQuery.cleanData. Monkey-patch this method to fire
- // the $destroy event on all removed nodes.
- originalCleanData = jQuery.cleanData;
- jQuery.cleanData = function(elems) {
- var events;
- for (var i = 0, elem; (elem = elems[i]) != null; i++) {
- events = jQuery._data(elem, "events");
- if (events && events.$destroy) {
- jQuery(elem).triggerHandler('$destroy');
- }
- }
- originalCleanData(elems);
- };
- } else {
- jqLite = JQLite;
- }
-
- angular.element = jqLite;
-
- // Prevent double-proxying.
- bindJQueryFired = true;
-}
-
-/**
- * throw error if the argument is falsy.
- */
-function assertArg(arg, name, reason) {
- if (!arg) {
- throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
- }
- return arg;
-}
-
-function assertArgFn(arg, name, acceptArrayAnnotation) {
- if (acceptArrayAnnotation && isArray(arg)) {
- arg = arg[arg.length - 1];
- }
-
- assertArg(isFunction(arg), name, 'not a function, got ' +
- (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
- return arg;
-}
-
-/**
- * throw error if the name given is hasOwnProperty
- * @param {String} name the name to test
- * @param {String} context the context in which the name is used, such as module or directive
- */
-function assertNotHasOwnProperty(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
- }
-}
-
-/**
- * Return the value accessible from the object by path. Any undefined traversals are ignored
- * @param {Object} obj starting object
- * @param {String} path path to traverse
- * @param {boolean} [bindFnToScope=true]
- * @returns {Object} value as accessible by path
- */
-//TODO(misko): this function needs to be removed
-function getter(obj, path, bindFnToScope) {
- if (!path) return obj;
- var keys = path.split('.');
- var key;
- var lastInstance = obj;
- var len = keys.length;
-
- for (var i = 0; i < len; i++) {
- key = keys[i];
- if (obj) {
- obj = (lastInstance = obj)[key];
- }
- }
- if (!bindFnToScope && isFunction(obj)) {
- return bind(lastInstance, obj);
- }
- return obj;
-}
-
-/**
- * Return the DOM siblings between the first and last node in the given array.
- * @param {Array} array like object
- * @returns {Array} the inputted object or a jqLite collection containing the nodes
- */
-function getBlockNodes(nodes) {
- // TODO(perf): update `nodes` instead of creating a new object?
- var node = nodes[0];
- var endNode = nodes[nodes.length - 1];
- var blockNodes;
-
- for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
- if (blockNodes || nodes[i] !== node) {
- if (!blockNodes) {
- blockNodes = jqLite(slice.call(nodes, 0, i));
- }
- blockNodes.push(node);
- }
- }
-
- return blockNodes || nodes;
-}
-
-
-/**
- * Creates a new object without a prototype. This object is useful for lookup without having to
- * guard against prototypically inherited properties via hasOwnProperty.
- *
- * Related micro-benchmarks:
- * - http://jsperf.com/object-create2
- * - http://jsperf.com/proto-map-lookup/2
- * - http://jsperf.com/for-in-vs-object-keys2
- *
- * @returns {Object}
- */
-function createMap() {
- return Object.create(null);
-}
-
-var NODE_TYPE_ELEMENT = 1;
-var NODE_TYPE_ATTRIBUTE = 2;
-var NODE_TYPE_TEXT = 3;
-var NODE_TYPE_COMMENT = 8;
-var NODE_TYPE_DOCUMENT = 9;
-var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
-
-/**
- * @ngdoc type
- * @name angular.Module
- * @module ng
- * @description
- *
- * Interface for configuring angular {@link angular.module modules}.
- */
-
-function setupModuleLoader(window) {
-
- var $injectorMinErr = minErr('$injector');
- var ngMinErr = minErr('ng');
-
- function ensure(obj, name, factory) {
- return obj[name] || (obj[name] = factory());
- }
-
- var angular = ensure(window, 'angular', Object);
-
- // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
- angular.$$minErr = angular.$$minErr || minErr;
-
- return ensure(angular, 'module', function() {
- /** @type {Object.} */
- var modules = {};
-
- /**
- * @ngdoc function
- * @name angular.module
- * @module ng
- * @description
- *
- * The `angular.module` is a global place for creating, registering and retrieving Angular
- * modules.
- * All modules (angular core or 3rd party) that should be available to an application must be
- * registered using this mechanism.
- *
- * Passing one argument retrieves an existing {@link angular.Module},
- * whereas passing more than one argument creates a new {@link angular.Module}
- *
- *
- * # Module
- *
- * A module is a collection of services, directives, controllers, filters, and configuration information.
- * `angular.module` is used to configure the {@link auto.$injector $injector}.
- *
- * ```js
- * // Create a new module
- * var myModule = angular.module('myModule', []);
- *
- * // register a new service
- * myModule.value('appName', 'MyCoolApp');
- *
- * // configure existing services inside initialization blocks.
- * myModule.config(['$locationProvider', function($locationProvider) {
- * // Configure existing providers
- * $locationProvider.hashPrefix('!');
- * }]);
- * ```
- *
- * Then you can create an injector and load your modules like this:
- *
- * ```js
- * var injector = angular.injector(['ng', 'myModule'])
- * ```
- *
- * However it's more likely that you'll just use
- * {@link ng.directive:ngApp ngApp} or
- * {@link angular.bootstrap} to simplify this process for you.
- *
- * @param {!string} name The name of the module to create or retrieve.
- * @param {!Array.=} requires If specified then new module is being created. If
- * unspecified then the module is being retrieved for further configuration.
- * @param {Function=} configFn Optional configuration function for the module. Same as
- * {@link angular.Module#config Module#config()}.
- * @returns {angular.Module} new module with the {@link angular.Module} api.
- */
- return function module(name, requires, configFn) {
- var assertNotHasOwnProperty = function(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
- }
- };
-
- assertNotHasOwnProperty(name, 'module');
- if (requires && modules.hasOwnProperty(name)) {
- modules[name] = null;
- }
- return ensure(modules, name, function() {
- if (!requires) {
- throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
- "the module name or forgot to load it. If registering a module ensure that you " +
- "specify the dependencies as the second argument.", name);
- }
-
- /** @type {!Array.>} */
- var invokeQueue = [];
-
- /** @type {!Array.} */
- var configBlocks = [];
-
- /** @type {!Array.} */
- var runBlocks = [];
-
- var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
-
- /** @type {angular.Module} */
- var moduleInstance = {
- // Private state
- _invokeQueue: invokeQueue,
- _configBlocks: configBlocks,
- _runBlocks: runBlocks,
-
- /**
- * @ngdoc property
- * @name angular.Module#requires
- * @module ng
- *
- * @description
- * Holds the list of modules which the injector will load before the current module is
- * loaded.
- */
- requires: requires,
-
- /**
- * @ngdoc property
- * @name angular.Module#name
- * @module ng
- *
- * @description
- * Name of the module.
- */
- name: name,
-
-
- /**
- * @ngdoc method
- * @name angular.Module#provider
- * @module ng
- * @param {string} name service name
- * @param {Function} providerType Construction function for creating new instance of the
- * service.
- * @description
- * See {@link auto.$provide#provider $provide.provider()}.
- */
- provider: invokeLaterAndSetModuleName('$provide', 'provider'),
-
- /**
- * @ngdoc method
- * @name angular.Module#factory
- * @module ng
- * @param {string} name service name
- * @param {Function} providerFunction Function for creating new instance of the service.
- * @description
- * See {@link auto.$provide#factory $provide.factory()}.
- */
- factory: invokeLaterAndSetModuleName('$provide', 'factory'),
-
- /**
- * @ngdoc method
- * @name angular.Module#service
- * @module ng
- * @param {string} name service name
- * @param {Function} constructor A constructor function that will be instantiated.
- * @description
- * See {@link auto.$provide#service $provide.service()}.
- */
- service: invokeLaterAndSetModuleName('$provide', 'service'),
-
- /**
- * @ngdoc method
- * @name angular.Module#value
- * @module ng
- * @param {string} name service name
- * @param {*} object Service instance object.
- * @description
- * See {@link auto.$provide#value $provide.value()}.
- */
- value: invokeLater('$provide', 'value'),
-
- /**
- * @ngdoc method
- * @name angular.Module#constant
- * @module ng
- * @param {string} name constant name
- * @param {*} object Constant value.
- * @description
- * Because the constants are fixed, they get applied before other provide methods.
- * See {@link auto.$provide#constant $provide.constant()}.
- */
- constant: invokeLater('$provide', 'constant', 'unshift'),
-
- /**
- * @ngdoc method
- * @name angular.Module#decorator
- * @module ng
- * @param {string} name The name of the service to decorate.
- * @param {Function} decorFn This function will be invoked when the service needs to be
- * instantiated and should return the decorated service instance.
- * @description
- * See {@link auto.$provide#decorator $provide.decorator()}.
- */
- decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
-
- /**
- * @ngdoc method
- * @name angular.Module#animation
- * @module ng
- * @param {string} name animation name
- * @param {Function} animationFactory Factory function for creating new instance of an
- * animation.
- * @description
- *
- * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
- *
- *
- * Defines an animation hook that can be later used with
- * {@link $animate $animate} service and directives that use this service.
- *
- * ```js
- * module.animation('.animation-name', function($inject1, $inject2) {
- * return {
- * eventName : function(element, done) {
- * //code to run the animation
- * //once complete, then run done()
- * return function cancellationFunction(element) {
- * //code to cancel the animation
- * }
- * }
- * }
- * })
- * ```
- *
- * See {@link ng.$animateProvider#register $animateProvider.register()} and
- * {@link ngAnimate ngAnimate module} for more information.
- */
- animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#filter
- * @module ng
- * @param {string} name Filter name - this must be a valid angular expression identifier
- * @param {Function} filterFactory Factory function for creating new instance of filter.
- * @description
- * See {@link ng.$filterProvider#register $filterProvider.register()}.
- *
- *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
- * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
- * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
- * (`myapp_subsection_filterx`).
- *
- */
- filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#controller
- * @module ng
- * @param {string|Object} name Controller name, or an object map of controllers where the
- * keys are the names and the values are the constructors.
- * @param {Function} constructor Controller constructor function.
- * @description
- * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
- */
- controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#directive
- * @module ng
- * @param {string|Object} name Directive name, or an object map of directives where the
- * keys are the names and the values are the factories.
- * @param {Function} directiveFactory Factory function for creating new instance of
- * directives.
- * @description
- * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
- */
- directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
-
- /**
- * @ngdoc method
- * @name angular.Module#component
- * @module ng
- * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
- * @param {Object} options Component definition object (a simplified
- * {@link ng.$compile#directive-definition-object directive definition object})
- *
- * @description
- * See {@link ng.$compileProvider#component $compileProvider.component()}.
- */
- component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
-
- /**
- * @ngdoc method
- * @name angular.Module#config
- * @module ng
- * @param {Function} configFn Execute this function on module load. Useful for service
- * configuration.
- * @description
- * Use this method to register work which needs to be performed on module loading.
- * For more about how to configure services, see
- * {@link providers#provider-recipe Provider Recipe}.
- */
- config: config,
-
- /**
- * @ngdoc method
- * @name angular.Module#run
- * @module ng
- * @param {Function} initializationFn Execute this function after injector creation.
- * Useful for application initialization.
- * @description
- * Use this method to register work which should be performed when the injector is done
- * loading all modules.
- */
- run: function(block) {
- runBlocks.push(block);
- return this;
- }
- };
-
- if (configFn) {
- config(configFn);
- }
-
- return moduleInstance;
-
- /**
- * @param {string} provider
- * @param {string} method
- * @param {String=} insertMethod
- * @returns {angular.Module}
- */
- function invokeLater(provider, method, insertMethod, queue) {
- if (!queue) queue = invokeQueue;
- return function() {
- queue[insertMethod || 'push']([provider, method, arguments]);
- return moduleInstance;
- };
- }
-
- /**
- * @param {string} provider
- * @param {string} method
- * @returns {angular.Module}
- */
- function invokeLaterAndSetModuleName(provider, method) {
- return function(recipeName, factoryFunction) {
- if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
- invokeQueue.push([provider, method, arguments]);
- return moduleInstance;
- };
- }
- });
- };
- });
-
-}
-
-/* global shallowCopy: true */
-
-/**
- * Creates a shallow copy of an object, an array or a primitive.
- *
- * Assumes that there are no proto properties for objects.
- */
-function shallowCopy(src, dst) {
- if (isArray(src)) {
- dst = dst || [];
-
- for (var i = 0, ii = src.length; i < ii; i++) {
- dst[i] = src[i];
- }
- } else if (isObject(src)) {
- dst = dst || {};
-
- for (var key in src) {
- if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
- dst[key] = src[key];
- }
- }
- }
-
- return dst || src;
-}
-
-/* global toDebugString: true */
-
-function serializeObject(obj) {
- var seen = [];
-
- return JSON.stringify(obj, function(key, val) {
- val = toJsonReplacer(key, val);
- if (isObject(val)) {
-
- if (seen.indexOf(val) >= 0) return '...';
-
- seen.push(val);
- }
- return val;
- });
-}
-
-function toDebugString(obj) {
- if (typeof obj === 'function') {
- return obj.toString().replace(/ \{[\s\S]*$/, '');
- } else if (isUndefined(obj)) {
- return 'undefined';
- } else if (typeof obj !== 'string') {
- return serializeObject(obj);
- }
- return obj;
-}
-
-/* global angularModule: true,
- version: true,
-
- $CompileProvider,
-
- htmlAnchorDirective,
- inputDirective,
- inputDirective,
- formDirective,
- scriptDirective,
- selectDirective,
- styleDirective,
- optionDirective,
- ngBindDirective,
- ngBindHtmlDirective,
- ngBindTemplateDirective,
- ngClassDirective,
- ngClassEvenDirective,
- ngClassOddDirective,
- ngCloakDirective,
- ngControllerDirective,
- ngFormDirective,
- ngHideDirective,
- ngIfDirective,
- ngIncludeDirective,
- ngIncludeFillContentDirective,
- ngInitDirective,
- ngNonBindableDirective,
- ngPluralizeDirective,
- ngRepeatDirective,
- ngShowDirective,
- ngStyleDirective,
- ngSwitchDirective,
- ngSwitchWhenDirective,
- ngSwitchDefaultDirective,
- ngOptionsDirective,
- ngTranscludeDirective,
- ngModelDirective,
- ngListDirective,
- ngChangeDirective,
- patternDirective,
- patternDirective,
- requiredDirective,
- requiredDirective,
- minlengthDirective,
- minlengthDirective,
- maxlengthDirective,
- maxlengthDirective,
- ngValueDirective,
- ngModelOptionsDirective,
- ngAttributeAliasDirectives,
- ngEventDirectives,
-
- $AnchorScrollProvider,
- $AnimateProvider,
- $CoreAnimateCssProvider,
- $$CoreAnimateJsProvider,
- $$CoreAnimateQueueProvider,
- $$AnimateRunnerFactoryProvider,
- $$AnimateAsyncRunFactoryProvider,
- $BrowserProvider,
- $CacheFactoryProvider,
- $ControllerProvider,
- $DateProvider,
- $DocumentProvider,
- $ExceptionHandlerProvider,
- $FilterProvider,
- $$ForceReflowProvider,
- $InterpolateProvider,
- $IntervalProvider,
- $$HashMapProvider,
- $HttpProvider,
- $HttpParamSerializerProvider,
- $HttpParamSerializerJQLikeProvider,
- $HttpBackendProvider,
- $xhrFactoryProvider,
- $jsonpCallbacksProvider,
- $LocationProvider,
- $LogProvider,
- $ParseProvider,
- $RootScopeProvider,
- $QProvider,
- $$QProvider,
- $$SanitizeUriProvider,
- $SceProvider,
- $SceDelegateProvider,
- $SnifferProvider,
- $TemplateCacheProvider,
- $TemplateRequestProvider,
- $$TestabilityProvider,
- $TimeoutProvider,
- $$RAFProvider,
- $WindowProvider,
- $$jqLiteProvider,
- $$CookieReaderProvider
-*/
-
-
-/**
- * @ngdoc object
- * @name angular.version
- * @module ng
- * @description
- * An object that contains information about the current AngularJS version.
- *
- * This object has the following properties:
- *
- * - `full` – `{string}` – Full version string, such as "0.9.18".
- * - `major` – `{number}` – Major version number, such as "0".
- * - `minor` – `{number}` – Minor version number, such as "9".
- * - `dot` – `{number}` – Dot version number, such as "18".
- * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
- */
-var version = {
- full: '1.5.8', // all of these placeholder strings will be replaced by grunt's
- major: 1, // package task
- minor: 5,
- dot: 8,
- codeName: 'arbitrary-fallbacks'
-};
-
-
-function publishExternalAPI(angular) {
- extend(angular, {
- 'bootstrap': bootstrap,
- 'copy': copy,
- 'extend': extend,
- 'merge': merge,
- 'equals': equals,
- 'element': jqLite,
- 'forEach': forEach,
- 'injector': createInjector,
- 'noop': noop,
- 'bind': bind,
- 'toJson': toJson,
- 'fromJson': fromJson,
- 'identity': identity,
- 'isUndefined': isUndefined,
- 'isDefined': isDefined,
- 'isString': isString,
- 'isFunction': isFunction,
- 'isObject': isObject,
- 'isNumber': isNumber,
- 'isElement': isElement,
- 'isArray': isArray,
- 'version': version,
- 'isDate': isDate,
- 'lowercase': lowercase,
- 'uppercase': uppercase,
- 'callbacks': {$$counter: 0},
- 'getTestability': getTestability,
- '$$minErr': minErr,
- '$$csp': csp,
- 'reloadWithDebugInfo': reloadWithDebugInfo
- });
-
- angularModule = setupModuleLoader(window);
-
- angularModule('ng', ['ngLocale'], ['$provide',
- function ngModule($provide) {
- // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
- $provide.provider({
- $$sanitizeUri: $$SanitizeUriProvider
- });
- $provide.provider('$compile', $CompileProvider).
- directive({
- a: htmlAnchorDirective,
- input: inputDirective,
- textarea: inputDirective,
- form: formDirective,
- script: scriptDirective,
- select: selectDirective,
- style: styleDirective,
- option: optionDirective,
- ngBind: ngBindDirective,
- ngBindHtml: ngBindHtmlDirective,
- ngBindTemplate: ngBindTemplateDirective,
- ngClass: ngClassDirective,
- ngClassEven: ngClassEvenDirective,
- ngClassOdd: ngClassOddDirective,
- ngCloak: ngCloakDirective,
- ngController: ngControllerDirective,
- ngForm: ngFormDirective,
- ngHide: ngHideDirective,
- ngIf: ngIfDirective,
- ngInclude: ngIncludeDirective,
- ngInit: ngInitDirective,
- ngNonBindable: ngNonBindableDirective,
- ngPluralize: ngPluralizeDirective,
- ngRepeat: ngRepeatDirective,
- ngShow: ngShowDirective,
- ngStyle: ngStyleDirective,
- ngSwitch: ngSwitchDirective,
- ngSwitchWhen: ngSwitchWhenDirective,
- ngSwitchDefault: ngSwitchDefaultDirective,
- ngOptions: ngOptionsDirective,
- ngTransclude: ngTranscludeDirective,
- ngModel: ngModelDirective,
- ngList: ngListDirective,
- ngChange: ngChangeDirective,
- pattern: patternDirective,
- ngPattern: patternDirective,
- required: requiredDirective,
- ngRequired: requiredDirective,
- minlength: minlengthDirective,
- ngMinlength: minlengthDirective,
- maxlength: maxlengthDirective,
- ngMaxlength: maxlengthDirective,
- ngValue: ngValueDirective,
- ngModelOptions: ngModelOptionsDirective
- }).
- directive({
- ngInclude: ngIncludeFillContentDirective
- }).
- directive(ngAttributeAliasDirectives).
- directive(ngEventDirectives);
- $provide.provider({
- $anchorScroll: $AnchorScrollProvider,
- $animate: $AnimateProvider,
- $animateCss: $CoreAnimateCssProvider,
- $$animateJs: $$CoreAnimateJsProvider,
- $$animateQueue: $$CoreAnimateQueueProvider,
- $$AnimateRunner: $$AnimateRunnerFactoryProvider,
- $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
- $browser: $BrowserProvider,
- $cacheFactory: $CacheFactoryProvider,
- $controller: $ControllerProvider,
- $document: $DocumentProvider,
- $exceptionHandler: $ExceptionHandlerProvider,
- $filter: $FilterProvider,
- $$forceReflow: $$ForceReflowProvider,
- $interpolate: $InterpolateProvider,
- $interval: $IntervalProvider,
- $http: $HttpProvider,
- $httpParamSerializer: $HttpParamSerializerProvider,
- $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
- $httpBackend: $HttpBackendProvider,
- $xhrFactory: $xhrFactoryProvider,
- $jsonpCallbacks: $jsonpCallbacksProvider,
- $location: $LocationProvider,
- $log: $LogProvider,
- $parse: $ParseProvider,
- $rootScope: $RootScopeProvider,
- $q: $QProvider,
- $$q: $$QProvider,
- $sce: $SceProvider,
- $sceDelegate: $SceDelegateProvider,
- $sniffer: $SnifferProvider,
- $templateCache: $TemplateCacheProvider,
- $templateRequest: $TemplateRequestProvider,
- $$testability: $$TestabilityProvider,
- $timeout: $TimeoutProvider,
- $window: $WindowProvider,
- $$rAF: $$RAFProvider,
- $$jqLite: $$jqLiteProvider,
- $$HashMap: $$HashMapProvider,
- $$cookieReader: $$CookieReaderProvider
- });
- }
- ]);
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Any commits to this file should be reviewed with security in mind. *
- * Changes to this file can potentially create security vulnerabilities. *
- * An approval from 2 Core members with history of modifying *
- * this file is required. *
- * *
- * Does the change somehow allow for arbitrary javascript to be executed? *
- * Or allows for someone to change the prototype of built-in objects? *
- * Or gives undesired access to variables likes document or window? *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-/* global JQLitePrototype: true,
- addEventListenerFn: true,
- removeEventListenerFn: true,
- BOOLEAN_ATTR: true,
- ALIASED_ATTR: true,
-*/
-
-//////////////////////////////////
-//JQLite
-//////////////////////////////////
-
-/**
- * @ngdoc function
- * @name angular.element
- * @module ng
- * @kind function
- *
- * @description
- * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
- *
- * If jQuery is available, `angular.element` is an alias for the
- * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
- * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
- *
- * jqLite is a tiny, API-compatible subset of jQuery that allows
- * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
- * commonly needed functionality with the goal of having a very small footprint.
- *
- * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
- * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
- * specific version of jQuery if multiple versions exist on the page.
- *
- *
**Note:** All element references in Angular are always wrapped with jQuery or
- * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.
- *
- *
**Note:** Keep in mind that this function will not find elements
- * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
- * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.
- *
- * ## Angular's jqLite
- * jqLite provides only the following jQuery methods:
- *
- * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
- * - [`after()`](http://api.jquery.com/after/)
- * - [`append()`](http://api.jquery.com/append/)
- * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
- * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
- * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
- * - [`clone()`](http://api.jquery.com/clone/)
- * - [`contents()`](http://api.jquery.com/contents/)
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
- * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
- * - [`data()`](http://api.jquery.com/data/)
- * - [`detach()`](http://api.jquery.com/detach/)
- * - [`empty()`](http://api.jquery.com/empty/)
- * - [`eq()`](http://api.jquery.com/eq/)
- * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
- * - [`hasClass()`](http://api.jquery.com/hasClass/)
- * - [`html()`](http://api.jquery.com/html/)
- * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
- * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
- * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
- * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
- * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
- * - [`prepend()`](http://api.jquery.com/prepend/)
- * - [`prop()`](http://api.jquery.com/prop/)
- * - [`ready()`](http://api.jquery.com/ready/)
- * - [`remove()`](http://api.jquery.com/remove/)
- * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
- * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
- * - [`removeData()`](http://api.jquery.com/removeData/)
- * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
- * - [`text()`](http://api.jquery.com/text/)
- * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
- * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
- * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
- * - [`val()`](http://api.jquery.com/val/)
- * - [`wrap()`](http://api.jquery.com/wrap/)
- *
- * ## jQuery/jqLite Extras
- * Angular also provides the following additional methods and events to both jQuery and jqLite:
- *
- * ### Events
- * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
- * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
- * element before it is removed.
- *
- * ### Methods
- * - `controller(name)` - retrieves the controller of the current element or its parent. By default
- * retrieves controller associated with the `ngController` directive. If `name` is provided as
- * camelCase directive name, then the controller for this directive will be retrieved (e.g.
- * `'ngModel'`).
- * - `injector()` - retrieves the injector of the current element or its parent.
- * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
- * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
- * be enabled.
- * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
- * current element. This getter should be used only on elements that contain a directive which starts a new isolate
- * scope. Calling `scope()` on this element always returns the original non-isolate scope.
- * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
- * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
- * parent element is reached.
- *
- * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
- * https://github.com/angular/angular.js/issues/14251 for more information.
- *
- * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
- * @returns {Object} jQuery object.
- */
-
-JQLite.expando = 'ng339';
-
-var jqCache = JQLite.cache = {},
- jqId = 1,
- addEventListenerFn = function(element, type, fn) {
- element.addEventListener(type, fn, false);
- },
- removeEventListenerFn = function(element, type, fn) {
- element.removeEventListener(type, fn, false);
- };
-
-/*
- * !!! This is an undocumented "private" function !!!
- */
-JQLite._data = function(node) {
- //jQuery always returns an object on cache miss
- return this.cache[node[this.expando]] || {};
-};
-
-function jqNextId() { return ++jqId; }
-
-
-var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
-var MOZ_HACK_REGEXP = /^moz([A-Z])/;
-var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
-var jqLiteMinErr = minErr('jqLite');
-
-/**
- * Converts snake_case to camelCase.
- * Also there is special case for Moz prefix starting with upper case letter.
- * @param name Name to normalize
- */
-function camelCase(name) {
- return name.
- replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
- return offset ? letter.toUpperCase() : letter;
- }).
- replace(MOZ_HACK_REGEXP, 'Moz$1');
-}
-
-var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
-var HTML_REGEXP = /<|?\w+;/;
-var TAG_NAME_REGEXP = /<([\w:-]+)/;
-var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
-
-var wrapMap = {
- 'option': [1, ''],
-
- 'thead': [1, '
', '
'],
- 'col': [2, '
', '
'],
- 'tr': [2, '
', '
'],
- 'td': [3, '
', '
'],
- '_default': [0, "", ""]
-};
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-
-function jqLiteIsTextNode(html) {
- return !HTML_REGEXP.test(html);
-}
-
-function jqLiteAcceptsData(node) {
- // The window object can accept data but has no nodeType
- // Otherwise we are only interested in elements (1) and documents (9)
- var nodeType = node.nodeType;
- return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
-}
-
-function jqLiteHasData(node) {
- for (var key in jqCache[node.ng339]) {
- return true;
- }
- return false;
-}
-
-function jqLiteCleanData(nodes) {
- for (var i = 0, ii = nodes.length; i < ii; i++) {
- jqLiteRemoveData(nodes[i]);
- }
-}
-
-function jqLiteBuildFragment(html, context) {
- var tmp, tag, wrap,
- fragment = context.createDocumentFragment(),
- nodes = [], i;
-
- if (jqLiteIsTextNode(html)) {
- // Convert non-html into a text node
- nodes.push(context.createTextNode(html));
- } else {
- // Convert html into DOM nodes
- tmp = fragment.appendChild(context.createElement("div"));
- tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
- wrap = wrapMap[tag] || wrapMap._default;
- tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>$2>") + wrap[2];
-
- // Descend through wrappers to the right content
- i = wrap[0];
- while (i--) {
- tmp = tmp.lastChild;
- }
-
- nodes = concat(nodes, tmp.childNodes);
-
- tmp = fragment.firstChild;
- tmp.textContent = "";
- }
-
- // Remove wrapper from fragment
- fragment.textContent = "";
- fragment.innerHTML = ""; // Clear inner HTML
- forEach(nodes, function(node) {
- fragment.appendChild(node);
- });
-
- return fragment;
-}
-
-function jqLiteParseHTML(html, context) {
- context = context || window.document;
- var parsed;
-
- if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
- return [context.createElement(parsed[1])];
- }
-
- if ((parsed = jqLiteBuildFragment(html, context))) {
- return parsed.childNodes;
- }
-
- return [];
-}
-
-function jqLiteWrapNode(node, wrapper) {
- var parent = node.parentNode;
-
- if (parent) {
- parent.replaceChild(wrapper, node);
- }
-
- wrapper.appendChild(node);
-}
-
-
-// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
-var jqLiteContains = window.Node.prototype.contains || function(arg) {
- // jshint bitwise: false
- return !!(this.compareDocumentPosition(arg) & 16);
- // jshint bitwise: true
-};
-
-/////////////////////////////////////////////
-function JQLite(element) {
- if (element instanceof JQLite) {
- return element;
- }
-
- var argIsString;
-
- if (isString(element)) {
- element = trim(element);
- argIsString = true;
- }
- if (!(this instanceof JQLite)) {
- if (argIsString && element.charAt(0) != '<') {
- throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
- }
- return new JQLite(element);
- }
-
- if (argIsString) {
- jqLiteAddNodes(this, jqLiteParseHTML(element));
- } else {
- jqLiteAddNodes(this, element);
- }
-}
-
-function jqLiteClone(element) {
- return element.cloneNode(true);
-}
-
-function jqLiteDealoc(element, onlyDescendants) {
- if (!onlyDescendants) jqLiteRemoveData(element);
-
- if (element.querySelectorAll) {
- var descendants = element.querySelectorAll('*');
- for (var i = 0, l = descendants.length; i < l; i++) {
- jqLiteRemoveData(descendants[i]);
- }
- }
-}
-
-function jqLiteOff(element, type, fn, unsupported) {
- if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
-
- var expandoStore = jqLiteExpandoStore(element);
- var events = expandoStore && expandoStore.events;
- var handle = expandoStore && expandoStore.handle;
-
- if (!handle) return; //no listeners registered
-
- if (!type) {
- for (type in events) {
- if (type !== '$destroy') {
- removeEventListenerFn(element, type, handle);
- }
- delete events[type];
- }
- } else {
-
- var removeHandler = function(type) {
- var listenerFns = events[type];
- if (isDefined(fn)) {
- arrayRemove(listenerFns || [], fn);
- }
- if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
- removeEventListenerFn(element, type, handle);
- delete events[type];
- }
- };
-
- forEach(type.split(' '), function(type) {
- removeHandler(type);
- if (MOUSE_EVENT_MAP[type]) {
- removeHandler(MOUSE_EVENT_MAP[type]);
- }
- });
- }
-}
-
-function jqLiteRemoveData(element, name) {
- var expandoId = element.ng339;
- var expandoStore = expandoId && jqCache[expandoId];
-
- if (expandoStore) {
- if (name) {
- delete expandoStore.data[name];
- return;
- }
-
- if (expandoStore.handle) {
- if (expandoStore.events.$destroy) {
- expandoStore.handle({}, '$destroy');
- }
- jqLiteOff(element);
- }
- delete jqCache[expandoId];
- element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
- }
-}
-
-
-function jqLiteExpandoStore(element, createIfNecessary) {
- var expandoId = element.ng339,
- expandoStore = expandoId && jqCache[expandoId];
-
- if (createIfNecessary && !expandoStore) {
- element.ng339 = expandoId = jqNextId();
- expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
- }
-
- return expandoStore;
-}
-
-
-function jqLiteData(element, key, value) {
- if (jqLiteAcceptsData(element)) {
-
- var isSimpleSetter = isDefined(value);
- var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
- var massGetter = !key;
- var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
- var data = expandoStore && expandoStore.data;
-
- if (isSimpleSetter) { // data('key', value)
- data[key] = value;
- } else {
- if (massGetter) { // data()
- return data;
- } else {
- if (isSimpleGetter) { // data('key')
- // don't force creation of expandoStore if it doesn't exist yet
- return data && data[key];
- } else { // mass-setter: data({key1: val1, key2: val2})
- extend(data, key);
- }
- }
- }
- }
-}
-
-function jqLiteHasClass(element, selector) {
- if (!element.getAttribute) return false;
- return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
- indexOf(" " + selector + " ") > -1);
-}
-
-function jqLiteRemoveClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- forEach(cssClasses.split(' '), function(cssClass) {
- element.setAttribute('class', trim(
- (" " + (element.getAttribute('class') || '') + " ")
- .replace(/[\n\t]/g, " ")
- .replace(" " + trim(cssClass) + " ", " "))
- );
- });
- }
-}
-
-function jqLiteAddClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
- .replace(/[\n\t]/g, " ");
-
- forEach(cssClasses.split(' '), function(cssClass) {
- cssClass = trim(cssClass);
- if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
- existingClasses += cssClass + ' ';
- }
- });
-
- element.setAttribute('class', trim(existingClasses));
- }
-}
-
-
-function jqLiteAddNodes(root, elements) {
- // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
-
- if (elements) {
-
- // if a Node (the most common case)
- if (elements.nodeType) {
- root[root.length++] = elements;
- } else {
- var length = elements.length;
-
- // if an Array or NodeList and not a Window
- if (typeof length === 'number' && elements.window !== elements) {
- if (length) {
- for (var i = 0; i < length; i++) {
- root[root.length++] = elements[i];
- }
- }
- } else {
- root[root.length++] = elements;
- }
- }
- }
-}
-
-
-function jqLiteController(element, name) {
- return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
-}
-
-function jqLiteInheritedData(element, name, value) {
- // if element is the document object work with the html element instead
- // this makes $(document).scope() possible
- if (element.nodeType == NODE_TYPE_DOCUMENT) {
- element = element.documentElement;
- }
- var names = isArray(name) ? name : [name];
-
- while (element) {
- for (var i = 0, ii = names.length; i < ii; i++) {
- if (isDefined(value = jqLite.data(element, names[i]))) return value;
- }
-
- // If dealing with a document fragment node with a host element, and no parent, use the host
- // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
- // to lookup parent controllers.
- element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
- }
-}
-
-function jqLiteEmpty(element) {
- jqLiteDealoc(element, true);
- while (element.firstChild) {
- element.removeChild(element.firstChild);
- }
-}
-
-function jqLiteRemove(element, keepData) {
- if (!keepData) jqLiteDealoc(element);
- var parent = element.parentNode;
- if (parent) parent.removeChild(element);
-}
-
-
-function jqLiteDocumentLoaded(action, win) {
- win = win || window;
- if (win.document.readyState === 'complete') {
- // Force the action to be run async for consistent behavior
- // from the action's point of view
- // i.e. it will definitely not be in a $apply
- win.setTimeout(action);
- } else {
- // No need to unbind this handler as load is only ever called once
- jqLite(win).on('load', action);
- }
-}
-
-//////////////////////////////////////////
-// Functions which are declared directly.
-//////////////////////////////////////////
-var JQLitePrototype = JQLite.prototype = {
- ready: function(fn) {
- var fired = false;
-
- function trigger() {
- if (fired) return;
- fired = true;
- fn();
- }
-
- // check if document is already loaded
- if (window.document.readyState === 'complete') {
- window.setTimeout(trigger);
- } else {
- this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
- // we can not use jqLite since we are not done loading and jQuery could be loaded later.
- // jshint -W064
- JQLite(window).on('load', trigger); // fallback to window.onload for others
- // jshint +W064
- }
- },
- toString: function() {
- var value = [];
- forEach(this, function(e) { value.push('' + e);});
- return '[' + value.join(', ') + ']';
- },
-
- eq: function(index) {
- return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
- },
-
- length: 0,
- push: push,
- sort: [].sort,
- splice: [].splice
-};
-
-//////////////////////////////////////////
-// Functions iterating getter/setters.
-// these functions return self on setter and
-// value on get.
-//////////////////////////////////////////
-var BOOLEAN_ATTR = {};
-forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
- BOOLEAN_ATTR[lowercase(value)] = value;
-});
-var BOOLEAN_ELEMENTS = {};
-forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
- BOOLEAN_ELEMENTS[value] = true;
-});
-var ALIASED_ATTR = {
- 'ngMinlength': 'minlength',
- 'ngMaxlength': 'maxlength',
- 'ngMin': 'min',
- 'ngMax': 'max',
- 'ngPattern': 'pattern'
-};
-
-function getBooleanAttrName(element, name) {
- // check dom last since we will most likely fail on name
- var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
-
- // booleanAttr is here twice to minimize DOM access
- return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
-}
-
-function getAliasedAttrName(name) {
- return ALIASED_ATTR[name];
-}
-
-forEach({
- data: jqLiteData,
- removeData: jqLiteRemoveData,
- hasData: jqLiteHasData,
- cleanData: jqLiteCleanData
-}, function(fn, name) {
- JQLite[name] = fn;
-});
-
-forEach({
- data: jqLiteData,
- inheritedData: jqLiteInheritedData,
-
- scope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
- },
-
- isolateScope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
- },
-
- controller: jqLiteController,
-
- injector: function(element) {
- return jqLiteInheritedData(element, '$injector');
- },
-
- removeAttr: function(element, name) {
- element.removeAttribute(name);
- },
-
- hasClass: jqLiteHasClass,
-
- css: function(element, name, value) {
- name = camelCase(name);
-
- if (isDefined(value)) {
- element.style[name] = value;
- } else {
- return element.style[name];
- }
- },
-
- attr: function(element, name, value) {
- var nodeType = element.nodeType;
- if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
- return;
- }
- var lowercasedName = lowercase(name);
- if (BOOLEAN_ATTR[lowercasedName]) {
- if (isDefined(value)) {
- if (!!value) {
- element[name] = true;
- element.setAttribute(name, lowercasedName);
- } else {
- element[name] = false;
- element.removeAttribute(lowercasedName);
- }
- } else {
- return (element[name] ||
- (element.attributes.getNamedItem(name) || noop).specified)
- ? lowercasedName
- : undefined;
- }
- } else if (isDefined(value)) {
- element.setAttribute(name, value);
- } else if (element.getAttribute) {
- // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
- // some elements (e.g. Document) don't have get attribute, so return undefined
- var ret = element.getAttribute(name, 2);
- // normalize non-existing attributes to undefined (as jQuery)
- return ret === null ? undefined : ret;
- }
- },
-
- prop: function(element, name, value) {
- if (isDefined(value)) {
- element[name] = value;
- } else {
- return element[name];
- }
- },
-
- text: (function() {
- getText.$dv = '';
- return getText;
-
- function getText(element, value) {
- if (isUndefined(value)) {
- var nodeType = element.nodeType;
- return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
- }
- element.textContent = value;
- }
- })(),
-
- val: function(element, value) {
- if (isUndefined(value)) {
- if (element.multiple && nodeName_(element) === 'select') {
- var result = [];
- forEach(element.options, function(option) {
- if (option.selected) {
- result.push(option.value || option.text);
- }
- });
- return result.length === 0 ? null : result;
- }
- return element.value;
- }
- element.value = value;
- },
-
- html: function(element, value) {
- if (isUndefined(value)) {
- return element.innerHTML;
- }
- jqLiteDealoc(element, true);
- element.innerHTML = value;
- },
-
- empty: jqLiteEmpty
-}, function(fn, name) {
- /**
- * Properties: writes return selection, reads return first value
- */
- JQLite.prototype[name] = function(arg1, arg2) {
- var i, key;
- var nodeCount = this.length;
-
- // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
- // in a way that survives minification.
- // jqLiteEmpty takes no arguments but is a setter.
- if (fn !== jqLiteEmpty &&
- (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
- if (isObject(arg1)) {
-
- // we are a write, but the object properties are the key/values
- for (i = 0; i < nodeCount; i++) {
- if (fn === jqLiteData) {
- // data() takes the whole object in jQuery
- fn(this[i], arg1);
- } else {
- for (key in arg1) {
- fn(this[i], key, arg1[key]);
- }
- }
- }
- // return self for chaining
- return this;
- } else {
- // we are a read, so read the first child.
- // TODO: do we still need this?
- var value = fn.$dv;
- // Only if we have $dv do we iterate over all, otherwise it is just the first element.
- var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
- for (var j = 0; j < jj; j++) {
- var nodeValue = fn(this[j], arg1, arg2);
- value = value ? value + nodeValue : nodeValue;
- }
- return value;
- }
- } else {
- // we are a write, so apply to all children
- for (i = 0; i < nodeCount; i++) {
- fn(this[i], arg1, arg2);
- }
- // return self for chaining
- return this;
- }
- };
-});
-
-function createEventHandler(element, events) {
- var eventHandler = function(event, type) {
- // jQuery specific api
- event.isDefaultPrevented = function() {
- return event.defaultPrevented;
- };
-
- var eventFns = events[type || event.type];
- var eventFnsLength = eventFns ? eventFns.length : 0;
-
- if (!eventFnsLength) return;
-
- if (isUndefined(event.immediatePropagationStopped)) {
- var originalStopImmediatePropagation = event.stopImmediatePropagation;
- event.stopImmediatePropagation = function() {
- event.immediatePropagationStopped = true;
-
- if (event.stopPropagation) {
- event.stopPropagation();
- }
-
- if (originalStopImmediatePropagation) {
- originalStopImmediatePropagation.call(event);
- }
- };
- }
-
- event.isImmediatePropagationStopped = function() {
- return event.immediatePropagationStopped === true;
- };
-
- // Some events have special handlers that wrap the real handler
- var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
-
- // Copy event handlers in case event handlers array is modified during execution.
- if ((eventFnsLength > 1)) {
- eventFns = shallowCopy(eventFns);
- }
-
- for (var i = 0; i < eventFnsLength; i++) {
- if (!event.isImmediatePropagationStopped()) {
- handlerWrapper(element, event, eventFns[i]);
- }
- }
- };
-
- // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
- // events on `element`
- eventHandler.elem = element;
- return eventHandler;
-}
-
-function defaultHandlerWrapper(element, event, handler) {
- handler.call(element, event);
-}
-
-function specialMouseHandlerWrapper(target, event, handler) {
- // Refer to jQuery's implementation of mouseenter & mouseleave
- // Read about mouseenter and mouseleave:
- // http://www.quirksmode.org/js/events_mouse.html#link8
- var related = event.relatedTarget;
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if (!related || (related !== target && !jqLiteContains.call(target, related))) {
- handler.call(target, event);
- }
-}
-
-//////////////////////////////////////////
-// Functions iterating traversal.
-// These functions chain results into a single
-// selector.
-//////////////////////////////////////////
-forEach({
- removeData: jqLiteRemoveData,
-
- on: function jqLiteOn(element, type, fn, unsupported) {
- if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
-
- // Do not add event handlers to non-elements because they will not be cleaned up.
- if (!jqLiteAcceptsData(element)) {
- return;
- }
-
- var expandoStore = jqLiteExpandoStore(element, true);
- var events = expandoStore.events;
- var handle = expandoStore.handle;
-
- if (!handle) {
- handle = expandoStore.handle = createEventHandler(element, events);
- }
-
- // http://jsperf.com/string-indexof-vs-split
- var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
- var i = types.length;
-
- var addHandler = function(type, specialHandlerWrapper, noEventListener) {
- var eventFns = events[type];
-
- if (!eventFns) {
- eventFns = events[type] = [];
- eventFns.specialHandlerWrapper = specialHandlerWrapper;
- if (type !== '$destroy' && !noEventListener) {
- addEventListenerFn(element, type, handle);
- }
- }
-
- eventFns.push(fn);
- };
-
- while (i--) {
- type = types[i];
- if (MOUSE_EVENT_MAP[type]) {
- addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
- addHandler(type, undefined, true);
- } else {
- addHandler(type);
- }
- }
- },
-
- off: jqLiteOff,
-
- one: function(element, type, fn) {
- element = jqLite(element);
-
- //add the listener twice so that when it is called
- //you can remove the original function and still be
- //able to call element.off(ev, fn) normally
- element.on(type, function onFn() {
- element.off(type, fn);
- element.off(type, onFn);
- });
- element.on(type, fn);
- },
-
- replaceWith: function(element, replaceNode) {
- var index, parent = element.parentNode;
- jqLiteDealoc(element);
- forEach(new JQLite(replaceNode), function(node) {
- if (index) {
- parent.insertBefore(node, index.nextSibling);
- } else {
- parent.replaceChild(node, element);
- }
- index = node;
- });
- },
-
- children: function(element) {
- var children = [];
- forEach(element.childNodes, function(element) {
- if (element.nodeType === NODE_TYPE_ELEMENT) {
- children.push(element);
- }
- });
- return children;
- },
-
- contents: function(element) {
- return element.contentDocument || element.childNodes || [];
- },
-
- append: function(element, node) {
- var nodeType = element.nodeType;
- if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
-
- node = new JQLite(node);
-
- for (var i = 0, ii = node.length; i < ii; i++) {
- var child = node[i];
- element.appendChild(child);
- }
- },
-
- prepend: function(element, node) {
- if (element.nodeType === NODE_TYPE_ELEMENT) {
- var index = element.firstChild;
- forEach(new JQLite(node), function(child) {
- element.insertBefore(child, index);
- });
- }
- },
-
- wrap: function(element, wrapNode) {
- jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
- },
-
- remove: jqLiteRemove,
-
- detach: function(element) {
- jqLiteRemove(element, true);
- },
-
- after: function(element, newElement) {
- var index = element, parent = element.parentNode;
- newElement = new JQLite(newElement);
-
- for (var i = 0, ii = newElement.length; i < ii; i++) {
- var node = newElement[i];
- parent.insertBefore(node, index.nextSibling);
- index = node;
- }
- },
-
- addClass: jqLiteAddClass,
- removeClass: jqLiteRemoveClass,
-
- toggleClass: function(element, selector, condition) {
- if (selector) {
- forEach(selector.split(' '), function(className) {
- var classCondition = condition;
- if (isUndefined(classCondition)) {
- classCondition = !jqLiteHasClass(element, className);
- }
- (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
- });
- }
- },
-
- parent: function(element) {
- var parent = element.parentNode;
- return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
- },
-
- next: function(element) {
- return element.nextElementSibling;
- },
-
- find: function(element, selector) {
- if (element.getElementsByTagName) {
- return element.getElementsByTagName(selector);
- } else {
- return [];
- }
- },
-
- clone: jqLiteClone,
-
- triggerHandler: function(element, event, extraParameters) {
-
- var dummyEvent, eventFnsCopy, handlerArgs;
- var eventName = event.type || event;
- var expandoStore = jqLiteExpandoStore(element);
- var events = expandoStore && expandoStore.events;
- var eventFns = events && events[eventName];
-
- if (eventFns) {
- // Create a dummy event to pass to the handlers
- dummyEvent = {
- preventDefault: function() { this.defaultPrevented = true; },
- isDefaultPrevented: function() { return this.defaultPrevented === true; },
- stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
- isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
- stopPropagation: noop,
- type: eventName,
- target: element
- };
-
- // If a custom event was provided then extend our dummy event with it
- if (event.type) {
- dummyEvent = extend(dummyEvent, event);
- }
-
- // Copy event handlers in case event handlers array is modified during execution.
- eventFnsCopy = shallowCopy(eventFns);
- handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
-
- forEach(eventFnsCopy, function(fn) {
- if (!dummyEvent.isImmediatePropagationStopped()) {
- fn.apply(element, handlerArgs);
- }
- });
- }
- }
-}, function(fn, name) {
- /**
- * chaining functions
- */
- JQLite.prototype[name] = function(arg1, arg2, arg3) {
- var value;
-
- for (var i = 0, ii = this.length; i < ii; i++) {
- if (isUndefined(value)) {
- value = fn(this[i], arg1, arg2, arg3);
- if (isDefined(value)) {
- // any function which returns a value needs to be wrapped
- value = jqLite(value);
- }
- } else {
- jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
- }
- }
- return isDefined(value) ? value : this;
- };
-
- // bind legacy bind/unbind to on/off
- JQLite.prototype.bind = JQLite.prototype.on;
- JQLite.prototype.unbind = JQLite.prototype.off;
-});
-
-
-// Provider for private $$jqLite service
-function $$jqLiteProvider() {
- this.$get = function $$jqLite() {
- return extend(JQLite, {
- hasClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteHasClass(node, classes);
- },
- addClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteAddClass(node, classes);
- },
- removeClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteRemoveClass(node, classes);
- }
- });
- };
-}
-
-/**
- * Computes a hash of an 'obj'.
- * Hash of a:
- * string is string
- * number is number as string
- * object is either result of calling $$hashKey function on the object or uniquely generated id,
- * that is also assigned to the $$hashKey property of the object.
- *
- * @param obj
- * @returns {string} hash string such that the same input will have the same hash string.
- * The resulting string key is in 'type:hashKey' format.
- */
-function hashKey(obj, nextUidFn) {
- var key = obj && obj.$$hashKey;
-
- if (key) {
- if (typeof key === 'function') {
- key = obj.$$hashKey();
- }
- return key;
- }
-
- var objType = typeof obj;
- if (objType == 'function' || (objType == 'object' && obj !== null)) {
- key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
- } else {
- key = objType + ':' + obj;
- }
-
- return key;
-}
-
-/**
- * HashMap which can use objects as keys
- */
-function HashMap(array, isolatedUid) {
- if (isolatedUid) {
- var uid = 0;
- this.nextUid = function() {
- return ++uid;
- };
- }
- forEach(array, this.put, this);
-}
-HashMap.prototype = {
- /**
- * Store key value pair
- * @param key key to store can be any type
- * @param value value to store can be any type
- */
- put: function(key, value) {
- this[hashKey(key, this.nextUid)] = value;
- },
-
- /**
- * @param key
- * @returns {Object} the value for the key
- */
- get: function(key) {
- return this[hashKey(key, this.nextUid)];
- },
-
- /**
- * Remove the key/value pair
- * @param key
- */
- remove: function(key) {
- var value = this[key = hashKey(key, this.nextUid)];
- delete this[key];
- return value;
- }
-};
-
-var $$HashMapProvider = [function() {
- this.$get = [function() {
- return HashMap;
- }];
-}];
-
-/**
- * @ngdoc function
- * @module ng
- * @name angular.injector
- * @kind function
- *
- * @description
- * Creates an injector object that can be used for retrieving services as well as for
- * dependency injection (see {@link guide/di dependency injection}).
- *
- * @param {Array.} modules A list of module functions or their aliases. See
- * {@link angular.module}. The `ng` module must be explicitly added.
- * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
- * disallows argument name annotation inference.
- * @returns {injector} Injector object. See {@link auto.$injector $injector}.
- *
- * @example
- * Typical usage
- * ```js
- * // create an injector
- * var $injector = angular.injector(['ng']);
- *
- * // use the injector to kick off your application
- * // use the type inference to auto inject arguments, or use implicit injection
- * $injector.invoke(function($rootScope, $compile, $document) {
- * $compile($document)($rootScope);
- * $rootScope.$digest();
- * });
- * ```
- *
- * Sometimes you want to get access to the injector of a currently running Angular app
- * from outside Angular. Perhaps, you want to inject and compile some markup after the
- * application has been bootstrapped. You can do this using the extra `injector()` added
- * to JQuery/jqLite elements. See {@link angular.element}.
- *
- * *This is fairly rare but could be the case if a third party library is injecting the
- * markup.*
- *
- * In the following example a new block of HTML containing a `ng-controller`
- * directive is added to the end of the document body by JQuery. We then compile and link
- * it into the current AngularJS scope.
- *
- * ```js
- * var $div = $('
{{content.label}}
');
- * $(document.body).append($div);
- *
- * angular.element(document).injector().invoke(function($compile) {
- * var scope = angular.element($div).scope();
- * $compile($div)(scope);
- * });
- * ```
- */
-
-
-/**
- * @ngdoc module
- * @name auto
- * @installation
- * @description
- *
- * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
- */
-
-var ARROW_ARG = /^([^\(]+?)=>/;
-var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
-var FN_ARG_SPLIT = /,/;
-var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
-var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
-var $injectorMinErr = minErr('$injector');
-
-function stringifyFn(fn) {
- // Support: Chrome 50-51 only
- // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
- // (See https://github.com/angular/angular.js/issues/14487.)
- // TODO (gkalpak): Remove workaround when Chrome v52 is released
- return Function.prototype.toString.call(fn) + ' ';
-}
-
-function extractArgs(fn) {
- var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
- args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
- return args;
-}
-
-function anonFn(fn) {
- // For anonymous functions, showing at the very least the function signature can help in
- // debugging.
- var args = extractArgs(fn);
- if (args) {
- return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
- }
- return 'fn';
-}
-
-function annotate(fn, strictDi, name) {
- var $inject,
- argDecl,
- last;
-
- if (typeof fn === 'function') {
- if (!($inject = fn.$inject)) {
- $inject = [];
- if (fn.length) {
- if (strictDi) {
- if (!isString(name) || !name) {
- name = fn.name || anonFn(fn);
- }
- throw $injectorMinErr('strictdi',
- '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
- }
- argDecl = extractArgs(fn);
- forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
- arg.replace(FN_ARG, function(all, underscore, name) {
- $inject.push(name);
- });
- });
- }
- fn.$inject = $inject;
- }
- } else if (isArray(fn)) {
- last = fn.length - 1;
- assertArgFn(fn[last], 'fn');
- $inject = fn.slice(0, last);
- } else {
- assertArgFn(fn, 'fn', true);
- }
- return $inject;
-}
-
-///////////////////////////////////////
-
-/**
- * @ngdoc service
- * @name $injector
- *
- * @description
- *
- * `$injector` is used to retrieve object instances as defined by
- * {@link auto.$provide provider}, instantiate types, invoke methods,
- * and load modules.
- *
- * The following always holds true:
- *
- * ```js
- * var $injector = angular.injector();
- * expect($injector.get('$injector')).toBe($injector);
- * expect($injector.invoke(function($injector) {
- * return $injector;
- * })).toBe($injector);
- * ```
- *
- * # Injection Function Annotation
- *
- * JavaScript does not have annotations, and annotations are needed for dependency injection. The
- * following are all valid ways of annotating function with injection arguments and are equivalent.
- *
- * ```js
- * // inferred (only works if code not minified/obfuscated)
- * $injector.invoke(function(serviceA){});
- *
- * // annotated
- * function explicit(serviceA) {};
- * explicit.$inject = ['serviceA'];
- * $injector.invoke(explicit);
- *
- * // inline
- * $injector.invoke(['serviceA', function(serviceA){}]);
- * ```
- *
- * ## Inference
- *
- * In JavaScript calling `toString()` on a function returns the function definition. The definition
- * can then be parsed and the function arguments can be extracted. This method of discovering
- * annotations is disallowed when the injector is in strict mode.
- * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
- * argument names.
- *
- * ## `$inject` Annotation
- * By adding an `$inject` property onto a function the injection parameters can be specified.
- *
- * ## Inline
- * As an array of injection names, where the last item in the array is the function to call.
- */
-
-/**
- * @ngdoc method
- * @name $injector#get
- *
- * @description
- * Return an instance of the service.
- *
- * @param {string} name The name of the instance to retrieve.
- * @param {string=} caller An optional string to provide the origin of the function call for error messages.
- * @return {*} The instance.
- */
-
-/**
- * @ngdoc method
- * @name $injector#invoke
- *
- * @description
- * Invoke the method and supply the method arguments from the `$injector`.
- *
- * @param {Function|Array.} fn The injectable function to invoke. Function parameters are
- * injected according to the {@link guide/di $inject Annotation} rules.
- * @param {Object=} self The `this` for the invoked method.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {*} the value returned by the invoked `fn` function.
- */
-
-/**
- * @ngdoc method
- * @name $injector#has
- *
- * @description
- * Allows the user to query if the particular service exists.
- *
- * @param {string} name Name of the service to query.
- * @returns {boolean} `true` if injector has given service.
- */
-
-/**
- * @ngdoc method
- * @name $injector#instantiate
- * @description
- * Create a new instance of JS type. The method takes a constructor function, invokes the new
- * operator, and supplies all of the arguments to the constructor function as specified by the
- * constructor annotation.
- *
- * @param {Function} Type Annotated constructor function.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {Object} new instance of `Type`.
- */
-
-/**
- * @ngdoc method
- * @name $injector#annotate
- *
- * @description
- * Returns an array of service names which the function is requesting for injection. This API is
- * used by the injector to determine which services need to be injected into the function when the
- * function is invoked. There are three ways in which the function can be annotated with the needed
- * dependencies.
- *
- * # Argument names
- *
- * The simplest form is to extract the dependencies from the arguments of the function. This is done
- * by converting the function into a string using `toString()` method and extracting the argument
- * names.
- * ```js
- * // Given
- * function MyController($scope, $route) {
- * // ...
- * }
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * ```
- *
- * You can disallow this method by using strict injection mode.
- *
- * This method does not work with code minification / obfuscation. For this reason the following
- * annotation strategies are supported.
- *
- * # The `$inject` property
- *
- * If a function has an `$inject` property and its value is an array of strings, then the strings
- * represent names of services to be injected into the function.
- * ```js
- * // Given
- * var MyController = function(obfuscatedScope, obfuscatedRoute) {
- * // ...
- * }
- * // Define function dependencies
- * MyController['$inject'] = ['$scope', '$route'];
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * ```
- *
- * # The array notation
- *
- * It is often desirable to inline Injected functions and that's when setting the `$inject` property
- * is very inconvenient. In these situations using the array notation to specify the dependencies in
- * a way that survives minification is a better choice:
- *
- * ```js
- * // We wish to write this (not minification / obfuscation safe)
- * injector.invoke(function($compile, $rootScope) {
- * // ...
- * });
- *
- * // We are forced to write break inlining
- * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
- * // ...
- * };
- * tmpFn.$inject = ['$compile', '$rootScope'];
- * injector.invoke(tmpFn);
- *
- * // To better support inline function the inline annotation is supported
- * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
- * // ...
- * }]);
- *
- * // Therefore
- * expect(injector.annotate(
- * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
- * ).toEqual(['$compile', '$rootScope']);
- * ```
- *
- * @param {Function|Array.} fn Function for which dependent service names need to
- * be retrieved as described above.
- *
- * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
- *
- * @returns {Array.} The names of the services which the function requires.
- */
-
-
-
-
-/**
- * @ngdoc service
- * @name $provide
- *
- * @description
- *
- * The {@link auto.$provide $provide} service has a number of methods for registering components
- * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
- * {@link angular.Module}.
- *
- * An Angular **service** is a singleton object created by a **service factory**. These **service
- * factories** are functions which, in turn, are created by a **service provider**.
- * The **service providers** are constructor functions. When instantiated they must contain a
- * property called `$get`, which holds the **service factory** function.
- *
- * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
- * correct **service provider**, instantiating it and then calling its `$get` **service factory**
- * function to get the instance of the **service**.
- *
- * Often services have no configuration options and there is no need to add methods to the service
- * provider. The provider will be no more than a constructor function with a `$get` property. For
- * these cases the {@link auto.$provide $provide} service has additional helper methods to register
- * services without specifying a provider.
- *
- * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
- * {@link auto.$injector $injector}
- * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
- * providers and services.
- * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
- * services, not providers.
- * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
- * that will be wrapped in a **service provider** object, whose `$get` property will contain the
- * given factory function.
- * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
- * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
- * a new object using the given constructor function.
- * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
- * will be able to modify or replace the implementation of another service.
- *
- * See the individual methods for more information and examples.
- */
-
-/**
- * @ngdoc method
- * @name $provide#provider
- * @description
- *
- * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
- * are constructor functions, whose instances are responsible for "providing" a factory for a
- * service.
- *
- * Service provider names start with the name of the service they provide followed by `Provider`.
- * For example, the {@link ng.$log $log} service has a provider called
- * {@link ng.$logProvider $logProvider}.
- *
- * Service provider objects can have additional methods which allow configuration of the provider
- * and its service. Importantly, you can configure what kind of service is created by the `$get`
- * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
- * method {@link ng.$logProvider#debugEnabled debugEnabled}
- * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
- * console or not.
- *
- * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
- 'Provider'` key.
- * @param {(Object|function())} provider If the provider is:
- *
- * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
- * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
- * - `Constructor`: a new instance of the provider will be created using
- * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
- *
- * @returns {Object} registered provider instance
-
- * @example
- *
- * The following example shows how to create a simple event tracking service and register it using
- * {@link auto.$provide#provider $provide.provider()}.
- *
- * ```js
- * // Define the eventTracker provider
- * function EventTrackerProvider() {
- * var trackingUrl = '/track';
- *
- * // A provider method for configuring where the tracked events should been saved
- * this.setTrackingUrl = function(url) {
- * trackingUrl = url;
- * };
- *
- * // The service factory function
- * this.$get = ['$http', function($http) {
- * var trackedEvents = {};
- * return {
- * // Call this to track an event
- * event: function(event) {
- * var count = trackedEvents[event] || 0;
- * count += 1;
- * trackedEvents[event] = count;
- * return count;
- * },
- * // Call this to save the tracked events to the trackingUrl
- * save: function() {
- * $http.post(trackingUrl, trackedEvents);
- * }
- * };
- * }];
- * }
- *
- * describe('eventTracker', function() {
- * var postSpy;
- *
- * beforeEach(module(function($provide) {
- * // Register the eventTracker provider
- * $provide.provider('eventTracker', EventTrackerProvider);
- * }));
- *
- * beforeEach(module(function(eventTrackerProvider) {
- * // Configure eventTracker provider
- * eventTrackerProvider.setTrackingUrl('/custom-track');
- * }));
- *
- * it('tracks events', inject(function(eventTracker) {
- * expect(eventTracker.event('login')).toEqual(1);
- * expect(eventTracker.event('login')).toEqual(2);
- * }));
- *
- * it('saves to the tracking url', inject(function(eventTracker, $http) {
- * postSpy = spyOn($http, 'post');
- * eventTracker.event('login');
- * eventTracker.save();
- * expect(postSpy).toHaveBeenCalled();
- * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
- * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
- * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
- * }));
- * });
- * ```
- */
-
-/**
- * @ngdoc method
- * @name $provide#factory
- * @description
- *
- * Register a **service factory**, which will be called to return the service instance.
- * This is short for registering a service where its provider consists of only a `$get` property,
- * which is the given service factory function.
- * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
- * configure your service in a provider.
- *
- * @param {string} name The name of the instance.
- * @param {Function|Array.} $getFn The injectable $getFn for the instance creation.
- * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service
- * ```js
- * $provide.factory('ping', ['$http', function($http) {
- * return function ping() {
- * return $http.send('/ping');
- * };
- * }]);
- * ```
- * You would then inject and use this service like this:
- * ```js
- * someModule.controller('Ctrl', ['ping', function(ping) {
- * ping();
- * }]);
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#service
- * @description
- *
- * Register a **service constructor**, which will be invoked with `new` to create the service
- * instance.
- * This is short for registering a service where its provider's `$get` property is a factory
- * function that returns an instance instantiated by the injector from the service constructor
- * function.
- *
- * Internally it looks a bit like this:
- *
- * ```
- * {
- * $get: function() {
- * return $injector.instantiate(constructor);
- * }
- * }
- * ```
- *
- *
- * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
- * as a type/class.
- *
- * @param {string} name The name of the instance.
- * @param {Function|Array.} constructor An injectable class (constructor function)
- * that will be instantiated.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service using
- * {@link auto.$provide#service $provide.service(class)}.
- * ```js
- * var Ping = function($http) {
- * this.$http = $http;
- * };
- *
- * Ping.$inject = ['$http'];
- *
- * Ping.prototype.send = function() {
- * return this.$http.get('/ping');
- * };
- * $provide.service('ping', Ping);
- * ```
- * You would then inject and use this service like this:
- * ```js
- * someModule.controller('Ctrl', ['ping', function(ping) {
- * ping.send();
- * }]);
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#value
- * @description
- *
- * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
- * number, an array, an object or a function. This is short for registering a service where its
- * provider's `$get` property is a factory function that takes no arguments and returns the **value
- * service**. That also means it is not possible to inject other services into a value service.
- *
- * Value services are similar to constant services, except that they cannot be injected into a
- * module configuration function (see {@link angular.Module#config}) but they can be overridden by
- * an Angular {@link auto.$provide#decorator decorator}.
- *
- * @param {string} name The name of the instance.
- * @param {*} value The value.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here are some examples of creating value services.
- * ```js
- * $provide.value('ADMIN_USER', 'admin');
- *
- * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
- *
- * $provide.value('halfOf', function(value) {
- * return value / 2;
- * });
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#constant
- * @description
- *
- * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
- * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
- * possible to inject other services into a constant.
- *
- * But unlike {@link auto.$provide#value value}, a constant can be
- * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
- * be overridden by an Angular {@link auto.$provide#decorator decorator}.
- *
- * @param {string} name The name of the constant.
- * @param {*} value The constant value.
- * @returns {Object} registered instance
- *
- * @example
- * Here a some examples of creating constants:
- * ```js
- * $provide.constant('SHARD_HEIGHT', 306);
- *
- * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
- *
- * $provide.constant('double', function(value) {
- * return value * 2;
- * });
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#decorator
- * @description
- *
- * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
- * intercepts the creation of a service, allowing it to override or modify the behavior of the
- * service. The return value of the decorator function may be the original service, or a new service
- * that replaces (or wraps and delegates to) the original service.
- *
- * You can find out more about using decorators in the {@link guide/decorators} guide.
- *
- * @param {string} name The name of the service to decorate.
- * @param {Function|Array.} decorator This function will be invoked when the service needs to be
- * provided and should return the decorated service instance. The function is called using
- * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
- * Local injection arguments:
- *
- * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
- * decorated or delegated to.
- *
- * @example
- * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
- * calls to {@link ng.$log#error $log.warn()}.
- * ```js
- * $provide.decorator('$log', ['$delegate', function($delegate) {
- * $delegate.warn = $delegate.error;
- * return $delegate;
- * }]);
- * ```
- */
-
-
-function createInjector(modulesToLoad, strictDi) {
- strictDi = (strictDi === true);
- var INSTANTIATING = {},
- providerSuffix = 'Provider',
- path = [],
- loadedModules = new HashMap([], true),
- providerCache = {
- $provide: {
- provider: supportObject(provider),
- factory: supportObject(factory),
- service: supportObject(service),
- value: supportObject(value),
- constant: supportObject(constant),
- decorator: decorator
- }
- },
- providerInjector = (providerCache.$injector =
- createInternalInjector(providerCache, function(serviceName, caller) {
- if (angular.isString(caller)) {
- path.push(caller);
- }
- throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
- })),
- instanceCache = {},
- protoInstanceInjector =
- createInternalInjector(instanceCache, function(serviceName, caller) {
- var provider = providerInjector.get(serviceName + providerSuffix, caller);
- return instanceInjector.invoke(
- provider.$get, provider, undefined, serviceName);
- }),
- instanceInjector = protoInstanceInjector;
-
- providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
- var runBlocks = loadModules(modulesToLoad);
- instanceInjector = protoInstanceInjector.get('$injector');
- instanceInjector.strictDi = strictDi;
- forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
-
- return instanceInjector;
-
- ////////////////////////////////////
- // $provider
- ////////////////////////////////////
-
- function supportObject(delegate) {
- return function(key, value) {
- if (isObject(key)) {
- forEach(key, reverseParams(delegate));
- } else {
- return delegate(key, value);
- }
- };
- }
-
- function provider(name, provider_) {
- assertNotHasOwnProperty(name, 'service');
- if (isFunction(provider_) || isArray(provider_)) {
- provider_ = providerInjector.instantiate(provider_);
- }
- if (!provider_.$get) {
- throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
- }
- return providerCache[name + providerSuffix] = provider_;
- }
-
- function enforceReturnValue(name, factory) {
- return function enforcedReturnValue() {
- var result = instanceInjector.invoke(factory, this);
- if (isUndefined(result)) {
- throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
- }
- return result;
- };
- }
-
- function factory(name, factoryFn, enforce) {
- return provider(name, {
- $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
- });
- }
-
- function service(name, constructor) {
- return factory(name, ['$injector', function($injector) {
- return $injector.instantiate(constructor);
- }]);
- }
-
- function value(name, val) { return factory(name, valueFn(val), false); }
-
- function constant(name, value) {
- assertNotHasOwnProperty(name, 'constant');
- providerCache[name] = value;
- instanceCache[name] = value;
- }
-
- function decorator(serviceName, decorFn) {
- var origProvider = providerInjector.get(serviceName + providerSuffix),
- orig$get = origProvider.$get;
-
- origProvider.$get = function() {
- var origInstance = instanceInjector.invoke(orig$get, origProvider);
- return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
- };
- }
-
- ////////////////////////////////////
- // Module Loading
- ////////////////////////////////////
- function loadModules(modulesToLoad) {
- assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
- var runBlocks = [], moduleFn;
- forEach(modulesToLoad, function(module) {
- if (loadedModules.get(module)) return;
- loadedModules.put(module, true);
-
- function runInvokeQueue(queue) {
- var i, ii;
- for (i = 0, ii = queue.length; i < ii; i++) {
- var invokeArgs = queue[i],
- provider = providerInjector.get(invokeArgs[0]);
-
- provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
- }
- }
-
- try {
- if (isString(module)) {
- moduleFn = angularModule(module);
- runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
- runInvokeQueue(moduleFn._invokeQueue);
- runInvokeQueue(moduleFn._configBlocks);
- } else if (isFunction(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else if (isArray(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else {
- assertArgFn(module, 'module');
- }
- } catch (e) {
- if (isArray(module)) {
- module = module[module.length - 1];
- }
- if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
- // Safari & FF's stack traces don't contain error.message content
- // unlike those of Chrome and IE
- // So if stack doesn't contain message, we create a new string that contains both.
- // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
- /* jshint -W022 */
- e = e.message + '\n' + e.stack;
- }
- throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
- module, e.stack || e.message || e);
- }
- });
- return runBlocks;
- }
-
- ////////////////////////////////////
- // internal Injector
- ////////////////////////////////////
-
- function createInternalInjector(cache, factory) {
-
- function getService(serviceName, caller) {
- if (cache.hasOwnProperty(serviceName)) {
- if (cache[serviceName] === INSTANTIATING) {
- throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
- serviceName + ' <- ' + path.join(' <- '));
- }
- return cache[serviceName];
- } else {
- try {
- path.unshift(serviceName);
- cache[serviceName] = INSTANTIATING;
- return cache[serviceName] = factory(serviceName, caller);
- } catch (err) {
- if (cache[serviceName] === INSTANTIATING) {
- delete cache[serviceName];
- }
- throw err;
- } finally {
- path.shift();
- }
- }
- }
-
-
- function injectionArgs(fn, locals, serviceName) {
- var args = [],
- $inject = createInjector.$$annotate(fn, strictDi, serviceName);
-
- for (var i = 0, length = $inject.length; i < length; i++) {
- var key = $inject[i];
- if (typeof key !== 'string') {
- throw $injectorMinErr('itkn',
- 'Incorrect injection token! Expected service name as string, got {0}', key);
- }
- args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
- getService(key, serviceName));
- }
- return args;
- }
-
- function isClass(func) {
- // IE 9-11 do not support classes and IE9 leaks with the code below.
- if (msie <= 11) {
- return false;
- }
- // Support: Edge 12-13 only
- // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
- return typeof func === 'function'
- && /^(?:class\b|constructor\()/.test(stringifyFn(func));
- }
-
- function invoke(fn, self, locals, serviceName) {
- if (typeof locals === 'string') {
- serviceName = locals;
- locals = null;
- }
-
- var args = injectionArgs(fn, locals, serviceName);
- if (isArray(fn)) {
- fn = fn[fn.length - 1];
- }
-
- if (!isClass(fn)) {
- // http://jsperf.com/angularjs-invoke-apply-vs-switch
- // #5388
- return fn.apply(self, args);
- } else {
- args.unshift(null);
- return new (Function.prototype.bind.apply(fn, args))();
- }
- }
-
-
- function instantiate(Type, locals, serviceName) {
- // Check if Type is annotated and use just the given function at n-1 as parameter
- // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
- var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
- var args = injectionArgs(Type, locals, serviceName);
- // Empty object at position 0 is ignored for invocation with `new`, but required.
- args.unshift(null);
- return new (Function.prototype.bind.apply(ctor, args))();
- }
-
-
- return {
- invoke: invoke,
- instantiate: instantiate,
- get: getService,
- annotate: createInjector.$$annotate,
- has: function(name) {
- return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
- }
- };
- }
-}
-
-createInjector.$$annotate = annotate;
-
-/**
- * @ngdoc provider
- * @name $anchorScrollProvider
- *
- * @description
- * Use `$anchorScrollProvider` to disable automatic scrolling whenever
- * {@link ng.$location#hash $location.hash()} changes.
- */
-function $AnchorScrollProvider() {
-
- var autoScrollingEnabled = true;
-
- /**
- * @ngdoc method
- * @name $anchorScrollProvider#disableAutoScrolling
- *
- * @description
- * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
- * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
- * Use this method to disable automatic scrolling.
- *
- * If automatic scrolling is disabled, one must explicitly call
- * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
- * current hash.
- */
- this.disableAutoScrolling = function() {
- autoScrollingEnabled = false;
- };
-
- /**
- * @ngdoc service
- * @name $anchorScroll
- * @kind function
- * @requires $window
- * @requires $location
- * @requires $rootScope
- *
- * @description
- * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
- * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
- * in the
- * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
- *
- * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
- * match any anchor whenever it changes. This can be disabled by calling
- * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
- *
- * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
- * vertical scroll-offset (either fixed or dynamic).
- *
- * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
- * {@link ng.$location#hash $location.hash()} will be used.
- *
- * @property {(number|function|jqLite)} yOffset
- * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
- * positioned elements at the top of the page, such as navbars, headers etc.
- *
- * `yOffset` can be specified in various ways:
- * - **number**: A fixed number of pixels to be used as offset.
- * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
- * a number representing the offset (in pixels).
- * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
- * the top of the page to the element's bottom will be used as offset.
- * **Note**: The element will be taken into account only as long as its `position` is set to
- * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
- * their height and/or positioning according to the viewport's size.
- *
- *
- *
- * In order for `yOffset` to work properly, scrolling should take place on the document's root and
- * not some child element.
- *
-
-
- angular.module('anchorScrollOffsetExample', [])
- .run(['$anchorScroll', function($anchorScroll) {
- $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
- }])
- .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
- function ($anchorScroll, $location, $scope) {
- $scope.gotoAnchor = function(x) {
- var newHash = 'anchor' + x;
- if ($location.hash() !== newHash) {
- // set the $location.hash to `newHash` and
- // $anchorScroll will automatically scroll to it
- $location.hash('anchor' + x);
- } else {
- // call $anchorScroll() explicitly,
- // since $location.hash hasn't changed
- $anchorScroll();
- }
- };
- }
- ]);
-
-
- body {
- padding-top: 50px;
- }
-
- .anchor {
- border: 2px dashed DarkOrchid;
- padding: 10px 10px 200px 10px;
- }
-
- .fixed-header {
- background-color: rgba(0, 0, 0, 0.2);
- height: 50px;
- position: fixed;
- top: 0; left: 0; right: 0;
- }
-
- .fixed-header > a {
- display: inline-block;
- margin: 5px 15px;
- }
-
-
- */
- this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
- var document = $window.document;
-
- // Helper function to get first anchor from a NodeList
- // (using `Array#some()` instead of `angular#forEach()` since it's more performant
- // and working in all supported browsers.)
- function getFirstAnchor(list) {
- var result = null;
- Array.prototype.some.call(list, function(element) {
- if (nodeName_(element) === 'a') {
- result = element;
- return true;
- }
- });
- return result;
- }
-
- function getYOffset() {
-
- var offset = scroll.yOffset;
-
- if (isFunction(offset)) {
- offset = offset();
- } else if (isElement(offset)) {
- var elem = offset[0];
- var style = $window.getComputedStyle(elem);
- if (style.position !== 'fixed') {
- offset = 0;
- } else {
- offset = elem.getBoundingClientRect().bottom;
- }
- } else if (!isNumber(offset)) {
- offset = 0;
- }
-
- return offset;
- }
-
- function scrollTo(elem) {
- if (elem) {
- elem.scrollIntoView();
-
- var offset = getYOffset();
-
- if (offset) {
- // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
- // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
- // top of the viewport.
- //
- // IF the number of pixels from the top of `elem` to the end of the page's content is less
- // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
- // way down the page.
- //
- // This is often the case for elements near the bottom of the page.
- //
- // In such cases we do not need to scroll the whole `offset` up, just the difference between
- // the top of the element and the offset, which is enough to align the top of `elem` at the
- // desired position.
- var elemTop = elem.getBoundingClientRect().top;
- $window.scrollBy(0, elemTop - offset);
- }
- } else {
- $window.scrollTo(0, 0);
- }
- }
-
- function scroll(hash) {
- hash = isString(hash) ? hash : $location.hash();
- var elm;
-
- // empty hash, scroll to the top of the page
- if (!hash) scrollTo(null);
-
- // element with given id
- else if ((elm = document.getElementById(hash))) scrollTo(elm);
-
- // first anchor with given name :-D
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
-
- // no element and hash == 'top', scroll to the top of the page
- else if (hash === 'top') scrollTo(null);
- }
-
- // does not scroll when user clicks on anchor link that is currently on
- // (no url change, no $location.hash() change), browser native does scroll
- if (autoScrollingEnabled) {
- $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
- function autoScrollWatchAction(newVal, oldVal) {
- // skip the initial scroll if $location.hash is empty
- if (newVal === oldVal && newVal === '') return;
-
- jqLiteDocumentLoaded(function() {
- $rootScope.$evalAsync(scroll);
- });
- });
- }
-
- return scroll;
- }];
-}
-
-var $animateMinErr = minErr('$animate');
-var ELEMENT_NODE = 1;
-var NG_ANIMATE_CLASSNAME = 'ng-animate';
-
-function mergeClasses(a,b) {
- if (!a && !b) return '';
- if (!a) return b;
- if (!b) return a;
- if (isArray(a)) a = a.join(' ');
- if (isArray(b)) b = b.join(' ');
- return a + ' ' + b;
-}
-
-function extractElementNode(element) {
- for (var i = 0; i < element.length; i++) {
- var elm = element[i];
- if (elm.nodeType === ELEMENT_NODE) {
- return elm;
- }
- }
-}
-
-function splitClasses(classes) {
- if (isString(classes)) {
- classes = classes.split(' ');
- }
-
- // Use createMap() to prevent class assumptions involving property names in
- // Object.prototype
- var obj = createMap();
- forEach(classes, function(klass) {
- // sometimes the split leaves empty string values
- // incase extra spaces were applied to the options
- if (klass.length) {
- obj[klass] = true;
- }
- });
- return obj;
-}
-
-// if any other type of options value besides an Object value is
-// passed into the $animate.method() animation then this helper code
-// will be run which will ignore it. While this patch is not the
-// greatest solution to this, a lot of existing plugins depend on
-// $animate to either call the callback (< 1.2) or return a promise
-// that can be changed. This helper function ensures that the options
-// are wiped clean incase a callback function is provided.
-function prepareAnimateOptions(options) {
- return isObject(options)
- ? options
- : {};
-}
-
-var $$CoreAnimateJsProvider = function() {
- this.$get = noop;
-};
-
-// this is prefixed with Core since it conflicts with
-// the animateQueueProvider defined in ngAnimate/animateQueue.js
-var $$CoreAnimateQueueProvider = function() {
- var postDigestQueue = new HashMap();
- var postDigestElements = [];
-
- this.$get = ['$$AnimateRunner', '$rootScope',
- function($$AnimateRunner, $rootScope) {
- return {
- enabled: noop,
- on: noop,
- off: noop,
- pin: noop,
-
- push: function(element, event, options, domOperation) {
- domOperation && domOperation();
-
- options = options || {};
- options.from && element.css(options.from);
- options.to && element.css(options.to);
-
- if (options.addClass || options.removeClass) {
- addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
- }
-
- var runner = new $$AnimateRunner(); // jshint ignore:line
-
- // since there are no animations to run the runner needs to be
- // notified that the animation call is complete.
- runner.complete();
- return runner;
- }
- };
-
-
- function updateData(data, classes, value) {
- var changed = false;
- if (classes) {
- classes = isString(classes) ? classes.split(' ') :
- isArray(classes) ? classes : [];
- forEach(classes, function(className) {
- if (className) {
- changed = true;
- data[className] = value;
- }
- });
- }
- return changed;
- }
-
- function handleCSSClassChanges() {
- forEach(postDigestElements, function(element) {
- var data = postDigestQueue.get(element);
- if (data) {
- var existing = splitClasses(element.attr('class'));
- var toAdd = '';
- var toRemove = '';
- forEach(data, function(status, className) {
- var hasClass = !!existing[className];
- if (status !== hasClass) {
- if (status) {
- toAdd += (toAdd.length ? ' ' : '') + className;
- } else {
- toRemove += (toRemove.length ? ' ' : '') + className;
- }
- }
- });
-
- forEach(element, function(elm) {
- toAdd && jqLiteAddClass(elm, toAdd);
- toRemove && jqLiteRemoveClass(elm, toRemove);
- });
- postDigestQueue.remove(element);
- }
- });
- postDigestElements.length = 0;
- }
-
-
- function addRemoveClassesPostDigest(element, add, remove) {
- var data = postDigestQueue.get(element) || {};
-
- var classesAdded = updateData(data, add, true);
- var classesRemoved = updateData(data, remove, false);
-
- if (classesAdded || classesRemoved) {
-
- postDigestQueue.put(element, data);
- postDigestElements.push(element);
-
- if (postDigestElements.length === 1) {
- $rootScope.$$postDigest(handleCSSClassChanges);
- }
- }
- }
- }];
-};
-
-/**
- * @ngdoc provider
- * @name $animateProvider
- *
- * @description
- * Default implementation of $animate that doesn't perform any animations, instead just
- * synchronously performs DOM updates and resolves the returned runner promise.
- *
- * In order to enable animations the `ngAnimate` module has to be loaded.
- *
- * To see the functional implementation check out `src/ngAnimate/animate.js`.
- */
-var $AnimateProvider = ['$provide', function($provide) {
- var provider = this;
-
- this.$$registeredAnimations = Object.create(null);
-
- /**
- * @ngdoc method
- * @name $animateProvider#register
- *
- * @description
- * Registers a new injectable animation factory function. The factory function produces the
- * animation object which contains callback functions for each event that is expected to be
- * animated.
- *
- * * `eventFn`: `function(element, ... , doneFunction, options)`
- * The element to animate, the `doneFunction` and the options fed into the animation. Depending
- * on the type of animation additional arguments will be injected into the animation function. The
- * list below explains the function signatures for the different animation methods:
- *
- * - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
- * - addClass: function(element, addedClasses, doneFunction, options)
- * - removeClass: function(element, removedClasses, doneFunction, options)
- * - enter, leave, move: function(element, doneFunction, options)
- * - animate: function(element, fromStyles, toStyles, doneFunction, options)
- *
- * Make sure to trigger the `doneFunction` once the animation is fully complete.
- *
- * ```js
- * return {
- * //enter, leave, move signature
- * eventFn : function(element, done, options) {
- * //code to run the animation
- * //once complete, then run done()
- * return function endFunction(wasCancelled) {
- * //code to cancel the animation
- * }
- * }
- * }
- * ```
- *
- * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
- * @param {Function} factory The factory function that will be executed to return the animation
- * object.
- */
- this.register = function(name, factory) {
- if (name && name.charAt(0) !== '.') {
- throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
- }
-
- var key = name + '-animation';
- provider.$$registeredAnimations[name.substr(1)] = key;
- $provide.factory(key, factory);
- };
-
- /**
- * @ngdoc method
- * @name $animateProvider#classNameFilter
- *
- * @description
- * Sets and/or returns the CSS class regular expression that is checked when performing
- * an animation. Upon bootstrap the classNameFilter value is not set at all and will
- * therefore enable $animate to attempt to perform an animation on any element that is triggered.
- * When setting the `classNameFilter` value, animations will only be performed on elements
- * that successfully match the filter expression. This in turn can boost performance
- * for low-powered devices as well as applications containing a lot of structural operations.
- * @param {RegExp=} expression The className expression which will be checked against all animations
- * @return {RegExp} The current CSS className expression value. If null then there is no expression value
- */
- this.classNameFilter = function(expression) {
- if (arguments.length === 1) {
- this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
- if (this.$$classNameFilter) {
- var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
- if (reservedRegex.test(this.$$classNameFilter.toString())) {
- throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
-
- }
- }
- }
- return this.$$classNameFilter;
- };
-
- this.$get = ['$$animateQueue', function($$animateQueue) {
- function domInsert(element, parentElement, afterElement) {
- // if for some reason the previous element was removed
- // from the dom sometime before this code runs then let's
- // just stick to using the parent element as the anchor
- if (afterElement) {
- var afterNode = extractElementNode(afterElement);
- if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
- afterElement = null;
- }
- }
- afterElement ? afterElement.after(element) : parentElement.prepend(element);
- }
-
- /**
- * @ngdoc service
- * @name $animate
- * @description The $animate service exposes a series of DOM utility methods that provide support
- * for animation hooks. The default behavior is the application of DOM operations, however,
- * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
- * to ensure that animation runs with the triggered DOM operation.
- *
- * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
- * included and only when it is active then the animation hooks that `$animate` triggers will be
- * functional. Once active then all structural `ng-` directives will trigger animations as they perform
- * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
- * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
- *
- * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
- *
- * To learn more about enabling animation support, click here to visit the
- * {@link ngAnimate ngAnimate module page}.
- */
- return {
- // we don't call it directly since non-existant arguments may
- // be interpreted as null within the sub enabled function
-
- /**
- *
- * @ngdoc method
- * @name $animate#on
- * @kind function
- * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
- * has fired on the given element or among any of its children. Once the listener is fired, the provided callback
- * is fired with the following params:
- *
- * ```js
- * $animate.on('enter', container,
- * function callback(element, phase) {
- * // cool we detected an enter animation within the container
- * }
- * );
- * ```
- *
- * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
- * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
- * as well as among its children
- * @param {Function} callback the callback function that will be fired when the listener is triggered
- *
- * The arguments present in the callback function are:
- * * `element` - The captured DOM element that the animation was fired on.
- * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
- */
- on: $$animateQueue.on,
-
- /**
- *
- * @ngdoc method
- * @name $animate#off
- * @kind function
- * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
- * can be used in three different ways depending on the arguments:
- *
- * ```js
- * // remove all the animation event listeners listening for `enter`
- * $animate.off('enter');
- *
- * // remove listeners for all animation events from the container element
- * $animate.off(container);
- *
- * // remove all the animation event listeners listening for `enter` on the given element and its children
- * $animate.off('enter', container);
- *
- * // remove the event listener function provided by `callback` that is set
- * // to listen for `enter` on the given `container` as well as its children
- * $animate.off('enter', container, callback);
- * ```
- *
- * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
- * addClass, removeClass, etc...), or the container element. If it is the element, all other
- * arguments are ignored.
- * @param {DOMElement=} container the container element the event listener was placed on
- * @param {Function=} callback the callback function that was registered as the listener
- */
- off: $$animateQueue.off,
-
- /**
- * @ngdoc method
- * @name $animate#pin
- * @kind function
- * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
- * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
- * element despite being outside the realm of the application or within another application. Say for example if the application
- * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated
- * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
- * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
- *
- * Note that this feature is only active when the `ngAnimate` module is used.
- *
- * @param {DOMElement} element the external element that will be pinned
- * @param {DOMElement} parentElement the host parent element that will be associated with the external element
- */
- pin: $$animateQueue.pin,
-
- /**
- *
- * @ngdoc method
- * @name $animate#enabled
- * @kind function
- * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
- * function can be called in four ways:
- *
- * ```js
- * // returns true or false
- * $animate.enabled();
- *
- * // changes the enabled state for all animations
- * $animate.enabled(false);
- * $animate.enabled(true);
- *
- * // returns true or false if animations are enabled for an element
- * $animate.enabled(element);
- *
- * // changes the enabled state for an element and its children
- * $animate.enabled(element, true);
- * $animate.enabled(element, false);
- * ```
- *
- * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
- * @param {boolean=} enabled whether or not the animations will be enabled for the element
- *
- * @return {boolean} whether or not animations are enabled
- */
- enabled: $$animateQueue.enabled,
-
- /**
- * @ngdoc method
- * @name $animate#cancel
- * @kind function
- * @description Cancels the provided animation.
- *
- * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
- */
- cancel: function(runner) {
- runner.end && runner.end();
- },
-
- /**
- *
- * @ngdoc method
- * @name $animate#enter
- * @kind function
- * @description Inserts the element into the DOM either after the `after` element (if provided) or
- * as the first child within the `parent` element and then triggers an animation.
- * A promise is returned that will be resolved during the next digest once the animation
- * has completed.
- *
- * @param {DOMElement} element the element which will be inserted into the DOM
- * @param {DOMElement} parent the parent element which will append the element as
- * a child (so long as the after element is not present)
- * @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- enter: function(element, parent, after, options) {
- parent = parent && jqLite(parent);
- after = after && jqLite(after);
- parent = parent || after.parent();
- domInsert(element, parent, after);
- return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
- },
-
- /**
- *
- * @ngdoc method
- * @name $animate#move
- * @kind function
- * @description Inserts (moves) the element into its new position in the DOM either after
- * the `after` element (if provided) or as the first child within the `parent` element
- * and then triggers an animation. A promise is returned that will be resolved
- * during the next digest once the animation has completed.
- *
- * @param {DOMElement} element the element which will be moved into the new DOM position
- * @param {DOMElement} parent the parent element which will append the element as
- * a child (so long as the after element is not present)
- * @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- move: function(element, parent, after, options) {
- parent = parent && jqLite(parent);
- after = after && jqLite(after);
- parent = parent || after.parent();
- domInsert(element, parent, after);
- return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
- },
-
- /**
- * @ngdoc method
- * @name $animate#leave
- * @kind function
- * @description Triggers an animation and then removes the element from the DOM.
- * When the function is called a promise is returned that will be resolved during the next
- * digest once the animation has completed.
- *
- * @param {DOMElement} element the element which will be removed from the DOM
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- leave: function(element, options) {
- return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
- element.remove();
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#addClass
- * @kind function
- *
- * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
- * execution, the addClass operation will only be handled after the next digest and it will not trigger an
- * animation if element already contains the CSS class or if the class is removed at a later step.
- * Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- addClass: function(element, className, options) {
- options = prepareAnimateOptions(options);
- options.addClass = mergeClasses(options.addclass, className);
- return $$animateQueue.push(element, 'addClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#removeClass
- * @kind function
- *
- * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
- * execution, the removeClass operation will only be handled after the next digest and it will not trigger an
- * animation if element does not contain the CSS class or if the class is added at a later step.
- * Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- removeClass: function(element, className, options) {
- options = prepareAnimateOptions(options);
- options.removeClass = mergeClasses(options.removeClass, className);
- return $$animateQueue.push(element, 'removeClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#setClass
- * @kind function
- *
- * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
- * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
- * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
- * passed. Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
- * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- setClass: function(element, add, remove, options) {
- options = prepareAnimateOptions(options);
- options.addClass = mergeClasses(options.addClass, add);
- options.removeClass = mergeClasses(options.removeClass, remove);
- return $$animateQueue.push(element, 'setClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#animate
- * @kind function
- *
- * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
- * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
- * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
- * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
- * style in `to`, the style in `from` is applied immediately, and no animation is run.
- * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
- * method (or as part of the `options` parameter):
- *
- * ```js
- * ngModule.animation('.my-inline-animation', function() {
- * return {
- * animate : function(element, from, to, done, options) {
- * //animation
- * done();
- * }
- * }
- * });
- * ```
- *
- * @param {DOMElement} element the element which the CSS styles will be applied to
- * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
- * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
- * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
- * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
- * (Note that if no animation is detected then this value will not be applied to the element.)
- * @param {object=} options an optional collection of options/styles that will be applied to the element.
- * The object can have the following properties:
- *
- * - **addClass** - `{string}` - space-separated CSS classes to add to element
- * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
- * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
- * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
- *
- * @return {Promise} the animation callback promise
- */
- animate: function(element, from, to, className, options) {
- options = prepareAnimateOptions(options);
- options.from = options.from ? extend(options.from, from) : from;
- options.to = options.to ? extend(options.to, to) : to;
-
- className = className || 'ng-inline-animate';
- options.tempClasses = mergeClasses(options.tempClasses, className);
- return $$animateQueue.push(element, 'animate', options);
- }
- };
- }];
-}];
-
-var $$AnimateAsyncRunFactoryProvider = function() {
- this.$get = ['$$rAF', function($$rAF) {
- var waitQueue = [];
-
- function waitForTick(fn) {
- waitQueue.push(fn);
- if (waitQueue.length > 1) return;
- $$rAF(function() {
- for (var i = 0; i < waitQueue.length; i++) {
- waitQueue[i]();
- }
- waitQueue = [];
- });
- }
-
- return function() {
- var passed = false;
- waitForTick(function() {
- passed = true;
- });
- return function(callback) {
- passed ? callback() : waitForTick(callback);
- };
- };
- }];
-};
-
-var $$AnimateRunnerFactoryProvider = function() {
- this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
- function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
-
- var INITIAL_STATE = 0;
- var DONE_PENDING_STATE = 1;
- var DONE_COMPLETE_STATE = 2;
-
- AnimateRunner.chain = function(chain, callback) {
- var index = 0;
-
- next();
- function next() {
- if (index === chain.length) {
- callback(true);
- return;
- }
-
- chain[index](function(response) {
- if (response === false) {
- callback(false);
- return;
- }
- index++;
- next();
- });
- }
- };
-
- AnimateRunner.all = function(runners, callback) {
- var count = 0;
- var status = true;
- forEach(runners, function(runner) {
- runner.done(onProgress);
- });
-
- function onProgress(response) {
- status = status && response;
- if (++count === runners.length) {
- callback(status);
- }
- }
- };
-
- function AnimateRunner(host) {
- this.setHost(host);
-
- var rafTick = $$animateAsyncRun();
- var timeoutTick = function(fn) {
- $timeout(fn, 0, false);
- };
-
- this._doneCallbacks = [];
- this._tick = function(fn) {
- var doc = $document[0];
-
- // the document may not be ready or attached
- // to the module for some internal tests
- if (doc && doc.hidden) {
- timeoutTick(fn);
- } else {
- rafTick(fn);
- }
- };
- this._state = 0;
- }
-
- AnimateRunner.prototype = {
- setHost: function(host) {
- this.host = host || {};
- },
-
- done: function(fn) {
- if (this._state === DONE_COMPLETE_STATE) {
- fn();
- } else {
- this._doneCallbacks.push(fn);
- }
- },
-
- progress: noop,
-
- getPromise: function() {
- if (!this.promise) {
- var self = this;
- this.promise = $q(function(resolve, reject) {
- self.done(function(status) {
- status === false ? reject() : resolve();
- });
- });
- }
- return this.promise;
- },
-
- then: function(resolveHandler, rejectHandler) {
- return this.getPromise().then(resolveHandler, rejectHandler);
- },
-
- 'catch': function(handler) {
- return this.getPromise()['catch'](handler);
- },
-
- 'finally': function(handler) {
- return this.getPromise()['finally'](handler);
- },
-
- pause: function() {
- if (this.host.pause) {
- this.host.pause();
- }
- },
-
- resume: function() {
- if (this.host.resume) {
- this.host.resume();
- }
- },
-
- end: function() {
- if (this.host.end) {
- this.host.end();
- }
- this._resolve(true);
- },
-
- cancel: function() {
- if (this.host.cancel) {
- this.host.cancel();
- }
- this._resolve(false);
- },
-
- complete: function(response) {
- var self = this;
- if (self._state === INITIAL_STATE) {
- self._state = DONE_PENDING_STATE;
- self._tick(function() {
- self._resolve(response);
- });
- }
- },
-
- _resolve: function(response) {
- if (this._state !== DONE_COMPLETE_STATE) {
- forEach(this._doneCallbacks, function(fn) {
- fn(response);
- });
- this._doneCallbacks.length = 0;
- this._state = DONE_COMPLETE_STATE;
- }
- }
- };
-
- return AnimateRunner;
- }];
-};
-
-/**
- * @ngdoc service
- * @name $animateCss
- * @kind object
- *
- * @description
- * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
- * then the `$animateCss` service will actually perform animations.
- *
- * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
- */
-var $CoreAnimateCssProvider = function() {
- this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
-
- return function(element, initialOptions) {
- // all of the animation functions should create
- // a copy of the options data, however, if a
- // parent service has already created a copy then
- // we should stick to using that
- var options = initialOptions || {};
- if (!options.$$prepared) {
- options = copy(options);
- }
-
- // there is no point in applying the styles since
- // there is no animation that goes on at all in
- // this version of $animateCss.
- if (options.cleanupStyles) {
- options.from = options.to = null;
- }
-
- if (options.from) {
- element.css(options.from);
- options.from = null;
- }
-
- /* jshint newcap: false */
- var closed, runner = new $$AnimateRunner();
- return {
- start: run,
- end: run
- };
-
- function run() {
- $$rAF(function() {
- applyAnimationContents();
- if (!closed) {
- runner.complete();
- }
- closed = true;
- });
- return runner;
- }
-
- function applyAnimationContents() {
- if (options.addClass) {
- element.addClass(options.addClass);
- options.addClass = null;
- }
- if (options.removeClass) {
- element.removeClass(options.removeClass);
- options.removeClass = null;
- }
- if (options.to) {
- element.css(options.to);
- options.to = null;
- }
- }
- };
- }];
-};
-
-/* global stripHash: true */
-
-/**
- * ! This is a private undocumented service !
- *
- * @name $browser
- * @requires $log
- * @description
- * This object has two goals:
- *
- * - hide all the global state in the browser caused by the window object
- * - abstract away all the browser specific features and inconsistencies
- *
- * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
- * service, which can be used for convenient testing of the application without the interaction with
- * the real browser apis.
- */
-/**
- * @param {object} window The global window object.
- * @param {object} document jQuery wrapped document.
- * @param {object} $log window.console or an object with the same interface.
- * @param {object} $sniffer $sniffer service
- */
-function Browser(window, document, $log, $sniffer) {
- var self = this,
- location = window.location,
- history = window.history,
- setTimeout = window.setTimeout,
- clearTimeout = window.clearTimeout,
- pendingDeferIds = {};
-
- self.isMock = false;
-
- var outstandingRequestCount = 0;
- var outstandingRequestCallbacks = [];
-
- // TODO(vojta): remove this temporary api
- self.$$completeOutstandingRequest = completeOutstandingRequest;
- self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
-
- /**
- * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
- * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
- */
- function completeOutstandingRequest(fn) {
- try {
- fn.apply(null, sliceArgs(arguments, 1));
- } finally {
- outstandingRequestCount--;
- if (outstandingRequestCount === 0) {
- while (outstandingRequestCallbacks.length) {
- try {
- outstandingRequestCallbacks.pop()();
- } catch (e) {
- $log.error(e);
- }
- }
- }
- }
- }
-
- function getHash(url) {
- var index = url.indexOf('#');
- return index === -1 ? '' : url.substr(index);
- }
-
- /**
- * @private
- * Note: this method is used only by scenario runner
- * TODO(vojta): prefix this method with $$ ?
- * @param {function()} callback Function that will be called when no outstanding request
- */
- self.notifyWhenNoOutstandingRequests = function(callback) {
- if (outstandingRequestCount === 0) {
- callback();
- } else {
- outstandingRequestCallbacks.push(callback);
- }
- };
-
- //////////////////////////////////////////////////////////////
- // URL API
- //////////////////////////////////////////////////////////////
-
- var cachedState, lastHistoryState,
- lastBrowserUrl = location.href,
- baseElement = document.find('base'),
- pendingLocation = null,
- getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
- try {
- return history.state;
- } catch (e) {
- // MSIE can reportedly throw when there is no state (UNCONFIRMED).
- }
- };
-
- cacheState();
- lastHistoryState = cachedState;
-
- /**
- * @name $browser#url
- *
- * @description
- * GETTER:
- * Without any argument, this method just returns current value of location.href.
- *
- * SETTER:
- * With at least one argument, this method sets url to new value.
- * If html5 history api supported, pushState/replaceState is used, otherwise
- * location.href/location.replace is used.
- * Returns its own instance to allow chaining
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to change url.
- *
- * @param {string} url New url (when used as setter)
- * @param {boolean=} replace Should new url replace current history record?
- * @param {object=} state object to use with pushState/replaceState
- */
- self.url = function(url, replace, state) {
- // In modern browsers `history.state` is `null` by default; treating it separately
- // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
- // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
- if (isUndefined(state)) {
- state = null;
- }
-
- // Android Browser BFCache causes location, history reference to become stale.
- if (location !== window.location) location = window.location;
- if (history !== window.history) history = window.history;
-
- // setter
- if (url) {
- var sameState = lastHistoryState === state;
-
- // Don't change anything if previous and current URLs and states match. This also prevents
- // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
- // See https://github.com/angular/angular.js/commit/ffb2701
- if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
- return self;
- }
- var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
- lastBrowserUrl = url;
- lastHistoryState = state;
- // Don't use history API if only the hash changed
- // due to a bug in IE10/IE11 which leads
- // to not firing a `hashchange` nor `popstate` event
- // in some cases (see #9143).
- if ($sniffer.history && (!sameBase || !sameState)) {
- history[replace ? 'replaceState' : 'pushState'](state, '', url);
- cacheState();
- // Do the assignment again so that those two variables are referentially identical.
- lastHistoryState = cachedState;
- } else {
- if (!sameBase) {
- pendingLocation = url;
- }
- if (replace) {
- location.replace(url);
- } else if (!sameBase) {
- location.href = url;
- } else {
- location.hash = getHash(url);
- }
- if (location.href !== url) {
- pendingLocation = url;
- }
- }
- if (pendingLocation) {
- pendingLocation = url;
- }
- return self;
- // getter
- } else {
- // - pendingLocation is needed as browsers don't allow to read out
- // the new location.href if a reload happened or if there is a bug like in iOS 9 (see
- // https://openradar.appspot.com/22186109).
- // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
- return pendingLocation || location.href.replace(/%27/g,"'");
- }
- };
-
- /**
- * @name $browser#state
- *
- * @description
- * This method is a getter.
- *
- * Return history.state or null if history.state is undefined.
- *
- * @returns {object} state
- */
- self.state = function() {
- return cachedState;
- };
-
- var urlChangeListeners = [],
- urlChangeInit = false;
-
- function cacheStateAndFireUrlChange() {
- pendingLocation = null;
- cacheState();
- fireUrlChange();
- }
-
- // This variable should be used *only* inside the cacheState function.
- var lastCachedState = null;
- function cacheState() {
- // This should be the only place in $browser where `history.state` is read.
- cachedState = getCurrentState();
- cachedState = isUndefined(cachedState) ? null : cachedState;
-
- // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
- if (equals(cachedState, lastCachedState)) {
- cachedState = lastCachedState;
- }
- lastCachedState = cachedState;
- }
-
- function fireUrlChange() {
- if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
- return;
- }
-
- lastBrowserUrl = self.url();
- lastHistoryState = cachedState;
- forEach(urlChangeListeners, function(listener) {
- listener(self.url(), cachedState);
- });
- }
-
- /**
- * @name $browser#onUrlChange
- *
- * @description
- * Register callback function that will be called, when url changes.
- *
- * It's only called when the url is changed from outside of angular:
- * - user types different url into address bar
- * - user clicks on history (forward/back) button
- * - user clicks on a link
- *
- * It's not called when url is changed by $browser.url() method
- *
- * The listener gets called with new url as parameter.
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to monitor url changes in angular apps.
- *
- * @param {function(string)} listener Listener function to be called when url changes.
- * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
- */
- self.onUrlChange = function(callback) {
- // TODO(vojta): refactor to use node's syntax for events
- if (!urlChangeInit) {
- // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
- // don't fire popstate when user change the address bar and don't fire hashchange when url
- // changed by push/replaceState
-
- // html5 history api - popstate event
- if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
- // hashchange event
- jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
-
- urlChangeInit = true;
- }
-
- urlChangeListeners.push(callback);
- return callback;
- };
-
- /**
- * @private
- * Remove popstate and hashchange handler from window.
- *
- * NOTE: this api is intended for use only by $rootScope.
- */
- self.$$applicationDestroyed = function() {
- jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
- };
-
- /**
- * Checks whether the url has changed outside of Angular.
- * Needs to be exported to be able to check for changes that have been done in sync,
- * as hashchange/popstate events fire in async.
- */
- self.$$checkUrlChange = fireUrlChange;
-
- //////////////////////////////////////////////////////////////
- // Misc API
- //////////////////////////////////////////////////////////////
-
- /**
- * @name $browser#baseHref
- *
- * @description
- * Returns current
- * (always relative - without domain)
- *
- * @returns {string} The current base href
- */
- self.baseHref = function() {
- var href = baseElement.attr('href');
- return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
- };
-
- /**
- * @name $browser#defer
- * @param {function()} fn A function, who's execution should be deferred.
- * @param {number=} [delay=0] of milliseconds to defer the function execution.
- * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
- *
- * @description
- * Executes a fn asynchronously via `setTimeout(fn, delay)`.
- *
- * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
- * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
- * via `$browser.defer.flush()`.
- *
- */
- self.defer = function(fn, delay) {
- var timeoutId;
- outstandingRequestCount++;
- timeoutId = setTimeout(function() {
- delete pendingDeferIds[timeoutId];
- completeOutstandingRequest(fn);
- }, delay || 0);
- pendingDeferIds[timeoutId] = true;
- return timeoutId;
- };
-
-
- /**
- * @name $browser#defer.cancel
- *
- * @description
- * Cancels a deferred task identified with `deferId`.
- *
- * @param {*} deferId Token returned by the `$browser.defer` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
- * canceled.
- */
- self.defer.cancel = function(deferId) {
- if (pendingDeferIds[deferId]) {
- delete pendingDeferIds[deferId];
- clearTimeout(deferId);
- completeOutstandingRequest(noop);
- return true;
- }
- return false;
- };
-
-}
-
-function $BrowserProvider() {
- this.$get = ['$window', '$log', '$sniffer', '$document',
- function($window, $log, $sniffer, $document) {
- return new Browser($window, $document, $log, $sniffer);
- }];
-}
-
-/**
- * @ngdoc service
- * @name $cacheFactory
- *
- * @description
- * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
- * them.
- *
- * ```js
- *
- * var cache = $cacheFactory('cacheId');
- * expect($cacheFactory.get('cacheId')).toBe(cache);
- * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
- *
- * cache.put("key", "value");
- * cache.put("another key", "another value");
- *
- * // We've specified no options on creation
- * expect(cache.info()).toEqual({id: 'cacheId', size: 2});
- *
- * ```
- *
- *
- * @param {string} cacheId Name or id of the newly created cache.
- * @param {object=} options Options object that specifies the cache behavior. Properties:
- *
- * - `{number=}` `capacity` — turns the cache into LRU cache.
- *
- * @returns {object} Newly created cache object with the following set of methods:
- *
- * - `{object}` `info()` — Returns id, size, and options of cache.
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
- * it.
- * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
- * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
- * - `{void}` `removeAll()` — Removes all cached values.
- * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
- *
- * @example
-
-
-
-
-
-
-
-
Cached Values
-
-
- :
-
-
-
-
Cache Info
-
-
- :
-
-
-
-
-
- angular.module('cacheExampleApp', []).
- controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
- $scope.keys = [];
- $scope.cache = $cacheFactory('cacheId');
- $scope.put = function(key, value) {
- if (angular.isUndefined($scope.cache.get(key))) {
- $scope.keys.push(key);
- }
- $scope.cache.put(key, angular.isUndefined(value) ? null : value);
- };
- }]);
-
-
- p {
- margin: 10px 0 3px;
- }
-
-
- */
-function $CacheFactoryProvider() {
-
- this.$get = function() {
- var caches = {};
-
- function cacheFactory(cacheId, options) {
- if (cacheId in caches) {
- throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
- }
-
- var size = 0,
- stats = extend({}, options, {id: cacheId}),
- data = createMap(),
- capacity = (options && options.capacity) || Number.MAX_VALUE,
- lruHash = createMap(),
- freshEnd = null,
- staleEnd = null;
-
- /**
- * @ngdoc type
- * @name $cacheFactory.Cache
- *
- * @description
- * A cache object used to store and retrieve data, primarily used by
- * {@link $http $http} and the {@link ng.directive:script script} directive to cache
- * templates and other data.
- *
- * ```js
- * angular.module('superCache')
- * .factory('superCache', ['$cacheFactory', function($cacheFactory) {
- * return $cacheFactory('super-cache');
- * }]);
- * ```
- *
- * Example test:
- *
- * ```js
- * it('should behave like a cache', inject(function(superCache) {
- * superCache.put('key', 'value');
- * superCache.put('another key', 'another value');
- *
- * expect(superCache.info()).toEqual({
- * id: 'super-cache',
- * size: 2
- * });
- *
- * superCache.remove('another key');
- * expect(superCache.get('another key')).toBeUndefined();
- *
- * superCache.removeAll();
- * expect(superCache.info()).toEqual({
- * id: 'super-cache',
- * size: 0
- * });
- * }));
- * ```
- */
- return caches[cacheId] = {
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#put
- * @kind function
- *
- * @description
- * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
- * retrieved later, and incrementing the size of the cache if the key was not already
- * present in the cache. If behaving like an LRU cache, it will also remove stale
- * entries from the set.
- *
- * It will not insert undefined values into the cache.
- *
- * @param {string} key the key under which the cached data is stored.
- * @param {*} value the value to store alongside the key. If it is undefined, the key
- * will not be stored.
- * @returns {*} the value stored.
- */
- put: function(key, value) {
- if (isUndefined(value)) return;
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
-
- refresh(lruEntry);
- }
-
- if (!(key in data)) size++;
- data[key] = value;
-
- if (size > capacity) {
- this.remove(staleEnd.key);
- }
-
- return value;
- },
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#get
- * @kind function
- *
- * @description
- * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
- *
- * @param {string} key the key of the data to be retrieved
- * @returns {*} the value stored.
- */
- get: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- refresh(lruEntry);
- }
-
- return data[key];
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#remove
- * @kind function
- *
- * @description
- * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
- *
- * @param {string} key the key of the entry to be removed
- */
- remove: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- if (lruEntry == freshEnd) freshEnd = lruEntry.p;
- if (lruEntry == staleEnd) staleEnd = lruEntry.n;
- link(lruEntry.n,lruEntry.p);
-
- delete lruHash[key];
- }
-
- if (!(key in data)) return;
-
- delete data[key];
- size--;
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#removeAll
- * @kind function
- *
- * @description
- * Clears the cache object of any entries.
- */
- removeAll: function() {
- data = createMap();
- size = 0;
- lruHash = createMap();
- freshEnd = staleEnd = null;
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#destroy
- * @kind function
- *
- * @description
- * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
- * removing it from the {@link $cacheFactory $cacheFactory} set.
- */
- destroy: function() {
- data = null;
- stats = null;
- lruHash = null;
- delete caches[cacheId];
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#info
- * @kind function
- *
- * @description
- * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
- *
- * @returns {object} an object with the following properties:
- *
- *
**id**: the id of the cache instance
- *
**size**: the number of entries kept in the cache instance
- *
**...**: any additional properties from the options object when creating the
- * cache.
- *
- */
- info: function() {
- return extend({}, stats, {size: size});
- }
- };
-
-
- /**
- * makes the `entry` the freshEnd of the LRU linked list
- */
- function refresh(entry) {
- if (entry != freshEnd) {
- if (!staleEnd) {
- staleEnd = entry;
- } else if (staleEnd == entry) {
- staleEnd = entry.n;
- }
-
- link(entry.n, entry.p);
- link(entry, freshEnd);
- freshEnd = entry;
- freshEnd.n = null;
- }
- }
-
-
- /**
- * bidirectionally links two entries of the LRU linked list
- */
- function link(nextEntry, prevEntry) {
- if (nextEntry != prevEntry) {
- if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
- if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
- }
- }
- }
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory#info
- *
- * @description
- * Get information about all the caches that have been created
- *
- * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
- */
- cacheFactory.info = function() {
- var info = {};
- forEach(caches, function(cache, cacheId) {
- info[cacheId] = cache.info();
- });
- return info;
- };
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory#get
- *
- * @description
- * Get access to a cache object by the `cacheId` used when it was created.
- *
- * @param {string} cacheId Name or id of a cache to access.
- * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
- */
- cacheFactory.get = function(cacheId) {
- return caches[cacheId];
- };
-
-
- return cacheFactory;
- };
-}
-
-/**
- * @ngdoc service
- * @name $templateCache
- *
- * @description
- * The first time a template is used, it is loaded in the template cache for quick retrieval. You
- * can load templates directly into the cache in a `script` tag, or by consuming the
- * `$templateCache` service directly.
- *
- * Adding via the `script` tag:
- *
- * ```html
- *
- * ```
- *
- * **Note:** the `script` tag containing the template does not need to be included in the `head` of
- * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
- * element with ng-app attribute), otherwise the template will be ignored.
- *
- * Adding via the `$templateCache` service:
- *
- * ```js
- * var myApp = angular.module('myApp', []);
- * myApp.run(function($templateCache) {
- * $templateCache.put('templateId.html', 'This is the content of the template');
- * });
- * ```
- *
- * To retrieve the template later, simply use it in your HTML:
- * ```html
- *
- * ```
- *
- * or get it via Javascript:
- * ```js
- * $templateCache.get('templateId.html')
- * ```
- *
- * See {@link ng.$cacheFactory $cacheFactory}.
- *
- */
-function $TemplateCacheProvider() {
- this.$get = ['$cacheFactory', function($cacheFactory) {
- return $cacheFactory('templates');
- }];
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Any commits to this file should be reviewed with security in mind. *
- * Changes to this file can potentially create security vulnerabilities. *
- * An approval from 2 Core members with history of modifying *
- * this file is required. *
- * *
- * Does the change somehow allow for arbitrary javascript to be executed? *
- * Or allows for someone to change the prototype of built-in objects? *
- * Or gives undesired access to variables likes document or window? *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
- *
- * DOM-related variables:
- *
- * - "node" - DOM Node
- * - "element" - DOM Element or Node
- * - "$node" or "$element" - jqLite-wrapped node or element
- *
- *
- * Compiler related stuff:
- *
- * - "linkFn" - linking fn of a single directive
- * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
- * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node
- * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
- */
-
-
-/**
- * @ngdoc service
- * @name $compile
- * @kind function
- *
- * @description
- * Compiles an HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
- *
- * The compilation is a process of walking the DOM tree and matching DOM elements to
- * {@link ng.$compileProvider#directive directives}.
- *
- *
- * **Note:** This document is an in-depth reference of all directive options.
- * For a gentle introduction to directives with examples of common use cases,
- * see the {@link guide/directive directive guide}.
- *
- *
- * ## Comprehensive Directive API
- *
- * There are many different options for a directive.
- *
- * The difference resides in the return value of the factory function.
- * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
- * that defines the directive properties, or just the `postLink` function (all other properties will have
- * the default values).
- *
- *
- * **Best Practice:** It's recommended to use the "directive definition object" form.
- *
- * **Note:** Any unspecified options will use the default value. You can see the default values below.
- *
- *
- * Therefore the above can be simplified as:
- *
- * ```js
- * var myModule = angular.module(...);
- *
- * myModule.directive('directiveName', function factory(injectables) {
- * var directiveDefinitionObject = {
- * link: function postLink(scope, iElement, iAttrs) { ... }
- * };
- * return directiveDefinitionObject;
- * // or
- * // return function postLink(scope, iElement, iAttrs) { ... }
- * });
- * ```
- *
- * ### Life-cycle hooks
- * Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the
- * directive:
- * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
- * had their bindings initialized (and before the pre & post linking functions for the directives on
- * this element). This is a good place to put initialization code for your controller.
- * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
- * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
- * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
- * component such as cloning the bound value to prevent accidental mutation of the outer value.
- * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
- * changes. Any actions that you wish to take in response to the changes that you detect must be
- * invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
- * could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not
- * be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
- * if detecting changes, you must store the previous value(s) for comparison to the current values.
- * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
- * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
- * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
- * components will have their `$onDestroy()` hook called before child components.
- * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
- * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
- * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
- * they are waiting for their template to load asynchronously and their own compilation and linking has been
- * suspended until that occurs.
- *
- * #### Comparison with Angular 2 life-cycle hooks
- * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are
- * some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2:
- *
- * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.
- * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.
- * In Angular 2 you can only define hooks on the prototype of the Component class.
- * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to
- * `ngDoCheck` in Angular 2
- * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
- * propagated throughout the application.
- * Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
- * error or do nothing depending upon the state of `enableProdMode()`.
- *
- * #### Life-cycle hook examples
- *
- * This example shows how you can check for mutations to a Date object even though the identity of the object
- * has not changed.
- *
- *
- *
- * angular.module('do-check-module', [])
- * .component('app', {
- * template:
- * 'Month: ' +
- * 'Date: {{ $ctrl.date }}' +
- * '',
- * controller: function() {
- * this.date = new Date();
- * this.month = this.date.getMonth();
- * this.updateDate = function() {
- * this.date.setMonth(this.month);
- * };
- * }
- * })
- * .component('test', {
- * bindings: { date: '<' },
- * template:
- * '
{{ $ctrl.log | json }}
',
- * controller: function() {
- * var previousValue;
- * this.log = [];
- * this.$doCheck = function() {
- * var currentValue = this.date && this.date.valueOf();
- * if (previousValue !== currentValue) {
- * this.log.push('doCheck: date mutated: ' + this.date);
- * previousValue = currentValue;
- * }
- * };
- * }
- * });
- *
- *
- *
- *
- *
- *
- * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
- * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
- * arrays or objects can have a negative impact on your application performance)
- *
- *
- *
- *
',
- * controller: function() {
- * this.log = [];
- *
- * this.$doCheck = function() {
- * if (this.items_ref !== this.items) {
- * this.log.push('doCheck: items changed');
- * this.items_ref = this.items;
- * }
- * if (!angular.equals(this.items_clone, this.items)) {
- * this.log.push('doCheck: items mutated');
- * this.items_clone = angular.copy(this.items);
- * }
- * };
- * }
- * });
- *
- *
- *
- *
- * ### Directive Definition Object
- *
- * The directive definition object provides instructions to the {@link ng.$compile
- * compiler}. The attributes are:
- *
- * #### `multiElement`
- * When this property is set to true, the HTML compiler will collect DOM nodes between
- * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
- * together as the directive elements. It is recommended that this feature be used on directives
- * which are not strictly behavioral (such as {@link ngClick}), and which
- * do not manipulate or replace child nodes (such as {@link ngInclude}).
- *
- * #### `priority`
- * When there are multiple directives defined on a single DOM element, sometimes it
- * is necessary to specify the order in which the directives are applied. The `priority` is used
- * to sort the directives before their `compile` functions get called. Priority is defined as a
- * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
- * are also run in priority order, but post-link functions are run in reverse order. The order
- * of directives with the same priority is undefined. The default priority is `0`.
- *
- * #### `terminal`
- * If set to true then the current `priority` will be the last set of directives
- * which will execute (any directives at the current priority will still execute
- * as the order of execution on same `priority` is undefined). Note that expressions
- * and other directives used in the directive's template will also be excluded from execution.
- *
- * #### `scope`
- * The scope property can be `true`, an object or a falsy value:
- *
- * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
- *
- * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
- * the directive's element. If multiple directives on the same element request a new scope,
- * only one new scope is created. The new scope rule does not apply for the root of the template
- * since the root of the template always gets a new scope.
- *
- * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
- * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
- * scope. This is useful when creating reusable components, which should not accidentally read or modify
- * data in the parent scope.
- *
- * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
- * directive's element. These local properties are useful for aliasing values for templates. The keys in
- * the object hash map to the name of the property on the isolate scope; the values define how the property
- * is bound to the parent scope, via matching attributes on the directive's element:
- *
- * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
- * always a string since DOM attributes are strings. If no `attr` name is specified then the
- * attribute name is assumed to be the same as the local name. Given `` and the isolate scope definition `scope: { localName:'@myAttr' }`,
- * the directive's scope property `localName` will reflect the interpolated value of `hello
- * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
- * scope. The `name` is read from the parent scope (not the directive's scope).
- *
- * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
- * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
- * If no `attr` name is specified then the attribute name is assumed to be the same as the local
- * name. Given `` and the isolate scope definition `scope: {
- * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
- * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
- * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
- * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
- * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
- * will be thrown upon discovering changes to the local value, since it will be impossible to sync
- * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
- * method is used for tracking changes, and the equality check is based on object identity.
- * However, if an object literal or an array literal is passed as the binding expression, the
- * equality check is done by value (using the {@link angular.equals} function). It's also possible
- * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
- * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
- *
- * * `<` or `` and directive definition of
- * `scope: { localModel:'` and the isolate scope definition `scope: {
- * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
- * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
- * via an expression to the parent scope. This can be done by passing a map of local variable names
- * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
- * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
- *
- * In general it's possible to apply more than one directive to one element, but there might be limitations
- * depending on the type of scope required by the directives. The following points will help explain these limitations.
- * For simplicity only two directives are taken into account, but it is also applicable for several directives:
- *
- * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
- * * **child scope** + **no scope** => Both directives will share one single child scope
- * * **child scope** + **child scope** => Both directives will share one single child scope
- * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use
- * its parent's scope
- * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
- * be applied to the same element.
- * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives
- * cannot be applied to the same element.
- *
- *
- * #### `bindToController`
- * This property is used to bind scope properties directly to the controller. It can be either
- * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
- * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
- * definition: `controller: 'myCtrl as myAlias'`.
- *
- * When an isolate scope is used for a directive (see above), `bindToController: true` will
- * allow a component to have its properties bound to the controller, rather than to scope.
- *
- * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
- * properties. You can access these bindings once they have been initialized by providing a controller method called
- * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
- * initialized.
- *
- *
- * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
- * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
- * code that relies upon bindings inside a `$onInit` method on the controller, instead.
- *
- *
- * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
- * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
- * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
- * scope (useful for component directives).
- *
- * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
- *
- *
- * #### `controller`
- * Controller constructor function. The controller is instantiated before the
- * pre-linking phase and can be accessed by other directives (see
- * `require` attribute). This allows the directives to communicate with each other and augment
- * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
- *
- * * `$scope` - Current scope associated with the element
- * * `$element` - Current element
- * * `$attrs` - Current attributes object for the element
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
- * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
- * * `scope`: (optional) override the scope.
- * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
- * * `futureParentElement` (optional):
- * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
- * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
- * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
- * and when the `cloneLinkinFn` is passed,
- * as those elements need to created and cloned in a special way when they are defined outside their
- * usual containers (e.g. like `