├── .gitignore ├── LICENSE.txt ├── README.md ├── css ├── app.css ├── bootstrap │ ├── bootstrap-responsive.css │ ├── bootstrap-responsive.min.css │ ├── bootstrap.css │ └── bootstrap.min.css └── jqueryui │ ├── jquery-ui-1.10.3.custom.css │ └── jquery-ui-1.10.3.custom.min.css ├── img ├── bandsaw │ ├── front.png │ ├── homePage.png │ └── rear.png ├── bootstrap │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png ├── chopsaw │ ├── front.png │ └── rear.png ├── drillpress │ ├── bits.png │ └── front.png ├── grid.png ├── instructions │ ├── drag.gif │ ├── drag.png │ ├── hint.png │ ├── rearrange.gif │ ├── rearrange.png │ ├── replace.gif │ ├── replace.png │ ├── scoreSingle.gif │ └── totalScore.png ├── jointer │ ├── cuts.png │ └── front.png ├── jumbotron.png ├── routers │ ├── bits.png │ ├── handheldFront.png │ ├── handheldSide.png │ ├── inTableFront.png │ └── inTableTop.png └── tablesaw │ └── front.png ├── index.html ├── js ├── app.js ├── controllers.js ├── directives.js ├── jquery.tap.js ├── jquery.tap.min.js └── lib │ ├── angular │ ├── angular-bootstrap-prettify.js │ ├── angular-bootstrap-prettify.min.js │ ├── angular-bootstrap.js │ ├── angular-bootstrap.min.js │ ├── angular-cookies.js │ ├── angular-cookies.min.js │ ├── angular-loader.js │ ├── angular-loader.min.js │ ├── angular-mocks.js │ ├── angular-resource.js │ ├── angular-resource.min.js │ ├── angular-sanitize.js │ ├── angular-sanitize.min.js │ ├── angular-scenario.js │ ├── angular.js │ └── angular.min.js │ ├── bootstrap │ ├── bootstrap.js │ └── bootstrap.min.js │ ├── jquery │ ├── jquery-1.10.2.js │ ├── jquery-1.10.2.min.js │ └── jquery-1.10.2.min.map │ └── jqueryui │ ├── jquery-ui-1.10.3.custom.js │ └── jquery-ui-1.10.3.custom.min.js └── partials ├── details.html └── main.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013 Jesse Smick 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FabLabMachineTest 2 | 3 | A website for my High School wood shop teacher to give to students to help study for the machine tests before they can use them. 4 | 5 | 6 | ## Libraries Used 7 | 8 | * [jQuery](http://jquery.com/) 9 | * [jQueryUI](http://jqueryui.com/) 10 | * [AngularJS](http://angularjs.org/) 11 | * [Twitter Bootstrap](http://twitter.github.io/bootstrap/) 12 | -------------------------------------------------------------------------------- /css/app.css: -------------------------------------------------------------------------------- 1 | img[draggable="false"] { 2 | -webkit-user-drag: none; 3 | user-drag: none; 4 | 5 | -webkit-user-select: none; 6 | -moz-user-select: none; 7 | -ms-user-select: none; 8 | user-select: none; 9 | } 10 | 11 | /* Large/Desktop */ 12 | @media (max-width: 979px) { 13 | .navbar-fixed-top { 14 | margin-bottom: 0; 15 | position: fixed !important; 16 | } 17 | 18 | [ng-view] { 19 | padding: 50px 0 0 0 !important; 20 | } 21 | 22 | /* ~85% jumbotron */ 23 | .jumbotron { 24 | height: 366px !important; 25 | } 26 | 27 | .jumbotron .fablab { 28 | -webkit-background-size: 340px 307px !important; 29 | -moz-background-size: 340px 307px !important; 30 | background-size: 340px 307px !important; 31 | 32 | background-position: center 81px !important; 33 | } 34 | 35 | .jumbotron::after { 36 | -webkit-background-size: 81px !important; 37 | -moz-background-size: 81px !important; 38 | background-size: 81px !important; 39 | } 40 | 41 | } 42 | 43 | /* Medium/Tablet */ 44 | @media (max-width: 767px) { 45 | /* ~75% jumbotron */ 46 | .jumbotron { 47 | height: 307px !important; 48 | } 49 | 50 | .jumbotron .fablab { 51 | -webkit-background-size: 300px 271px !important; 52 | -moz-background-size: 300px 271px !important; 53 | background-size: 300px 271px !important; 54 | 55 | background-position: center 70px !important; 56 | } 57 | 58 | .jumbotron::after { 59 | -webkit-background-size: 75px !important; 60 | -moz-background-size: 75px !important; 61 | background-size: 75px !important; 62 | } 63 | 64 | .navbar-fixed-top { 65 | margin: 0 !important; 66 | } 67 | 68 | .container .marketing .row-fluid .machine { 69 | margin-bottom: 35px; 70 | } 71 | 72 | .container .marketing .row-fluid:last-of-type .machine:last-of-type { 73 | margin-bottom: 0; 74 | } 75 | 76 | .machine > h2 { 77 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 78 | filter: alpha(opacity=100); 79 | 80 | opacity: 1 !important; 81 | } 82 | 83 | .jumbotron, footer, header { 84 | margin: 0 -20px; 85 | } 86 | 87 | } 88 | 89 | /* Small/Phone */ 90 | @media (max-width: 480px) { 91 | body { 92 | padding: 0 !important; 93 | } 94 | 95 | /* ~65% jumbotron */ 96 | .jumbotron { 97 | height: 258px !important; 98 | } 99 | 100 | .jumbotron .fablab { 101 | -webkit-background-size: 260px 235px !important; 102 | -moz-background-size: 260px 235px !important; 103 | background-size: 260px 235px !important; 104 | 105 | background-position: center 60px !important; 106 | } 107 | 108 | .jumbotron::after { 109 | -webkit-background-size: 55px !important; 110 | -moz-background-size: 55px !important; 111 | background-size: 55px !important; 112 | } 113 | 114 | .marketing-byline { 115 | font-size: 18px !important; 116 | } 117 | 118 | .jumbotron, footer, header { 119 | margin: 0 !important; 120 | } 121 | 122 | #instructions img { 123 | margin: 0 !important; 124 | } 125 | 126 | .check-total, #instructions { 127 | padding: 0 15px; 128 | } 129 | 130 | } 131 | 132 | /* Sticky Footer */ 133 | html, body { 134 | height: 100%; 135 | } 136 | 137 | #wrap { 138 | min-height: 100%; 139 | height: auto !important; 140 | height: 100%; 141 | margin: 0 auto -71px; /* -(footer-height + 31) */ 142 | } 143 | 144 | #wrap::after { 145 | content: ''; 146 | display: block; /* must be >= footer */ 147 | height: 150px; 148 | } 149 | 150 | footer { 151 | height: 40px; 152 | text-align: center; 153 | padding: 15px 0; 154 | border-top: 1px solid #C0C0C0; 155 | background-color: #EBEBEB; 156 | } 157 | 158 | footer p { 159 | margin-bottom: 0; 160 | color: #777; 161 | } 162 | 163 | /* Main */ 164 | #wrap > div[ng-controller='MainCtrl'] { 165 | padding-top: 41px; 166 | } 167 | 168 | .navbar .brand { 169 | font-weight: bold; 170 | } 171 | 172 | /* Push down to compensate for nav */ 173 | [ng-view] { 174 | padding: 40px 0 0 0; 175 | } 176 | 177 | /* jumbotron adapted from Twitter Bootstrap jumbotron */ 178 | .jumbotron, header { 179 | position: relative; 180 | top: 0; 181 | color: #fff; 182 | text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); 183 | background: #204EC5; /* Old browsers */ 184 | background: -webkit-linear-gradient(45deg, #164299 0%, #4069D6 100%); 185 | background: -moz-linear-gradient(45deg, #164299 0%, #4069D6 100%); 186 | background: -o-linear-gradient(45deg, #164299 0%, #4069D6 100%); 187 | background: linear-gradient(45deg, #164299 0%, #4069D6 100%); 188 | 189 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#204EC5', endColorstr='#9c9c9c',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ 190 | 191 | -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.2), inset 0 -3px 7px rgba(0, 0, 0, 0.2); 192 | box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.2), inset 0 -3px 7px rgba(0, 0, 0, 0.2); 193 | } 194 | 195 | .jumbotron { 196 | height: 490px; 197 | text-align: center; 198 | background-attachment: fixed; 199 | } 200 | 201 | header { 202 | padding: 40px 0; 203 | } 204 | 205 | header h1 { 206 | font-size: 60px; 207 | } 208 | 209 | .jumbotron .fablab { 210 | position: absolute; 211 | height: 100%; 212 | width: 100%; 213 | background-image: url("../img/jumbotron.png"); 214 | background-repeat: no-repeat; 215 | background-position: center 106px; 216 | 217 | -webkit-background-size: 400px 362px; 218 | -moz-background-size: 400px 362px; 219 | background-size: 400px 362px; 220 | 221 | background-attachment: fixed; 222 | } 223 | 224 | .jumbotron::after, header::after { 225 | content: ''; 226 | display: block; 227 | position: absolute; 228 | top: 0; 229 | right: 0; 230 | bottom: 0; 231 | left: 0; 232 | 233 | /* 234 | **** CSS Blueprint Grid **** 235 | background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.2) 2px, transparent 2px), 236 | -webkit-linear-gradient(90deg, rgba(255, 255, 255, 0.2) 2px, transparent 2px), 237 | -webkit-linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), 238 | -webkit-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px); 239 | 240 | background-image: -moz-linear-gradient(rgba(255, 255, 255, 0.2) 2px, transparent 2px), 241 | -moz-linear-gradient(90deg, rgba(255, 255, 255, 0.2) 2px, transparent 2px), 242 | -moz-linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), 243 | -moz-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px); 244 | 245 | background-image: -o-linear-gradient(rgba(255, 255, 255, 0.2) 2px, transparent 2px), 246 | -o-linear-gradient(90deg, rgba(255, 255, 255, 0.2) 2px, transparent 2px), 247 | -o-linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), 248 | -o-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px); 249 | 250 | background-image: linear-gradient(rgba(255, 255, 255, 0.2) 2px, transparent 2px), 251 | linear-gradient(90deg, rgba(255, 255, 255, 0.2) 2px, transparent 2px), 252 | linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), 253 | linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px); 254 | 255 | -webkit-background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px; 256 | -moz-background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px; 257 | background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px; 258 | 259 | background-position: -2px -2px, -2px -2px, -1px -1px, -1px -1px; 260 | */ 261 | 262 | /* Image replica of above - a lot of current browsers cannot do the 90deg rotation */ 263 | background-image: url("../img/grid.png"); 264 | 265 | -webkit-background-size: 100px; 266 | -moz-background-size: 100px; 267 | background-size: 100px; 268 | 269 | background-position: -2px; 270 | } 271 | 272 | .jumbotron::after { 273 | background-attachment: fixed; 274 | } 275 | 276 | header::after { 277 | -webkit-background-size: 75px; 278 | -moz-background-size: 75px; 279 | background-size: 75px; 280 | } 281 | 282 | .marketing { 283 | text-align: center; 284 | color: #5A5A5A; 285 | } 286 | 287 | .marketing h1 { 288 | margin: 40px 0 10px; 289 | font-size: 60px; 290 | font-weight: 200; 291 | line-height: 1; 292 | letter-spacing: -1px; 293 | } 294 | 295 | .marketing a.machine { 296 | color: #545454; 297 | position: relative; 298 | border-radius: 4px; 299 | height: 340px; 300 | padding: 0; 301 | background-position: center 0; 302 | background-repeat: no-repeat; 303 | 304 | -webkit-box-sizing: border-box; 305 | -moz-box-sizing: border-box; 306 | -ms-box-sizing: border-box; 307 | box-sizing: border-box; 308 | } 309 | 310 | .marketing a.machine:hover, .marketing a.machine:active { 311 | text-decoration: none; 312 | } 313 | 314 | .marketing .marketing-byline { 315 | margin-bottom: 30px; 316 | font-size: 20px; 317 | font-weight: 300; 318 | line-height: 1.25; 319 | color: #999; 320 | } 321 | 322 | .machine > h2 { 323 | border-bottom-left-radius: 4px; 324 | border-bottom-right-radius: 4px; 325 | 326 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 327 | filter: alpha(opacity=0); 328 | opacity: 0; 329 | 330 | -webkit-transition: opacity .25s ease-out; 331 | -moz-transition: opacity .25s ease-out; 332 | -o-transition: opacity .25s ease-out; 333 | -ms-transition: opacity .25s ease-out; 334 | transition: opacity .25s ease-out; 335 | 336 | text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 30px rgba(0, 0, 0, 0.075); 337 | 338 | -webkit-box-shadow: 0 0 3px #999; 339 | box-shadow: 0 0 3px #999; 340 | 341 | background-color: #ffffff; 342 | background-color: rgba(255, 255, 255, 0.86); 343 | position: absolute; 344 | width: 100%; 345 | bottom: 0; 346 | margin-bottom: 0; 347 | } 348 | 349 | .machine:hover > h2 { 350 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 351 | filter: alpha(opacity=100); 352 | opacity: 1; 353 | } 354 | 355 | .machine:active > h2 { 356 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 357 | filter: alpha(opacity=100); 358 | opacity: 1; 359 | } 360 | 361 | .container .marketing .row-fluid:first-of-type .machine { 362 | margin-bottom: 35px; 363 | } 364 | 365 | /******** For the Instructions ********/ 366 | #instructions { 367 | text-align: left; 368 | } 369 | 370 | #instructions h1 { 371 | text-align: center; 372 | } 373 | 374 | #instructions h3, #instructions .page-header { 375 | clear: both; 376 | } 377 | 378 | .instructGif { 379 | display: inline-block; 380 | position: relative; 381 | } 382 | 383 | #instructions img { 384 | margin-left: 25px; 385 | } 386 | 387 | .instructGif:hover { 388 | cursor: pointer; 389 | } 390 | 391 | .instructGif::before { 392 | content: ""; 393 | position: absolute; 394 | bottom: 16px; 395 | right: 16px; 396 | width: 29px; 397 | height: 54px; 398 | border: 16px solid transparent; 399 | border-width: 0 16px; 400 | } 401 | 402 | .instructGif.static::before { 403 | top: -webkit-calc(50% - 50px); 404 | top: calc(50% - 50px); 405 | left: -webkit-calc(50% - 38px); 406 | left: calc(50% - 38px); 407 | width: 0; 408 | height: 0; 409 | border: 52px solid transparent; 410 | border-width: 52px 0 52px 98px; 411 | border-left-color: #76FF76; 412 | } 413 | 414 | .instructGif:hover::before { 415 | border-color: #FF7676; 416 | } 417 | 418 | .instructGif.static:hover::before { 419 | border-color: transparent; 420 | border-left-color: #FFFFFF; 421 | } 422 | /**************************** details.html ****************************/ 423 | .details { 424 | position: relative; 425 | } 426 | 427 | .alert { 428 | position: fixed; 429 | top: 35px; 430 | left: 0; 431 | width: 50%; 432 | margin-left: 25%; 433 | text-align: center; 434 | z-index: 9001; 435 | } 436 | 437 | .alert-error { 438 | background-color: rgba(242, 222, 222, 0.93); 439 | } 440 | 441 | .container > .row-fluid { 442 | margin: 20px 0; 443 | padding: 10px; 444 | border-radius: 6px; 445 | width: auto; 446 | } 447 | 448 | .machine-title { 449 | text-align: center; 450 | } 451 | 452 | .parts-list { 453 | list-style: none; 454 | margin: 0; 455 | background-color: #FFF; 456 | border-radius: 6px; 457 | } 458 | 459 | .part { 460 | position: relative; 461 | cursor: move; 462 | cursor: -webkit-grab; 463 | cursor: -moz-grab; 464 | cursor: grab; 465 | background-color: #FFFFFF; 466 | padding: 5px 9px; 467 | margin: 0 0 -1px; 468 | border: 1px solid #C4C4C4; 469 | } 470 | 471 | .part:first-of-type { 472 | border-radius: 6px 6px 0 0; 473 | } 474 | 475 | .part:last-of-type { 476 | border-radius: 0 0 6px 6px; 477 | } 478 | 479 | .part.ui-state-disabled { 480 | color: #EEEEEE; 481 | background-color: #999999; 482 | 483 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, rgba(0, 0, 0, 0)), color-stop(0.5, rgba(0, 0, 0, 0)), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0))); 484 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)); 485 | background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)); 486 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)); 487 | background-image: -ms-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)); 488 | background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 0)); 489 | 490 | -image -webkit-background-size: 40px 40px; 491 | -moz-background-size: 40px 40px; 492 | background-size: 40px 40px; 493 | } 494 | 495 | .part:not(.ui-state-disabled):hover { 496 | background-color: #E4E4E4; 497 | } 498 | 499 | .part-letter { 500 | float: left; 501 | top: 5px; 502 | left: 9px; 503 | padding-right: 5px; 504 | } 505 | 506 | .part.ui-state-disabled .part-letter { 507 | border-color: #DDDDDD; 508 | } 509 | 510 | .part-name { 511 | padding: 0 20px 0 5px; 512 | margin-left: 14px; 513 | display: block; 514 | border-left: 1px solid #AAAAAA; 515 | } 516 | 517 | .get-description { 518 | position: absolute; 519 | margin: 0; 520 | top: 8px; 521 | right: 9px; 522 | cursor: pointer; 523 | } 524 | 525 | .part-description { 526 | display: block; 527 | color: #333; 528 | padding: 3px 5px 6px 5px; 529 | line-height: 1.5em; 530 | margin-top: 5px; 531 | font-size: 0.85em; 532 | background-color: #F9F9F9; 533 | border-left: 5px solid #0088CC; 534 | border-radius: 4px; 535 | 536 | -webkit-box-shadow: 0 0 5px #555555 inset; 537 | box-shadow: 0 0 5px #555555 inset; 538 | } 539 | 540 | .ui-draggable-dragging { 541 | height: 20px; 542 | width: 20px; 543 | background-color: #FFFFFF; 544 | background-color: rgba(255, 255, 255, 0.7); 545 | text-align: center; 546 | border-radius: 20px; 547 | border: 2px solid #0088CC; 548 | cursor: move; 549 | cursor: -webkit-grabbing; 550 | cursor: -moz-grabbing; 551 | cursor: grabbing; 552 | } 553 | 554 | .part-drop { 555 | position: absolute; 556 | height: 20px; 557 | width: 20px; 558 | text-align: center; 559 | color: #ffffff; 560 | font-weight: bold; 561 | background: rgba(0, 0, 0, 0); 562 | border-radius: 20px; 563 | border-width: 3px; 564 | border-style: solid; 565 | } 566 | 567 | .part-drop.ui-state-highlight { 568 | background-color: rgba(0, 0, 0, 0.75); 569 | cursor: move; 570 | cursor: -webkit-grab; 571 | cursor: -moz-grab; 572 | cursor: grab; 573 | } 574 | 575 | .part-drop.ui-state-hover { 576 | background-color: rgba(255, 255, 255, 0.4); 577 | } 578 | 579 | .part-drop.ui-draggable-disabled { 580 | background-color: rgba(0, 0, 0, 0); 581 | } 582 | 583 | .part-drop.ui-state-hover, .part-drop.ui-draggable-disabled { 584 | color: rgba(0, 0, 0, 0); 585 | } 586 | 587 | .drop-wrapper { 588 | position: relative; 589 | float: left; 590 | } 591 | 592 | .check-parts { 593 | padding-top: 15px; 594 | } 595 | 596 | .score { 597 | padding-top: 10px; 598 | margin-bottom: 0; 599 | } 600 | 601 | /*** Touch specific classes ***/ 602 | .ui-touch-active { 603 | background-color: #555555 !important; 604 | color: #DDDDDD; 605 | } 606 | 607 | .part-drop.ui-touch-active { 608 | background-color: #DDDDDD !important; 609 | color: #333333 !important; 610 | } 611 | -------------------------------------------------------------------------------- /css/bootstrap/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | .clearfix { 12 | *zoom: 1; 13 | } 14 | 15 | .clearfix:before, 16 | .clearfix:after { 17 | display: table; 18 | line-height: 0; 19 | content: ""; 20 | } 21 | 22 | .clearfix:after { 23 | clear: both; 24 | } 25 | 26 | .hide-text { 27 | font: 0/0 a; 28 | color: transparent; 29 | text-shadow: none; 30 | background-color: transparent; 31 | border: 0; 32 | } 33 | 34 | .input-block-level { 35 | display: block; 36 | width: 100%; 37 | min-height: 30px; 38 | -webkit-box-sizing: border-box; 39 | -moz-box-sizing: border-box; 40 | box-sizing: border-box; 41 | } 42 | 43 | @-ms-viewport { 44 | width: device-width; 45 | } 46 | 47 | .hidden { 48 | display: none; 49 | visibility: hidden; 50 | } 51 | 52 | .visible-phone { 53 | display: none !important; 54 | } 55 | 56 | .visible-tablet { 57 | display: none !important; 58 | } 59 | 60 | .hidden-desktop { 61 | display: none !important; 62 | } 63 | 64 | .visible-desktop { 65 | display: inherit !important; 66 | } 67 | 68 | @media (min-width: 768px) and (max-width: 979px) { 69 | .hidden-desktop { 70 | display: inherit !important; 71 | } 72 | .visible-desktop { 73 | display: none !important ; 74 | } 75 | .visible-tablet { 76 | display: inherit !important; 77 | } 78 | .hidden-tablet { 79 | display: none !important; 80 | } 81 | } 82 | 83 | @media (max-width: 767px) { 84 | .hidden-desktop { 85 | display: inherit !important; 86 | } 87 | .visible-desktop { 88 | display: none !important; 89 | } 90 | .visible-phone { 91 | display: inherit !important; 92 | } 93 | .hidden-phone { 94 | display: none !important; 95 | } 96 | } 97 | 98 | .visible-print { 99 | display: none !important; 100 | } 101 | 102 | @media print { 103 | .visible-print { 104 | display: inherit !important; 105 | } 106 | .hidden-print { 107 | display: none !important; 108 | } 109 | } 110 | 111 | @media (min-width: 1200px) { 112 | .row { 113 | margin-left: -30px; 114 | *zoom: 1; 115 | } 116 | .row:before, 117 | .row:after { 118 | display: table; 119 | line-height: 0; 120 | content: ""; 121 | } 122 | .row:after { 123 | clear: both; 124 | } 125 | [class*="span"] { 126 | float: left; 127 | min-height: 1px; 128 | margin-left: 30px; 129 | } 130 | .container, 131 | .navbar-static-top .container, 132 | .navbar-fixed-top .container, 133 | .navbar-fixed-bottom .container { 134 | width: 1170px; 135 | } 136 | .span12 { 137 | width: 1170px; 138 | } 139 | .span11 { 140 | width: 1070px; 141 | } 142 | .span10 { 143 | width: 970px; 144 | } 145 | .span9 { 146 | width: 870px; 147 | } 148 | .span8 { 149 | width: 770px; 150 | } 151 | .span7 { 152 | width: 670px; 153 | } 154 | .span6 { 155 | width: 570px; 156 | } 157 | .span5 { 158 | width: 470px; 159 | } 160 | .span4 { 161 | width: 370px; 162 | } 163 | .span3 { 164 | width: 270px; 165 | } 166 | .span2 { 167 | width: 170px; 168 | } 169 | .span1 { 170 | width: 70px; 171 | } 172 | .offset12 { 173 | margin-left: 1230px; 174 | } 175 | .offset11 { 176 | margin-left: 1130px; 177 | } 178 | .offset10 { 179 | margin-left: 1030px; 180 | } 181 | .offset9 { 182 | margin-left: 930px; 183 | } 184 | .offset8 { 185 | margin-left: 830px; 186 | } 187 | .offset7 { 188 | margin-left: 730px; 189 | } 190 | .offset6 { 191 | margin-left: 630px; 192 | } 193 | .offset5 { 194 | margin-left: 530px; 195 | } 196 | .offset4 { 197 | margin-left: 430px; 198 | } 199 | .offset3 { 200 | margin-left: 330px; 201 | } 202 | .offset2 { 203 | margin-left: 230px; 204 | } 205 | .offset1 { 206 | margin-left: 130px; 207 | } 208 | .row-fluid { 209 | width: 100%; 210 | *zoom: 1; 211 | } 212 | .row-fluid:before, 213 | .row-fluid:after { 214 | display: table; 215 | line-height: 0; 216 | content: ""; 217 | } 218 | .row-fluid:after { 219 | clear: both; 220 | } 221 | .row-fluid [class*="span"] { 222 | display: block; 223 | float: left; 224 | width: 100%; 225 | min-height: 30px; 226 | margin-left: 2.564102564102564%; 227 | *margin-left: 2.5109110747408616%; 228 | -webkit-box-sizing: border-box; 229 | -moz-box-sizing: border-box; 230 | box-sizing: border-box; 231 | } 232 | .row-fluid [class*="span"]:first-child { 233 | margin-left: 0; 234 | } 235 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 236 | margin-left: 2.564102564102564%; 237 | } 238 | .row-fluid .span12 { 239 | width: 100%; 240 | *width: 99.94680851063829%; 241 | } 242 | .row-fluid .span11 { 243 | width: 91.45299145299145%; 244 | *width: 91.39979996362975%; 245 | } 246 | .row-fluid .span10 { 247 | width: 82.90598290598291%; 248 | *width: 82.8527914166212%; 249 | } 250 | .row-fluid .span9 { 251 | width: 74.35897435897436%; 252 | *width: 74.30578286961266%; 253 | } 254 | .row-fluid .span8 { 255 | width: 65.81196581196582%; 256 | *width: 65.75877432260411%; 257 | } 258 | .row-fluid .span7 { 259 | width: 57.26495726495726%; 260 | *width: 57.21176577559556%; 261 | } 262 | .row-fluid .span6 { 263 | width: 48.717948717948715%; 264 | *width: 48.664757228587014%; 265 | } 266 | .row-fluid .span5 { 267 | width: 40.17094017094017%; 268 | *width: 40.11774868157847%; 269 | } 270 | .row-fluid .span4 { 271 | width: 31.623931623931625%; 272 | *width: 31.570740134569924%; 273 | } 274 | .row-fluid .span3 { 275 | width: 23.076923076923077%; 276 | *width: 23.023731587561375%; 277 | } 278 | .row-fluid .span2 { 279 | width: 14.52991452991453%; 280 | *width: 14.476723040552828%; 281 | } 282 | .row-fluid .span1 { 283 | width: 5.982905982905983%; 284 | *width: 5.929714493544281%; 285 | } 286 | .row-fluid .offset12 { 287 | margin-left: 105.12820512820512%; 288 | *margin-left: 105.02182214948171%; 289 | } 290 | .row-fluid .offset12:first-child { 291 | margin-left: 102.56410256410257%; 292 | *margin-left: 102.45771958537915%; 293 | } 294 | .row-fluid .offset11 { 295 | margin-left: 96.58119658119658%; 296 | *margin-left: 96.47481360247316%; 297 | } 298 | .row-fluid .offset11:first-child { 299 | margin-left: 94.01709401709402%; 300 | *margin-left: 93.91071103837061%; 301 | } 302 | .row-fluid .offset10 { 303 | margin-left: 88.03418803418803%; 304 | *margin-left: 87.92780505546462%; 305 | } 306 | .row-fluid .offset10:first-child { 307 | margin-left: 85.47008547008548%; 308 | *margin-left: 85.36370249136206%; 309 | } 310 | .row-fluid .offset9 { 311 | margin-left: 79.48717948717949%; 312 | *margin-left: 79.38079650845607%; 313 | } 314 | .row-fluid .offset9:first-child { 315 | margin-left: 76.92307692307693%; 316 | *margin-left: 76.81669394435352%; 317 | } 318 | .row-fluid .offset8 { 319 | margin-left: 70.94017094017094%; 320 | *margin-left: 70.83378796144753%; 321 | } 322 | .row-fluid .offset8:first-child { 323 | margin-left: 68.37606837606839%; 324 | *margin-left: 68.26968539734497%; 325 | } 326 | .row-fluid .offset7 { 327 | margin-left: 62.393162393162385%; 328 | *margin-left: 62.28677941443899%; 329 | } 330 | .row-fluid .offset7:first-child { 331 | margin-left: 59.82905982905982%; 332 | *margin-left: 59.72267685033642%; 333 | } 334 | .row-fluid .offset6 { 335 | margin-left: 53.84615384615384%; 336 | *margin-left: 53.739770867430444%; 337 | } 338 | .row-fluid .offset6:first-child { 339 | margin-left: 51.28205128205128%; 340 | *margin-left: 51.175668303327875%; 341 | } 342 | .row-fluid .offset5 { 343 | margin-left: 45.299145299145295%; 344 | *margin-left: 45.1927623204219%; 345 | } 346 | .row-fluid .offset5:first-child { 347 | margin-left: 42.73504273504273%; 348 | *margin-left: 42.62865975631933%; 349 | } 350 | .row-fluid .offset4 { 351 | margin-left: 36.75213675213675%; 352 | *margin-left: 36.645753773413354%; 353 | } 354 | .row-fluid .offset4:first-child { 355 | margin-left: 34.18803418803419%; 356 | *margin-left: 34.081651209310785%; 357 | } 358 | .row-fluid .offset3 { 359 | margin-left: 28.205128205128204%; 360 | *margin-left: 28.0987452264048%; 361 | } 362 | .row-fluid .offset3:first-child { 363 | margin-left: 25.641025641025642%; 364 | *margin-left: 25.53464266230224%; 365 | } 366 | .row-fluid .offset2 { 367 | margin-left: 19.65811965811966%; 368 | *margin-left: 19.551736679396257%; 369 | } 370 | .row-fluid .offset2:first-child { 371 | margin-left: 17.094017094017094%; 372 | *margin-left: 16.98763411529369%; 373 | } 374 | .row-fluid .offset1 { 375 | margin-left: 11.11111111111111%; 376 | *margin-left: 11.004728132387708%; 377 | } 378 | .row-fluid .offset1:first-child { 379 | margin-left: 8.547008547008547%; 380 | *margin-left: 8.440625568285142%; 381 | } 382 | input, 383 | textarea, 384 | .uneditable-input { 385 | margin-left: 0; 386 | } 387 | .controls-row [class*="span"] + [class*="span"] { 388 | margin-left: 30px; 389 | } 390 | input.span12, 391 | textarea.span12, 392 | .uneditable-input.span12 { 393 | width: 1156px; 394 | } 395 | input.span11, 396 | textarea.span11, 397 | .uneditable-input.span11 { 398 | width: 1056px; 399 | } 400 | input.span10, 401 | textarea.span10, 402 | .uneditable-input.span10 { 403 | width: 956px; 404 | } 405 | input.span9, 406 | textarea.span9, 407 | .uneditable-input.span9 { 408 | width: 856px; 409 | } 410 | input.span8, 411 | textarea.span8, 412 | .uneditable-input.span8 { 413 | width: 756px; 414 | } 415 | input.span7, 416 | textarea.span7, 417 | .uneditable-input.span7 { 418 | width: 656px; 419 | } 420 | input.span6, 421 | textarea.span6, 422 | .uneditable-input.span6 { 423 | width: 556px; 424 | } 425 | input.span5, 426 | textarea.span5, 427 | .uneditable-input.span5 { 428 | width: 456px; 429 | } 430 | input.span4, 431 | textarea.span4, 432 | .uneditable-input.span4 { 433 | width: 356px; 434 | } 435 | input.span3, 436 | textarea.span3, 437 | .uneditable-input.span3 { 438 | width: 256px; 439 | } 440 | input.span2, 441 | textarea.span2, 442 | .uneditable-input.span2 { 443 | width: 156px; 444 | } 445 | input.span1, 446 | textarea.span1, 447 | .uneditable-input.span1 { 448 | width: 56px; 449 | } 450 | .thumbnails { 451 | margin-left: -30px; 452 | } 453 | .thumbnails > li { 454 | margin-left: 30px; 455 | } 456 | .row-fluid .thumbnails { 457 | margin-left: 0; 458 | } 459 | } 460 | 461 | @media (min-width: 768px) and (max-width: 979px) { 462 | .row { 463 | margin-left: -20px; 464 | *zoom: 1; 465 | } 466 | .row:before, 467 | .row:after { 468 | display: table; 469 | line-height: 0; 470 | content: ""; 471 | } 472 | .row:after { 473 | clear: both; 474 | } 475 | [class*="span"] { 476 | float: left; 477 | min-height: 1px; 478 | margin-left: 20px; 479 | } 480 | .container, 481 | .navbar-static-top .container, 482 | .navbar-fixed-top .container, 483 | .navbar-fixed-bottom .container { 484 | width: 724px; 485 | } 486 | .span12 { 487 | width: 724px; 488 | } 489 | .span11 { 490 | width: 662px; 491 | } 492 | .span10 { 493 | width: 600px; 494 | } 495 | .span9 { 496 | width: 538px; 497 | } 498 | .span8 { 499 | width: 476px; 500 | } 501 | .span7 { 502 | width: 414px; 503 | } 504 | .span6 { 505 | width: 352px; 506 | } 507 | .span5 { 508 | width: 290px; 509 | } 510 | .span4 { 511 | width: 228px; 512 | } 513 | .span3 { 514 | width: 166px; 515 | } 516 | .span2 { 517 | width: 104px; 518 | } 519 | .span1 { 520 | width: 42px; 521 | } 522 | .offset12 { 523 | margin-left: 764px; 524 | } 525 | .offset11 { 526 | margin-left: 702px; 527 | } 528 | .offset10 { 529 | margin-left: 640px; 530 | } 531 | .offset9 { 532 | margin-left: 578px; 533 | } 534 | .offset8 { 535 | margin-left: 516px; 536 | } 537 | .offset7 { 538 | margin-left: 454px; 539 | } 540 | .offset6 { 541 | margin-left: 392px; 542 | } 543 | .offset5 { 544 | margin-left: 330px; 545 | } 546 | .offset4 { 547 | margin-left: 268px; 548 | } 549 | .offset3 { 550 | margin-left: 206px; 551 | } 552 | .offset2 { 553 | margin-left: 144px; 554 | } 555 | .offset1 { 556 | margin-left: 82px; 557 | } 558 | .row-fluid { 559 | width: 100%; 560 | *zoom: 1; 561 | } 562 | .row-fluid:before, 563 | .row-fluid:after { 564 | display: table; 565 | line-height: 0; 566 | content: ""; 567 | } 568 | .row-fluid:after { 569 | clear: both; 570 | } 571 | .row-fluid [class*="span"] { 572 | display: block; 573 | float: left; 574 | width: 100%; 575 | min-height: 30px; 576 | margin-left: 2.7624309392265194%; 577 | *margin-left: 2.709239449864817%; 578 | -webkit-box-sizing: border-box; 579 | -moz-box-sizing: border-box; 580 | box-sizing: border-box; 581 | } 582 | .row-fluid [class*="span"]:first-child { 583 | margin-left: 0; 584 | } 585 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 586 | margin-left: 2.7624309392265194%; 587 | } 588 | .row-fluid .span12 { 589 | width: 100%; 590 | *width: 99.94680851063829%; 591 | } 592 | .row-fluid .span11 { 593 | width: 91.43646408839778%; 594 | *width: 91.38327259903608%; 595 | } 596 | .row-fluid .span10 { 597 | width: 82.87292817679558%; 598 | *width: 82.81973668743387%; 599 | } 600 | .row-fluid .span9 { 601 | width: 74.30939226519337%; 602 | *width: 74.25620077583166%; 603 | } 604 | .row-fluid .span8 { 605 | width: 65.74585635359117%; 606 | *width: 65.69266486422946%; 607 | } 608 | .row-fluid .span7 { 609 | width: 57.18232044198895%; 610 | *width: 57.12912895262725%; 611 | } 612 | .row-fluid .span6 { 613 | width: 48.61878453038674%; 614 | *width: 48.56559304102504%; 615 | } 616 | .row-fluid .span5 { 617 | width: 40.05524861878453%; 618 | *width: 40.00205712942283%; 619 | } 620 | .row-fluid .span4 { 621 | width: 31.491712707182323%; 622 | *width: 31.43852121782062%; 623 | } 624 | .row-fluid .span3 { 625 | width: 22.92817679558011%; 626 | *width: 22.87498530621841%; 627 | } 628 | .row-fluid .span2 { 629 | width: 14.3646408839779%; 630 | *width: 14.311449394616199%; 631 | } 632 | .row-fluid .span1 { 633 | width: 5.801104972375691%; 634 | *width: 5.747913483013988%; 635 | } 636 | .row-fluid .offset12 { 637 | margin-left: 105.52486187845304%; 638 | *margin-left: 105.41847889972962%; 639 | } 640 | .row-fluid .offset12:first-child { 641 | margin-left: 102.76243093922652%; 642 | *margin-left: 102.6560479605031%; 643 | } 644 | .row-fluid .offset11 { 645 | margin-left: 96.96132596685082%; 646 | *margin-left: 96.8549429881274%; 647 | } 648 | .row-fluid .offset11:first-child { 649 | margin-left: 94.1988950276243%; 650 | *margin-left: 94.09251204890089%; 651 | } 652 | .row-fluid .offset10 { 653 | margin-left: 88.39779005524862%; 654 | *margin-left: 88.2914070765252%; 655 | } 656 | .row-fluid .offset10:first-child { 657 | margin-left: 85.6353591160221%; 658 | *margin-left: 85.52897613729868%; 659 | } 660 | .row-fluid .offset9 { 661 | margin-left: 79.8342541436464%; 662 | *margin-left: 79.72787116492299%; 663 | } 664 | .row-fluid .offset9:first-child { 665 | margin-left: 77.07182320441989%; 666 | *margin-left: 76.96544022569647%; 667 | } 668 | .row-fluid .offset8 { 669 | margin-left: 71.2707182320442%; 670 | *margin-left: 71.16433525332079%; 671 | } 672 | .row-fluid .offset8:first-child { 673 | margin-left: 68.50828729281768%; 674 | *margin-left: 68.40190431409427%; 675 | } 676 | .row-fluid .offset7 { 677 | margin-left: 62.70718232044199%; 678 | *margin-left: 62.600799341718584%; 679 | } 680 | .row-fluid .offset7:first-child { 681 | margin-left: 59.94475138121547%; 682 | *margin-left: 59.838368402492065%; 683 | } 684 | .row-fluid .offset6 { 685 | margin-left: 54.14364640883978%; 686 | *margin-left: 54.037263430116376%; 687 | } 688 | .row-fluid .offset6:first-child { 689 | margin-left: 51.38121546961326%; 690 | *margin-left: 51.27483249088986%; 691 | } 692 | .row-fluid .offset5 { 693 | margin-left: 45.58011049723757%; 694 | *margin-left: 45.47372751851417%; 695 | } 696 | .row-fluid .offset5:first-child { 697 | margin-left: 42.81767955801105%; 698 | *margin-left: 42.71129657928765%; 699 | } 700 | .row-fluid .offset4 { 701 | margin-left: 37.01657458563536%; 702 | *margin-left: 36.91019160691196%; 703 | } 704 | .row-fluid .offset4:first-child { 705 | margin-left: 34.25414364640884%; 706 | *margin-left: 34.14776066768544%; 707 | } 708 | .row-fluid .offset3 { 709 | margin-left: 28.45303867403315%; 710 | *margin-left: 28.346655695309746%; 711 | } 712 | .row-fluid .offset3:first-child { 713 | margin-left: 25.69060773480663%; 714 | *margin-left: 25.584224756083227%; 715 | } 716 | .row-fluid .offset2 { 717 | margin-left: 19.88950276243094%; 718 | *margin-left: 19.783119783707537%; 719 | } 720 | .row-fluid .offset2:first-child { 721 | margin-left: 17.12707182320442%; 722 | *margin-left: 17.02068884448102%; 723 | } 724 | .row-fluid .offset1 { 725 | margin-left: 11.32596685082873%; 726 | *margin-left: 11.219583872105325%; 727 | } 728 | .row-fluid .offset1:first-child { 729 | margin-left: 8.56353591160221%; 730 | *margin-left: 8.457152932878806%; 731 | } 732 | input, 733 | textarea, 734 | .uneditable-input { 735 | margin-left: 0; 736 | } 737 | .controls-row [class*="span"] + [class*="span"] { 738 | margin-left: 20px; 739 | } 740 | input.span12, 741 | textarea.span12, 742 | .uneditable-input.span12 { 743 | width: 710px; 744 | } 745 | input.span11, 746 | textarea.span11, 747 | .uneditable-input.span11 { 748 | width: 648px; 749 | } 750 | input.span10, 751 | textarea.span10, 752 | .uneditable-input.span10 { 753 | width: 586px; 754 | } 755 | input.span9, 756 | textarea.span9, 757 | .uneditable-input.span9 { 758 | width: 524px; 759 | } 760 | input.span8, 761 | textarea.span8, 762 | .uneditable-input.span8 { 763 | width: 462px; 764 | } 765 | input.span7, 766 | textarea.span7, 767 | .uneditable-input.span7 { 768 | width: 400px; 769 | } 770 | input.span6, 771 | textarea.span6, 772 | .uneditable-input.span6 { 773 | width: 338px; 774 | } 775 | input.span5, 776 | textarea.span5, 777 | .uneditable-input.span5 { 778 | width: 276px; 779 | } 780 | input.span4, 781 | textarea.span4, 782 | .uneditable-input.span4 { 783 | width: 214px; 784 | } 785 | input.span3, 786 | textarea.span3, 787 | .uneditable-input.span3 { 788 | width: 152px; 789 | } 790 | input.span2, 791 | textarea.span2, 792 | .uneditable-input.span2 { 793 | width: 90px; 794 | } 795 | input.span1, 796 | textarea.span1, 797 | .uneditable-input.span1 { 798 | width: 28px; 799 | } 800 | } 801 | 802 | @media (max-width: 767px) { 803 | body { 804 | padding-right: 20px; 805 | padding-left: 20px; 806 | } 807 | .navbar-fixed-top, 808 | .navbar-fixed-bottom, 809 | .navbar-static-top { 810 | margin-right: -20px; 811 | margin-left: -20px; 812 | } 813 | .container-fluid { 814 | padding: 0; 815 | } 816 | .dl-horizontal dt { 817 | float: none; 818 | width: auto; 819 | clear: none; 820 | text-align: left; 821 | } 822 | .dl-horizontal dd { 823 | margin-left: 0; 824 | } 825 | .container { 826 | width: auto; 827 | } 828 | .row-fluid { 829 | width: 100%; 830 | } 831 | .row, 832 | .thumbnails { 833 | margin-left: 0; 834 | } 835 | .thumbnails > li { 836 | float: none; 837 | margin-left: 0; 838 | } 839 | [class*="span"], 840 | .uneditable-input[class*="span"], 841 | .row-fluid [class*="span"] { 842 | display: block; 843 | float: none; 844 | width: 100%; 845 | margin-left: 0; 846 | -webkit-box-sizing: border-box; 847 | -moz-box-sizing: border-box; 848 | box-sizing: border-box; 849 | } 850 | .span12, 851 | .row-fluid .span12 { 852 | width: 100%; 853 | -webkit-box-sizing: border-box; 854 | -moz-box-sizing: border-box; 855 | box-sizing: border-box; 856 | } 857 | .row-fluid [class*="offset"]:first-child { 858 | margin-left: 0; 859 | } 860 | .input-large, 861 | .input-xlarge, 862 | .input-xxlarge, 863 | input[class*="span"], 864 | select[class*="span"], 865 | textarea[class*="span"], 866 | .uneditable-input { 867 | display: block; 868 | width: 100%; 869 | min-height: 30px; 870 | -webkit-box-sizing: border-box; 871 | -moz-box-sizing: border-box; 872 | box-sizing: border-box; 873 | } 874 | .input-prepend input, 875 | .input-append input, 876 | .input-prepend input[class*="span"], 877 | .input-append input[class*="span"] { 878 | display: inline-block; 879 | width: auto; 880 | } 881 | .controls-row [class*="span"] + [class*="span"] { 882 | margin-left: 0; 883 | } 884 | .modal { 885 | position: fixed; 886 | top: 20px; 887 | right: 20px; 888 | left: 20px; 889 | width: auto; 890 | margin: 0; 891 | } 892 | .modal.fade { 893 | top: -100px; 894 | } 895 | .modal.fade.in { 896 | top: 20px; 897 | } 898 | } 899 | 900 | @media (max-width: 480px) { 901 | .nav-collapse { 902 | -webkit-transform: translate3d(0, 0, 0); 903 | } 904 | .page-header h1 small { 905 | display: block; 906 | line-height: 20px; 907 | } 908 | input[type="checkbox"], 909 | input[type="radio"] { 910 | border: 1px solid #ccc; 911 | } 912 | .form-horizontal .control-label { 913 | float: none; 914 | width: auto; 915 | padding-top: 0; 916 | text-align: left; 917 | } 918 | .form-horizontal .controls { 919 | margin-left: 0; 920 | } 921 | .form-horizontal .control-list { 922 | padding-top: 0; 923 | } 924 | .form-horizontal .form-actions { 925 | padding-right: 10px; 926 | padding-left: 10px; 927 | } 928 | .media .pull-left, 929 | .media .pull-right { 930 | display: block; 931 | float: none; 932 | margin-bottom: 10px; 933 | } 934 | .media-object { 935 | margin-right: 0; 936 | margin-left: 0; 937 | } 938 | .modal { 939 | top: 10px; 940 | right: 10px; 941 | left: 10px; 942 | } 943 | .modal-header .close { 944 | padding: 10px; 945 | margin: -10px; 946 | } 947 | .carousel-caption { 948 | position: static; 949 | } 950 | } 951 | 952 | @media (max-width: 979px) { 953 | body { 954 | padding-top: 0; 955 | } 956 | .navbar-fixed-top, 957 | .navbar-fixed-bottom { 958 | position: static; 959 | } 960 | .navbar-fixed-top { 961 | margin-bottom: 20px; 962 | } 963 | .navbar-fixed-bottom { 964 | margin-top: 20px; 965 | } 966 | .navbar-fixed-top .navbar-inner, 967 | .navbar-fixed-bottom .navbar-inner { 968 | padding: 5px; 969 | } 970 | .navbar .container { 971 | width: auto; 972 | padding: 0; 973 | } 974 | .navbar .brand { 975 | padding-right: 10px; 976 | padding-left: 10px; 977 | margin: 0 0 0 -5px; 978 | } 979 | .nav-collapse { 980 | clear: both; 981 | } 982 | .nav-collapse .nav { 983 | float: none; 984 | margin: 0 0 10px; 985 | } 986 | .nav-collapse .nav > li { 987 | float: none; 988 | } 989 | .nav-collapse .nav > li > a { 990 | margin-bottom: 2px; 991 | } 992 | .nav-collapse .nav > .divider-vertical { 993 | display: none; 994 | } 995 | .nav-collapse .nav .nav-header { 996 | color: #777777; 997 | text-shadow: none; 998 | } 999 | .nav-collapse .nav > li > a, 1000 | .nav-collapse .dropdown-menu a { 1001 | padding: 9px 15px; 1002 | font-weight: bold; 1003 | color: #777777; 1004 | -webkit-border-radius: 3px; 1005 | -moz-border-radius: 3px; 1006 | border-radius: 3px; 1007 | } 1008 | .nav-collapse .btn { 1009 | padding: 4px 10px 4px; 1010 | font-weight: normal; 1011 | -webkit-border-radius: 4px; 1012 | -moz-border-radius: 4px; 1013 | border-radius: 4px; 1014 | } 1015 | .nav-collapse .dropdown-menu li + li a { 1016 | margin-bottom: 2px; 1017 | } 1018 | .nav-collapse .nav > li > a:hover, 1019 | .nav-collapse .nav > li > a:focus, 1020 | .nav-collapse .dropdown-menu a:hover, 1021 | .nav-collapse .dropdown-menu a:focus { 1022 | background-color: #f2f2f2; 1023 | } 1024 | .navbar-inverse .nav-collapse .nav > li > a, 1025 | .navbar-inverse .nav-collapse .dropdown-menu a { 1026 | color: #999999; 1027 | } 1028 | .navbar-inverse .nav-collapse .nav > li > a:hover, 1029 | .navbar-inverse .nav-collapse .nav > li > a:focus, 1030 | .navbar-inverse .nav-collapse .dropdown-menu a:hover, 1031 | .navbar-inverse .nav-collapse .dropdown-menu a:focus { 1032 | background-color: #111111; 1033 | } 1034 | .nav-collapse.in .btn-group { 1035 | padding: 0; 1036 | margin-top: 5px; 1037 | } 1038 | .nav-collapse .dropdown-menu { 1039 | position: static; 1040 | top: auto; 1041 | left: auto; 1042 | display: none; 1043 | float: none; 1044 | max-width: none; 1045 | padding: 0; 1046 | margin: 0 15px; 1047 | background-color: transparent; 1048 | border: none; 1049 | -webkit-border-radius: 0; 1050 | -moz-border-radius: 0; 1051 | border-radius: 0; 1052 | -webkit-box-shadow: none; 1053 | -moz-box-shadow: none; 1054 | box-shadow: none; 1055 | } 1056 | .nav-collapse .open > .dropdown-menu { 1057 | display: block; 1058 | } 1059 | .nav-collapse .dropdown-menu:before, 1060 | .nav-collapse .dropdown-menu:after { 1061 | display: none; 1062 | } 1063 | .nav-collapse .dropdown-menu .divider { 1064 | display: none; 1065 | } 1066 | .nav-collapse .nav > li > .dropdown-menu:before, 1067 | .nav-collapse .nav > li > .dropdown-menu:after { 1068 | display: none; 1069 | } 1070 | .nav-collapse .navbar-form, 1071 | .nav-collapse .navbar-search { 1072 | float: none; 1073 | padding: 10px 15px; 1074 | margin: 10px 0; 1075 | border-top: 1px solid #f2f2f2; 1076 | border-bottom: 1px solid #f2f2f2; 1077 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1078 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1079 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1080 | } 1081 | .navbar-inverse .nav-collapse .navbar-form, 1082 | .navbar-inverse .nav-collapse .navbar-search { 1083 | border-top-color: #111111; 1084 | border-bottom-color: #111111; 1085 | } 1086 | .navbar .nav-collapse .nav.pull-right { 1087 | float: none; 1088 | margin-left: 0; 1089 | } 1090 | .nav-collapse, 1091 | .nav-collapse.collapse { 1092 | height: 0; 1093 | overflow: hidden; 1094 | } 1095 | .navbar .btn-navbar { 1096 | display: block; 1097 | } 1098 | .navbar-static .navbar-inner { 1099 | padding-right: 10px; 1100 | padding-left: 10px; 1101 | } 1102 | } 1103 | 1104 | @media (min-width: 980px) { 1105 | .nav-collapse.collapse { 1106 | height: auto !important; 1107 | overflow: visible !important; 1108 | } 1109 | } 1110 | -------------------------------------------------------------------------------- /css/bootstrap/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /css/jqueryui/jquery-ui-1.10.3.custom.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.3 - 2013-06-23 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.tooltip.css 4 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ 5 | 6 | /* Layout helpers 7 | ----------------------------------*/ 8 | .ui-helper-hidden { 9 | display: none; 10 | } 11 | .ui-helper-hidden-accessible { 12 | border: 0; 13 | clip: rect(0 0 0 0); 14 | height: 1px; 15 | margin: -1px; 16 | overflow: hidden; 17 | padding: 0; 18 | position: absolute; 19 | width: 1px; 20 | } 21 | .ui-helper-reset { 22 | margin: 0; 23 | padding: 0; 24 | border: 0; 25 | outline: 0; 26 | line-height: 1.3; 27 | text-decoration: none; 28 | font-size: 100%; 29 | list-style: none; 30 | } 31 | .ui-helper-clearfix:before, 32 | .ui-helper-clearfix:after { 33 | content: ""; 34 | display: table; 35 | border-collapse: collapse; 36 | } 37 | .ui-helper-clearfix:after { 38 | clear: both; 39 | } 40 | .ui-helper-clearfix { 41 | min-height: 0; /* support: IE7 */ 42 | } 43 | .ui-helper-zfix { 44 | width: 100%; 45 | height: 100%; 46 | top: 0; 47 | left: 0; 48 | position: absolute; 49 | opacity: 0; 50 | filter:Alpha(Opacity=0); 51 | } 52 | 53 | .ui-front { 54 | z-index: 100; 55 | } 56 | 57 | 58 | /* Interaction Cues 59 | ----------------------------------*/ 60 | .ui-state-disabled { 61 | cursor: default !important; 62 | } 63 | 64 | 65 | /* Icons 66 | ----------------------------------*/ 67 | 68 | /* states and images */ 69 | .ui-icon { 70 | display: block; 71 | text-indent: -99999px; 72 | overflow: hidden; 73 | background-repeat: no-repeat; 74 | } 75 | 76 | 77 | /* Misc visuals 78 | ----------------------------------*/ 79 | 80 | /* Overlays */ 81 | .ui-widget-overlay { 82 | position: fixed; 83 | top: 0; 84 | left: 0; 85 | width: 100%; 86 | height: 100%; 87 | } 88 | .ui-tooltip { 89 | padding: 8px; 90 | position: absolute; 91 | z-index: 9999; 92 | max-width: 300px; 93 | -webkit-box-shadow: 0 0 5px #aaa; 94 | box-shadow: 0 0 5px #aaa; 95 | } 96 | body .ui-tooltip { 97 | border-width: 2px; 98 | } 99 | -------------------------------------------------------------------------------- /css/jqueryui/jquery-ui-1.10.3.custom.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.3 - 2013-06-23 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.tooltip.css 4 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ 5 | 6 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px} -------------------------------------------------------------------------------- /img/bandsaw/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/bandsaw/front.png -------------------------------------------------------------------------------- /img/bandsaw/homePage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/bandsaw/homePage.png -------------------------------------------------------------------------------- /img/bandsaw/rear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/bandsaw/rear.png -------------------------------------------------------------------------------- /img/bootstrap/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/bootstrap/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /img/bootstrap/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/bootstrap/glyphicons-halflings.png -------------------------------------------------------------------------------- /img/chopsaw/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/chopsaw/front.png -------------------------------------------------------------------------------- /img/chopsaw/rear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/chopsaw/rear.png -------------------------------------------------------------------------------- /img/drillpress/bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/drillpress/bits.png -------------------------------------------------------------------------------- /img/drillpress/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/drillpress/front.png -------------------------------------------------------------------------------- /img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/grid.png -------------------------------------------------------------------------------- /img/instructions/drag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/drag.gif -------------------------------------------------------------------------------- /img/instructions/drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/drag.png -------------------------------------------------------------------------------- /img/instructions/hint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/hint.png -------------------------------------------------------------------------------- /img/instructions/rearrange.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/rearrange.gif -------------------------------------------------------------------------------- /img/instructions/rearrange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/rearrange.png -------------------------------------------------------------------------------- /img/instructions/replace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/replace.gif -------------------------------------------------------------------------------- /img/instructions/replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/replace.png -------------------------------------------------------------------------------- /img/instructions/scoreSingle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/scoreSingle.gif -------------------------------------------------------------------------------- /img/instructions/totalScore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/instructions/totalScore.png -------------------------------------------------------------------------------- /img/jointer/cuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/jointer/cuts.png -------------------------------------------------------------------------------- /img/jointer/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/jointer/front.png -------------------------------------------------------------------------------- /img/jumbotron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/jumbotron.png -------------------------------------------------------------------------------- /img/routers/bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/routers/bits.png -------------------------------------------------------------------------------- /img/routers/handheldFront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/routers/handheldFront.png -------------------------------------------------------------------------------- /img/routers/handheldSide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/routers/handheldSide.png -------------------------------------------------------------------------------- /img/routers/inTableFront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/routers/inTableFront.png -------------------------------------------------------------------------------- /img/routers/inTableTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/routers/inTableTop.png -------------------------------------------------------------------------------- /img/tablesaw/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janka102/FabLabMachineTest/1db9ad2ca3eda789ce9a8be0bd357b77bd13fb49/img/tablesaw/front.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fab Lab 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 55 | 56 | 57 |
58 | 59 |
60 | 61 | 62 | 68 | 69 | 70 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /js/app.js: -------------------------------------------------------------------------------- 1 | // Declare app level module with routes 2 | var app = angular.module('fabLab', [], ['$routeProvider', 3 | function($routeProvider) { 4 | $routeProvider.when('/', { 5 | templateUrl: 'partials/main.html', 6 | controller: MainCtrl 7 | }); 8 | 9 | $routeProvider.when('/:machine', { 10 | templateUrl: 'partials/details.html', 11 | controller: MachineCtrl 12 | }); 13 | 14 | $routeProvider.otherwise({ 15 | redirectTo: '/' 16 | }); 17 | } 18 | ]); 19 | 20 | function checkParts(view) { 21 | var machineViews = $('.machine-view'), 22 | numCorrect = 0, 23 | partsLength = 0, 24 | incompleteViews = 0, 25 | scoreObj, 26 | message1 = 'Uh-oh! %msg%', 27 | message2 = '%msg%', 28 | score = function(percent) { 29 | var bad = [':(', '(O.O)', 'ಠ╭╮ಠ', 'ರ_ರ', 'you should probably try again'], 30 | medium = ['maybe next time you\'ll get it'], 31 | good = [':)', '(^∇^)', '(^_^)', '◕‿◕', 'very good!'], 32 | cssClass = '', 33 | scoreMessage = '', 34 | getRand = function(array) { 35 | return array[Math.floor(Math.random() * array.length)]; 36 | }; 37 | 38 | switch (true) { 39 | // [0, 70] is red 40 | case (percent >= 0 && percent <= 70): 41 | cssClass = 'text-error'; 42 | scoreMessage = getRand(bad); 43 | break; 44 | 45 | // (70, 90) is yellow 46 | case (percent > 70 && percent < 90): 47 | cssClass = 'text-warning'; 48 | scoreMessage = getRand(medium); 49 | break; 50 | 51 | // [90, 100] is green 52 | default: 53 | cssClass = 'text-success'; 54 | scoreMessage = getRand(good); 55 | } 56 | 57 | return { 58 | 'klass': cssClass, 59 | 'message': scoreMessage 60 | }; 61 | }; 62 | 63 | if (view !== undefined && view instanceof HTMLElement) { 64 | view = $(view); 65 | 66 | machineViews = view.parents('.span3').siblings('.machine-view'); 67 | } 68 | 69 | machineViews.each(function() { 70 | var self = $(this), 71 | parts = self.find('.part-group'), 72 | viewPartsLength = parts.length, 73 | filledViewPartsLength = parts.has('.ui-state-highlight').length, 74 | viewNumCorrect = 0, 75 | percent = 0; 76 | 77 | if (filledViewPartsLength === 0) { 78 | incompleteViews += 1; 79 | self.siblings().find('.score').html(message1.replace('%msg%', 'You did not fill in any parts!')); 80 | return; 81 | } else if (filledViewPartsLength < viewPartsLength) { 82 | incompleteViews += 1; 83 | 84 | parts.children(':not(".ui-state-highlight")').each(function() { 85 | $(this).css('border-color', 'rgb(238, 95, 91)'); 86 | }); 87 | 88 | self.siblings().find('.score').html(message1.replace('%msg%', 'You forgot ' + (viewPartsLength - filledViewPartsLength) + ' part' + ((viewPartsLength - filledViewPartsLength) !== 1 ? 's' : '') + '!')); 89 | return; 90 | } 91 | 92 | parts.each(function() { 93 | var self = $(this); 94 | 95 | if (self.data('part-id') === self.children().data('part-id')) { 96 | viewNumCorrect += 1; 97 | 98 | self.children().css('border-color', 'rgb(98, 196, 98)'); 99 | } else { 100 | self.children().css('border-color', 'rgb(238, 95, 91)'); 101 | } 102 | }); 103 | 104 | numCorrect += viewNumCorrect; 105 | partsLength += viewPartsLength; 106 | 107 | percent = (viewNumCorrect / viewPartsLength) * 100; 108 | scoreObj = score(percent); 109 | 110 | // console.log(this, percent, scoreMessage); 111 | 112 | self.siblings().find('.score').html(message2.replace(/text-[a-z]+/, scoreObj.klass).replace('%msg%', 'You got ' + viewNumCorrect + ' out of ' + viewPartsLength + ' correct, that\'s ' + percent.toFixed(2) + '%... ' + scoreObj.message)); 113 | }); 114 | 115 | if (incompleteViews === 0) { 116 | scoreObj = score(numCorrect / partsLength * 100); 117 | $('.check-total').find('.score').html(message2.replace(/text-[a-z]+/, scoreObj.klass).replace('%msg%', 'Total: You got ' + numCorrect + ' out of ' + partsLength + ' correct, that\'s ' + ((numCorrect / partsLength) * 100).toFixed(2) + '%... ' + scoreObj.message)); 118 | } 119 | } 120 | 121 | function resetParts(view) { 122 | var partsList = $('.parts-list'), 123 | partDrops = $('.part-drop'), 124 | score = $('.score'), 125 | scoreTotal = $('.check-total').find('.score'); 126 | 127 | if (view !== undefined && view instanceof HTMLElement) { 128 | view = $(view); 129 | 130 | partsList = view.parents('.span3').find('.parts-list'); 131 | partDrops = view.parents('.span3').siblings('.machine-view').find('.part-drop'); 132 | 133 | score = scoreTotal = view.siblings('.score'); 134 | } 135 | 136 | // Clears out old scores and flashes "Reset..." 137 | score.html(''); 138 | scoreTotal.html('Reset...'); 139 | setTimeout(function() { 140 | scoreTotal.html(''); 141 | }, 1250); 142 | 143 | partsList.children().each(function() { 144 | $(this).data('dropped', false).draggable('enable').removeClass('ui-state-disabled'); 145 | }); 146 | 147 | partDrops.each(function() { 148 | var self = $(this); 149 | self.removeData('part-id').text('').removeClass('ui-state-highlight').css('border-color', self.data('border-color')); 150 | }); 151 | 152 | //console.log('machine reset!'); 153 | } 154 | -------------------------------------------------------------------------------- /js/directives.js: -------------------------------------------------------------------------------- 1 | var VIEW_NAME_REGEX = new RegExp(/[a-zA-Z_]+[a-z]/g), 2 | dragOps = { 3 | addClass: false, 4 | cursorAt: { 5 | left: 17, 6 | top: 17 7 | }, 8 | revert: 'invalid', 9 | zIndex: 900, 10 | start: function() { 11 | var self = $(this); 12 | //console.log('drag-start', self); 13 | self.addClass('ui-state-disabled'); 14 | }, 15 | stop: function() { 16 | var self = $(this); 17 | //console.log('drag-stop', self); 18 | if (!self.data('dropped')) { 19 | self.draggable('enable'); 20 | self.removeClass('ui-state-disabled'); 21 | } 22 | } 23 | }, 24 | dropOps = { 25 | addClasses: false, 26 | tolerance: 'intersect', 27 | over: function() { 28 | var self = $(this); 29 | //console.log('drop-over', self); 30 | self.add(self.siblings()).addClass('ui-state-hover'); 31 | }, 32 | out: function() { 33 | var self = $(this); 34 | //console.log('drop-out', self); 35 | self.add(self.siblings()).removeClass('ui-state-hover'); 36 | }, 37 | drop: function(event, ui) { 38 | var self = $(this), 39 | selfGroup = self.add(self.siblings()), 40 | prevPart = ui.draggable, 41 | prevGroup = prevPart.add(prevPart.siblings()), 42 | letter = prevPart.data('part-id').replace(VIEW_NAME_REGEX, ''), // gets the single uppercase part letter 43 | selfID = self.data('part-id'), 44 | partsList = self.parents('.machine-view').siblings('.span3'), 45 | score = partsList.find('.score').add($('.check-total').find('.score')); 46 | //console.log('drop-drop', self); 47 | 48 | if (score.length) { 49 | score.html(''); 50 | 51 | self.parent().siblings().add(self.parent()).children().each(function() { 52 | var self = $(this); 53 | 54 | self.css('border-color', self.data('border-color')); 55 | }); 56 | } 57 | 58 | if (selfGroup.hasClass('ui-state-hover')) { 59 | selfGroup.removeClass('ui-state-hover'); 60 | } 61 | 62 | // Dragged from the list to a spot... 63 | if (!prevPart.hasClass('part-drop')) { 64 | // that is empty 65 | if (self.data('part-id') === undefined) { 66 | //console.log('list to empty'); 67 | prevPart.data('dropped', true).draggable('disable'); 68 | } else { // that is already occupied 69 | //console.log('list to occupied'); 70 | //console.log(self.clone()); 71 | 72 | prevPart.data('dropped', true).draggable('disable'); 73 | prevPart.siblings().each(function() { 74 | var self = $(this); 75 | 76 | if (self.data('part-id') === selfID) { 77 | self.data('dropped', false).draggable('enable').removeClass('ui-state-disabled'); 78 | 79 | return false; 80 | } 81 | }); 82 | } 83 | 84 | selfGroup.addClass('ui-state-highlight').text(letter).data('part-id', prevPart.data('part-id')); 85 | } else { // Rearrange... 86 | // to a different part... 87 | if (self.data('part-id') !== prevPart.data('part-id')) { 88 | // that is empty 89 | if (self.data('part-id') === undefined) { 90 | //console.log('rearrange to empty'); 91 | prevGroup.removeClass('ui-state-highlight').text(''); 92 | } else { // that is already occupied 93 | //console.log('rearrange to occupied', prevPart.data('part-id'), '>', self.data('part-id')); 94 | selfGroup.data('part-id', prevPart.data('part-id')); 95 | //console.log(self.data('part-id')); 96 | selfGroup.text(prevPart.text()); 97 | 98 | // prevGroup.data('part-id', selfID); 99 | // prevGroup.text(selfID.replace(VIEW_NAME_REGEX, '')); 100 | 101 | prevGroup.removeData('part-id').text('').removeClass('ui-state-highlight'); 102 | partsList.find('.part').each(function() { 103 | var self = $(this); 104 | 105 | if (self.data('part-id') === selfID) { 106 | self.data('dropped', false).draggable('enable').removeClass('ui-state-disabled'); 107 | } 108 | }); 109 | 110 | return; 111 | } 112 | } else { // to a spot that is of the same part 113 | //console.log('canceled drop b/c part was the same', self.data('part-id'), prevPart.data('part-id')) 114 | return false; 115 | } 116 | 117 | selfGroup.addClass('ui-state-highlight').text(letter).data('part-id', prevPart.data('part-id')); 118 | prevGroup.removeData('part-id'); 119 | } 120 | 121 | //console.log(self.data()); 122 | } 123 | }, 124 | rearrangeOps = { 125 | addClass: false, 126 | cursorAt: { 127 | left: 17, 128 | top: 17 129 | }, 130 | revert: 'invalid', 131 | zIndex: 900, 132 | start: function() { 133 | var self = $(this); 134 | //console.log('rearrange-start', self); 135 | 136 | if (!self.data('part-id')) { 137 | //console.log('canceled rearrange b/c it has no partID'); 138 | return false; 139 | } else { 140 | self.add(self.siblings()).addClass('ui-draggable-disabled'); 141 | } 142 | }, 143 | stop: function() { 144 | var self = $(this); 145 | //console.log('rearrange-stop', self); 146 | 147 | self.add(self.siblings()).removeClass('ui-draggable-disabled'); 148 | } 149 | }; 150 | 151 | /* Directives */ 152 | 153 | app.directive('uiDraggable', function() { 154 | return { 155 | restrict: 'A', 156 | link: function(scope, elem, attrs) { 157 | var vars = scope.$eval(attrs.uiDraggable), 158 | options = dragOps; 159 | 160 | //console.log(vars); 161 | options.scope = vars.scope; 162 | options.helper = function() { 163 | return $('
').text(vars.helper.letter); 164 | }; 165 | 166 | elem.draggable(options).tap(function() { 167 | var self = $(this), 168 | touchActive = self.siblings('.ui-touch-active') 169 | .add(self.parents('.span3').siblings('.span9').find('.ui-touch-active')); 170 | 171 | if (!self.hasClass('ui-draggable-disabled')) { 172 | //console.log('touch-drag', self.clone()); 173 | 174 | self.toggleClass('ui-touch-active'); 175 | 176 | if (touchActive.length) { 177 | touchActive.removeClass('ui-touch-active'); 178 | } 179 | } 180 | }); 181 | 182 | //console.log('drAGGable:', options); 183 | } 184 | }; 185 | }).directive('uiDroppable', function() { 186 | return { 187 | restrict: 'A', 188 | link: function(scope, elem, attrs) { 189 | var vars = scope.$eval(attrs.uiDroppable), 190 | options = dropOps; 191 | 192 | options.scope = vars.scope; 193 | 194 | elem.droppable(options).tap(function() { 195 | var self = $(this), 196 | listTouchActive = self.parents('.span9').siblings('.span3').find('.ui-touch-active'), 197 | dropTouchActive = self.parent().siblings().find('.ui-touch-active'), 198 | touchActive = listTouchActive.add(dropTouchActive); 199 | 200 | //console.log(listTouchActive, dropTouchActive, self); 201 | 202 | if (touchActive.length) { 203 | //console.log('touch-drop', touchActive.clone()); 204 | 205 | // Makes touchActive more like the actual ui-draggable I am passing it in as 206 | touchActive.context = touchActive[0]; 207 | delete touchActive.prevObject; 208 | delete touchActive.selector; 209 | 210 | options.drop.call(self, event, { 211 | draggable: touchActive.eq(0) 212 | }); 213 | 214 | touchActive.removeClass('ui-touch-active'); 215 | } else if (!listTouchActive.length && !self.hasClass('ui-draggable-disabled') && self.hasClass('ui-state-highlight')) { 216 | //console.log('touch-rearrange', self.clone()); 217 | 218 | self.add(self.siblings()).toggleClass('ui-touch-active'); 219 | 220 | if (touchActive.length) { 221 | touchActive.removeClass('ui-touch-active'); 222 | } 223 | } 224 | }); 225 | 226 | //console.log('drOPPable:', options); 227 | } 228 | }; 229 | }).directive('uiRearrange', function() { 230 | return { 231 | restrict: 'A', 232 | link: function(scope, elem, attrs) { 233 | var vars = scope.$eval(attrs.uiRearrange), 234 | options = rearrangeOps; 235 | 236 | //console.log(vars); 237 | options.scope = vars.scope; 238 | 239 | options.helper = function() { 240 | return $('
').text(elem.data('part-id') ? elem.data('part-id').replace(VIEW_NAME_REGEX, '') : ''); 241 | }; 242 | 243 | elem.draggable(options); 244 | //console.log('rearrange:', options); 245 | } 246 | }; 247 | }).directive('addPartId', function() { 248 | return { 249 | restrict: 'A', 250 | link: function(scope, elem) { 251 | elem.data('part-id', scope.partId); 252 | //console.log(elem.data('part-id')); 253 | } 254 | }; 255 | }).directive('addPartDescription', function() { 256 | return { 257 | restrict: 'A', 258 | link: function(scope, elem) { 259 | var icon, description; 260 | 261 | if (scope.part.description) { 262 | icon = $('').click(function() { 263 | scope.toggle(event); 264 | }); 265 | description = $('' + scope.part.description + ''); 266 | 267 | elem.append(icon).append(description); 268 | // console.log('description', elem); 269 | } 270 | } 271 | }; 272 | }).directive('stylePart', function() { 273 | return { 274 | restrict: 'A', 275 | link: function(scope, elem, attrs) { 276 | var DEFAULT_COLOR = 'rgb(0, 136, 204)', 277 | vars = scope.$eval(attrs.stylePart), 278 | part = vars.part, 279 | count = vars.count, 280 | viewIndex = vars.viewIndex, 281 | name = vars.name, 282 | borderColors = scope[name + 'BorderColors'], 283 | style = { 284 | left: part['x' + count] + '%', 285 | top: part['y' + count] + '%' 286 | }, 287 | colors = scope[name + 'Colors'], 288 | randColor = function() { 289 | if (colors.currentviewIndex !== viewIndex) { 290 | // console.log('currentviewIndex:', colors.currentviewIndex, 'viewIndex:', viewIndex); 291 | 292 | // reset 293 | scope[name + 'Colors'].currentIndex = null; 294 | 295 | colors.currentviewIndex = viewIndex; 296 | colors.colors = borderColors.slice(0); 297 | 298 | // console.log(borderColors); 299 | } 300 | 301 | if (colors.currentPart !== part.name) { 302 | colors.currentPart = part.name; 303 | 304 | if (colors.currentIndex !== null) { 305 | colors.colors.splice(colors.currentIndex, 1); 306 | } 307 | 308 | colors.currentIndex = Math.floor(Math.random() * colors.colors.length); 309 | } 310 | 311 | var currentColor = colors.colors[colors.currentIndex]; 312 | 313 | scope[name + 'Colors'] = colors; 314 | 315 | // console.log(colors.colors, colors.currentIndex, currentColor); 316 | 317 | return currentColor; 318 | }; 319 | 320 | style['border-color'] = borderColors.length ? randColor() : DEFAULT_COLOR; 321 | 322 | elem.css(style).data('border-color', style['border-color']); 323 | } 324 | }; 325 | }); 326 | -------------------------------------------------------------------------------- /js/jquery.tap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * From https://github.com/jonpacker/jquery.tap 3 | * The only difference is that the mapping to click events is deleted. Lines 71-73 4 | */ 5 | 6 | ;(function($, undefined) { 7 | 'use strict'; 8 | var incrementalElementId = 0, 9 | mutex = 0; 10 | $.fn.tap = function(threshold, callback) { 11 | if (typeof threshold === 'function') { 12 | callback = threshold; 13 | threshold = 15; 14 | } 15 | if ('ontouchstart' in window) { 16 | this.each(function() { 17 | var moveDistance = 0, 18 | touch = null, 19 | elementId = ++incrementalElementId, 20 | startPoint = null, 21 | touching = false, 22 | self = this, 23 | $self = $(this); 24 | 25 | $self.bind('touchstart', function(e) { 26 | if (mutex !== 0) {return;} 27 | else {mutex = elementId;} 28 | 29 | touching = true; 30 | moveDistance = 0; 31 | 32 | if (e.originalEvent.touches && e.originalEvent.touches[0]) { 33 | touch = e.originalEvent.touches[0]; 34 | startPoint = { x: touch.screenX, y: touch.screenY }; 35 | } 36 | }); 37 | 38 | $self.bind('touchend', function() { 39 | if (mutex === elementId) {mutex = 0;} 40 | if (!touching) {return;} 41 | touching = false; 42 | if (moveDistance < threshold) { 43 | callback.apply(self, [].slice.call(arguments)); 44 | } else { 45 | $self.trigger('tap-failed'); 46 | } 47 | }); 48 | 49 | $self.bind('touchmove', function(e) { 50 | if (!touching) {return;} 51 | if (e.originalEvent.touches.length === 0 || startPoint === null) { 52 | return touching = false; 53 | } 54 | 55 | touch = e.originalEvent.touches[0]; 56 | 57 | moveDistance = Math.sqrt(Math.pow(touch.screenX - startPoint.x, 2) + 58 | Math.pow(touch.screenY - startPoint.y, 2)); 59 | 60 | if (moveDistance > threshold) { 61 | $self.trigger('exceed-tap-threshold'); 62 | touching = false; 63 | } 64 | }); 65 | 66 | $self.bind('touchcancel', function() { 67 | if (mutex === elementId) {mutex = 0;} 68 | touching = false; 69 | $self.trigger('tap-failed'); 70 | }); 71 | }); 72 | }/* else { 73 | this.click(callback); 74 | }*/ 75 | return this; 76 | }; 77 | })(window.jQuery || window.$); 78 | -------------------------------------------------------------------------------- /js/jquery.tap.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * From https://github.com/jonpacker/jquery.tap - reminified by uglifyjs 3 | * The only difference is that the mapping to click events is deleted. 4 | */ 5 | !function(n){var t=0,e=0;n.fn.tap=function(i,o){return"function"==typeof i&&(o=i,i=15),"ontouchstart"in window&&this.each(function(){var c=0,r=null,u=++t,a=null,h=!1,l=this,s=n(this);s.bind("touchstart",function(n){0==e&&(e=u,h=!0,c=0,n.originalEvent.touches&&n.originalEvent.touches[0]&&(r=n.originalEvent.touches[0],a={x:r.screenX,y:r.screenY}))}),s.bind("touchend",function(){e==u&&(e=0),h&&(h=!1,i>c?o.apply(l,[].slice.call(arguments)):s.trigger("tap-failed"))}),s.bind("touchmove",function(n){if(h){if(0==n.originalEvent.touches.length||null===a)return h=!1;r=n.originalEvent.touches[0],c=Math.sqrt(Math.pow(r.screenX-a.x,2)+Math.pow(r.screenY-a.y,2)),c>i&&(s.trigger("exceed-tap-threshold"),h=!1)}}),s.bind("touchcancel",function(){e==u&&(e=0),h=!1,s.trigger("tap-failed")})}),this}}(window.jQuery||window.$); 6 | -------------------------------------------------------------------------------- /js/lib/angular/angular-bootstrap-prettify.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(q,k,I){'use strict';function G(c){return c.replace(/\&/g,"&").replace(/\/g,">").replace(/"/g,""")}function D(c,e){var b=k.element("
"+e+"
");c.html("");c.append(b.contents());return c}var t={},w={value:{}},L={"angular.js":"http://code.angularjs.org/"+k.version.full+"/angular.min.js","angular-resource.js":"http://code.angularjs.org/"+k.version.full+"/angular-resource.min.js","angular-sanitize.js":"http://code.angularjs.org/"+k.version.full+"/angular-sanitize.min.js", 7 | "angular-cookies.js":"http://code.angularjs.org/"+k.version.full+"/angular-cookies.min.js"};t.jsFiddle=function(c,e,b){return{terminal:!0,link:function(x,a,r){function d(a,b){return''}var H={html:"",css:"",js:""};k.forEach(r.jsFiddle.split(" "),function(a,b){var d=a.split(".")[1];H[d]+=d=="html"?b==0?"
\n"+c(a,2):"\n\n\n <\!-- CACHE FILE: "+a+' --\>\n 38 | 39 | 40 | */ 41 | factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { 42 | var cookies = {}, 43 | lastCookies = {}, 44 | lastBrowserCookies, 45 | runEval = false, 46 | copy = angular.copy, 47 | isUndefined = angular.isUndefined; 48 | 49 | //creates a poller fn that copies all cookies from the $browser to service & inits the service 50 | $browser.addPollFn(function() { 51 | var currentCookies = $browser.cookies(); 52 | if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl 53 | lastBrowserCookies = currentCookies; 54 | copy(currentCookies, lastCookies); 55 | copy(currentCookies, cookies); 56 | if (runEval) $rootScope.$apply(); 57 | } 58 | })(); 59 | 60 | runEval = true; 61 | 62 | //at the end of each eval, push cookies 63 | //TODO: this should happen before the "delayed" watches fire, because if some cookies are not 64 | // strings or browser refuses to store some cookies, we update the model in the push fn. 65 | $rootScope.$watch(push); 66 | 67 | return cookies; 68 | 69 | 70 | /** 71 | * Pushes all the cookies from the service to the browser and verifies if all cookies were stored. 72 | */ 73 | function push() { 74 | var name, 75 | value, 76 | browserCookies, 77 | updated; 78 | 79 | //delete any cookies deleted in $cookies 80 | for (name in lastCookies) { 81 | if (isUndefined(cookies[name])) { 82 | $browser.cookies(name, undefined); 83 | } 84 | } 85 | 86 | //update all cookies updated in $cookies 87 | for(name in cookies) { 88 | value = cookies[name]; 89 | if (!angular.isString(value)) { 90 | if (angular.isDefined(lastCookies[name])) { 91 | cookies[name] = lastCookies[name]; 92 | } else { 93 | delete cookies[name]; 94 | } 95 | } else if (value !== lastCookies[name]) { 96 | $browser.cookies(name, value); 97 | updated = true; 98 | } 99 | } 100 | 101 | //verify what was actually stored 102 | if (updated){ 103 | updated = false; 104 | browserCookies = $browser.cookies(); 105 | 106 | for (name in cookies) { 107 | if (cookies[name] !== browserCookies[name]) { 108 | //delete or reset all cookies that the browser dropped from $cookies 109 | if (isUndefined(browserCookies[name])) { 110 | delete cookies[name]; 111 | } else { 112 | cookies[name] = browserCookies[name]; 113 | } 114 | updated = true; 115 | } 116 | } 117 | } 118 | } 119 | }]). 120 | 121 | 122 | /** 123 | * @ngdoc object 124 | * @name ngCookies.$cookieStore 125 | * @requires $cookies 126 | * 127 | * @description 128 | * Provides a key-value (string-object) storage, that is backed by session cookies. 129 | * Objects put or retrieved from this storage are automatically serialized or 130 | * deserialized by angular's toJson/fromJson. 131 | * @example 132 | */ 133 | factory('$cookieStore', ['$cookies', function($cookies) { 134 | 135 | return { 136 | /** 137 | * @ngdoc method 138 | * @name ngCookies.$cookieStore#get 139 | * @methodOf ngCookies.$cookieStore 140 | * 141 | * @description 142 | * Returns the value of given cookie key 143 | * 144 | * @param {string} key Id to use for lookup. 145 | * @returns {Object} Deserialized cookie value. 146 | */ 147 | get: function(key) { 148 | var value = $cookies[key]; 149 | return value ? angular.fromJson(value) : value; 150 | }, 151 | 152 | /** 153 | * @ngdoc method 154 | * @name ngCookies.$cookieStore#put 155 | * @methodOf ngCookies.$cookieStore 156 | * 157 | * @description 158 | * Sets a value for given cookie key 159 | * 160 | * @param {string} key Id for the `value`. 161 | * @param {Object} value Value to be stored. 162 | */ 163 | put: function(key, value) { 164 | $cookies[key] = angular.toJson(value); 165 | }, 166 | 167 | /** 168 | * @ngdoc method 169 | * @name ngCookies.$cookieStore#remove 170 | * @methodOf ngCookies.$cookieStore 171 | * 172 | * @description 173 | * Remove given cookie 174 | * 175 | * @param {string} key Id of the key-value pair to delete. 176 | */ 177 | remove: function(key) { 178 | delete $cookies[key]; 179 | } 180 | }; 181 | 182 | }]); 183 | 184 | 185 | })(window, window.angular); 186 | -------------------------------------------------------------------------------- /js/lib/angular/angular-cookies.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(m,f,l){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,i=!1,j=f.copy,k=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,j(a,g),j(a,c),i&&d.$apply())})();i=!0;d.$watch(function(){var a,e,d;for(a in g)k(c[a])&&b.cookies(a,l);for(a in c)e=c[a],f.isString(e)?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(k(e[a])?delete c[a]:c[a]=e[a])});return c}]).factory("$cookieStore", 7 | ["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular); 8 | -------------------------------------------------------------------------------- /js/lib/angular/angular-loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.0.7 3 | * (c) 2010-2012 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | 7 | ( 8 | 9 | /** 10 | * @ngdoc interface 11 | * @name angular.Module 12 | * @description 13 | * 14 | * Interface for configuring angular {@link angular.module modules}. 15 | */ 16 | 17 | function setupModuleLoader(window) { 18 | 19 | function ensure(obj, name, factory) { 20 | return obj[name] || (obj[name] = factory()); 21 | } 22 | 23 | return ensure(ensure(window, 'angular', Object), 'module', function() { 24 | /** @type {Object.} */ 25 | var modules = {}; 26 | 27 | /** 28 | * @ngdoc function 29 | * @name angular.module 30 | * @description 31 | * 32 | * The `angular.module` is a global place for creating and registering Angular modules. All 33 | * modules (angular core or 3rd party) that should be available to an application must be 34 | * registered using this mechanism. 35 | * 36 | * 37 | * # Module 38 | * 39 | * A module is a collocation of services, directives, filters, and configuration information. Module 40 | * is used to configure the {@link AUTO.$injector $injector}. 41 | * 42 | *
 43 |      * // Create a new module
 44 |      * var myModule = angular.module('myModule', []);
 45 |      *
 46 |      * // register a new service
 47 |      * myModule.value('appName', 'MyCoolApp');
 48 |      *
 49 |      * // configure existing services inside initialization blocks.
 50 |      * myModule.config(function($locationProvider) {
 51 | 'use strict';
 52 |      *   // Configure existing providers
 53 |      *   $locationProvider.hashPrefix('!');
 54 |      * });
 55 |      * 
56 | * 57 | * Then you can create an injector and load your modules like this: 58 | * 59 | *
 60 |      * var injector = angular.injector(['ng', 'MyModule'])
 61 |      * 
62 | * 63 | * However it's more likely that you'll just use 64 | * {@link ng.directive:ngApp ngApp} or 65 | * {@link angular.bootstrap} to simplify this process for you. 66 | * 67 | * @param {!string} name The name of the module to create or retrieve. 68 | * @param {Array.=} requires If specified then new module is being created. If unspecified then the 69 | * the module is being retrieved for further configuration. 70 | * @param {Function} configFn Optional configuration function for the module. Same as 71 | * {@link angular.Module#config Module#config()}. 72 | * @returns {module} new module with the {@link angular.Module} api. 73 | */ 74 | return function module(name, requires, configFn) { 75 | if (requires && modules.hasOwnProperty(name)) { 76 | modules[name] = null; 77 | } 78 | return ensure(modules, name, function() { 79 | if (!requires) { 80 | throw Error('No module: ' + name); 81 | } 82 | 83 | /** @type {!Array.>} */ 84 | var invokeQueue = []; 85 | 86 | /** @type {!Array.} */ 87 | var runBlocks = []; 88 | 89 | var config = invokeLater('$injector', 'invoke'); 90 | 91 | /** @type {angular.Module} */ 92 | var moduleInstance = { 93 | // Private state 94 | _invokeQueue: invokeQueue, 95 | _runBlocks: runBlocks, 96 | 97 | /** 98 | * @ngdoc property 99 | * @name angular.Module#requires 100 | * @propertyOf angular.Module 101 | * @returns {Array.} List of module names which must be loaded before this module. 102 | * @description 103 | * Holds the list of modules which the injector will load before the current module is loaded. 104 | */ 105 | requires: requires, 106 | 107 | /** 108 | * @ngdoc property 109 | * @name angular.Module#name 110 | * @propertyOf angular.Module 111 | * @returns {string} Name of the module. 112 | * @description 113 | */ 114 | name: name, 115 | 116 | 117 | /** 118 | * @ngdoc method 119 | * @name angular.Module#provider 120 | * @methodOf angular.Module 121 | * @param {string} name service name 122 | * @param {Function} providerType Construction function for creating new instance of the service. 123 | * @description 124 | * See {@link AUTO.$provide#provider $provide.provider()}. 125 | */ 126 | provider: invokeLater('$provide', 'provider'), 127 | 128 | /** 129 | * @ngdoc method 130 | * @name angular.Module#factory 131 | * @methodOf angular.Module 132 | * @param {string} name service name 133 | * @param {Function} providerFunction Function for creating new instance of the service. 134 | * @description 135 | * See {@link AUTO.$provide#factory $provide.factory()}. 136 | */ 137 | factory: invokeLater('$provide', 'factory'), 138 | 139 | /** 140 | * @ngdoc method 141 | * @name angular.Module#service 142 | * @methodOf angular.Module 143 | * @param {string} name service name 144 | * @param {Function} constructor A constructor function that will be instantiated. 145 | * @description 146 | * See {@link AUTO.$provide#service $provide.service()}. 147 | */ 148 | service: invokeLater('$provide', 'service'), 149 | 150 | /** 151 | * @ngdoc method 152 | * @name angular.Module#value 153 | * @methodOf angular.Module 154 | * @param {string} name service name 155 | * @param {*} object Service instance object. 156 | * @description 157 | * See {@link AUTO.$provide#value $provide.value()}. 158 | */ 159 | value: invokeLater('$provide', 'value'), 160 | 161 | /** 162 | * @ngdoc method 163 | * @name angular.Module#constant 164 | * @methodOf angular.Module 165 | * @param {string} name constant name 166 | * @param {*} object Constant value. 167 | * @description 168 | * Because the constant are fixed, they get applied before other provide methods. 169 | * See {@link AUTO.$provide#constant $provide.constant()}. 170 | */ 171 | constant: invokeLater('$provide', 'constant', 'unshift'), 172 | 173 | /** 174 | * @ngdoc method 175 | * @name angular.Module#filter 176 | * @methodOf angular.Module 177 | * @param {string} name Filter name. 178 | * @param {Function} filterFactory Factory function for creating new instance of filter. 179 | * @description 180 | * See {@link ng.$filterProvider#register $filterProvider.register()}. 181 | */ 182 | filter: invokeLater('$filterProvider', 'register'), 183 | 184 | /** 185 | * @ngdoc method 186 | * @name angular.Module#controller 187 | * @methodOf angular.Module 188 | * @param {string} name Controller name. 189 | * @param {Function} constructor Controller constructor function. 190 | * @description 191 | * See {@link ng.$controllerProvider#register $controllerProvider.register()}. 192 | */ 193 | controller: invokeLater('$controllerProvider', 'register'), 194 | 195 | /** 196 | * @ngdoc method 197 | * @name angular.Module#directive 198 | * @methodOf angular.Module 199 | * @param {string} name directive name 200 | * @param {Function} directiveFactory Factory function for creating new instance of 201 | * directives. 202 | * @description 203 | * See {@link ng.$compileProvider#directive $compileProvider.directive()}. 204 | */ 205 | directive: invokeLater('$compileProvider', 'directive'), 206 | 207 | /** 208 | * @ngdoc method 209 | * @name angular.Module#config 210 | * @methodOf angular.Module 211 | * @param {Function} configFn Execute this function on module load. Useful for service 212 | * configuration. 213 | * @description 214 | * Use this method to register work which needs to be performed on module loading. 215 | */ 216 | config: config, 217 | 218 | /** 219 | * @ngdoc method 220 | * @name angular.Module#run 221 | * @methodOf angular.Module 222 | * @param {Function} initializationFn Execute this function after injector creation. 223 | * Useful for application initialization. 224 | * @description 225 | * Use this method to register work which should be performed when the injector is done 226 | * loading all modules. 227 | */ 228 | run: function(block) { 229 | runBlocks.push(block); 230 | return this; 231 | } 232 | }; 233 | 234 | if (configFn) { 235 | config(configFn); 236 | } 237 | 238 | return moduleInstance; 239 | 240 | /** 241 | * @param {string} provider 242 | * @param {string} method 243 | * @param {String=} insertMethod 244 | * @returns {angular.Module} 245 | */ 246 | function invokeLater(provider, method, insertMethod) { 247 | return function() { 248 | invokeQueue[insertMethod || 'push']([provider, method, arguments]); 249 | return moduleInstance; 250 | } 251 | } 252 | }); 253 | }; 254 | }); 255 | 256 | } 257 | 258 | )(window); 259 | 260 | /** 261 | * Closure compiler type information 262 | * 263 | * @typedef { { 264 | * requires: !Array., 265 | * invokeQueue: !Array.>, 266 | * 267 | * service: function(string, Function):angular.Module, 268 | * factory: function(string, Function):angular.Module, 269 | * value: function(string, *):angular.Module, 270 | * 271 | * filter: function(string, Function):angular.Module, 272 | * 273 | * init: function(Function):angular.Module 274 | * } } 275 | */ 276 | angular.Module; 277 | 278 | -------------------------------------------------------------------------------- /js/lib/angular/angular-loader.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(i){'use strict';function d(c,b,e){return c[b]||(c[b]=e())}return d(d(i,"angular",Object),"module",function(){var c={};return function(b,e,f){e&&c.hasOwnProperty(b)&&(c[b]=null);return d(c,b,function(){function a(a,b,d){return function(){c[d||"push"]([a,b,arguments]);return g}}if(!e)throw Error("No module: "+b);var c=[],d=[],h=a("$injector","invoke"),g={_invokeQueue:c,_runBlocks:d,requires:e,name:b,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"), 7 | value:a("$provide","value"),constant:a("$provide","constant","unshift"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:h,run:function(a){d.push(a);return this}};f&&h(f);return g})}})})(window); 8 | -------------------------------------------------------------------------------- /js/lib/angular/angular-resource.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.0.7 3 | * (c) 2010-2012 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) { 7 | 'use strict'; 8 | 9 | /** 10 | * @ngdoc overview 11 | * @name ngResource 12 | * @description 13 | */ 14 | 15 | /** 16 | * @ngdoc object 17 | * @name ngResource.$resource 18 | * @requires $http 19 | * 20 | * @description 21 | * A factory which creates a resource object that lets you interact with 22 | * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources. 23 | * 24 | * The returned resource object has action methods which provide high-level behaviors without 25 | * the need to interact with the low level {@link ng.$http $http} service. 26 | * 27 | * # Installation 28 | * To use $resource make sure you have included the `angular-resource.js` that comes in Angular 29 | * package. You can also find this file on Google CDN, bower as well as at 30 | * {@link http://code.angularjs.org/ code.angularjs.org}. 31 | * 32 | * Finally load the module in your application: 33 | * 34 | * angular.module('app', ['ngResource']); 35 | * 36 | * and you are ready to get started! 37 | * 38 | * @param {string} url A parameterized URL template with parameters prefixed by `:` as in 39 | * `/user/:username`. If you are using a URL with a port number (e.g. 40 | * `http://example.com:8080/api`), you'll need to escape the colon character before the port 41 | * number, like this: `$resource('http://example.com\\:8080/api')`. 42 | * 43 | * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in 44 | * `actions` methods. 45 | * 46 | * Each key value in the parameter object is first bound to url template if present and then any 47 | * excess keys are appended to the url search query after the `?`. 48 | * 49 | * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in 50 | * URL `/path/greet?salutation=Hello`. 51 | * 52 | * If the parameter value is prefixed with `@` then the value of that parameter is extracted from 53 | * the data object (useful for non-GET operations). 54 | * 55 | * @param {Object.=} actions Hash with declaration of custom action that should extend the 56 | * default set of resource actions. The declaration should be created in the following format: 57 | * 58 | * {action1: {method:?, params:?, isArray:?}, 59 | * action2: {method:?, params:?, isArray:?}, 60 | * ...} 61 | * 62 | * Where: 63 | * 64 | * - `action` – {string} – The name of action. This name becomes the name of the method on your 65 | * resource object. 66 | * - `method` – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, `DELETE`, 67 | * and `JSONP` 68 | * - `params` – {object=} – Optional set of pre-bound parameters for this action. 69 | * - isArray – {boolean=} – If true then the returned object for this action is an array, see 70 | * `returns` section. 71 | * 72 | * @returns {Object} A resource "class" object with methods for the default set of resource actions 73 | * optionally extended with custom `actions`. The default set contains these actions: 74 | * 75 | * { 'get': {method:'GET'}, 76 | * 'save': {method:'POST'}, 77 | * 'query': {method:'GET', isArray:true}, 78 | * 'remove': {method:'DELETE'}, 79 | * 'delete': {method:'DELETE'} }; 80 | * 81 | * Calling these methods invoke an {@link ng.$http} with the specified http method, 82 | * destination and parameters. When the data is returned from the server then the object is an 83 | * instance of the resource class. The actions `save`, `remove` and `delete` are available on it 84 | * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, 85 | * read, update, delete) on server-side data like this: 86 | *
 87 |         var User = $resource('/user/:userId', {userId:'@id'});
 88 |         var user = User.get({userId:123}, function() {
 89 |           user.abc = true;
 90 |           user.$save();
 91 |         });
 92 |      
93 | * 94 | * It is important to realize that invoking a $resource object method immediately returns an 95 | * empty reference (object or array depending on `isArray`). Once the data is returned from the 96 | * server the existing reference is populated with the actual data. This is a useful trick since 97 | * usually the resource is assigned to a model which is then rendered by the view. Having an empty 98 | * object results in no rendering, once the data arrives from the server then the object is 99 | * populated with the data and the view automatically re-renders itself showing the new data. This 100 | * means that in most case one never has to write a callback function for the action methods. 101 | * 102 | * The action methods on the class object or instance object can be invoked with the following 103 | * parameters: 104 | * 105 | * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])` 106 | * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])` 107 | * - non-GET instance actions: `instance.$action([parameters], [success], [error])` 108 | * 109 | * 110 | * @example 111 | * 112 | * # Credit card resource 113 | * 114 | *
115 |      // Define CreditCard class
116 |      var CreditCard = $resource('/user/:userId/card/:cardId',
117 |       {userId:123, cardId:'@id'}, {
118 |        charge: {method:'POST', params:{charge:true}}
119 |       });
120 | 
121 |      // We can retrieve a collection from the server
122 |      var cards = CreditCard.query(function() {
123 |        // GET: /user/123/card
124 |        // server returns: [ {id:456, number:'1234', name:'Smith'} ];
125 | 
126 |        var card = cards[0];
127 |        // each item is an instance of CreditCard
128 |        expect(card instanceof CreditCard).toEqual(true);
129 |        card.name = "J. Smith";
130 |        // non GET methods are mapped onto the instances
131 |        card.$save();
132 |        // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
133 |        // server returns: {id:456, number:'1234', name: 'J. Smith'};
134 | 
135 |        // our custom method is mapped as well.
136 |        card.$charge({amount:9.99});
137 |        // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
138 |      });
139 | 
140 |      // we can create an instance as well
141 |      var newCard = new CreditCard({number:'0123'});
142 |      newCard.name = "Mike Smith";
143 |      newCard.$save();
144 |      // POST: /user/123/card {number:'0123', name:'Mike Smith'}
145 |      // server returns: {id:789, number:'01234', name: 'Mike Smith'};
146 |      expect(newCard.id).toEqual(789);
147 |  * 
148 | * 149 | * The object returned from this function execution is a resource "class" which has "static" method 150 | * for each action in the definition. 151 | * 152 | * Calling these methods invoke `$http` on the `url` template with the given `method` and `params`. 153 | * When the data is returned from the server then the object is an instance of the resource type and 154 | * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD 155 | * operations (create, read, update, delete) on server-side data. 156 | 157 |
158 |      var User = $resource('/user/:userId', {userId:'@id'});
159 |      var user = User.get({userId:123}, function() {
160 |        user.abc = true;
161 |        user.$save();
162 |      });
163 |    
164 | * 165 | * It's worth noting that the success callback for `get`, `query` and other method gets passed 166 | * in the response that came from the server as well as $http header getter function, so one 167 | * could rewrite the above example and get access to http headers as: 168 | * 169 |
170 |      var User = $resource('/user/:userId', {userId:'@id'});
171 |      User.get({userId:123}, function(u, getResponseHeaders){
172 |        u.abc = true;
173 |        u.$save(function(u, putResponseHeaders) {
174 |          //u => saved user object
175 |          //putResponseHeaders => $http header getter
176 |        });
177 |      });
178 |    
179 | 180 | * # Buzz client 181 | 182 | Let's look at what a buzz client created with the `$resource` service looks like: 183 | 184 | 185 | 205 | 206 |
207 | 208 | 209 |
210 |
211 |

212 | 213 | {{item.actor.name}} 214 | Expand replies: {{item.links.replies[0].count}} 215 |

216 | {{item.object.content | html}} 217 |
218 | 219 | {{reply.actor.name}}: {{reply.content | html}} 220 |
221 |
222 |
223 |
224 | 225 | 226 |
227 | */ 228 | angular.module('ngResource', ['ng']). 229 | factory('$resource', ['$http', '$parse', function($http, $parse) { 230 | var DEFAULT_ACTIONS = { 231 | 'get': {method:'GET'}, 232 | 'save': {method:'POST'}, 233 | 'query': {method:'GET', isArray:true}, 234 | 'remove': {method:'DELETE'}, 235 | 'delete': {method:'DELETE'} 236 | }; 237 | var noop = angular.noop, 238 | forEach = angular.forEach, 239 | extend = angular.extend, 240 | copy = angular.copy, 241 | isFunction = angular.isFunction, 242 | getter = function(obj, path) { 243 | return $parse(path)(obj); 244 | }; 245 | 246 | /** 247 | * We need our custom method because encodeURIComponent is too aggressive and doesn't follow 248 | * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path 249 | * segments: 250 | * segment = *pchar 251 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 252 | * pct-encoded = "%" HEXDIG HEXDIG 253 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 254 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 255 | * / "*" / "+" / "," / ";" / "=" 256 | */ 257 | function encodeUriSegment(val) { 258 | return encodeUriQuery(val, true). 259 | replace(/%26/gi, '&'). 260 | replace(/%3D/gi, '='). 261 | replace(/%2B/gi, '+'); 262 | } 263 | 264 | 265 | /** 266 | * This method is intended for encoding *key* or *value* parts of query component. We need a custom 267 | * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be 268 | * encoded per http://tools.ietf.org/html/rfc3986: 269 | * query = *( pchar / "/" / "?" ) 270 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 271 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 272 | * pct-encoded = "%" HEXDIG HEXDIG 273 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 274 | * / "*" / "+" / "," / ";" / "=" 275 | */ 276 | function encodeUriQuery(val, pctEncodeSpaces) { 277 | return encodeURIComponent(val). 278 | replace(/%40/gi, '@'). 279 | replace(/%3A/gi, ':'). 280 | replace(/%24/g, '$'). 281 | replace(/%2C/gi, ','). 282 | replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); 283 | } 284 | 285 | function Route(template, defaults) { 286 | this.template = template = template + '#'; 287 | this.defaults = defaults || {}; 288 | var urlParams = this.urlParams = {}; 289 | forEach(template.split(/\W/), function(param){ 290 | if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) { 291 | urlParams[param] = true; 292 | } 293 | }); 294 | this.template = template.replace(/\\:/g, ':'); 295 | } 296 | 297 | Route.prototype = { 298 | url: function(params) { 299 | var self = this, 300 | url = this.template, 301 | val, 302 | encodedVal; 303 | 304 | params = params || {}; 305 | forEach(this.urlParams, function(_, urlParam){ 306 | val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; 307 | if (angular.isDefined(val) && val !== null) { 308 | encodedVal = encodeUriSegment(val); 309 | url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1"); 310 | } else { 311 | url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match, 312 | leadingSlashes, tail) { 313 | if (tail.charAt(0) == '/') { 314 | return tail; 315 | } else { 316 | return leadingSlashes + tail; 317 | } 318 | }); 319 | } 320 | }); 321 | url = url.replace(/\/?#$/, ''); 322 | var query = []; 323 | forEach(params, function(value, key){ 324 | if (!self.urlParams[key]) { 325 | query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value)); 326 | } 327 | }); 328 | query.sort(); 329 | url = url.replace(/\/*$/, ''); 330 | return url + (query.length ? '?' + query.join('&') : ''); 331 | } 332 | }; 333 | 334 | 335 | function ResourceFactory(url, paramDefaults, actions) { 336 | var route = new Route(url); 337 | 338 | actions = extend({}, DEFAULT_ACTIONS, actions); 339 | 340 | function extractParams(data, actionParams){ 341 | var ids = {}; 342 | actionParams = extend({}, paramDefaults, actionParams); 343 | forEach(actionParams, function(value, key){ 344 | ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value; 345 | }); 346 | return ids; 347 | } 348 | 349 | function Resource(value){ 350 | copy(value || {}, this); 351 | } 352 | 353 | forEach(actions, function(action, name) { 354 | action.method = angular.uppercase(action.method); 355 | var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH'; 356 | Resource[name] = function(a1, a2, a3, a4) { 357 | var params = {}; 358 | var data; 359 | var success = noop; 360 | var error = null; 361 | switch(arguments.length) { 362 | case 4: 363 | error = a4; 364 | success = a3; 365 | //fallthrough 366 | case 3: 367 | case 2: 368 | if (isFunction(a2)) { 369 | if (isFunction(a1)) { 370 | success = a1; 371 | error = a2; 372 | break; 373 | } 374 | 375 | success = a2; 376 | error = a3; 377 | //fallthrough 378 | } else { 379 | params = a1; 380 | data = a2; 381 | success = a3; 382 | break; 383 | } 384 | case 1: 385 | if (isFunction(a1)) success = a1; 386 | else if (hasBody) data = a1; 387 | else params = a1; 388 | break; 389 | case 0: break; 390 | default: 391 | throw "Expected between 0-4 arguments [params, data, success, error], got " + 392 | arguments.length + " arguments."; 393 | } 394 | 395 | var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data)); 396 | $http({ 397 | method: action.method, 398 | url: route.url(extend({}, extractParams(data, action.params || {}), params)), 399 | data: data 400 | }).then(function(response) { 401 | var data = response.data; 402 | 403 | if (data) { 404 | if (action.isArray) { 405 | value.length = 0; 406 | forEach(data, function(item) { 407 | value.push(new Resource(item)); 408 | }); 409 | } else { 410 | copy(data, value); 411 | } 412 | } 413 | (success||noop)(value, response.headers); 414 | }, error); 415 | 416 | return value; 417 | }; 418 | 419 | 420 | Resource.prototype['$' + name] = function(a1, a2, a3) { 421 | var params = extractParams(this), 422 | success = noop, 423 | error; 424 | 425 | switch(arguments.length) { 426 | case 3: params = a1; success = a2; error = a3; break; 427 | case 2: 428 | case 1: 429 | if (isFunction(a1)) { 430 | success = a1; 431 | error = a2; 432 | } else { 433 | params = a1; 434 | success = a2 || noop; 435 | } 436 | case 0: break; 437 | default: 438 | throw "Expected between 1-3 arguments [params, success, error], got " + 439 | arguments.length + " arguments."; 440 | } 441 | var data = hasBody ? this : undefined; 442 | Resource[name].call(this, params, data, success, error); 443 | }; 444 | }); 445 | 446 | Resource.bind = function(additionalParamDefaults){ 447 | return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions); 448 | }; 449 | 450 | return Resource; 451 | } 452 | 453 | return ResourceFactory; 454 | }]); 455 | 456 | 457 | })(window, window.angular); 458 | -------------------------------------------------------------------------------- /js/lib/angular/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(C,d,w){'use strict';d.module("ngResource",["ng"]).factory("$resource",["$http","$parse",function(x,y){function s(b,e){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,e?"%20":"+")}function t(b,e){this.template=b+="#";this.defaults=e||{};var a=this.urlParams={};h(b.split(/\W/),function(f){f&&RegExp("(^|[^\\\\]):"+f+"\\W").test(b)&&(a[f]=!0)});this.template=b.replace(/\\:/g,":")}function u(b,e,a){function f(m,a){var b= 7 | {},a=o({},e,a);h(a,function(a,z){var c;a.charAt&&a.charAt(0)=="@"?(c=a.substr(1),c=y(c)(m)):c=a;b[z]=c});return b}function g(a){v(a||{},this)}var k=new t(b),a=o({},A,a);h(a,function(a,b){a.method=d.uppercase(a.method);var e=a.method=="POST"||a.method=="PUT"||a.method=="PATCH";g[b]=function(b,c,d,B){var j={},i,l=p,q=null;switch(arguments.length){case 4:q=B,l=d;case 3:case 2:if(r(c)){if(r(b)){l=b;q=c;break}l=c;q=d}else{j=b;i=c;l=d;break}case 1:r(b)?l=b:e?i=b:j=b;break;case 0:break;default:throw"Expected between 0-4 arguments [params, data, success, error], got "+ 8 | arguments.length+" arguments.";}var n=this instanceof g?this:a.isArray?[]:new g(i);x({method:a.method,url:k.url(o({},f(i,a.params||{}),j)),data:i}).then(function(b){var c=b.data;if(c)a.isArray?(n.length=0,h(c,function(a){n.push(new g(a))})):v(c,n);(l||p)(n,b.headers)},q);return n};g.prototype["$"+b]=function(a,d,h){var m=f(this),j=p,i;switch(arguments.length){case 3:m=a;j=d;i=h;break;case 2:case 1:r(a)?(j=a,i=d):(m=a,j=d||p);case 0:break;default:throw"Expected between 1-3 arguments [params, success, error], got "+ 9 | arguments.length+" arguments.";}g[b].call(this,m,e?this:w,j,i)}});g.bind=function(d){return u(b,o({},e,d),a)};return g}var A={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},p=d.noop,h=d.forEach,o=d.extend,v=d.copy,r=d.isFunction;t.prototype={url:function(b){var e=this,a=this.template,f,g,b=b||{};h(this.urlParams,function(h,c){f=b.hasOwnProperty(c)?b[c]:e.defaults[c];d.isDefined(f)&&f!==null?(g=s(f,!0).replace(/%26/gi,"&").replace(/%3D/gi, 10 | "=").replace(/%2B/gi,"+"),a=a.replace(RegExp(":"+c+"(\\W)","g"),g+"$1")):a=a.replace(RegExp("(/?):"+c+"(\\W)","g"),function(a,b,c){return c.charAt(0)=="/"?c:b+c})});var a=a.replace(/\/?#$/,""),k=[];h(b,function(a,b){e.urlParams[b]||k.push(s(b)+"="+s(a))});k.sort();a=a.replace(/\/*$/,"");return a+(k.length?"?"+k.join("&"):"")}};return u}])})(window,window.angular); 11 | -------------------------------------------------------------------------------- /js/lib/angular/angular-sanitize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.0.7 3 | * (c) 2010-2012 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) { 7 | 'use strict'; 8 | 9 | /** 10 | * @ngdoc overview 11 | * @name ngSanitize 12 | * @description 13 | */ 14 | 15 | /* 16 | * HTML Parser By Misko Hevery (misko@hevery.com) 17 | * based on: HTML Parser By John Resig (ejohn.org) 18 | * Original code by Erik Arvidsson, Mozilla Public License 19 | * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js 20 | * 21 | * // Use like so: 22 | * htmlParser(htmlString, { 23 | * start: function(tag, attrs, unary) {}, 24 | * end: function(tag) {}, 25 | * chars: function(text) {}, 26 | * comment: function(text) {} 27 | * }); 28 | * 29 | */ 30 | 31 | 32 | /** 33 | * @ngdoc service 34 | * @name ngSanitize.$sanitize 35 | * @function 36 | * 37 | * @description 38 | * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are 39 | * then serialized back to properly escaped html string. This means that no unsafe input can make 40 | * it into the returned string, however, since our parser is more strict than a typical browser 41 | * parser, it's possible that some obscure input, which would be recognized as valid HTML by a 42 | * browser, won't make it through the sanitizer. 43 | * 44 | * @param {string} html Html input. 45 | * @returns {string} Sanitized html. 46 | * 47 | * @example 48 | 49 | 50 | 58 |
59 | Snippet: 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 71 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
FilterSourceRendered
html filter 69 |
<div ng-bind-html="snippet">
</div>
70 |
72 |
73 |
no filter
<div ng-bind="snippet">
</div>
unsafe html filter
<div ng-bind-html-unsafe="snippet">
</div>
86 |
87 |
88 | 89 | it('should sanitize the html snippet ', function() { 90 | expect(using('#html-filter').element('div').html()). 91 | toBe('

an html\nclick here\nsnippet

'); 92 | }); 93 | 94 | it('should escape snippet without any filter', function() { 95 | expect(using('#escaped-html').element('div').html()). 96 | toBe("<p style=\"color:blue\">an html\n" + 97 | "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + 98 | "snippet</p>"); 99 | }); 100 | 101 | it('should inline raw snippet if filtered as unsafe', function() { 102 | expect(using('#html-unsafe-filter').element("div").html()). 103 | toBe("

an html\n" + 104 | "click here\n" + 105 | "snippet

"); 106 | }); 107 | 108 | it('should update', function() { 109 | input('snippet').enter('new text'); 110 | expect(using('#html-filter').binding('snippet')).toBe('new text'); 111 | expect(using('#escaped-html').element('div').html()).toBe("new <b>text</b>"); 112 | expect(using('#html-unsafe-filter').binding("snippet")).toBe('new text'); 113 | }); 114 |
115 |
116 | */ 117 | var $sanitize = function(html) { 118 | var buf = []; 119 | htmlParser(html, htmlSanitizeWriter(buf)); 120 | return buf.join(''); 121 | }; 122 | 123 | 124 | // Regular Expressions for parsing tags and attributes 125 | var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, 126 | END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, 127 | ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, 128 | BEGIN_TAG_REGEXP = /^/g, 131 | CDATA_REGEXP = //g, 132 | URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/, 133 | NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character) 134 | 135 | 136 | // Good source of info about elements and attributes 137 | // http://dev.w3.org/html5/spec/Overview.html#semantics 138 | // http://simon.html5.org/html-elements 139 | 140 | // Safe Void Elements - HTML5 141 | // http://dev.w3.org/html5/spec/Overview.html#void-elements 142 | var voidElements = makeMap("area,br,col,hr,img,wbr"); 143 | 144 | // Elements that you can, intentionally, leave open (and which close themselves) 145 | // http://dev.w3.org/html5/spec/Overview.html#optional-tags 146 | var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), 147 | optionalEndTagInlineElements = makeMap("rp,rt"), 148 | optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements); 149 | 150 | // Safe Block Elements - HTML5 151 | var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," + 152 | "blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," + 153 | "header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); 154 | 155 | // Inline Elements - HTML5 156 | var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," + 157 | "big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," + 158 | "span,strike,strong,sub,sup,time,tt,u,var")); 159 | 160 | 161 | // Special Elements (can contain anything) 162 | var specialElements = makeMap("script,style"); 163 | 164 | var validElements = angular.extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements); 165 | 166 | //Attributes that have href and hence need to be sanitized 167 | var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap"); 168 | var validAttrs = angular.extend({}, uriAttrs, makeMap( 169 | 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ 170 | 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+ 171 | 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+ 172 | 'scope,scrolling,shape,span,start,summary,target,title,type,'+ 173 | 'valign,value,vspace,width')); 174 | 175 | function makeMap(str) { 176 | var obj = {}, items = str.split(','), i; 177 | for (i = 0; i < items.length; i++) obj[items[i]] = true; 178 | return obj; 179 | } 180 | 181 | 182 | /** 183 | * @example 184 | * htmlParser(htmlString, { 185 | * start: function(tag, attrs, unary) {}, 186 | * end: function(tag) {}, 187 | * chars: function(text) {}, 188 | * comment: function(text) {} 189 | * }); 190 | * 191 | * @param {string} html string 192 | * @param {object} handler 193 | */ 194 | function htmlParser( html, handler ) { 195 | var index, chars, match, stack = [], last = html; 196 | stack.last = function() { return stack[ stack.length - 1 ]; }; 197 | 198 | while ( html ) { 199 | chars = true; 200 | 201 | // Make sure we're not in a script or style element 202 | if ( !stack.last() || !specialElements[ stack.last() ] ) { 203 | 204 | // Comment 205 | if ( html.indexOf(""); 207 | 208 | if ( index >= 0 ) { 209 | if (handler.comment) handler.comment( html.substring( 4, index ) ); 210 | html = html.substring( index + 3 ); 211 | chars = false; 212 | } 213 | 214 | // end tag 215 | } else if ( BEGING_END_TAGE_REGEXP.test(html) ) { 216 | match = html.match( END_TAG_REGEXP ); 217 | 218 | if ( match ) { 219 | html = html.substring( match[0].length ); 220 | match[0].replace( END_TAG_REGEXP, parseEndTag ); 221 | chars = false; 222 | } 223 | 224 | // start tag 225 | } else if ( BEGIN_TAG_REGEXP.test(html) ) { 226 | match = html.match( START_TAG_REGEXP ); 227 | 228 | if ( match ) { 229 | html = html.substring( match[0].length ); 230 | match[0].replace( START_TAG_REGEXP, parseStartTag ); 231 | chars = false; 232 | } 233 | } 234 | 235 | if ( chars ) { 236 | index = html.indexOf("<"); 237 | 238 | var text = index < 0 ? html : html.substring( 0, index ); 239 | html = index < 0 ? "" : html.substring( index ); 240 | 241 | if (handler.chars) handler.chars( decodeEntities(text) ); 242 | } 243 | 244 | } else { 245 | html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), function(all, text){ 246 | text = text. 247 | replace(COMMENT_REGEXP, "$1"). 248 | replace(CDATA_REGEXP, "$1"); 249 | 250 | if (handler.chars) handler.chars( decodeEntities(text) ); 251 | 252 | return ""; 253 | }); 254 | 255 | parseEndTag( "", stack.last() ); 256 | } 257 | 258 | if ( html == last ) { 259 | throw "Parse Error: " + html; 260 | } 261 | last = html; 262 | } 263 | 264 | // Clean up any remaining tags 265 | parseEndTag(); 266 | 267 | function parseStartTag( tag, tagName, rest, unary ) { 268 | tagName = angular.lowercase(tagName); 269 | if ( blockElements[ tagName ] ) { 270 | while ( stack.last() && inlineElements[ stack.last() ] ) { 271 | parseEndTag( "", stack.last() ); 272 | } 273 | } 274 | 275 | if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) { 276 | parseEndTag( "", tagName ); 277 | } 278 | 279 | unary = voidElements[ tagName ] || !!unary; 280 | 281 | if ( !unary ) 282 | stack.push( tagName ); 283 | 284 | var attrs = {}; 285 | 286 | rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) { 287 | var value = doubleQuotedValue 288 | || singleQoutedValue 289 | || unqoutedValue 290 | || ''; 291 | 292 | attrs[name] = decodeEntities(value); 293 | }); 294 | if (handler.start) handler.start( tagName, attrs, unary ); 295 | } 296 | 297 | function parseEndTag( tag, tagName ) { 298 | var pos = 0, i; 299 | tagName = angular.lowercase(tagName); 300 | if ( tagName ) 301 | // Find the closest opened tag of the same type 302 | for ( pos = stack.length - 1; pos >= 0; pos-- ) 303 | if ( stack[ pos ] == tagName ) 304 | break; 305 | 306 | if ( pos >= 0 ) { 307 | // Close all the open elements, up the stack 308 | for ( i = stack.length - 1; i >= pos; i-- ) 309 | if (handler.end) handler.end( stack[ i ] ); 310 | 311 | // Remove the open elements from the stack 312 | stack.length = pos; 313 | } 314 | } 315 | } 316 | 317 | /** 318 | * decodes all entities into regular string 319 | * @param value 320 | * @returns {string} A string with decoded entities. 321 | */ 322 | var hiddenPre=document.createElement("pre"); 323 | function decodeEntities(value) { 324 | hiddenPre.innerHTML=value.replace(//g, '>'); 343 | } 344 | 345 | /** 346 | * create an HTML/XML writer which writes to buffer 347 | * @param {Array} buf use buf.jain('') to get out sanitized html string 348 | * @returns {object} in the form of { 349 | * start: function(tag, attrs, unary) {}, 350 | * end: function(tag) {}, 351 | * chars: function(text) {}, 352 | * comment: function(text) {} 353 | * } 354 | */ 355 | function htmlSanitizeWriter(buf){ 356 | var ignore = false; 357 | var out = angular.bind(buf, buf.push); 358 | return { 359 | start: function(tag, attrs, unary){ 360 | tag = angular.lowercase(tag); 361 | if (!ignore && specialElements[tag]) { 362 | ignore = tag; 363 | } 364 | if (!ignore && validElements[tag] == true) { 365 | out('<'); 366 | out(tag); 367 | angular.forEach(attrs, function(value, key){ 368 | var lkey=angular.lowercase(key); 369 | if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) { 370 | out(' '); 371 | out(key); 372 | out('="'); 373 | out(encodeEntities(value)); 374 | out('"'); 375 | } 376 | }); 377 | out(unary ? '/>' : '>'); 378 | } 379 | }, 380 | end: function(tag){ 381 | tag = angular.lowercase(tag); 382 | if (!ignore && validElements[tag] == true) { 383 | out(''); 386 | } 387 | if (tag == ignore) { 388 | ignore = false; 389 | } 390 | }, 391 | chars: function(chars){ 392 | if (!ignore) { 393 | out(encodeEntities(chars)); 394 | } 395 | } 396 | }; 397 | } 398 | 399 | 400 | // define ngSanitize module and register $sanitize service 401 | angular.module('ngSanitize', []).value('$sanitize', $sanitize); 402 | 403 | /** 404 | * @ngdoc directive 405 | * @name ngSanitize.directive:ngBindHtml 406 | * 407 | * @description 408 | * Creates a binding that will sanitize the result of evaluating the `expression` with the 409 | * {@link ngSanitize.$sanitize $sanitize} service and innerHTML the result into the current element. 410 | * 411 | * See {@link ngSanitize.$sanitize $sanitize} docs for examples. 412 | * 413 | * @element ANY 414 | * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate. 415 | */ 416 | angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) { 417 | return function(scope, element, attr) { 418 | element.addClass('ng-binding').data('$binding', attr.ngBindHtml); 419 | scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) { 420 | value = $sanitize(value); 421 | element.html(value || ''); 422 | }); 423 | }; 424 | }]); 425 | 426 | /** 427 | * @ngdoc filter 428 | * @name ngSanitize.filter:linky 429 | * @function 430 | * 431 | * @description 432 | * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and 433 | * plain email address links. 434 | * 435 | * @param {string} text Input text. 436 | * @returns {string} Html-linkified text. 437 | * 438 | * @usage 439 | 440 | * 441 | * @example 442 | 443 | 444 | 454 |
455 | Snippet: 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 467 | 470 | 471 | 472 | 473 | 474 | 475 | 476 |
FilterSourceRendered
linky filter 465 |
<div ng-bind-html="snippet | linky">
</div>
466 |
468 |
469 |
no filter
<div ng-bind="snippet">
</div>
477 | 478 | 479 | it('should linkify the snippet with urls', function() { 480 | expect(using('#linky-filter').binding('snippet | linky')). 481 | toBe('Pretty text with some links: ' + 482 | 'http://angularjs.org/, ' + 483 | 'us@somewhere.org, ' + 484 | 'another@somewhere.org, ' + 485 | 'and one more: ftp://127.0.0.1/.'); 486 | }); 487 | 488 | it ('should not linkify snippet without the linky filter', function() { 489 | expect(using('#escaped-html').binding('snippet')). 490 | toBe("Pretty text with some links:\n" + 491 | "http://angularjs.org/,\n" + 492 | "mailto:us@somewhere.org,\n" + 493 | "another@somewhere.org,\n" + 494 | "and one more: ftp://127.0.0.1/."); 495 | }); 496 | 497 | it('should update', function() { 498 | input('snippet').enter('new http://link.'); 499 | expect(using('#linky-filter').binding('snippet | linky')). 500 | toBe('new http://link.'); 501 | expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); 502 | }); 503 | 504 | 505 | */ 506 | angular.module('ngSanitize').filter('linky', function() { 507 | var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/, 508 | MAILTO_REGEXP = /^mailto:/; 509 | 510 | return function(text) { 511 | if (!text) return text; 512 | var match; 513 | var raw = text; 514 | var html = []; 515 | // TODO(vojta): use $sanitize instead 516 | var writer = htmlSanitizeWriter(html); 517 | var url; 518 | var i; 519 | while ((match = raw.match(LINKY_URL_REGEXP))) { 520 | // We can not end in these as they are sometimes found at the end of the sentence 521 | url = match[0]; 522 | // if we did not match ftp/http/mailto then assume mailto 523 | if (match[2] == match[3]) url = 'mailto:' + url; 524 | i = match.index; 525 | writer.chars(raw.substr(0, i)); 526 | writer.start('a', {href:url}); 527 | writer.chars(match[0].replace(MAILTO_REGEXP, '')); 528 | writer.end('a'); 529 | raw = raw.substring(i + match[0].length); 530 | } 531 | writer.chars(raw); 532 | return html.join(''); 533 | }; 534 | }); 535 | 536 | 537 | })(window, window.angular); 538 | -------------------------------------------------------------------------------- /js/lib/angular/angular-sanitize.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(I,g){'use strict';function i(a){var d={},a=a.split(","),b;for(b=0;b=0;e--)if(f[e]==b)break;if(e>=0){for(c=f.length-1;c>=e;c--)d.end&&d.end(f[c]);f.length= 7 | e}}var c,h,f=[],j=a;for(f.last=function(){return f[f.length-1]};a;){h=!0;if(!f.last()||!q[f.last()]){if(a.indexOf("<\!--")===0)c=a.indexOf("--\>"),c>=0&&(d.comment&&d.comment(a.substring(4,c)),a=a.substring(c+3),h=!1);else if(B.test(a)){if(c=a.match(r))a=a.substring(c[0].length),c[0].replace(r,e),h=!1}else if(C.test(a)&&(c=a.match(s)))a=a.substring(c[0].length),c[0].replace(s,b),h=!1;h&&(c=a.indexOf("<"),h=c<0?a:a.substring(0,c),a=c<0?"":a.substring(c),d.chars&&d.chars(k(h)))}else a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+ 8 | f.last()+"[^>]*>","i"),function(b,a){a=a.replace(D,"$1").replace(E,"$1");d.chars&&d.chars(k(a));return""}),e("",f.last());if(a==j)throw"Parse Error: "+a;j=a}e()}function k(a){l.innerHTML=a.replace(//g,">")}function u(a){var d=!1,b=g.bind(a,a.push);return{start:function(a,c,h){a=g.lowercase(a);!d&&q[a]&&(d=a);!d&&v[a]== 9 | !0&&(b("<"),b(a),g.forEach(c,function(a,c){var e=g.lowercase(c);if(G[e]==!0&&(w[e]!==!0||a.match(H)))b(" "),b(c),b('="'),b(t(a)),b('"')}),b(h?"/>":">"))},end:function(a){a=g.lowercase(a);!d&&v[a]==!0&&(b(""));a==d&&(d=!1)},chars:function(a){d||b(t(a))}}}var s=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,r=/^<\s*\/\s*([\w:-]+)[^>]*>/,A=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,C=/^/g, 10 | E=//g,H=/^((ftp|https?):\/\/|mailto:|#)/,F=/([^\#-~| |!])/g,p=i("area,br,col,hr,img,wbr"),x=i("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),y=i("rp,rt"),o=g.extend({},y,x),m=g.extend({},x,i("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,script,section,table,ul")),n=g.extend({},y,i("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")), 11 | q=i("script,style"),v=g.extend({},p,m,n,o),w=i("background,cite,href,longdesc,src,usemap"),G=g.extend({},w,i("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,span,start,summary,target,title,type,valign,value,vspace,width")),l=document.createElement("pre");g.module("ngSanitize",[]).value("$sanitize",function(a){var d=[]; 12 | z(a,u(d));return d.join("")});g.module("ngSanitize").directive("ngBindHtml",["$sanitize",function(a){return function(d,b,e){b.addClass("ng-binding").data("$binding",e.ngBindHtml);d.$watch(e.ngBindHtml,function(c){c=a(c);b.html(c||"")})}}]);g.module("ngSanitize").filter("linky",function(){var a=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,d=/^mailto:/;return function(b){if(!b)return b;for(var e=b,c=[],h=u(c),f,g;b=e.match(a);)f=b[0],b[2]==b[3]&&(f="mailto:"+f),g=b.index, 13 | h.chars(e.substr(0,g)),h.start("a",{href:f}),h.chars(b[0].replace(d,"")),h.end("a"),e=e.substring(g+b[0].length);h.chars(e);return c.join("")}})})(window,window.angular); 14 | -------------------------------------------------------------------------------- /js/lib/bootstrap/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('