├── .gitignore ├── README.markdown ├── bootstrap.css ├── collections3 ├── collections3.css ├── collections3.js ├── images │ ├── cat1.jpg │ ├── cat2.jpg │ ├── cat3.jpg │ ├── cat4.jpg │ ├── down.gif │ └── up.gif └── index.html ├── events2 ├── events2.js └── index.html ├── localstorage5 ├── backbone-localstorage.js ├── index.html ├── localstorage5.css └── localstorage5.js ├── remotestorage6 ├── index.html ├── public │ ├── backbone.js │ ├── bootstrap.css │ ├── remotestorage6.css │ └── remotestorage6.js ├── store.rb └── store_spec.rb ├── routing4 ├── index.html ├── routing4.css └── routing4.js └── super_basic1 ├── index.html └── superbasic1.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Backbone.js Tutorials/Examples/Explorations 2 | 3 | NOTE: web development moves fast, and these may be out of date. Pull requests etc. welcome. 4 | 5 | This is a collection of simple apps meant to illustrate and explore various techniques used in building Backbone.js apps. The motivation behind this was that the official [Backbone.js reference](http://backbonejs.org/), while filled with useful information, suffers a bit from being "too close too the code." Many things are glossed over with the reasoning that Backbone.js is open-ended and doesn't restrict you (which is true). However, there are definitely some ways that Backbone.js "suggests" you should structure your code, and it is hard to figure these out with what the official docs provide, outside of trial-and-error messing around and navigating the collection of sometimes out-of-date/badly/awkwardly/unconvincingly written tutorials and documentation resources online (although for the record there's a tremendous amount of great stuff online as well). 6 | 7 | ---- 8 | 9 | The code examples represent self-tutorials (or "explorations" or what-have-you) which progress roughly in terms of complexity, and in terms of what I thought were the basic concepts which I wanted to grasp, in the order I wanted to grasp them. 10 | 11 | 1. Super Basic 1 - This is basically "hello world" in Backbone.js. First I wanted to understand how to dump out Model data to Templates. Backbone.js doesn't provide much guidance on how to use its View's render() method (by design), and the example given in the docs is a rather confusing mishmash of Backbone.js, underscore.js functionality and jQuery, so it took me a bit to sort through it all. 12 | 13 | 2. Events are a core aspect of Backbone.js, and provide the support for its smooth implementation of automatic updating of various DOM elements, one of Backbone.js's true strengths I believe. This example simply shows how a click event can be caught in a hopefully "idiomatically" fashion. It implements a simple up/down counter. 14 | 15 | 3. Collections give one the ability to manipulate Models as...collections of objects. Much of this class's utility comes from the great [Underscore.js](http://documentcloud.github.com/underscore/) library, which, being a Ruby coder, made me feel right at home. The collection example ended up being a bit more complex than I had intended, and kind of "smells," but I probably learned the most on this one. I may re-factor this in the future to provide some more simplicity. *Note: I forget where I got the cat pics. I'll try to track them down and put in appropriate attribution, but if they are yours and you want me to take them down or give you credit just drop me a line (see my email below, or contact me via github).* 16 | 17 | 4. It's not immediately apparent what the function of routing in Backbone.js is, so I applied my own opinionated (but not original) interpretation here: it should be a way to respond in an event-driven fashion to RESTful urls. By the way, having the console open with this one is useful, it will show you more about what is going on, in terms of the Routing. 18 | 19 | 5. Backbone.sync using local storage: this example uses the backbone-localstorage.js module provided along with the Todos example in the default distribution. I wanted to try and implement something similar to the Todos example myself, sort of from scratch, and without using a server-side data storage (at first). This is less complex than the Todos example but more or less does the same thing in terms of allowing the user to input basic data (in this case a link and a description), delete it, and have it be restored from local storage upon reloading the app in the same browser later on. 20 | 21 | 6. Using a RESTful application server to store data remotely: basically, this is mostly the same as #5 but using default Backbone.Sync behavior, implemented on the server side using a Sinatra app (this assumes Ruby 1.9.2, Sinatra 1.3.2, Rspec 2.9 --it may work with other versions, but that's all I've tried it with). I intended this to be simple, but in order to implement the bare minimum required to get it working I had to build something slightly more involved...that said, it's still pretty simple. If you want to run the tests on the sinatra script, run `rspec store_spec.rb`. 22 | 23 | *TODO: "in the works"* 24 | 25 | 7 using Require.js (?) 26 | 27 | 8 Integrating Jasmine testing with Backbone.js 28 | 29 | 9 and beyond...? 30 | 31 | ## Summary 32 | 33 | These examples basically represent about a week of digging hardcore into Backbone.js in an attempt to really understand what the framework provides and what structures seem to fit best. At this point, I have a few conclusions. 34 | 35 | * It's pretty lightweight. This is mostly a good thing. At times, almost definitely because I'm a Ruby/Rails developer, I fall into the bad habit of assuming things are more magical than they actually are. 36 | 37 | * The docs are similarly lightweight. This is less of a good thing, as it can be quite frustrating getting "hello world" up and running, and the Todos tutorials is quite advanced (and also uses a few older conventions, like 'bind()' instead of 'on()' for events). The fact is, once you start digging around the web, it seems that there some pretty decent conventions for structuring apps with Backbone.js. 38 | 39 | * [Mapping this to an MVC concept requires a wee bit of re-thinking.](http://documentcloud.github.com/backbone/#FAQ-mvc) However, it's not hard to do; Backbone.js is quite flexible and at the same time makes it easy to build an MVC framework from the tools it provides. 40 | 41 | * The routing system is still a bit of a mystery. Honestly, I'm not sure how necessary it is other than to provide appropriate resource URLs...which maybe is the whole point. But this also means that you are intercepting calls to the server, and this seems a bit awkward to me. Need to keep thinking about this one. 42 | 43 | * Having never worked with it before, I am happy I got exposed to underscore.js. It's really nice. 44 | 45 | ## Resources 46 | 47 | (Great resources I found when I was trying to figure out how Backbone.js works, or should work.) 48 | 49 | * Again, [the official Backbone.js docs](http://documentcloud.github.com/backbone/). 50 | * [Backbone.js patterns](http://ricostacruz.com/backbone-patterns/) - outlines some good strategies especially in approaching templating. 51 | * [Tim Branyen's backbone boilerplate](https://github.com/backbone-boilerplate) - I checked out a few boilerplates, but this is the one I liked the most. Has a great initializer for the Router which helped me understand the routing, and which I'm using in modified form on the Routing example. (also, see my [first StackOverflow question](http://stackoverflow.com/questions/9939737/how-does-one-listen-to-the-router-respond-to-router-events-in-views-models-i) which was a result of me not understanding how routing works.) 52 | * The Backbone.js github wiki has a [great page consolidating a lot of web documentation resources](https://github.com/documentcloud/backbone/wiki/Extensions%2C-Plugins%2C-Resources). I have yet to really dig into it, although I know I've already checked out a good number of the items listed through separate Google searches. 53 | * [This explains why you may need to use the underscore bindAll() method in Backbone.js](http://lostechies.com/derickbailey/2011/06/15/solving-backbones-this-model-view-problem-with-underscore-js/). It's overall a good article to read just to wrap your head around how Backbone.js works. I also wanted to link to it to note that these guys (mostly Derick Bailey I think) have a lot of useful articles on Backbone.js. They don't always purse a strategy I agree with, but they are obviously thinking hard about how to solve problems "appropriately" in Backbone.js. Worth checking out. 54 | * Chris Japhr co-wrote a book on Backbone.js, and has [a lot of great articles on his site relating to Backbone.js](http://japhr.blogspot.jp/search/label/backbonejs) 55 | 56 | ## Author 57 | 58 | Dave Della Costa. dave-dellacosta at garage d co d jp 59 | 60 | Critiques, suggestions, pull requests welcome. 61 | -------------------------------------------------------------------------------- /bootstrap.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.0.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 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | nav, 19 | section { 20 | display: block; 21 | } 22 | audio, 23 | canvas, 24 | video { 25 | display: inline-block; 26 | *display: inline; 27 | *zoom: 1; 28 | } 29 | audio:not([controls]) { 30 | display: none; 31 | } 32 | html { 33 | font-size: 100%; 34 | -webkit-text-size-adjust: 100%; 35 | -ms-text-size-adjust: 100%; 36 | } 37 | a:focus { 38 | outline: thin dotted #333; 39 | outline: 5px auto -webkit-focus-ring-color; 40 | outline-offset: -2px; 41 | } 42 | a:hover, 43 | a:active { 44 | outline: 0; 45 | } 46 | sub, 47 | sup { 48 | position: relative; 49 | font-size: 75%; 50 | line-height: 0; 51 | vertical-align: baseline; 52 | } 53 | sup { 54 | top: -0.5em; 55 | } 56 | sub { 57 | bottom: -0.25em; 58 | } 59 | img { 60 | height: auto; 61 | border: 0; 62 | -ms-interpolation-mode: bicubic; 63 | vertical-align: middle; 64 | } 65 | button, 66 | input, 67 | select, 68 | textarea { 69 | margin: 0; 70 | font-size: 100%; 71 | vertical-align: middle; 72 | } 73 | button, 74 | input { 75 | *overflow: visible; 76 | line-height: normal; 77 | } 78 | button::-moz-focus-inner, 79 | input::-moz-focus-inner { 80 | padding: 0; 81 | border: 0; 82 | } 83 | button, 84 | input[type="button"], 85 | input[type="reset"], 86 | input[type="submit"] { 87 | cursor: pointer; 88 | -webkit-appearance: button; 89 | } 90 | input[type="search"] { 91 | -webkit-appearance: textfield; 92 | -webkit-box-sizing: content-box; 93 | -moz-box-sizing: content-box; 94 | box-sizing: content-box; 95 | } 96 | input[type="search"]::-webkit-search-decoration, 97 | input[type="search"]::-webkit-search-cancel-button { 98 | -webkit-appearance: none; 99 | } 100 | textarea { 101 | overflow: auto; 102 | vertical-align: top; 103 | } 104 | .clearfix { 105 | *zoom: 1; 106 | } 107 | .clearfix:before, 108 | .clearfix:after { 109 | display: table; 110 | content: ""; 111 | } 112 | .clearfix:after { 113 | clear: both; 114 | } 115 | .hide-text { 116 | overflow: hidden; 117 | text-indent: 100%; 118 | white-space: nowrap; 119 | } 120 | .input-block-level { 121 | display: block; 122 | width: 100%; 123 | min-height: 28px; 124 | /* Make inputs at least the height of their button counterpart */ 125 | 126 | /* Makes inputs behave like true block-level elements */ 127 | 128 | -webkit-box-sizing: border-box; 129 | -moz-box-sizing: border-box; 130 | -ms-box-sizing: border-box; 131 | box-sizing: border-box; 132 | } 133 | body { 134 | margin: 0; 135 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 136 | font-size: 13px; 137 | line-height: 18px; 138 | color: #333333; 139 | background-color: #ffffff; 140 | } 141 | a { 142 | color: #0088cc; 143 | text-decoration: none; 144 | } 145 | a:hover { 146 | color: #005580; 147 | text-decoration: underline; 148 | } 149 | .row { 150 | margin-left: -20px; 151 | *zoom: 1; 152 | } 153 | .row:before, 154 | .row:after { 155 | display: table; 156 | content: ""; 157 | } 158 | .row:after { 159 | clear: both; 160 | } 161 | [class*="span"] { 162 | float: left; 163 | margin-left: 20px; 164 | } 165 | .container, 166 | .navbar-fixed-top .container, 167 | .navbar-fixed-bottom .container { 168 | width: 940px; 169 | } 170 | .span12 { 171 | width: 940px; 172 | } 173 | .span11 { 174 | width: 860px; 175 | } 176 | .span10 { 177 | width: 780px; 178 | } 179 | .span9 { 180 | width: 700px; 181 | } 182 | .span8 { 183 | width: 620px; 184 | } 185 | .span7 { 186 | width: 540px; 187 | } 188 | .span6 { 189 | width: 460px; 190 | } 191 | .span5 { 192 | width: 380px; 193 | } 194 | .span4 { 195 | width: 300px; 196 | } 197 | .span3 { 198 | width: 220px; 199 | } 200 | .span2 { 201 | width: 140px; 202 | } 203 | .span1 { 204 | width: 60px; 205 | } 206 | .offset12 { 207 | margin-left: 980px; 208 | } 209 | .offset11 { 210 | margin-left: 900px; 211 | } 212 | .offset10 { 213 | margin-left: 820px; 214 | } 215 | .offset9 { 216 | margin-left: 740px; 217 | } 218 | .offset8 { 219 | margin-left: 660px; 220 | } 221 | .offset7 { 222 | margin-left: 580px; 223 | } 224 | .offset6 { 225 | margin-left: 500px; 226 | } 227 | .offset5 { 228 | margin-left: 420px; 229 | } 230 | .offset4 { 231 | margin-left: 340px; 232 | } 233 | .offset3 { 234 | margin-left: 260px; 235 | } 236 | .offset2 { 237 | margin-left: 180px; 238 | } 239 | .offset1 { 240 | margin-left: 100px; 241 | } 242 | .row-fluid { 243 | width: 100%; 244 | *zoom: 1; 245 | } 246 | .row-fluid:before, 247 | .row-fluid:after { 248 | display: table; 249 | content: ""; 250 | } 251 | .row-fluid:after { 252 | clear: both; 253 | } 254 | .row-fluid > [class*="span"] { 255 | float: left; 256 | margin-left: 2.127659574%; 257 | } 258 | .row-fluid > [class*="span"]:first-child { 259 | margin-left: 0; 260 | } 261 | .row-fluid > .span12 { 262 | width: 99.99999998999999%; 263 | } 264 | .row-fluid > .span11 { 265 | width: 91.489361693%; 266 | } 267 | .row-fluid > .span10 { 268 | width: 82.97872339599999%; 269 | } 270 | .row-fluid > .span9 { 271 | width: 74.468085099%; 272 | } 273 | .row-fluid > .span8 { 274 | width: 65.95744680199999%; 275 | } 276 | .row-fluid > .span7 { 277 | width: 57.446808505%; 278 | } 279 | .row-fluid > .span6 { 280 | width: 48.93617020799999%; 281 | } 282 | .row-fluid > .span5 { 283 | width: 40.425531911%; 284 | } 285 | .row-fluid > .span4 { 286 | width: 31.914893614%; 287 | } 288 | .row-fluid > .span3 { 289 | width: 23.404255317%; 290 | } 291 | .row-fluid > .span2 { 292 | width: 14.89361702%; 293 | } 294 | .row-fluid > .span1 { 295 | width: 6.382978723%; 296 | } 297 | .container { 298 | margin-left: auto; 299 | margin-right: auto; 300 | *zoom: 1; 301 | } 302 | .container:before, 303 | .container:after { 304 | display: table; 305 | content: ""; 306 | } 307 | .container:after { 308 | clear: both; 309 | } 310 | .container-fluid { 311 | padding-left: 20px; 312 | padding-right: 20px; 313 | *zoom: 1; 314 | } 315 | .container-fluid:before, 316 | .container-fluid:after { 317 | display: table; 318 | content: ""; 319 | } 320 | .container-fluid:after { 321 | clear: both; 322 | } 323 | p { 324 | margin: 0 0 9px; 325 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 326 | font-size: 13px; 327 | line-height: 18px; 328 | } 329 | p small { 330 | font-size: 11px; 331 | color: #999999; 332 | } 333 | .lead { 334 | margin-bottom: 18px; 335 | font-size: 20px; 336 | font-weight: 200; 337 | line-height: 27px; 338 | } 339 | h1, 340 | h2, 341 | h3, 342 | h4, 343 | h5, 344 | h6 { 345 | margin: 0; 346 | font-family: inherit; 347 | font-weight: bold; 348 | color: inherit; 349 | text-rendering: optimizelegibility; 350 | } 351 | h1 small, 352 | h2 small, 353 | h3 small, 354 | h4 small, 355 | h5 small, 356 | h6 small { 357 | font-weight: normal; 358 | color: #999999; 359 | } 360 | h1 { 361 | font-size: 30px; 362 | line-height: 36px; 363 | } 364 | h1 small { 365 | font-size: 18px; 366 | } 367 | h2 { 368 | font-size: 24px; 369 | line-height: 36px; 370 | } 371 | h2 small { 372 | font-size: 18px; 373 | } 374 | h3 { 375 | line-height: 27px; 376 | font-size: 18px; 377 | } 378 | h3 small { 379 | font-size: 14px; 380 | } 381 | h4, 382 | h5, 383 | h6 { 384 | line-height: 18px; 385 | } 386 | h4 { 387 | font-size: 14px; 388 | } 389 | h4 small { 390 | font-size: 12px; 391 | } 392 | h5 { 393 | font-size: 12px; 394 | } 395 | h6 { 396 | font-size: 11px; 397 | color: #999999; 398 | text-transform: uppercase; 399 | } 400 | .page-header { 401 | padding-bottom: 17px; 402 | margin: 18px 0; 403 | border-bottom: 1px solid #eeeeee; 404 | } 405 | .page-header h1 { 406 | line-height: 1; 407 | } 408 | ul, 409 | ol { 410 | padding: 0; 411 | margin: 0 0 9px 25px; 412 | } 413 | ul ul, 414 | ul ol, 415 | ol ol, 416 | ol ul { 417 | margin-bottom: 0; 418 | } 419 | ul { 420 | list-style: disc; 421 | } 422 | ol { 423 | list-style: decimal; 424 | } 425 | li { 426 | line-height: 18px; 427 | } 428 | ul.unstyled, 429 | ol.unstyled { 430 | margin-left: 0; 431 | list-style: none; 432 | } 433 | dl { 434 | margin-bottom: 18px; 435 | } 436 | dt, 437 | dd { 438 | line-height: 18px; 439 | } 440 | dt { 441 | font-weight: bold; 442 | line-height: 17px; 443 | } 444 | dd { 445 | margin-left: 9px; 446 | } 447 | .dl-horizontal dt { 448 | float: left; 449 | clear: left; 450 | width: 120px; 451 | text-align: right; 452 | } 453 | .dl-horizontal dd { 454 | margin-left: 130px; 455 | } 456 | hr { 457 | margin: 18px 0; 458 | border: 0; 459 | border-top: 1px solid #eeeeee; 460 | border-bottom: 1px solid #ffffff; 461 | } 462 | strong { 463 | font-weight: bold; 464 | } 465 | em { 466 | font-style: italic; 467 | } 468 | .muted { 469 | color: #999999; 470 | } 471 | abbr[title] { 472 | border-bottom: 1px dotted #ddd; 473 | cursor: help; 474 | } 475 | abbr.initialism { 476 | font-size: 90%; 477 | text-transform: uppercase; 478 | } 479 | blockquote { 480 | padding: 0 0 0 15px; 481 | margin: 0 0 18px; 482 | border-left: 5px solid #eeeeee; 483 | } 484 | blockquote p { 485 | margin-bottom: 0; 486 | font-size: 16px; 487 | font-weight: 300; 488 | line-height: 22.5px; 489 | } 490 | blockquote small { 491 | display: block; 492 | line-height: 18px; 493 | color: #999999; 494 | } 495 | blockquote small:before { 496 | content: '\2014 \00A0'; 497 | } 498 | blockquote.pull-right { 499 | float: right; 500 | padding-left: 0; 501 | padding-right: 15px; 502 | border-left: 0; 503 | border-right: 5px solid #eeeeee; 504 | } 505 | blockquote.pull-right p, 506 | blockquote.pull-right small { 507 | text-align: right; 508 | } 509 | q:before, 510 | q:after, 511 | blockquote:before, 512 | blockquote:after { 513 | content: ""; 514 | } 515 | address { 516 | display: block; 517 | margin-bottom: 18px; 518 | line-height: 18px; 519 | font-style: normal; 520 | } 521 | small { 522 | font-size: 100%; 523 | } 524 | cite { 525 | font-style: normal; 526 | } 527 | code, 528 | pre { 529 | padding: 0 3px 2px; 530 | font-family: Menlo, Monaco, "Courier New", monospace; 531 | font-size: 12px; 532 | color: #333333; 533 | -webkit-border-radius: 3px; 534 | -moz-border-radius: 3px; 535 | border-radius: 3px; 536 | } 537 | code { 538 | padding: 2px 4px; 539 | color: #d14; 540 | background-color: #f7f7f9; 541 | border: 1px solid #e1e1e8; 542 | } 543 | pre { 544 | display: block; 545 | padding: 8.5px; 546 | margin: 0 0 9px; 547 | font-size: 12.025px; 548 | line-height: 18px; 549 | background-color: #f5f5f5; 550 | border: 1px solid #ccc; 551 | border: 1px solid rgba(0, 0, 0, 0.15); 552 | -webkit-border-radius: 4px; 553 | -moz-border-radius: 4px; 554 | border-radius: 4px; 555 | white-space: pre; 556 | white-space: pre-wrap; 557 | word-break: break-all; 558 | word-wrap: break-word; 559 | } 560 | pre.prettyprint { 561 | margin-bottom: 18px; 562 | } 563 | pre code { 564 | padding: 0; 565 | color: inherit; 566 | background-color: transparent; 567 | border: 0; 568 | } 569 | .pre-scrollable { 570 | max-height: 340px; 571 | overflow-y: scroll; 572 | } 573 | form { 574 | margin: 0 0 18px; 575 | } 576 | fieldset { 577 | padding: 0; 578 | margin: 0; 579 | border: 0; 580 | } 581 | legend { 582 | display: block; 583 | width: 100%; 584 | padding: 0; 585 | margin-bottom: 27px; 586 | font-size: 19.5px; 587 | line-height: 36px; 588 | color: #333333; 589 | border: 0; 590 | border-bottom: 1px solid #eee; 591 | } 592 | legend small { 593 | font-size: 13.5px; 594 | color: #999999; 595 | } 596 | label, 597 | input, 598 | button, 599 | select, 600 | textarea { 601 | font-size: 13px; 602 | font-weight: normal; 603 | line-height: 18px; 604 | } 605 | input, 606 | button, 607 | select, 608 | textarea { 609 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 610 | } 611 | label { 612 | display: block; 613 | margin-bottom: 5px; 614 | color: #333333; 615 | } 616 | input, 617 | textarea, 618 | select, 619 | .uneditable-input { 620 | display: inline-block; 621 | width: 210px; 622 | height: 18px; 623 | padding: 4px; 624 | margin-bottom: 9px; 625 | font-size: 13px; 626 | line-height: 18px; 627 | color: #555555; 628 | border: 1px solid #cccccc; 629 | -webkit-border-radius: 3px; 630 | -moz-border-radius: 3px; 631 | border-radius: 3px; 632 | } 633 | .uneditable-textarea { 634 | width: auto; 635 | height: auto; 636 | } 637 | label input, 638 | label textarea, 639 | label select { 640 | display: block; 641 | } 642 | input[type="image"], 643 | input[type="checkbox"], 644 | input[type="radio"] { 645 | width: auto; 646 | height: auto; 647 | padding: 0; 648 | margin: 3px 0; 649 | *margin-top: 0; 650 | /* IE7 */ 651 | 652 | line-height: normal; 653 | cursor: pointer; 654 | -webkit-border-radius: 0; 655 | -moz-border-radius: 0; 656 | border-radius: 0; 657 | border: 0 \9; 658 | /* IE9 and down */ 659 | 660 | } 661 | input[type="image"] { 662 | border: 0; 663 | } 664 | input[type="file"] { 665 | width: auto; 666 | padding: initial; 667 | line-height: initial; 668 | border: initial; 669 | background-color: #ffffff; 670 | background-color: initial; 671 | -webkit-box-shadow: none; 672 | -moz-box-shadow: none; 673 | box-shadow: none; 674 | } 675 | input[type="button"], 676 | input[type="reset"], 677 | input[type="submit"] { 678 | width: auto; 679 | height: auto; 680 | } 681 | select, 682 | input[type="file"] { 683 | height: 28px; 684 | /* In IE7, the height of the select element cannot be changed by height, only font-size */ 685 | 686 | *margin-top: 4px; 687 | /* For IE7, add top margin to align select with labels */ 688 | 689 | line-height: 28px; 690 | } 691 | input[type="file"] { 692 | line-height: 18px \9; 693 | } 694 | select { 695 | width: 220px; 696 | background-color: #ffffff; 697 | } 698 | select[multiple], 699 | select[size] { 700 | height: auto; 701 | } 702 | input[type="image"] { 703 | -webkit-box-shadow: none; 704 | -moz-box-shadow: none; 705 | box-shadow: none; 706 | } 707 | textarea { 708 | height: auto; 709 | } 710 | input[type="hidden"] { 711 | display: none; 712 | } 713 | .radio, 714 | .checkbox { 715 | padding-left: 18px; 716 | } 717 | .radio input[type="radio"], 718 | .checkbox input[type="checkbox"] { 719 | float: left; 720 | margin-left: -18px; 721 | } 722 | .controls > .radio:first-child, 723 | .controls > .checkbox:first-child { 724 | padding-top: 5px; 725 | } 726 | .radio.inline, 727 | .checkbox.inline { 728 | display: inline-block; 729 | padding-top: 5px; 730 | margin-bottom: 0; 731 | vertical-align: middle; 732 | } 733 | .radio.inline + .radio.inline, 734 | .checkbox.inline + .checkbox.inline { 735 | margin-left: 10px; 736 | } 737 | input, 738 | textarea { 739 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 740 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 741 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 742 | -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; 743 | -moz-transition: border linear 0.2s, box-shadow linear 0.2s; 744 | -ms-transition: border linear 0.2s, box-shadow linear 0.2s; 745 | -o-transition: border linear 0.2s, box-shadow linear 0.2s; 746 | transition: border linear 0.2s, box-shadow linear 0.2s; 747 | } 748 | input:focus, 749 | textarea:focus { 750 | border-color: rgba(82, 168, 236, 0.8); 751 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 752 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 753 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 754 | outline: 0; 755 | outline: thin dotted \9; 756 | /* IE6-9 */ 757 | 758 | } 759 | input[type="file"]:focus, 760 | input[type="radio"]:focus, 761 | input[type="checkbox"]:focus, 762 | select:focus { 763 | -webkit-box-shadow: none; 764 | -moz-box-shadow: none; 765 | box-shadow: none; 766 | outline: thin dotted #333; 767 | outline: 5px auto -webkit-focus-ring-color; 768 | outline-offset: -2px; 769 | } 770 | .input-mini { 771 | width: 60px; 772 | } 773 | .input-small { 774 | width: 90px; 775 | } 776 | .input-medium { 777 | width: 150px; 778 | } 779 | .input-large { 780 | width: 210px; 781 | } 782 | .input-xlarge { 783 | width: 270px; 784 | } 785 | .input-xxlarge { 786 | width: 530px; 787 | } 788 | input[class*="span"], 789 | select[class*="span"], 790 | textarea[class*="span"], 791 | .uneditable-input { 792 | float: none; 793 | margin-left: 0; 794 | } 795 | input, 796 | textarea, 797 | .uneditable-input { 798 | margin-left: 0; 799 | } 800 | input.span12, textarea.span12, .uneditable-input.span12 { 801 | width: 930px; 802 | } 803 | input.span11, textarea.span11, .uneditable-input.span11 { 804 | width: 850px; 805 | } 806 | input.span10, textarea.span10, .uneditable-input.span10 { 807 | width: 770px; 808 | } 809 | input.span9, textarea.span9, .uneditable-input.span9 { 810 | width: 690px; 811 | } 812 | input.span8, textarea.span8, .uneditable-input.span8 { 813 | width: 610px; 814 | } 815 | input.span7, textarea.span7, .uneditable-input.span7 { 816 | width: 530px; 817 | } 818 | input.span6, textarea.span6, .uneditable-input.span6 { 819 | width: 450px; 820 | } 821 | input.span5, textarea.span5, .uneditable-input.span5 { 822 | width: 370px; 823 | } 824 | input.span4, textarea.span4, .uneditable-input.span4 { 825 | width: 290px; 826 | } 827 | input.span3, textarea.span3, .uneditable-input.span3 { 828 | width: 210px; 829 | } 830 | input.span2, textarea.span2, .uneditable-input.span2 { 831 | width: 130px; 832 | } 833 | input.span1, textarea.span1, .uneditable-input.span1 { 834 | width: 50px; 835 | } 836 | input[disabled], 837 | select[disabled], 838 | textarea[disabled], 839 | input[readonly], 840 | select[readonly], 841 | textarea[readonly] { 842 | background-color: #eeeeee; 843 | border-color: #ddd; 844 | cursor: not-allowed; 845 | } 846 | .control-group.warning > label, 847 | .control-group.warning .help-block, 848 | .control-group.warning .help-inline { 849 | color: #c09853; 850 | } 851 | .control-group.warning input, 852 | .control-group.warning select, 853 | .control-group.warning textarea { 854 | color: #c09853; 855 | border-color: #c09853; 856 | } 857 | .control-group.warning input:focus, 858 | .control-group.warning select:focus, 859 | .control-group.warning textarea:focus { 860 | border-color: #a47e3c; 861 | -webkit-box-shadow: 0 0 6px #dbc59e; 862 | -moz-box-shadow: 0 0 6px #dbc59e; 863 | box-shadow: 0 0 6px #dbc59e; 864 | } 865 | .control-group.warning .input-prepend .add-on, 866 | .control-group.warning .input-append .add-on { 867 | color: #c09853; 868 | background-color: #fcf8e3; 869 | border-color: #c09853; 870 | } 871 | .control-group.error > label, 872 | .control-group.error .help-block, 873 | .control-group.error .help-inline { 874 | color: #b94a48; 875 | } 876 | .control-group.error input, 877 | .control-group.error select, 878 | .control-group.error textarea { 879 | color: #b94a48; 880 | border-color: #b94a48; 881 | } 882 | .control-group.error input:focus, 883 | .control-group.error select:focus, 884 | .control-group.error textarea:focus { 885 | border-color: #953b39; 886 | -webkit-box-shadow: 0 0 6px #d59392; 887 | -moz-box-shadow: 0 0 6px #d59392; 888 | box-shadow: 0 0 6px #d59392; 889 | } 890 | .control-group.error .input-prepend .add-on, 891 | .control-group.error .input-append .add-on { 892 | color: #b94a48; 893 | background-color: #f2dede; 894 | border-color: #b94a48; 895 | } 896 | .control-group.success > label, 897 | .control-group.success .help-block, 898 | .control-group.success .help-inline { 899 | color: #468847; 900 | } 901 | .control-group.success input, 902 | .control-group.success select, 903 | .control-group.success textarea { 904 | color: #468847; 905 | border-color: #468847; 906 | } 907 | .control-group.success input:focus, 908 | .control-group.success select:focus, 909 | .control-group.success textarea:focus { 910 | border-color: #356635; 911 | -webkit-box-shadow: 0 0 6px #7aba7b; 912 | -moz-box-shadow: 0 0 6px #7aba7b; 913 | box-shadow: 0 0 6px #7aba7b; 914 | } 915 | .control-group.success .input-prepend .add-on, 916 | .control-group.success .input-append .add-on { 917 | color: #468847; 918 | background-color: #dff0d8; 919 | border-color: #468847; 920 | } 921 | input:focus:required:invalid, 922 | textarea:focus:required:invalid, 923 | select:focus:required:invalid { 924 | color: #b94a48; 925 | border-color: #ee5f5b; 926 | } 927 | input:focus:required:invalid:focus, 928 | textarea:focus:required:invalid:focus, 929 | select:focus:required:invalid:focus { 930 | border-color: #e9322d; 931 | -webkit-box-shadow: 0 0 6px #f8b9b7; 932 | -moz-box-shadow: 0 0 6px #f8b9b7; 933 | box-shadow: 0 0 6px #f8b9b7; 934 | } 935 | .form-actions { 936 | padding: 17px 20px 18px; 937 | margin-top: 18px; 938 | margin-bottom: 18px; 939 | background-color: #eeeeee; 940 | border-top: 1px solid #ddd; 941 | *zoom: 1; 942 | } 943 | .form-actions:before, 944 | .form-actions:after { 945 | display: table; 946 | content: ""; 947 | } 948 | .form-actions:after { 949 | clear: both; 950 | } 951 | .uneditable-input { 952 | display: block; 953 | background-color: #ffffff; 954 | border-color: #eee; 955 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 956 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 957 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 958 | cursor: not-allowed; 959 | } 960 | :-moz-placeholder { 961 | color: #999999; 962 | } 963 | ::-webkit-input-placeholder { 964 | color: #999999; 965 | } 966 | .help-block, 967 | .help-inline { 968 | color: #555555; 969 | } 970 | .help-block { 971 | display: block; 972 | margin-bottom: 9px; 973 | } 974 | .help-inline { 975 | display: inline-block; 976 | *display: inline; 977 | /* IE7 inline-block hack */ 978 | 979 | *zoom: 1; 980 | vertical-align: middle; 981 | padding-left: 5px; 982 | } 983 | .input-prepend, 984 | .input-append { 985 | margin-bottom: 5px; 986 | } 987 | .input-prepend input, 988 | .input-append input, 989 | .input-prepend select, 990 | .input-append select, 991 | .input-prepend .uneditable-input, 992 | .input-append .uneditable-input { 993 | *margin-left: 0; 994 | -webkit-border-radius: 0 3px 3px 0; 995 | -moz-border-radius: 0 3px 3px 0; 996 | border-radius: 0 3px 3px 0; 997 | } 998 | .input-prepend input:focus, 999 | .input-append input:focus, 1000 | .input-prepend select:focus, 1001 | .input-append select:focus, 1002 | .input-prepend .uneditable-input:focus, 1003 | .input-append .uneditable-input:focus { 1004 | position: relative; 1005 | z-index: 2; 1006 | } 1007 | .input-prepend .uneditable-input, 1008 | .input-append .uneditable-input { 1009 | border-left-color: #ccc; 1010 | } 1011 | .input-prepend .add-on, 1012 | .input-append .add-on { 1013 | display: inline-block; 1014 | width: auto; 1015 | min-width: 16px; 1016 | height: 18px; 1017 | padding: 4px 5px; 1018 | font-weight: normal; 1019 | line-height: 18px; 1020 | text-align: center; 1021 | text-shadow: 0 1px 0 #ffffff; 1022 | vertical-align: middle; 1023 | background-color: #eeeeee; 1024 | border: 1px solid #ccc; 1025 | } 1026 | .input-prepend .add-on, 1027 | .input-append .add-on, 1028 | .input-prepend .btn, 1029 | .input-append .btn { 1030 | -webkit-border-radius: 3px 0 0 3px; 1031 | -moz-border-radius: 3px 0 0 3px; 1032 | border-radius: 3px 0 0 3px; 1033 | } 1034 | .input-prepend .active, 1035 | .input-append .active { 1036 | background-color: #a9dba9; 1037 | border-color: #46a546; 1038 | } 1039 | .input-prepend .add-on, 1040 | .input-prepend .btn { 1041 | margin-right: -1px; 1042 | } 1043 | .input-append input, 1044 | .input-append select .uneditable-input { 1045 | -webkit-border-radius: 3px 0 0 3px; 1046 | -moz-border-radius: 3px 0 0 3px; 1047 | border-radius: 3px 0 0 3px; 1048 | } 1049 | .input-append .uneditable-input { 1050 | border-left-color: #eee; 1051 | border-right-color: #ccc; 1052 | } 1053 | .input-append .add-on, 1054 | .input-append .btn { 1055 | margin-left: -1px; 1056 | -webkit-border-radius: 0 3px 3px 0; 1057 | -moz-border-radius: 0 3px 3px 0; 1058 | border-radius: 0 3px 3px 0; 1059 | } 1060 | .input-prepend.input-append input, 1061 | .input-prepend.input-append select, 1062 | .input-prepend.input-append .uneditable-input { 1063 | -webkit-border-radius: 0; 1064 | -moz-border-radius: 0; 1065 | border-radius: 0; 1066 | } 1067 | .input-prepend.input-append .add-on:first-child, 1068 | .input-prepend.input-append .btn:first-child { 1069 | margin-right: -1px; 1070 | -webkit-border-radius: 3px 0 0 3px; 1071 | -moz-border-radius: 3px 0 0 3px; 1072 | border-radius: 3px 0 0 3px; 1073 | } 1074 | .input-prepend.input-append .add-on:last-child, 1075 | .input-prepend.input-append .btn:last-child { 1076 | margin-left: -1px; 1077 | -webkit-border-radius: 0 3px 3px 0; 1078 | -moz-border-radius: 0 3px 3px 0; 1079 | border-radius: 0 3px 3px 0; 1080 | } 1081 | .search-query { 1082 | padding-left: 14px; 1083 | padding-right: 14px; 1084 | margin-bottom: 0; 1085 | -webkit-border-radius: 14px; 1086 | -moz-border-radius: 14px; 1087 | border-radius: 14px; 1088 | } 1089 | .form-search input, 1090 | .form-inline input, 1091 | .form-horizontal input, 1092 | .form-search textarea, 1093 | .form-inline textarea, 1094 | .form-horizontal textarea, 1095 | .form-search select, 1096 | .form-inline select, 1097 | .form-horizontal select, 1098 | .form-search .help-inline, 1099 | .form-inline .help-inline, 1100 | .form-horizontal .help-inline, 1101 | .form-search .uneditable-input, 1102 | .form-inline .uneditable-input, 1103 | .form-horizontal .uneditable-input, 1104 | .form-search .input-prepend, 1105 | .form-inline .input-prepend, 1106 | .form-horizontal .input-prepend, 1107 | .form-search .input-append, 1108 | .form-inline .input-append, 1109 | .form-horizontal .input-append { 1110 | display: inline-block; 1111 | margin-bottom: 0; 1112 | } 1113 | .form-search .hide, 1114 | .form-inline .hide, 1115 | .form-horizontal .hide { 1116 | display: none; 1117 | } 1118 | .form-search label, 1119 | .form-inline label { 1120 | display: inline-block; 1121 | } 1122 | .form-search .input-append, 1123 | .form-inline .input-append, 1124 | .form-search .input-prepend, 1125 | .form-inline .input-prepend { 1126 | margin-bottom: 0; 1127 | } 1128 | .form-search .radio, 1129 | .form-search .checkbox, 1130 | .form-inline .radio, 1131 | .form-inline .checkbox { 1132 | padding-left: 0; 1133 | margin-bottom: 0; 1134 | vertical-align: middle; 1135 | } 1136 | .form-search .radio input[type="radio"], 1137 | .form-search .checkbox input[type="checkbox"], 1138 | .form-inline .radio input[type="radio"], 1139 | .form-inline .checkbox input[type="checkbox"] { 1140 | float: left; 1141 | margin-left: 0; 1142 | margin-right: 3px; 1143 | } 1144 | .control-group { 1145 | margin-bottom: 9px; 1146 | } 1147 | legend + .control-group { 1148 | margin-top: 18px; 1149 | -webkit-margin-top-collapse: separate; 1150 | } 1151 | .form-horizontal .control-group { 1152 | margin-bottom: 18px; 1153 | *zoom: 1; 1154 | } 1155 | .form-horizontal .control-group:before, 1156 | .form-horizontal .control-group:after { 1157 | display: table; 1158 | content: ""; 1159 | } 1160 | .form-horizontal .control-group:after { 1161 | clear: both; 1162 | } 1163 | .form-horizontal .control-label { 1164 | float: left; 1165 | width: 140px; 1166 | padding-top: 5px; 1167 | text-align: right; 1168 | } 1169 | .form-horizontal .controls { 1170 | margin-left: 160px; 1171 | /* Super jank IE7 fix to ensure the inputs in .input-append and input-prepend don't inherit the margin of the parent, in this case .controls */ 1172 | 1173 | *display: inline-block; 1174 | *margin-left: 0; 1175 | *padding-left: 20px; 1176 | } 1177 | .form-horizontal .help-block { 1178 | margin-top: 9px; 1179 | margin-bottom: 0; 1180 | } 1181 | .form-horizontal .form-actions { 1182 | padding-left: 160px; 1183 | } 1184 | table { 1185 | max-width: 100%; 1186 | border-collapse: collapse; 1187 | border-spacing: 0; 1188 | background-color: transparent; 1189 | } 1190 | .table { 1191 | width: 100%; 1192 | margin-bottom: 18px; 1193 | } 1194 | .table th, 1195 | .table td { 1196 | padding: 8px; 1197 | line-height: 18px; 1198 | text-align: left; 1199 | vertical-align: top; 1200 | border-top: 1px solid #dddddd; 1201 | } 1202 | .table th { 1203 | font-weight: bold; 1204 | } 1205 | .table thead th { 1206 | vertical-align: bottom; 1207 | } 1208 | .table colgroup + thead tr:first-child th, 1209 | .table colgroup + thead tr:first-child td, 1210 | .table thead:first-child tr:first-child th, 1211 | .table thead:first-child tr:first-child td { 1212 | border-top: 0; 1213 | } 1214 | .table tbody + tbody { 1215 | border-top: 2px solid #dddddd; 1216 | } 1217 | .table-condensed th, 1218 | .table-condensed td { 1219 | padding: 4px 5px; 1220 | } 1221 | .table-bordered { 1222 | border: 1px solid #dddddd; 1223 | border-left: 0; 1224 | border-collapse: separate; 1225 | *border-collapse: collapsed; 1226 | -webkit-border-radius: 4px; 1227 | -moz-border-radius: 4px; 1228 | border-radius: 4px; 1229 | } 1230 | .table-bordered th, 1231 | .table-bordered td { 1232 | border-left: 1px solid #dddddd; 1233 | } 1234 | .table-bordered thead:first-child tr:first-child th, 1235 | .table-bordered tbody:first-child tr:first-child th, 1236 | .table-bordered tbody:first-child tr:first-child td { 1237 | border-top: 0; 1238 | } 1239 | .table-bordered thead:first-child tr:first-child th:first-child, 1240 | .table-bordered tbody:first-child tr:first-child td:first-child { 1241 | -webkit-border-radius: 4px 0 0 0; 1242 | -moz-border-radius: 4px 0 0 0; 1243 | border-radius: 4px 0 0 0; 1244 | } 1245 | .table-bordered thead:first-child tr:first-child th:last-child, 1246 | .table-bordered tbody:first-child tr:first-child td:last-child { 1247 | -webkit-border-radius: 0 4px 0 0; 1248 | -moz-border-radius: 0 4px 0 0; 1249 | border-radius: 0 4px 0 0; 1250 | } 1251 | .table-bordered thead:last-child tr:last-child th:first-child, 1252 | .table-bordered tbody:last-child tr:last-child td:first-child { 1253 | -webkit-border-radius: 0 0 0 4px; 1254 | -moz-border-radius: 0 0 0 4px; 1255 | border-radius: 0 0 0 4px; 1256 | } 1257 | .table-bordered thead:last-child tr:last-child th:last-child, 1258 | .table-bordered tbody:last-child tr:last-child td:last-child { 1259 | -webkit-border-radius: 0 0 4px 0; 1260 | -moz-border-radius: 0 0 4px 0; 1261 | border-radius: 0 0 4px 0; 1262 | } 1263 | .table-striped tbody tr:nth-child(odd) td, 1264 | .table-striped tbody tr:nth-child(odd) th { 1265 | background-color: #f9f9f9; 1266 | } 1267 | .table tbody tr:hover td, 1268 | .table tbody tr:hover th { 1269 | background-color: #f5f5f5; 1270 | } 1271 | table .span1 { 1272 | float: none; 1273 | width: 44px; 1274 | margin-left: 0; 1275 | } 1276 | table .span2 { 1277 | float: none; 1278 | width: 124px; 1279 | margin-left: 0; 1280 | } 1281 | table .span3 { 1282 | float: none; 1283 | width: 204px; 1284 | margin-left: 0; 1285 | } 1286 | table .span4 { 1287 | float: none; 1288 | width: 284px; 1289 | margin-left: 0; 1290 | } 1291 | table .span5 { 1292 | float: none; 1293 | width: 364px; 1294 | margin-left: 0; 1295 | } 1296 | table .span6 { 1297 | float: none; 1298 | width: 444px; 1299 | margin-left: 0; 1300 | } 1301 | table .span7 { 1302 | float: none; 1303 | width: 524px; 1304 | margin-left: 0; 1305 | } 1306 | table .span8 { 1307 | float: none; 1308 | width: 604px; 1309 | margin-left: 0; 1310 | } 1311 | table .span9 { 1312 | float: none; 1313 | width: 684px; 1314 | margin-left: 0; 1315 | } 1316 | table .span10 { 1317 | float: none; 1318 | width: 764px; 1319 | margin-left: 0; 1320 | } 1321 | table .span11 { 1322 | float: none; 1323 | width: 844px; 1324 | margin-left: 0; 1325 | } 1326 | table .span12 { 1327 | float: none; 1328 | width: 924px; 1329 | margin-left: 0; 1330 | } 1331 | table .span13 { 1332 | float: none; 1333 | width: 1004px; 1334 | margin-left: 0; 1335 | } 1336 | table .span14 { 1337 | float: none; 1338 | width: 1084px; 1339 | margin-left: 0; 1340 | } 1341 | table .span15 { 1342 | float: none; 1343 | width: 1164px; 1344 | margin-left: 0; 1345 | } 1346 | table .span16 { 1347 | float: none; 1348 | width: 1244px; 1349 | margin-left: 0; 1350 | } 1351 | table .span17 { 1352 | float: none; 1353 | width: 1324px; 1354 | margin-left: 0; 1355 | } 1356 | table .span18 { 1357 | float: none; 1358 | width: 1404px; 1359 | margin-left: 0; 1360 | } 1361 | table .span19 { 1362 | float: none; 1363 | width: 1484px; 1364 | margin-left: 0; 1365 | } 1366 | table .span20 { 1367 | float: none; 1368 | width: 1564px; 1369 | margin-left: 0; 1370 | } 1371 | table .span21 { 1372 | float: none; 1373 | width: 1644px; 1374 | margin-left: 0; 1375 | } 1376 | table .span22 { 1377 | float: none; 1378 | width: 1724px; 1379 | margin-left: 0; 1380 | } 1381 | table .span23 { 1382 | float: none; 1383 | width: 1804px; 1384 | margin-left: 0; 1385 | } 1386 | table .span24 { 1387 | float: none; 1388 | width: 1884px; 1389 | margin-left: 0; 1390 | } 1391 | [class^="icon-"], 1392 | [class*=" icon-"] { 1393 | display: inline-block; 1394 | width: 14px; 1395 | height: 14px; 1396 | line-height: 14px; 1397 | vertical-align: text-top; 1398 | background-image: url("../img/glyphicons-halflings.png"); 1399 | background-position: 14px 14px; 1400 | background-repeat: no-repeat; 1401 | *margin-right: .3em; 1402 | } 1403 | [class^="icon-"]:last-child, 1404 | [class*=" icon-"]:last-child { 1405 | *margin-left: 0; 1406 | } 1407 | .icon-white { 1408 | background-image: url("../img/glyphicons-halflings-white.png"); 1409 | } 1410 | .icon-glass { 1411 | background-position: 0 0; 1412 | } 1413 | .icon-music { 1414 | background-position: -24px 0; 1415 | } 1416 | .icon-search { 1417 | background-position: -48px 0; 1418 | } 1419 | .icon-envelope { 1420 | background-position: -72px 0; 1421 | } 1422 | .icon-heart { 1423 | background-position: -96px 0; 1424 | } 1425 | .icon-star { 1426 | background-position: -120px 0; 1427 | } 1428 | .icon-star-empty { 1429 | background-position: -144px 0; 1430 | } 1431 | .icon-user { 1432 | background-position: -168px 0; 1433 | } 1434 | .icon-film { 1435 | background-position: -192px 0; 1436 | } 1437 | .icon-th-large { 1438 | background-position: -216px 0; 1439 | } 1440 | .icon-th { 1441 | background-position: -240px 0; 1442 | } 1443 | .icon-th-list { 1444 | background-position: -264px 0; 1445 | } 1446 | .icon-ok { 1447 | background-position: -288px 0; 1448 | } 1449 | .icon-remove { 1450 | background-position: -312px 0; 1451 | } 1452 | .icon-zoom-in { 1453 | background-position: -336px 0; 1454 | } 1455 | .icon-zoom-out { 1456 | background-position: -360px 0; 1457 | } 1458 | .icon-off { 1459 | background-position: -384px 0; 1460 | } 1461 | .icon-signal { 1462 | background-position: -408px 0; 1463 | } 1464 | .icon-cog { 1465 | background-position: -432px 0; 1466 | } 1467 | .icon-trash { 1468 | background-position: -456px 0; 1469 | } 1470 | .icon-home { 1471 | background-position: 0 -24px; 1472 | } 1473 | .icon-file { 1474 | background-position: -24px -24px; 1475 | } 1476 | .icon-time { 1477 | background-position: -48px -24px; 1478 | } 1479 | .icon-road { 1480 | background-position: -72px -24px; 1481 | } 1482 | .icon-download-alt { 1483 | background-position: -96px -24px; 1484 | } 1485 | .icon-download { 1486 | background-position: -120px -24px; 1487 | } 1488 | .icon-upload { 1489 | background-position: -144px -24px; 1490 | } 1491 | .icon-inbox { 1492 | background-position: -168px -24px; 1493 | } 1494 | .icon-play-circle { 1495 | background-position: -192px -24px; 1496 | } 1497 | .icon-repeat { 1498 | background-position: -216px -24px; 1499 | } 1500 | .icon-refresh { 1501 | background-position: -240px -24px; 1502 | } 1503 | .icon-list-alt { 1504 | background-position: -264px -24px; 1505 | } 1506 | .icon-lock { 1507 | background-position: -287px -24px; 1508 | } 1509 | .icon-flag { 1510 | background-position: -312px -24px; 1511 | } 1512 | .icon-headphones { 1513 | background-position: -336px -24px; 1514 | } 1515 | .icon-volume-off { 1516 | background-position: -360px -24px; 1517 | } 1518 | .icon-volume-down { 1519 | background-position: -384px -24px; 1520 | } 1521 | .icon-volume-up { 1522 | background-position: -408px -24px; 1523 | } 1524 | .icon-qrcode { 1525 | background-position: -432px -24px; 1526 | } 1527 | .icon-barcode { 1528 | background-position: -456px -24px; 1529 | } 1530 | .icon-tag { 1531 | background-position: 0 -48px; 1532 | } 1533 | .icon-tags { 1534 | background-position: -25px -48px; 1535 | } 1536 | .icon-book { 1537 | background-position: -48px -48px; 1538 | } 1539 | .icon-bookmark { 1540 | background-position: -72px -48px; 1541 | } 1542 | .icon-print { 1543 | background-position: -96px -48px; 1544 | } 1545 | .icon-camera { 1546 | background-position: -120px -48px; 1547 | } 1548 | .icon-font { 1549 | background-position: -144px -48px; 1550 | } 1551 | .icon-bold { 1552 | background-position: -167px -48px; 1553 | } 1554 | .icon-italic { 1555 | background-position: -192px -48px; 1556 | } 1557 | .icon-text-height { 1558 | background-position: -216px -48px; 1559 | } 1560 | .icon-text-width { 1561 | background-position: -240px -48px; 1562 | } 1563 | .icon-align-left { 1564 | background-position: -264px -48px; 1565 | } 1566 | .icon-align-center { 1567 | background-position: -288px -48px; 1568 | } 1569 | .icon-align-right { 1570 | background-position: -312px -48px; 1571 | } 1572 | .icon-align-justify { 1573 | background-position: -336px -48px; 1574 | } 1575 | .icon-list { 1576 | background-position: -360px -48px; 1577 | } 1578 | .icon-indent-left { 1579 | background-position: -384px -48px; 1580 | } 1581 | .icon-indent-right { 1582 | background-position: -408px -48px; 1583 | } 1584 | .icon-facetime-video { 1585 | background-position: -432px -48px; 1586 | } 1587 | .icon-picture { 1588 | background-position: -456px -48px; 1589 | } 1590 | .icon-pencil { 1591 | background-position: 0 -72px; 1592 | } 1593 | .icon-map-marker { 1594 | background-position: -24px -72px; 1595 | } 1596 | .icon-adjust { 1597 | background-position: -48px -72px; 1598 | } 1599 | .icon-tint { 1600 | background-position: -72px -72px; 1601 | } 1602 | .icon-edit { 1603 | background-position: -96px -72px; 1604 | } 1605 | .icon-share { 1606 | background-position: -120px -72px; 1607 | } 1608 | .icon-check { 1609 | background-position: -144px -72px; 1610 | } 1611 | .icon-move { 1612 | background-position: -168px -72px; 1613 | } 1614 | .icon-step-backward { 1615 | background-position: -192px -72px; 1616 | } 1617 | .icon-fast-backward { 1618 | background-position: -216px -72px; 1619 | } 1620 | .icon-backward { 1621 | background-position: -240px -72px; 1622 | } 1623 | .icon-play { 1624 | background-position: -264px -72px; 1625 | } 1626 | .icon-pause { 1627 | background-position: -288px -72px; 1628 | } 1629 | .icon-stop { 1630 | background-position: -312px -72px; 1631 | } 1632 | .icon-forward { 1633 | background-position: -336px -72px; 1634 | } 1635 | .icon-fast-forward { 1636 | background-position: -360px -72px; 1637 | } 1638 | .icon-step-forward { 1639 | background-position: -384px -72px; 1640 | } 1641 | .icon-eject { 1642 | background-position: -408px -72px; 1643 | } 1644 | .icon-chevron-left { 1645 | background-position: -432px -72px; 1646 | } 1647 | .icon-chevron-right { 1648 | background-position: -456px -72px; 1649 | } 1650 | .icon-plus-sign { 1651 | background-position: 0 -96px; 1652 | } 1653 | .icon-minus-sign { 1654 | background-position: -24px -96px; 1655 | } 1656 | .icon-remove-sign { 1657 | background-position: -48px -96px; 1658 | } 1659 | .icon-ok-sign { 1660 | background-position: -72px -96px; 1661 | } 1662 | .icon-question-sign { 1663 | background-position: -96px -96px; 1664 | } 1665 | .icon-info-sign { 1666 | background-position: -120px -96px; 1667 | } 1668 | .icon-screenshot { 1669 | background-position: -144px -96px; 1670 | } 1671 | .icon-remove-circle { 1672 | background-position: -168px -96px; 1673 | } 1674 | .icon-ok-circle { 1675 | background-position: -192px -96px; 1676 | } 1677 | .icon-ban-circle { 1678 | background-position: -216px -96px; 1679 | } 1680 | .icon-arrow-left { 1681 | background-position: -240px -96px; 1682 | } 1683 | .icon-arrow-right { 1684 | background-position: -264px -96px; 1685 | } 1686 | .icon-arrow-up { 1687 | background-position: -289px -96px; 1688 | } 1689 | .icon-arrow-down { 1690 | background-position: -312px -96px; 1691 | } 1692 | .icon-share-alt { 1693 | background-position: -336px -96px; 1694 | } 1695 | .icon-resize-full { 1696 | background-position: -360px -96px; 1697 | } 1698 | .icon-resize-small { 1699 | background-position: -384px -96px; 1700 | } 1701 | .icon-plus { 1702 | background-position: -408px -96px; 1703 | } 1704 | .icon-minus { 1705 | background-position: -433px -96px; 1706 | } 1707 | .icon-asterisk { 1708 | background-position: -456px -96px; 1709 | } 1710 | .icon-exclamation-sign { 1711 | background-position: 0 -120px; 1712 | } 1713 | .icon-gift { 1714 | background-position: -24px -120px; 1715 | } 1716 | .icon-leaf { 1717 | background-position: -48px -120px; 1718 | } 1719 | .icon-fire { 1720 | background-position: -72px -120px; 1721 | } 1722 | .icon-eye-open { 1723 | background-position: -96px -120px; 1724 | } 1725 | .icon-eye-close { 1726 | background-position: -120px -120px; 1727 | } 1728 | .icon-warning-sign { 1729 | background-position: -144px -120px; 1730 | } 1731 | .icon-plane { 1732 | background-position: -168px -120px; 1733 | } 1734 | .icon-calendar { 1735 | background-position: -192px -120px; 1736 | } 1737 | .icon-random { 1738 | background-position: -216px -120px; 1739 | } 1740 | .icon-comment { 1741 | background-position: -240px -120px; 1742 | } 1743 | .icon-magnet { 1744 | background-position: -264px -120px; 1745 | } 1746 | .icon-chevron-up { 1747 | background-position: -288px -120px; 1748 | } 1749 | .icon-chevron-down { 1750 | background-position: -313px -119px; 1751 | } 1752 | .icon-retweet { 1753 | background-position: -336px -120px; 1754 | } 1755 | .icon-shopping-cart { 1756 | background-position: -360px -120px; 1757 | } 1758 | .icon-folder-close { 1759 | background-position: -384px -120px; 1760 | } 1761 | .icon-folder-open { 1762 | background-position: -408px -120px; 1763 | } 1764 | .icon-resize-vertical { 1765 | background-position: -432px -119px; 1766 | } 1767 | .icon-resize-horizontal { 1768 | background-position: -456px -118px; 1769 | } 1770 | .dropdown { 1771 | position: relative; 1772 | } 1773 | .dropdown-toggle { 1774 | *margin-bottom: -3px; 1775 | } 1776 | .dropdown-toggle:active, 1777 | .open .dropdown-toggle { 1778 | outline: 0; 1779 | } 1780 | .caret { 1781 | display: inline-block; 1782 | width: 0; 1783 | height: 0; 1784 | vertical-align: top; 1785 | border-left: 4px solid transparent; 1786 | border-right: 4px solid transparent; 1787 | border-top: 4px solid #000000; 1788 | opacity: 0.3; 1789 | filter: alpha(opacity=30); 1790 | content: ""; 1791 | } 1792 | .dropdown .caret { 1793 | margin-top: 8px; 1794 | margin-left: 2px; 1795 | } 1796 | .dropdown:hover .caret, 1797 | .open.dropdown .caret { 1798 | opacity: 1; 1799 | filter: alpha(opacity=100); 1800 | } 1801 | .dropdown-menu { 1802 | position: absolute; 1803 | top: 100%; 1804 | left: 0; 1805 | z-index: 1000; 1806 | float: left; 1807 | display: none; 1808 | min-width: 160px; 1809 | padding: 4px 0; 1810 | margin: 0; 1811 | list-style: none; 1812 | background-color: #ffffff; 1813 | border-color: #ccc; 1814 | border-color: rgba(0, 0, 0, 0.2); 1815 | border-style: solid; 1816 | border-width: 1px; 1817 | -webkit-border-radius: 0 0 5px 5px; 1818 | -moz-border-radius: 0 0 5px 5px; 1819 | border-radius: 0 0 5px 5px; 1820 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 1821 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 1822 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 1823 | -webkit-background-clip: padding-box; 1824 | -moz-background-clip: padding; 1825 | background-clip: padding-box; 1826 | *border-right-width: 2px; 1827 | *border-bottom-width: 2px; 1828 | } 1829 | .dropdown-menu.pull-right { 1830 | right: 0; 1831 | left: auto; 1832 | } 1833 | .dropdown-menu .divider { 1834 | height: 1px; 1835 | margin: 8px 1px; 1836 | overflow: hidden; 1837 | background-color: #e5e5e5; 1838 | border-bottom: 1px solid #ffffff; 1839 | *width: 100%; 1840 | *margin: -5px 0 5px; 1841 | } 1842 | .dropdown-menu a { 1843 | display: block; 1844 | padding: 3px 15px; 1845 | clear: both; 1846 | font-weight: normal; 1847 | line-height: 18px; 1848 | color: #333333; 1849 | white-space: nowrap; 1850 | } 1851 | .dropdown-menu li > a:hover, 1852 | .dropdown-menu .active > a, 1853 | .dropdown-menu .active > a:hover { 1854 | color: #ffffff; 1855 | text-decoration: none; 1856 | background-color: #0088cc; 1857 | } 1858 | .dropdown.open { 1859 | *z-index: 1000; 1860 | } 1861 | .dropdown.open .dropdown-toggle { 1862 | color: #ffffff; 1863 | background: #ccc; 1864 | background: rgba(0, 0, 0, 0.3); 1865 | } 1866 | .dropdown.open .dropdown-menu { 1867 | display: block; 1868 | } 1869 | .pull-right .dropdown-menu { 1870 | left: auto; 1871 | right: 0; 1872 | } 1873 | .dropup .caret, 1874 | .navbar-fixed-bottom .dropdown .caret { 1875 | border-top: 0; 1876 | border-bottom: 4px solid #000000; 1877 | content: "\2191"; 1878 | } 1879 | .dropup .dropdown-menu, 1880 | .navbar-fixed-bottom .dropdown .dropdown-menu { 1881 | top: auto; 1882 | bottom: 100%; 1883 | margin-bottom: 1px; 1884 | } 1885 | .typeahead { 1886 | margin-top: 2px; 1887 | -webkit-border-radius: 4px; 1888 | -moz-border-radius: 4px; 1889 | border-radius: 4px; 1890 | } 1891 | .well { 1892 | min-height: 20px; 1893 | padding: 19px; 1894 | margin-bottom: 20px; 1895 | background-color: #f5f5f5; 1896 | border: 1px solid #eee; 1897 | border: 1px solid rgba(0, 0, 0, 0.05); 1898 | -webkit-border-radius: 4px; 1899 | -moz-border-radius: 4px; 1900 | border-radius: 4px; 1901 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 1902 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 1903 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 1904 | } 1905 | .well blockquote { 1906 | border-color: #ddd; 1907 | border-color: rgba(0, 0, 0, 0.15); 1908 | } 1909 | .well-large { 1910 | padding: 24px; 1911 | -webkit-border-radius: 6px; 1912 | -moz-border-radius: 6px; 1913 | border-radius: 6px; 1914 | } 1915 | .well-small { 1916 | padding: 9px; 1917 | -webkit-border-radius: 3px; 1918 | -moz-border-radius: 3px; 1919 | border-radius: 3px; 1920 | } 1921 | .fade { 1922 | -webkit-transition: opacity 0.15s linear; 1923 | -moz-transition: opacity 0.15s linear; 1924 | -ms-transition: opacity 0.15s linear; 1925 | -o-transition: opacity 0.15s linear; 1926 | transition: opacity 0.15s linear; 1927 | opacity: 0; 1928 | } 1929 | .fade.in { 1930 | opacity: 1; 1931 | } 1932 | .collapse { 1933 | -webkit-transition: height 0.35s ease; 1934 | -moz-transition: height 0.35s ease; 1935 | -ms-transition: height 0.35s ease; 1936 | -o-transition: height 0.35s ease; 1937 | transition: height 0.35s ease; 1938 | position: relative; 1939 | overflow: hidden; 1940 | height: 0; 1941 | } 1942 | .collapse.in { 1943 | height: auto; 1944 | } 1945 | .close { 1946 | float: right; 1947 | font-size: 20px; 1948 | font-weight: bold; 1949 | line-height: 18px; 1950 | color: #000000; 1951 | text-shadow: 0 1px 0 #ffffff; 1952 | opacity: 0.2; 1953 | filter: alpha(opacity=20); 1954 | } 1955 | .close:hover { 1956 | color: #000000; 1957 | text-decoration: none; 1958 | opacity: 0.4; 1959 | filter: alpha(opacity=40); 1960 | cursor: pointer; 1961 | } 1962 | .btn { 1963 | display: inline-block; 1964 | *display: inline; 1965 | /* IE7 inline-block hack */ 1966 | 1967 | *zoom: 1; 1968 | padding: 4px 10px 4px; 1969 | margin-bottom: 0; 1970 | font-size: 13px; 1971 | line-height: 18px; 1972 | color: #333333; 1973 | text-align: center; 1974 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 1975 | vertical-align: middle; 1976 | background-color: #f5f5f5; 1977 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); 1978 | background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); 1979 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); 1980 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); 1981 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); 1982 | background-image: linear-gradient(top, #ffffff, #e6e6e6); 1983 | background-repeat: repeat-x; 1984 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); 1985 | border-color: #e6e6e6 #e6e6e6 #bfbfbf; 1986 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 1987 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 1988 | border: 1px solid #cccccc; 1989 | border-bottom-color: #b3b3b3; 1990 | -webkit-border-radius: 4px; 1991 | -moz-border-radius: 4px; 1992 | border-radius: 4px; 1993 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 1994 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 1995 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 1996 | cursor: pointer; 1997 | *margin-left: .3em; 1998 | } 1999 | .btn:hover, 2000 | .btn:active, 2001 | .btn.active, 2002 | .btn.disabled, 2003 | .btn[disabled] { 2004 | background-color: #e6e6e6; 2005 | } 2006 | .btn:active, 2007 | .btn.active { 2008 | background-color: #cccccc \9; 2009 | } 2010 | .btn:first-child { 2011 | *margin-left: 0; 2012 | } 2013 | .btn:hover { 2014 | color: #333333; 2015 | text-decoration: none; 2016 | background-color: #e6e6e6; 2017 | background-position: 0 -15px; 2018 | -webkit-transition: background-position 0.1s linear; 2019 | -moz-transition: background-position 0.1s linear; 2020 | -ms-transition: background-position 0.1s linear; 2021 | -o-transition: background-position 0.1s linear; 2022 | transition: background-position 0.1s linear; 2023 | } 2024 | .btn:focus { 2025 | outline: thin dotted #333; 2026 | outline: 5px auto -webkit-focus-ring-color; 2027 | outline-offset: -2px; 2028 | } 2029 | .btn.active, 2030 | .btn:active { 2031 | background-image: none; 2032 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2033 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2034 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2035 | background-color: #e6e6e6; 2036 | background-color: #d9d9d9 \9; 2037 | outline: 0; 2038 | } 2039 | .btn.disabled, 2040 | .btn[disabled] { 2041 | cursor: default; 2042 | background-image: none; 2043 | background-color: #e6e6e6; 2044 | opacity: 0.65; 2045 | filter: alpha(opacity=65); 2046 | -webkit-box-shadow: none; 2047 | -moz-box-shadow: none; 2048 | box-shadow: none; 2049 | } 2050 | .btn-large { 2051 | padding: 9px 14px; 2052 | font-size: 15px; 2053 | line-height: normal; 2054 | -webkit-border-radius: 5px; 2055 | -moz-border-radius: 5px; 2056 | border-radius: 5px; 2057 | } 2058 | .btn-large [class^="icon-"] { 2059 | margin-top: 1px; 2060 | } 2061 | .btn-small { 2062 | padding: 5px 9px; 2063 | font-size: 11px; 2064 | line-height: 16px; 2065 | } 2066 | .btn-small [class^="icon-"] { 2067 | margin-top: -1px; 2068 | } 2069 | .btn-mini { 2070 | padding: 2px 6px; 2071 | font-size: 11px; 2072 | line-height: 14px; 2073 | } 2074 | .btn-primary, 2075 | .btn-primary:hover, 2076 | .btn-warning, 2077 | .btn-warning:hover, 2078 | .btn-danger, 2079 | .btn-danger:hover, 2080 | .btn-success, 2081 | .btn-success:hover, 2082 | .btn-info, 2083 | .btn-info:hover, 2084 | .btn-inverse, 2085 | .btn-inverse:hover { 2086 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 2087 | color: #ffffff; 2088 | } 2089 | .btn-primary.active, 2090 | .btn-warning.active, 2091 | .btn-danger.active, 2092 | .btn-success.active, 2093 | .btn-info.active, 2094 | .btn-inverse.active { 2095 | color: rgba(255, 255, 255, 0.75); 2096 | } 2097 | .btn-primary { 2098 | background-color: #0074cc; 2099 | background-image: -moz-linear-gradient(top, #0088cc, #0055cc); 2100 | background-image: -ms-linear-gradient(top, #0088cc, #0055cc); 2101 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); 2102 | background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); 2103 | background-image: -o-linear-gradient(top, #0088cc, #0055cc); 2104 | background-image: linear-gradient(top, #0088cc, #0055cc); 2105 | background-repeat: repeat-x; 2106 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); 2107 | border-color: #0055cc #0055cc #003580; 2108 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2109 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2110 | } 2111 | .btn-primary:hover, 2112 | .btn-primary:active, 2113 | .btn-primary.active, 2114 | .btn-primary.disabled, 2115 | .btn-primary[disabled] { 2116 | background-color: #0055cc; 2117 | } 2118 | .btn-primary:active, 2119 | .btn-primary.active { 2120 | background-color: #004099 \9; 2121 | } 2122 | .btn-warning { 2123 | background-color: #faa732; 2124 | background-image: -moz-linear-gradient(top, #fbb450, #f89406); 2125 | background-image: -ms-linear-gradient(top, #fbb450, #f89406); 2126 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); 2127 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406); 2128 | background-image: -o-linear-gradient(top, #fbb450, #f89406); 2129 | background-image: linear-gradient(top, #fbb450, #f89406); 2130 | background-repeat: repeat-x; 2131 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); 2132 | border-color: #f89406 #f89406 #ad6704; 2133 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2134 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2135 | } 2136 | .btn-warning:hover, 2137 | .btn-warning:active, 2138 | .btn-warning.active, 2139 | .btn-warning.disabled, 2140 | .btn-warning[disabled] { 2141 | background-color: #f89406; 2142 | } 2143 | .btn-warning:active, 2144 | .btn-warning.active { 2145 | background-color: #c67605 \9; 2146 | } 2147 | .btn-danger { 2148 | background-color: #da4f49; 2149 | background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); 2150 | background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); 2151 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); 2152 | background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); 2153 | background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); 2154 | background-image: linear-gradient(top, #ee5f5b, #bd362f); 2155 | background-repeat: repeat-x; 2156 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); 2157 | border-color: #bd362f #bd362f #802420; 2158 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2159 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2160 | } 2161 | .btn-danger:hover, 2162 | .btn-danger:active, 2163 | .btn-danger.active, 2164 | .btn-danger.disabled, 2165 | .btn-danger[disabled] { 2166 | background-color: #bd362f; 2167 | } 2168 | .btn-danger:active, 2169 | .btn-danger.active { 2170 | background-color: #942a25 \9; 2171 | } 2172 | .btn-success { 2173 | background-color: #5bb75b; 2174 | background-image: -moz-linear-gradient(top, #62c462, #51a351); 2175 | background-image: -ms-linear-gradient(top, #62c462, #51a351); 2176 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); 2177 | background-image: -webkit-linear-gradient(top, #62c462, #51a351); 2178 | background-image: -o-linear-gradient(top, #62c462, #51a351); 2179 | background-image: linear-gradient(top, #62c462, #51a351); 2180 | background-repeat: repeat-x; 2181 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); 2182 | border-color: #51a351 #51a351 #387038; 2183 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2184 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2185 | } 2186 | .btn-success:hover, 2187 | .btn-success:active, 2188 | .btn-success.active, 2189 | .btn-success.disabled, 2190 | .btn-success[disabled] { 2191 | background-color: #51a351; 2192 | } 2193 | .btn-success:active, 2194 | .btn-success.active { 2195 | background-color: #408140 \9; 2196 | } 2197 | .btn-info { 2198 | background-color: #49afcd; 2199 | background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); 2200 | background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); 2201 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); 2202 | background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); 2203 | background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); 2204 | background-image: linear-gradient(top, #5bc0de, #2f96b4); 2205 | background-repeat: repeat-x; 2206 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); 2207 | border-color: #2f96b4 #2f96b4 #1f6377; 2208 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2209 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2210 | } 2211 | .btn-info:hover, 2212 | .btn-info:active, 2213 | .btn-info.active, 2214 | .btn-info.disabled, 2215 | .btn-info[disabled] { 2216 | background-color: #2f96b4; 2217 | } 2218 | .btn-info:active, 2219 | .btn-info.active { 2220 | background-color: #24748c \9; 2221 | } 2222 | .btn-inverse { 2223 | background-color: #414141; 2224 | background-image: -moz-linear-gradient(top, #555555, #222222); 2225 | background-image: -ms-linear-gradient(top, #555555, #222222); 2226 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); 2227 | background-image: -webkit-linear-gradient(top, #555555, #222222); 2228 | background-image: -o-linear-gradient(top, #555555, #222222); 2229 | background-image: linear-gradient(top, #555555, #222222); 2230 | background-repeat: repeat-x; 2231 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); 2232 | border-color: #222222 #222222 #000000; 2233 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2234 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2235 | } 2236 | .btn-inverse:hover, 2237 | .btn-inverse:active, 2238 | .btn-inverse.active, 2239 | .btn-inverse.disabled, 2240 | .btn-inverse[disabled] { 2241 | background-color: #222222; 2242 | } 2243 | .btn-inverse:active, 2244 | .btn-inverse.active { 2245 | background-color: #080808 \9; 2246 | } 2247 | button.btn, 2248 | input[type="submit"].btn { 2249 | *padding-top: 2px; 2250 | *padding-bottom: 2px; 2251 | } 2252 | button.btn::-moz-focus-inner, 2253 | input[type="submit"].btn::-moz-focus-inner { 2254 | padding: 0; 2255 | border: 0; 2256 | } 2257 | button.btn.btn-large, 2258 | input[type="submit"].btn.btn-large { 2259 | *padding-top: 7px; 2260 | *padding-bottom: 7px; 2261 | } 2262 | button.btn.btn-small, 2263 | input[type="submit"].btn.btn-small { 2264 | *padding-top: 3px; 2265 | *padding-bottom: 3px; 2266 | } 2267 | button.btn.btn-mini, 2268 | input[type="submit"].btn.btn-mini { 2269 | *padding-top: 1px; 2270 | *padding-bottom: 1px; 2271 | } 2272 | .btn-group { 2273 | position: relative; 2274 | *zoom: 1; 2275 | *margin-left: .3em; 2276 | } 2277 | .btn-group:before, 2278 | .btn-group:after { 2279 | display: table; 2280 | content: ""; 2281 | } 2282 | .btn-group:after { 2283 | clear: both; 2284 | } 2285 | .btn-group:first-child { 2286 | *margin-left: 0; 2287 | } 2288 | .btn-group + .btn-group { 2289 | margin-left: 5px; 2290 | } 2291 | .btn-toolbar { 2292 | margin-top: 9px; 2293 | margin-bottom: 9px; 2294 | } 2295 | .btn-toolbar .btn-group { 2296 | display: inline-block; 2297 | *display: inline; 2298 | /* IE7 inline-block hack */ 2299 | 2300 | *zoom: 1; 2301 | } 2302 | .btn-group .btn { 2303 | position: relative; 2304 | float: left; 2305 | margin-left: -1px; 2306 | -webkit-border-radius: 0; 2307 | -moz-border-radius: 0; 2308 | border-radius: 0; 2309 | } 2310 | .btn-group .btn:first-child { 2311 | margin-left: 0; 2312 | -webkit-border-top-left-radius: 4px; 2313 | -moz-border-radius-topleft: 4px; 2314 | border-top-left-radius: 4px; 2315 | -webkit-border-bottom-left-radius: 4px; 2316 | -moz-border-radius-bottomleft: 4px; 2317 | border-bottom-left-radius: 4px; 2318 | } 2319 | .btn-group .btn:last-child, 2320 | .btn-group .dropdown-toggle { 2321 | -webkit-border-top-right-radius: 4px; 2322 | -moz-border-radius-topright: 4px; 2323 | border-top-right-radius: 4px; 2324 | -webkit-border-bottom-right-radius: 4px; 2325 | -moz-border-radius-bottomright: 4px; 2326 | border-bottom-right-radius: 4px; 2327 | } 2328 | .btn-group .btn.large:first-child { 2329 | margin-left: 0; 2330 | -webkit-border-top-left-radius: 6px; 2331 | -moz-border-radius-topleft: 6px; 2332 | border-top-left-radius: 6px; 2333 | -webkit-border-bottom-left-radius: 6px; 2334 | -moz-border-radius-bottomleft: 6px; 2335 | border-bottom-left-radius: 6px; 2336 | } 2337 | .btn-group .btn.large:last-child, 2338 | .btn-group .large.dropdown-toggle { 2339 | -webkit-border-top-right-radius: 6px; 2340 | -moz-border-radius-topright: 6px; 2341 | border-top-right-radius: 6px; 2342 | -webkit-border-bottom-right-radius: 6px; 2343 | -moz-border-radius-bottomright: 6px; 2344 | border-bottom-right-radius: 6px; 2345 | } 2346 | .btn-group .btn:hover, 2347 | .btn-group .btn:focus, 2348 | .btn-group .btn:active, 2349 | .btn-group .btn.active { 2350 | z-index: 2; 2351 | } 2352 | .btn-group .dropdown-toggle:active, 2353 | .btn-group.open .dropdown-toggle { 2354 | outline: 0; 2355 | } 2356 | .btn-group .dropdown-toggle { 2357 | padding-left: 8px; 2358 | padding-right: 8px; 2359 | -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 2360 | -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 2361 | box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 2362 | *padding-top: 3px; 2363 | *padding-bottom: 3px; 2364 | } 2365 | .btn-group .btn-mini.dropdown-toggle { 2366 | padding-left: 5px; 2367 | padding-right: 5px; 2368 | *padding-top: 1px; 2369 | *padding-bottom: 1px; 2370 | } 2371 | .btn-group .btn-small.dropdown-toggle { 2372 | *padding-top: 4px; 2373 | *padding-bottom: 4px; 2374 | } 2375 | .btn-group .btn-large.dropdown-toggle { 2376 | padding-left: 12px; 2377 | padding-right: 12px; 2378 | } 2379 | .btn-group.open { 2380 | *z-index: 1000; 2381 | } 2382 | .btn-group.open .dropdown-menu { 2383 | display: block; 2384 | margin-top: 1px; 2385 | -webkit-border-radius: 5px; 2386 | -moz-border-radius: 5px; 2387 | border-radius: 5px; 2388 | } 2389 | .btn-group.open .dropdown-toggle { 2390 | background-image: none; 2391 | -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2392 | -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2393 | box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 2394 | } 2395 | .btn .caret { 2396 | margin-top: 7px; 2397 | margin-left: 0; 2398 | } 2399 | .btn:hover .caret, 2400 | .open.btn-group .caret { 2401 | opacity: 1; 2402 | filter: alpha(opacity=100); 2403 | } 2404 | .btn-mini .caret { 2405 | margin-top: 5px; 2406 | } 2407 | .btn-small .caret { 2408 | margin-top: 6px; 2409 | } 2410 | .btn-large .caret { 2411 | margin-top: 6px; 2412 | border-left: 5px solid transparent; 2413 | border-right: 5px solid transparent; 2414 | border-top: 5px solid #000000; 2415 | } 2416 | .btn-primary .caret, 2417 | .btn-warning .caret, 2418 | .btn-danger .caret, 2419 | .btn-info .caret, 2420 | .btn-success .caret, 2421 | .btn-inverse .caret { 2422 | border-top-color: #ffffff; 2423 | border-bottom-color: #ffffff; 2424 | opacity: 0.75; 2425 | filter: alpha(opacity=75); 2426 | } 2427 | .alert { 2428 | padding: 8px 35px 8px 14px; 2429 | margin-bottom: 18px; 2430 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 2431 | background-color: #fcf8e3; 2432 | border: 1px solid #fbeed5; 2433 | -webkit-border-radius: 4px; 2434 | -moz-border-radius: 4px; 2435 | border-radius: 4px; 2436 | color: #c09853; 2437 | } 2438 | .alert-heading { 2439 | color: inherit; 2440 | } 2441 | .alert .close { 2442 | position: relative; 2443 | top: -2px; 2444 | right: -21px; 2445 | line-height: 18px; 2446 | } 2447 | .alert-success { 2448 | background-color: #dff0d8; 2449 | border-color: #d6e9c6; 2450 | color: #468847; 2451 | } 2452 | .alert-danger, 2453 | .alert-error { 2454 | background-color: #f2dede; 2455 | border-color: #eed3d7; 2456 | color: #b94a48; 2457 | } 2458 | .alert-info { 2459 | background-color: #d9edf7; 2460 | border-color: #bce8f1; 2461 | color: #3a87ad; 2462 | } 2463 | .alert-block { 2464 | padding-top: 14px; 2465 | padding-bottom: 14px; 2466 | } 2467 | .alert-block > p, 2468 | .alert-block > ul { 2469 | margin-bottom: 0; 2470 | } 2471 | .alert-block p + p { 2472 | margin-top: 5px; 2473 | } 2474 | .nav { 2475 | margin-left: 0; 2476 | margin-bottom: 18px; 2477 | list-style: none; 2478 | } 2479 | .nav > li > a { 2480 | display: block; 2481 | } 2482 | .nav > li > a:hover { 2483 | text-decoration: none; 2484 | background-color: #eeeeee; 2485 | } 2486 | .nav .nav-header { 2487 | display: block; 2488 | padding: 3px 15px; 2489 | font-size: 11px; 2490 | font-weight: bold; 2491 | line-height: 18px; 2492 | color: #999999; 2493 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 2494 | text-transform: uppercase; 2495 | } 2496 | .nav li + .nav-header { 2497 | margin-top: 9px; 2498 | } 2499 | .nav-list { 2500 | padding-left: 15px; 2501 | padding-right: 15px; 2502 | margin-bottom: 0; 2503 | } 2504 | .nav-list > li > a, 2505 | .nav-list .nav-header { 2506 | margin-left: -15px; 2507 | margin-right: -15px; 2508 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 2509 | } 2510 | .nav-list > li > a { 2511 | padding: 3px 15px; 2512 | } 2513 | .nav-list > .active > a, 2514 | .nav-list > .active > a:hover { 2515 | color: #ffffff; 2516 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); 2517 | background-color: #0088cc; 2518 | } 2519 | .nav-list [class^="icon-"] { 2520 | margin-right: 2px; 2521 | } 2522 | .nav-list .divider { 2523 | height: 1px; 2524 | margin: 8px 1px; 2525 | overflow: hidden; 2526 | background-color: #e5e5e5; 2527 | border-bottom: 1px solid #ffffff; 2528 | *width: 100%; 2529 | *margin: -5px 0 5px; 2530 | } 2531 | .nav-tabs, 2532 | .nav-pills { 2533 | *zoom: 1; 2534 | } 2535 | .nav-tabs:before, 2536 | .nav-pills:before, 2537 | .nav-tabs:after, 2538 | .nav-pills:after { 2539 | display: table; 2540 | content: ""; 2541 | } 2542 | .nav-tabs:after, 2543 | .nav-pills:after { 2544 | clear: both; 2545 | } 2546 | .nav-tabs > li, 2547 | .nav-pills > li { 2548 | float: left; 2549 | } 2550 | .nav-tabs > li > a, 2551 | .nav-pills > li > a { 2552 | padding-right: 12px; 2553 | padding-left: 12px; 2554 | margin-right: 2px; 2555 | line-height: 14px; 2556 | } 2557 | .nav-tabs { 2558 | border-bottom: 1px solid #ddd; 2559 | } 2560 | .nav-tabs > li { 2561 | margin-bottom: -1px; 2562 | } 2563 | .nav-tabs > li > a { 2564 | padding-top: 8px; 2565 | padding-bottom: 8px; 2566 | line-height: 18px; 2567 | border: 1px solid transparent; 2568 | -webkit-border-radius: 4px 4px 0 0; 2569 | -moz-border-radius: 4px 4px 0 0; 2570 | border-radius: 4px 4px 0 0; 2571 | } 2572 | .nav-tabs > li > a:hover { 2573 | border-color: #eeeeee #eeeeee #dddddd; 2574 | } 2575 | .nav-tabs > .active > a, 2576 | .nav-tabs > .active > a:hover { 2577 | color: #555555; 2578 | background-color: #ffffff; 2579 | border: 1px solid #ddd; 2580 | border-bottom-color: transparent; 2581 | cursor: default; 2582 | } 2583 | .nav-pills > li > a { 2584 | padding-top: 8px; 2585 | padding-bottom: 8px; 2586 | margin-top: 2px; 2587 | margin-bottom: 2px; 2588 | -webkit-border-radius: 5px; 2589 | -moz-border-radius: 5px; 2590 | border-radius: 5px; 2591 | } 2592 | .nav-pills > .active > a, 2593 | .nav-pills > .active > a:hover { 2594 | color: #ffffff; 2595 | background-color: #0088cc; 2596 | } 2597 | .nav-stacked > li { 2598 | float: none; 2599 | } 2600 | .nav-stacked > li > a { 2601 | margin-right: 0; 2602 | } 2603 | .nav-tabs.nav-stacked { 2604 | border-bottom: 0; 2605 | } 2606 | .nav-tabs.nav-stacked > li > a { 2607 | border: 1px solid #ddd; 2608 | -webkit-border-radius: 0; 2609 | -moz-border-radius: 0; 2610 | border-radius: 0; 2611 | } 2612 | .nav-tabs.nav-stacked > li:first-child > a { 2613 | -webkit-border-radius: 4px 4px 0 0; 2614 | -moz-border-radius: 4px 4px 0 0; 2615 | border-radius: 4px 4px 0 0; 2616 | } 2617 | .nav-tabs.nav-stacked > li:last-child > a { 2618 | -webkit-border-radius: 0 0 4px 4px; 2619 | -moz-border-radius: 0 0 4px 4px; 2620 | border-radius: 0 0 4px 4px; 2621 | } 2622 | .nav-tabs.nav-stacked > li > a:hover { 2623 | border-color: #ddd; 2624 | z-index: 2; 2625 | } 2626 | .nav-pills.nav-stacked > li > a { 2627 | margin-bottom: 3px; 2628 | } 2629 | .nav-pills.nav-stacked > li:last-child > a { 2630 | margin-bottom: 1px; 2631 | } 2632 | .nav-tabs .dropdown-menu, 2633 | .nav-pills .dropdown-menu { 2634 | margin-top: 1px; 2635 | border-width: 1px; 2636 | } 2637 | .nav-pills .dropdown-menu { 2638 | -webkit-border-radius: 4px; 2639 | -moz-border-radius: 4px; 2640 | border-radius: 4px; 2641 | } 2642 | .nav-tabs .dropdown-toggle .caret, 2643 | .nav-pills .dropdown-toggle .caret { 2644 | border-top-color: #0088cc; 2645 | border-bottom-color: #0088cc; 2646 | margin-top: 6px; 2647 | } 2648 | .nav-tabs .dropdown-toggle:hover .caret, 2649 | .nav-pills .dropdown-toggle:hover .caret { 2650 | border-top-color: #005580; 2651 | border-bottom-color: #005580; 2652 | } 2653 | .nav-tabs .active .dropdown-toggle .caret, 2654 | .nav-pills .active .dropdown-toggle .caret { 2655 | border-top-color: #333333; 2656 | border-bottom-color: #333333; 2657 | } 2658 | .nav > .dropdown.active > a:hover { 2659 | color: #000000; 2660 | cursor: pointer; 2661 | } 2662 | .nav-tabs .open .dropdown-toggle, 2663 | .nav-pills .open .dropdown-toggle, 2664 | .nav > .open.active > a:hover { 2665 | color: #ffffff; 2666 | background-color: #999999; 2667 | border-color: #999999; 2668 | } 2669 | .nav .open .caret, 2670 | .nav .open.active .caret, 2671 | .nav .open a:hover .caret { 2672 | border-top-color: #ffffff; 2673 | border-bottom-color: #ffffff; 2674 | opacity: 1; 2675 | filter: alpha(opacity=100); 2676 | } 2677 | .tabs-stacked .open > a:hover { 2678 | border-color: #999999; 2679 | } 2680 | .tabbable { 2681 | *zoom: 1; 2682 | } 2683 | .tabbable:before, 2684 | .tabbable:after { 2685 | display: table; 2686 | content: ""; 2687 | } 2688 | .tabbable:after { 2689 | clear: both; 2690 | } 2691 | .tab-content { 2692 | display: table; 2693 | width: 100%; 2694 | } 2695 | .tabs-below .nav-tabs, 2696 | .tabs-right .nav-tabs, 2697 | .tabs-left .nav-tabs { 2698 | border-bottom: 0; 2699 | } 2700 | .tab-content > .tab-pane, 2701 | .pill-content > .pill-pane { 2702 | display: none; 2703 | } 2704 | .tab-content > .active, 2705 | .pill-content > .active { 2706 | display: block; 2707 | } 2708 | .tabs-below .nav-tabs { 2709 | border-top: 1px solid #ddd; 2710 | } 2711 | .tabs-below .nav-tabs > li { 2712 | margin-top: -1px; 2713 | margin-bottom: 0; 2714 | } 2715 | .tabs-below .nav-tabs > li > a { 2716 | -webkit-border-radius: 0 0 4px 4px; 2717 | -moz-border-radius: 0 0 4px 4px; 2718 | border-radius: 0 0 4px 4px; 2719 | } 2720 | .tabs-below .nav-tabs > li > a:hover { 2721 | border-bottom-color: transparent; 2722 | border-top-color: #ddd; 2723 | } 2724 | .tabs-below .nav-tabs .active > a, 2725 | .tabs-below .nav-tabs .active > a:hover { 2726 | border-color: transparent #ddd #ddd #ddd; 2727 | } 2728 | .tabs-left .nav-tabs > li, 2729 | .tabs-right .nav-tabs > li { 2730 | float: none; 2731 | } 2732 | .tabs-left .nav-tabs > li > a, 2733 | .tabs-right .nav-tabs > li > a { 2734 | min-width: 74px; 2735 | margin-right: 0; 2736 | margin-bottom: 3px; 2737 | } 2738 | .tabs-left .nav-tabs { 2739 | float: left; 2740 | margin-right: 19px; 2741 | border-right: 1px solid #ddd; 2742 | } 2743 | .tabs-left .nav-tabs > li > a { 2744 | margin-right: -1px; 2745 | -webkit-border-radius: 4px 0 0 4px; 2746 | -moz-border-radius: 4px 0 0 4px; 2747 | border-radius: 4px 0 0 4px; 2748 | } 2749 | .tabs-left .nav-tabs > li > a:hover { 2750 | border-color: #eeeeee #dddddd #eeeeee #eeeeee; 2751 | } 2752 | .tabs-left .nav-tabs .active > a, 2753 | .tabs-left .nav-tabs .active > a:hover { 2754 | border-color: #ddd transparent #ddd #ddd; 2755 | *border-right-color: #ffffff; 2756 | } 2757 | .tabs-right .nav-tabs { 2758 | float: right; 2759 | margin-left: 19px; 2760 | border-left: 1px solid #ddd; 2761 | } 2762 | .tabs-right .nav-tabs > li > a { 2763 | margin-left: -1px; 2764 | -webkit-border-radius: 0 4px 4px 0; 2765 | -moz-border-radius: 0 4px 4px 0; 2766 | border-radius: 0 4px 4px 0; 2767 | } 2768 | .tabs-right .nav-tabs > li > a:hover { 2769 | border-color: #eeeeee #eeeeee #eeeeee #dddddd; 2770 | } 2771 | .tabs-right .nav-tabs .active > a, 2772 | .tabs-right .nav-tabs .active > a:hover { 2773 | border-color: #ddd #ddd #ddd transparent; 2774 | *border-left-color: #ffffff; 2775 | } 2776 | .navbar { 2777 | *position: relative; 2778 | *z-index: 2; 2779 | overflow: visible; 2780 | margin-bottom: 18px; 2781 | } 2782 | .navbar-inner { 2783 | padding-left: 20px; 2784 | padding-right: 20px; 2785 | background-color: #2c2c2c; 2786 | background-image: -moz-linear-gradient(top, #333333, #222222); 2787 | background-image: -ms-linear-gradient(top, #333333, #222222); 2788 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); 2789 | background-image: -webkit-linear-gradient(top, #333333, #222222); 2790 | background-image: -o-linear-gradient(top, #333333, #222222); 2791 | background-image: linear-gradient(top, #333333, #222222); 2792 | background-repeat: repeat-x; 2793 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); 2794 | -webkit-border-radius: 4px; 2795 | -moz-border-radius: 4px; 2796 | border-radius: 4px; 2797 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); 2798 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); 2799 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); 2800 | } 2801 | .navbar .container { 2802 | width: auto; 2803 | } 2804 | .btn-navbar { 2805 | display: none; 2806 | float: right; 2807 | padding: 7px 10px; 2808 | margin-left: 5px; 2809 | margin-right: 5px; 2810 | background-color: #2c2c2c; 2811 | background-image: -moz-linear-gradient(top, #333333, #222222); 2812 | background-image: -ms-linear-gradient(top, #333333, #222222); 2813 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); 2814 | background-image: -webkit-linear-gradient(top, #333333, #222222); 2815 | background-image: -o-linear-gradient(top, #333333, #222222); 2816 | background-image: linear-gradient(top, #333333, #222222); 2817 | background-repeat: repeat-x; 2818 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); 2819 | border-color: #222222 #222222 #000000; 2820 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 2821 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 2822 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); 2823 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); 2824 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); 2825 | } 2826 | .btn-navbar:hover, 2827 | .btn-navbar:active, 2828 | .btn-navbar.active, 2829 | .btn-navbar.disabled, 2830 | .btn-navbar[disabled] { 2831 | background-color: #222222; 2832 | } 2833 | .btn-navbar:active, 2834 | .btn-navbar.active { 2835 | background-color: #080808 \9; 2836 | } 2837 | .btn-navbar .icon-bar { 2838 | display: block; 2839 | width: 18px; 2840 | height: 2px; 2841 | background-color: #f5f5f5; 2842 | -webkit-border-radius: 1px; 2843 | -moz-border-radius: 1px; 2844 | border-radius: 1px; 2845 | -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); 2846 | -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); 2847 | box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); 2848 | } 2849 | .btn-navbar .icon-bar + .icon-bar { 2850 | margin-top: 3px; 2851 | } 2852 | .nav-collapse.collapse { 2853 | height: auto; 2854 | } 2855 | .navbar { 2856 | color: #999999; 2857 | } 2858 | .navbar .brand:hover { 2859 | text-decoration: none; 2860 | } 2861 | .navbar .brand { 2862 | float: left; 2863 | display: block; 2864 | padding: 8px 20px 12px; 2865 | margin-left: -20px; 2866 | font-size: 20px; 2867 | font-weight: 200; 2868 | line-height: 1; 2869 | color: #ffffff; 2870 | } 2871 | .navbar .navbar-text { 2872 | margin-bottom: 0; 2873 | line-height: 40px; 2874 | } 2875 | .navbar .btn, 2876 | .navbar .btn-group { 2877 | margin-top: 5px; 2878 | } 2879 | .navbar .btn-group .btn { 2880 | margin-top: 0; 2881 | } 2882 | .navbar-form { 2883 | margin-bottom: 0; 2884 | *zoom: 1; 2885 | } 2886 | .navbar-form:before, 2887 | .navbar-form:after { 2888 | display: table; 2889 | content: ""; 2890 | } 2891 | .navbar-form:after { 2892 | clear: both; 2893 | } 2894 | .navbar-form input, 2895 | .navbar-form select, 2896 | .navbar-form .radio, 2897 | .navbar-form .checkbox { 2898 | margin-top: 5px; 2899 | } 2900 | .navbar-form input, 2901 | .navbar-form select { 2902 | display: inline-block; 2903 | margin-bottom: 0; 2904 | } 2905 | .navbar-form input[type="image"], 2906 | .navbar-form input[type="checkbox"], 2907 | .navbar-form input[type="radio"] { 2908 | margin-top: 3px; 2909 | } 2910 | .navbar-form .input-append, 2911 | .navbar-form .input-prepend { 2912 | margin-top: 6px; 2913 | white-space: nowrap; 2914 | } 2915 | .navbar-form .input-append input, 2916 | .navbar-form .input-prepend input { 2917 | margin-top: 0; 2918 | } 2919 | .navbar-search { 2920 | position: relative; 2921 | float: left; 2922 | margin-top: 6px; 2923 | margin-bottom: 0; 2924 | } 2925 | .navbar-search .search-query { 2926 | padding: 4px 9px; 2927 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 2928 | font-size: 13px; 2929 | font-weight: normal; 2930 | line-height: 1; 2931 | color: #ffffff; 2932 | background-color: #626262; 2933 | border: 1px solid #151515; 2934 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); 2935 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); 2936 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); 2937 | -webkit-transition: none; 2938 | -moz-transition: none; 2939 | -ms-transition: none; 2940 | -o-transition: none; 2941 | transition: none; 2942 | } 2943 | .navbar-search .search-query:-moz-placeholder { 2944 | color: #cccccc; 2945 | } 2946 | .navbar-search .search-query::-webkit-input-placeholder { 2947 | color: #cccccc; 2948 | } 2949 | .navbar-search .search-query:focus, 2950 | .navbar-search .search-query.focused { 2951 | padding: 5px 10px; 2952 | color: #333333; 2953 | text-shadow: 0 1px 0 #ffffff; 2954 | background-color: #ffffff; 2955 | border: 0; 2956 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); 2957 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); 2958 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); 2959 | outline: 0; 2960 | } 2961 | .navbar-fixed-top, 2962 | .navbar-fixed-bottom { 2963 | position: fixed; 2964 | right: 0; 2965 | left: 0; 2966 | z-index: 1030; 2967 | margin-bottom: 0; 2968 | } 2969 | .navbar-fixed-top .navbar-inner, 2970 | .navbar-fixed-bottom .navbar-inner { 2971 | padding-left: 0; 2972 | padding-right: 0; 2973 | -webkit-border-radius: 0; 2974 | -moz-border-radius: 0; 2975 | border-radius: 0; 2976 | } 2977 | .navbar-fixed-top .container, 2978 | .navbar-fixed-bottom .container { 2979 | width: 940px; 2980 | } 2981 | .navbar-fixed-top { 2982 | top: 0; 2983 | } 2984 | .navbar-fixed-bottom { 2985 | bottom: 0; 2986 | } 2987 | .navbar .nav { 2988 | position: relative; 2989 | left: 0; 2990 | display: block; 2991 | float: left; 2992 | margin: 0 10px 0 0; 2993 | } 2994 | .navbar .nav.pull-right { 2995 | float: right; 2996 | } 2997 | .navbar .nav > li { 2998 | display: block; 2999 | float: left; 3000 | } 3001 | .navbar .nav > li > a { 3002 | float: none; 3003 | padding: 10px 10px 11px; 3004 | line-height: 19px; 3005 | color: #999999; 3006 | text-decoration: none; 3007 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 3008 | } 3009 | .navbar .nav > li > a:hover { 3010 | background-color: transparent; 3011 | color: #ffffff; 3012 | text-decoration: none; 3013 | } 3014 | .navbar .nav .active > a, 3015 | .navbar .nav .active > a:hover { 3016 | color: #ffffff; 3017 | text-decoration: none; 3018 | background-color: #222222; 3019 | } 3020 | .navbar .divider-vertical { 3021 | height: 40px; 3022 | width: 1px; 3023 | margin: 0 9px; 3024 | overflow: hidden; 3025 | background-color: #222222; 3026 | border-right: 1px solid #333333; 3027 | } 3028 | .navbar .nav.pull-right { 3029 | margin-left: 10px; 3030 | margin-right: 0; 3031 | } 3032 | .navbar .dropdown-menu { 3033 | margin-top: 1px; 3034 | -webkit-border-radius: 4px; 3035 | -moz-border-radius: 4px; 3036 | border-radius: 4px; 3037 | } 3038 | .navbar .dropdown-menu:before { 3039 | content: ''; 3040 | display: inline-block; 3041 | border-left: 7px solid transparent; 3042 | border-right: 7px solid transparent; 3043 | border-bottom: 7px solid #ccc; 3044 | border-bottom-color: rgba(0, 0, 0, 0.2); 3045 | position: absolute; 3046 | top: -7px; 3047 | left: 9px; 3048 | } 3049 | .navbar .dropdown-menu:after { 3050 | content: ''; 3051 | display: inline-block; 3052 | border-left: 6px solid transparent; 3053 | border-right: 6px solid transparent; 3054 | border-bottom: 6px solid #ffffff; 3055 | position: absolute; 3056 | top: -6px; 3057 | left: 10px; 3058 | } 3059 | .navbar-fixed-bottom .dropdown-menu:before { 3060 | border-top: 7px solid #ccc; 3061 | border-top-color: rgba(0, 0, 0, 0.2); 3062 | border-bottom: 0; 3063 | bottom: -7px; 3064 | top: auto; 3065 | } 3066 | .navbar-fixed-bottom .dropdown-menu:after { 3067 | border-top: 6px solid #ffffff; 3068 | border-bottom: 0; 3069 | bottom: -6px; 3070 | top: auto; 3071 | } 3072 | .navbar .nav .dropdown-toggle .caret, 3073 | .navbar .nav .open.dropdown .caret { 3074 | border-top-color: #ffffff; 3075 | border-bottom-color: #ffffff; 3076 | } 3077 | .navbar .nav .active .caret { 3078 | opacity: 1; 3079 | filter: alpha(opacity=100); 3080 | } 3081 | .navbar .nav .open > .dropdown-toggle, 3082 | .navbar .nav .active > .dropdown-toggle, 3083 | .navbar .nav .open.active > .dropdown-toggle { 3084 | background-color: transparent; 3085 | } 3086 | .navbar .nav .active > .dropdown-toggle:hover { 3087 | color: #ffffff; 3088 | } 3089 | .navbar .nav.pull-right .dropdown-menu, 3090 | .navbar .nav .dropdown-menu.pull-right { 3091 | left: auto; 3092 | right: 0; 3093 | } 3094 | .navbar .nav.pull-right .dropdown-menu:before, 3095 | .navbar .nav .dropdown-menu.pull-right:before { 3096 | left: auto; 3097 | right: 12px; 3098 | } 3099 | .navbar .nav.pull-right .dropdown-menu:after, 3100 | .navbar .nav .dropdown-menu.pull-right:after { 3101 | left: auto; 3102 | right: 13px; 3103 | } 3104 | .breadcrumb { 3105 | padding: 7px 14px; 3106 | margin: 0 0 18px; 3107 | list-style: none; 3108 | background-color: #fbfbfb; 3109 | background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); 3110 | background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); 3111 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); 3112 | background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); 3113 | background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); 3114 | background-image: linear-gradient(top, #ffffff, #f5f5f5); 3115 | background-repeat: repeat-x; 3116 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); 3117 | border: 1px solid #ddd; 3118 | -webkit-border-radius: 3px; 3119 | -moz-border-radius: 3px; 3120 | border-radius: 3px; 3121 | -webkit-box-shadow: inset 0 1px 0 #ffffff; 3122 | -moz-box-shadow: inset 0 1px 0 #ffffff; 3123 | box-shadow: inset 0 1px 0 #ffffff; 3124 | } 3125 | .breadcrumb li { 3126 | display: inline-block; 3127 | *display: inline; 3128 | /* IE7 inline-block hack */ 3129 | 3130 | *zoom: 1; 3131 | text-shadow: 0 1px 0 #ffffff; 3132 | } 3133 | .breadcrumb .divider { 3134 | padding: 0 5px; 3135 | color: #999999; 3136 | } 3137 | .breadcrumb .active a { 3138 | color: #333333; 3139 | } 3140 | .pagination { 3141 | height: 36px; 3142 | margin: 18px 0; 3143 | } 3144 | .pagination ul { 3145 | display: inline-block; 3146 | *display: inline; 3147 | /* IE7 inline-block hack */ 3148 | 3149 | *zoom: 1; 3150 | margin-left: 0; 3151 | margin-bottom: 0; 3152 | -webkit-border-radius: 3px; 3153 | -moz-border-radius: 3px; 3154 | border-radius: 3px; 3155 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 3156 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 3157 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 3158 | } 3159 | .pagination li { 3160 | display: inline; 3161 | } 3162 | .pagination a { 3163 | float: left; 3164 | padding: 0 14px; 3165 | line-height: 34px; 3166 | text-decoration: none; 3167 | border: 1px solid #ddd; 3168 | border-left-width: 0; 3169 | } 3170 | .pagination a:hover, 3171 | .pagination .active a { 3172 | background-color: #f5f5f5; 3173 | } 3174 | .pagination .active a { 3175 | color: #999999; 3176 | cursor: default; 3177 | } 3178 | .pagination .disabled span, 3179 | .pagination .disabled a, 3180 | .pagination .disabled a:hover { 3181 | color: #999999; 3182 | background-color: transparent; 3183 | cursor: default; 3184 | } 3185 | .pagination li:first-child a { 3186 | border-left-width: 1px; 3187 | -webkit-border-radius: 3px 0 0 3px; 3188 | -moz-border-radius: 3px 0 0 3px; 3189 | border-radius: 3px 0 0 3px; 3190 | } 3191 | .pagination li:last-child a { 3192 | -webkit-border-radius: 0 3px 3px 0; 3193 | -moz-border-radius: 0 3px 3px 0; 3194 | border-radius: 0 3px 3px 0; 3195 | } 3196 | .pagination-centered { 3197 | text-align: center; 3198 | } 3199 | .pagination-right { 3200 | text-align: right; 3201 | } 3202 | .pager { 3203 | margin-left: 0; 3204 | margin-bottom: 18px; 3205 | list-style: none; 3206 | text-align: center; 3207 | *zoom: 1; 3208 | } 3209 | .pager:before, 3210 | .pager:after { 3211 | display: table; 3212 | content: ""; 3213 | } 3214 | .pager:after { 3215 | clear: both; 3216 | } 3217 | .pager li { 3218 | display: inline; 3219 | } 3220 | .pager a { 3221 | display: inline-block; 3222 | padding: 5px 14px; 3223 | background-color: #fff; 3224 | border: 1px solid #ddd; 3225 | -webkit-border-radius: 15px; 3226 | -moz-border-radius: 15px; 3227 | border-radius: 15px; 3228 | } 3229 | .pager a:hover { 3230 | text-decoration: none; 3231 | background-color: #f5f5f5; 3232 | } 3233 | .pager .next a { 3234 | float: right; 3235 | } 3236 | .pager .previous a { 3237 | float: left; 3238 | } 3239 | .pager .disabled a, 3240 | .pager .disabled a:hover { 3241 | color: #999999; 3242 | background-color: #fff; 3243 | cursor: default; 3244 | } 3245 | .modal-open .dropdown-menu { 3246 | z-index: 2050; 3247 | } 3248 | .modal-open .dropdown.open { 3249 | *z-index: 2050; 3250 | } 3251 | .modal-open .popover { 3252 | z-index: 2060; 3253 | } 3254 | .modal-open .tooltip { 3255 | z-index: 2070; 3256 | } 3257 | .modal-backdrop { 3258 | position: fixed; 3259 | top: 0; 3260 | right: 0; 3261 | bottom: 0; 3262 | left: 0; 3263 | z-index: 1040; 3264 | background-color: #000000; 3265 | } 3266 | .modal-backdrop.fade { 3267 | opacity: 0; 3268 | } 3269 | .modal-backdrop, 3270 | .modal-backdrop.fade.in { 3271 | opacity: 0.8; 3272 | filter: alpha(opacity=80); 3273 | } 3274 | .modal { 3275 | position: fixed; 3276 | top: 50%; 3277 | left: 50%; 3278 | z-index: 1050; 3279 | overflow: auto; 3280 | width: 560px; 3281 | margin: -250px 0 0 -280px; 3282 | background-color: #ffffff; 3283 | border: 1px solid #999; 3284 | border: 1px solid rgba(0, 0, 0, 0.3); 3285 | *border: 1px solid #999; 3286 | /* IE6-7 */ 3287 | 3288 | -webkit-border-radius: 6px; 3289 | -moz-border-radius: 6px; 3290 | border-radius: 6px; 3291 | -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3292 | -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3293 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3294 | -webkit-background-clip: padding-box; 3295 | -moz-background-clip: padding-box; 3296 | background-clip: padding-box; 3297 | } 3298 | .modal.fade { 3299 | -webkit-transition: opacity .3s linear, top .3s ease-out; 3300 | -moz-transition: opacity .3s linear, top .3s ease-out; 3301 | -ms-transition: opacity .3s linear, top .3s ease-out; 3302 | -o-transition: opacity .3s linear, top .3s ease-out; 3303 | transition: opacity .3s linear, top .3s ease-out; 3304 | top: -25%; 3305 | } 3306 | .modal.fade.in { 3307 | top: 50%; 3308 | } 3309 | .modal-header { 3310 | padding: 9px 15px; 3311 | border-bottom: 1px solid #eee; 3312 | } 3313 | .modal-header .close { 3314 | margin-top: 2px; 3315 | } 3316 | .modal-body { 3317 | overflow-y: auto; 3318 | max-height: 400px; 3319 | padding: 15px; 3320 | } 3321 | .modal-form { 3322 | margin-bottom: 0; 3323 | } 3324 | .modal-footer { 3325 | padding: 14px 15px 15px; 3326 | margin-bottom: 0; 3327 | text-align: right; 3328 | background-color: #f5f5f5; 3329 | border-top: 1px solid #ddd; 3330 | -webkit-border-radius: 0 0 6px 6px; 3331 | -moz-border-radius: 0 0 6px 6px; 3332 | border-radius: 0 0 6px 6px; 3333 | -webkit-box-shadow: inset 0 1px 0 #ffffff; 3334 | -moz-box-shadow: inset 0 1px 0 #ffffff; 3335 | box-shadow: inset 0 1px 0 #ffffff; 3336 | *zoom: 1; 3337 | } 3338 | .modal-footer:before, 3339 | .modal-footer:after { 3340 | display: table; 3341 | content: ""; 3342 | } 3343 | .modal-footer:after { 3344 | clear: both; 3345 | } 3346 | .modal-footer .btn + .btn { 3347 | margin-left: 5px; 3348 | margin-bottom: 0; 3349 | } 3350 | .modal-footer .btn-group .btn + .btn { 3351 | margin-left: -1px; 3352 | } 3353 | .tooltip { 3354 | position: absolute; 3355 | z-index: 1020; 3356 | display: block; 3357 | visibility: visible; 3358 | padding: 5px; 3359 | font-size: 11px; 3360 | opacity: 0; 3361 | filter: alpha(opacity=0); 3362 | } 3363 | .tooltip.in { 3364 | opacity: 0.8; 3365 | filter: alpha(opacity=80); 3366 | } 3367 | .tooltip.top { 3368 | margin-top: -2px; 3369 | } 3370 | .tooltip.right { 3371 | margin-left: 2px; 3372 | } 3373 | .tooltip.bottom { 3374 | margin-top: 2px; 3375 | } 3376 | .tooltip.left { 3377 | margin-left: -2px; 3378 | } 3379 | .tooltip.top .tooltip-arrow { 3380 | bottom: 0; 3381 | left: 50%; 3382 | margin-left: -5px; 3383 | border-left: 5px solid transparent; 3384 | border-right: 5px solid transparent; 3385 | border-top: 5px solid #000000; 3386 | } 3387 | .tooltip.left .tooltip-arrow { 3388 | top: 50%; 3389 | right: 0; 3390 | margin-top: -5px; 3391 | border-top: 5px solid transparent; 3392 | border-bottom: 5px solid transparent; 3393 | border-left: 5px solid #000000; 3394 | } 3395 | .tooltip.bottom .tooltip-arrow { 3396 | top: 0; 3397 | left: 50%; 3398 | margin-left: -5px; 3399 | border-left: 5px solid transparent; 3400 | border-right: 5px solid transparent; 3401 | border-bottom: 5px solid #000000; 3402 | } 3403 | .tooltip.right .tooltip-arrow { 3404 | top: 50%; 3405 | left: 0; 3406 | margin-top: -5px; 3407 | border-top: 5px solid transparent; 3408 | border-bottom: 5px solid transparent; 3409 | border-right: 5px solid #000000; 3410 | } 3411 | .tooltip-inner { 3412 | max-width: 200px; 3413 | padding: 3px 8px; 3414 | color: #ffffff; 3415 | text-align: center; 3416 | text-decoration: none; 3417 | background-color: #000000; 3418 | -webkit-border-radius: 4px; 3419 | -moz-border-radius: 4px; 3420 | border-radius: 4px; 3421 | } 3422 | .tooltip-arrow { 3423 | position: absolute; 3424 | width: 0; 3425 | height: 0; 3426 | } 3427 | .popover { 3428 | position: absolute; 3429 | top: 0; 3430 | left: 0; 3431 | z-index: 1010; 3432 | display: none; 3433 | padding: 5px; 3434 | } 3435 | .popover.top { 3436 | margin-top: -5px; 3437 | } 3438 | .popover.right { 3439 | margin-left: 5px; 3440 | } 3441 | .popover.bottom { 3442 | margin-top: 5px; 3443 | } 3444 | .popover.left { 3445 | margin-left: -5px; 3446 | } 3447 | .popover.top .arrow { 3448 | bottom: 0; 3449 | left: 50%; 3450 | margin-left: -5px; 3451 | border-left: 5px solid transparent; 3452 | border-right: 5px solid transparent; 3453 | border-top: 5px solid #000000; 3454 | } 3455 | .popover.right .arrow { 3456 | top: 50%; 3457 | left: 0; 3458 | margin-top: -5px; 3459 | border-top: 5px solid transparent; 3460 | border-bottom: 5px solid transparent; 3461 | border-right: 5px solid #000000; 3462 | } 3463 | .popover.bottom .arrow { 3464 | top: 0; 3465 | left: 50%; 3466 | margin-left: -5px; 3467 | border-left: 5px solid transparent; 3468 | border-right: 5px solid transparent; 3469 | border-bottom: 5px solid #000000; 3470 | } 3471 | .popover.left .arrow { 3472 | top: 50%; 3473 | right: 0; 3474 | margin-top: -5px; 3475 | border-top: 5px solid transparent; 3476 | border-bottom: 5px solid transparent; 3477 | border-left: 5px solid #000000; 3478 | } 3479 | .popover .arrow { 3480 | position: absolute; 3481 | width: 0; 3482 | height: 0; 3483 | } 3484 | .popover-inner { 3485 | padding: 3px; 3486 | width: 280px; 3487 | overflow: hidden; 3488 | background: #000000; 3489 | background: rgba(0, 0, 0, 0.8); 3490 | -webkit-border-radius: 6px; 3491 | -moz-border-radius: 6px; 3492 | border-radius: 6px; 3493 | -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3494 | -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3495 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); 3496 | } 3497 | .popover-title { 3498 | padding: 9px 15px; 3499 | line-height: 1; 3500 | background-color: #f5f5f5; 3501 | border-bottom: 1px solid #eee; 3502 | -webkit-border-radius: 3px 3px 0 0; 3503 | -moz-border-radius: 3px 3px 0 0; 3504 | border-radius: 3px 3px 0 0; 3505 | } 3506 | .popover-content { 3507 | padding: 14px; 3508 | background-color: #ffffff; 3509 | -webkit-border-radius: 0 0 3px 3px; 3510 | -moz-border-radius: 0 0 3px 3px; 3511 | border-radius: 0 0 3px 3px; 3512 | -webkit-background-clip: padding-box; 3513 | -moz-background-clip: padding-box; 3514 | background-clip: padding-box; 3515 | } 3516 | .popover-content p, 3517 | .popover-content ul, 3518 | .popover-content ol { 3519 | margin-bottom: 0; 3520 | } 3521 | .thumbnails { 3522 | margin-left: -20px; 3523 | list-style: none; 3524 | *zoom: 1; 3525 | } 3526 | .thumbnails:before, 3527 | .thumbnails:after { 3528 | display: table; 3529 | content: ""; 3530 | } 3531 | .thumbnails:after { 3532 | clear: both; 3533 | } 3534 | .thumbnails > li { 3535 | float: left; 3536 | margin: 0 0 18px 20px; 3537 | } 3538 | .thumbnail { 3539 | display: block; 3540 | padding: 4px; 3541 | line-height: 1; 3542 | border: 1px solid #ddd; 3543 | -webkit-border-radius: 4px; 3544 | -moz-border-radius: 4px; 3545 | border-radius: 4px; 3546 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 3547 | -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 3548 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 3549 | } 3550 | a.thumbnail:hover { 3551 | border-color: #0088cc; 3552 | -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); 3553 | -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); 3554 | box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); 3555 | } 3556 | .thumbnail > img { 3557 | display: block; 3558 | max-width: 100%; 3559 | margin-left: auto; 3560 | margin-right: auto; 3561 | } 3562 | .thumbnail .caption { 3563 | padding: 9px; 3564 | } 3565 | .label { 3566 | padding: 1px 4px 2px; 3567 | font-size: 10.998px; 3568 | font-weight: bold; 3569 | line-height: 13px; 3570 | color: #ffffff; 3571 | vertical-align: middle; 3572 | white-space: nowrap; 3573 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 3574 | background-color: #999999; 3575 | -webkit-border-radius: 3px; 3576 | -moz-border-radius: 3px; 3577 | border-radius: 3px; 3578 | } 3579 | .label:hover { 3580 | color: #ffffff; 3581 | text-decoration: none; 3582 | } 3583 | .label-important { 3584 | background-color: #b94a48; 3585 | } 3586 | .label-important:hover { 3587 | background-color: #953b39; 3588 | } 3589 | .label-warning { 3590 | background-color: #f89406; 3591 | } 3592 | .label-warning:hover { 3593 | background-color: #c67605; 3594 | } 3595 | .label-success { 3596 | background-color: #468847; 3597 | } 3598 | .label-success:hover { 3599 | background-color: #356635; 3600 | } 3601 | .label-info { 3602 | background-color: #3a87ad; 3603 | } 3604 | .label-info:hover { 3605 | background-color: #2d6987; 3606 | } 3607 | .label-inverse { 3608 | background-color: #333333; 3609 | } 3610 | .label-inverse:hover { 3611 | background-color: #1a1a1a; 3612 | } 3613 | .badge { 3614 | padding: 1px 9px 2px; 3615 | font-size: 12.025px; 3616 | font-weight: bold; 3617 | white-space: nowrap; 3618 | color: #ffffff; 3619 | background-color: #999999; 3620 | -webkit-border-radius: 9px; 3621 | -moz-border-radius: 9px; 3622 | border-radius: 9px; 3623 | } 3624 | .badge:hover { 3625 | color: #ffffff; 3626 | text-decoration: none; 3627 | cursor: pointer; 3628 | } 3629 | .badge-error { 3630 | background-color: #b94a48; 3631 | } 3632 | .badge-error:hover { 3633 | background-color: #953b39; 3634 | } 3635 | .badge-warning { 3636 | background-color: #f89406; 3637 | } 3638 | .badge-warning:hover { 3639 | background-color: #c67605; 3640 | } 3641 | .badge-success { 3642 | background-color: #468847; 3643 | } 3644 | .badge-success:hover { 3645 | background-color: #356635; 3646 | } 3647 | .badge-info { 3648 | background-color: #3a87ad; 3649 | } 3650 | .badge-info:hover { 3651 | background-color: #2d6987; 3652 | } 3653 | .badge-inverse { 3654 | background-color: #333333; 3655 | } 3656 | .badge-inverse:hover { 3657 | background-color: #1a1a1a; 3658 | } 3659 | @-webkit-keyframes progress-bar-stripes { 3660 | from { 3661 | background-position: 0 0; 3662 | } 3663 | to { 3664 | background-position: 40px 0; 3665 | } 3666 | } 3667 | @-moz-keyframes progress-bar-stripes { 3668 | from { 3669 | background-position: 0 0; 3670 | } 3671 | to { 3672 | background-position: 40px 0; 3673 | } 3674 | } 3675 | @-ms-keyframes progress-bar-stripes { 3676 | from { 3677 | background-position: 0 0; 3678 | } 3679 | to { 3680 | background-position: 40px 0; 3681 | } 3682 | } 3683 | @keyframes progress-bar-stripes { 3684 | from { 3685 | background-position: 0 0; 3686 | } 3687 | to { 3688 | background-position: 40px 0; 3689 | } 3690 | } 3691 | .progress { 3692 | overflow: hidden; 3693 | height: 18px; 3694 | margin-bottom: 18px; 3695 | background-color: #f7f7f7; 3696 | background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); 3697 | background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); 3698 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); 3699 | background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); 3700 | background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); 3701 | background-image: linear-gradient(top, #f5f5f5, #f9f9f9); 3702 | background-repeat: repeat-x; 3703 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); 3704 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 3705 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 3706 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 3707 | -webkit-border-radius: 4px; 3708 | -moz-border-radius: 4px; 3709 | border-radius: 4px; 3710 | } 3711 | .progress .bar { 3712 | width: 0%; 3713 | height: 18px; 3714 | color: #ffffff; 3715 | font-size: 12px; 3716 | text-align: center; 3717 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 3718 | background-color: #0e90d2; 3719 | background-image: -moz-linear-gradient(top, #149bdf, #0480be); 3720 | background-image: -ms-linear-gradient(top, #149bdf, #0480be); 3721 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); 3722 | background-image: -webkit-linear-gradient(top, #149bdf, #0480be); 3723 | background-image: -o-linear-gradient(top, #149bdf, #0480be); 3724 | background-image: linear-gradient(top, #149bdf, #0480be); 3725 | background-repeat: repeat-x; 3726 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); 3727 | -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 3728 | -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 3729 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 3730 | -webkit-box-sizing: border-box; 3731 | -moz-box-sizing: border-box; 3732 | -ms-box-sizing: border-box; 3733 | box-sizing: border-box; 3734 | -webkit-transition: width 0.6s ease; 3735 | -moz-transition: width 0.6s ease; 3736 | -ms-transition: width 0.6s ease; 3737 | -o-transition: width 0.6s ease; 3738 | transition: width 0.6s ease; 3739 | } 3740 | .progress-striped .bar { 3741 | background-color: #149bdf; 3742 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); 3743 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3744 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3745 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3746 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3747 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3748 | -webkit-background-size: 40px 40px; 3749 | -moz-background-size: 40px 40px; 3750 | -o-background-size: 40px 40px; 3751 | background-size: 40px 40px; 3752 | } 3753 | .progress.active .bar { 3754 | -webkit-animation: progress-bar-stripes 2s linear infinite; 3755 | -moz-animation: progress-bar-stripes 2s linear infinite; 3756 | animation: progress-bar-stripes 2s linear infinite; 3757 | } 3758 | .progress-danger .bar { 3759 | background-color: #dd514c; 3760 | background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); 3761 | background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); 3762 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); 3763 | background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); 3764 | background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); 3765 | background-image: linear-gradient(top, #ee5f5b, #c43c35); 3766 | background-repeat: repeat-x; 3767 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); 3768 | } 3769 | .progress-danger.progress-striped .bar { 3770 | background-color: #ee5f5b; 3771 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); 3772 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3773 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3774 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3775 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3776 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3777 | } 3778 | .progress-success .bar { 3779 | background-color: #5eb95e; 3780 | background-image: -moz-linear-gradient(top, #62c462, #57a957); 3781 | background-image: -ms-linear-gradient(top, #62c462, #57a957); 3782 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); 3783 | background-image: -webkit-linear-gradient(top, #62c462, #57a957); 3784 | background-image: -o-linear-gradient(top, #62c462, #57a957); 3785 | background-image: linear-gradient(top, #62c462, #57a957); 3786 | background-repeat: repeat-x; 3787 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); 3788 | } 3789 | .progress-success.progress-striped .bar { 3790 | background-color: #62c462; 3791 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); 3792 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3793 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3794 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3795 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3796 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3797 | } 3798 | .progress-info .bar { 3799 | background-color: #4bb1cf; 3800 | background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); 3801 | background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); 3802 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); 3803 | background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); 3804 | background-image: -o-linear-gradient(top, #5bc0de, #339bb9); 3805 | background-image: linear-gradient(top, #5bc0de, #339bb9); 3806 | background-repeat: repeat-x; 3807 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); 3808 | } 3809 | .progress-info.progress-striped .bar { 3810 | background-color: #5bc0de; 3811 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); 3812 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3813 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3814 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3815 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3816 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3817 | } 3818 | .progress-warning .bar { 3819 | background-color: #faa732; 3820 | background-image: -moz-linear-gradient(top, #fbb450, #f89406); 3821 | background-image: -ms-linear-gradient(top, #fbb450, #f89406); 3822 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); 3823 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406); 3824 | background-image: -o-linear-gradient(top, #fbb450, #f89406); 3825 | background-image: linear-gradient(top, #fbb450, #f89406); 3826 | background-repeat: repeat-x; 3827 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); 3828 | } 3829 | .progress-warning.progress-striped .bar { 3830 | background-color: #fbb450; 3831 | background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); 3832 | background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3833 | background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3834 | background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3835 | background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3836 | background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 3837 | } 3838 | .accordion { 3839 | margin-bottom: 18px; 3840 | } 3841 | .accordion-group { 3842 | margin-bottom: 2px; 3843 | border: 1px solid #e5e5e5; 3844 | -webkit-border-radius: 4px; 3845 | -moz-border-radius: 4px; 3846 | border-radius: 4px; 3847 | } 3848 | .accordion-heading { 3849 | border-bottom: 0; 3850 | } 3851 | .accordion-heading .accordion-toggle { 3852 | display: block; 3853 | padding: 8px 15px; 3854 | } 3855 | .accordion-inner { 3856 | padding: 9px 15px; 3857 | border-top: 1px solid #e5e5e5; 3858 | } 3859 | .carousel { 3860 | position: relative; 3861 | margin-bottom: 18px; 3862 | line-height: 1; 3863 | } 3864 | .carousel-inner { 3865 | overflow: hidden; 3866 | width: 100%; 3867 | position: relative; 3868 | } 3869 | .carousel .item { 3870 | display: none; 3871 | position: relative; 3872 | -webkit-transition: 0.6s ease-in-out left; 3873 | -moz-transition: 0.6s ease-in-out left; 3874 | -ms-transition: 0.6s ease-in-out left; 3875 | -o-transition: 0.6s ease-in-out left; 3876 | transition: 0.6s ease-in-out left; 3877 | } 3878 | .carousel .item > img { 3879 | display: block; 3880 | line-height: 1; 3881 | } 3882 | .carousel .active, 3883 | .carousel .next, 3884 | .carousel .prev { 3885 | display: block; 3886 | } 3887 | .carousel .active { 3888 | left: 0; 3889 | } 3890 | .carousel .next, 3891 | .carousel .prev { 3892 | position: absolute; 3893 | top: 0; 3894 | width: 100%; 3895 | } 3896 | .carousel .next { 3897 | left: 100%; 3898 | } 3899 | .carousel .prev { 3900 | left: -100%; 3901 | } 3902 | .carousel .next.left, 3903 | .carousel .prev.right { 3904 | left: 0; 3905 | } 3906 | .carousel .active.left { 3907 | left: -100%; 3908 | } 3909 | .carousel .active.right { 3910 | left: 100%; 3911 | } 3912 | .carousel-control { 3913 | position: absolute; 3914 | top: 40%; 3915 | left: 15px; 3916 | width: 40px; 3917 | height: 40px; 3918 | margin-top: -20px; 3919 | font-size: 60px; 3920 | font-weight: 100; 3921 | line-height: 30px; 3922 | color: #ffffff; 3923 | text-align: center; 3924 | background: #222222; 3925 | border: 3px solid #ffffff; 3926 | -webkit-border-radius: 23px; 3927 | -moz-border-radius: 23px; 3928 | border-radius: 23px; 3929 | opacity: 0.5; 3930 | filter: alpha(opacity=50); 3931 | } 3932 | .carousel-control.right { 3933 | left: auto; 3934 | right: 15px; 3935 | } 3936 | .carousel-control:hover { 3937 | color: #ffffff; 3938 | text-decoration: none; 3939 | opacity: 0.9; 3940 | filter: alpha(opacity=90); 3941 | } 3942 | .carousel-caption { 3943 | position: absolute; 3944 | left: 0; 3945 | right: 0; 3946 | bottom: 0; 3947 | padding: 10px 15px 5px; 3948 | background: #333333; 3949 | background: rgba(0, 0, 0, 0.75); 3950 | } 3951 | .carousel-caption h4, 3952 | .carousel-caption p { 3953 | color: #ffffff; 3954 | } 3955 | .hero-unit { 3956 | padding: 60px; 3957 | margin-bottom: 30px; 3958 | background-color: #eeeeee; 3959 | -webkit-border-radius: 6px; 3960 | -moz-border-radius: 6px; 3961 | border-radius: 6px; 3962 | } 3963 | .hero-unit h1 { 3964 | margin-bottom: 0; 3965 | font-size: 60px; 3966 | line-height: 1; 3967 | color: inherit; 3968 | letter-spacing: -1px; 3969 | } 3970 | .hero-unit p { 3971 | font-size: 18px; 3972 | font-weight: 200; 3973 | line-height: 27px; 3974 | color: inherit; 3975 | } 3976 | .pull-right { 3977 | float: right; 3978 | } 3979 | .pull-left { 3980 | float: left; 3981 | } 3982 | .hide { 3983 | display: none; 3984 | } 3985 | .show { 3986 | display: block; 3987 | } 3988 | .invisible { 3989 | visibility: hidden; 3990 | } 3991 | -------------------------------------------------------------------------------- /collections3/collections3.css: -------------------------------------------------------------------------------- 1 | img.angry_cat_pic { 2 | height: 100px; 3 | width: 100px; 4 | } 5 | 6 | #contents { 7 | width: 500px; 8 | margin-left: auto; 9 | margin-right: auto; 10 | } 11 | 12 | #angry_cats { 13 | margin-top: 30px; 14 | } 15 | 16 | #angry_cats th { 17 | font-size: 24px; 18 | } 19 | 20 | #angry_cats td, table#angry_cats th { 21 | padding: 12px; 22 | } 23 | 24 | #angry_cats td.rank div { 25 | display: block; 26 | text-align: center; 27 | } 28 | 29 | #angry_cats .rank_up img, .rank_down img { 30 | padding: 8px; 31 | padding-right: 24px; 32 | padding-left: 24px; 33 | margin: 2px; 34 | color: #fff; 35 | background-color: #000; 36 | border-radius: 8px; 37 | cursor: pointer; 38 | cursor: hand; 39 | } 40 | 41 | #angry_cats .rank_up img:hover, .rank_down img:hover { 42 | background-color: #ccc; 43 | } 44 | 45 | #angry_cats td.name { 46 | font-size: 20px; 47 | font-weight: bold; 48 | } 49 | 50 | #angry_cats .rank { 51 | font-size: 20px; 52 | font-weight: bold; 53 | } 54 | -------------------------------------------------------------------------------- /collections3/collections3.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | 3 | // AngryCat model 4 | window.AngryCat = Backbone.Model.extend({ 5 | defaults: { 6 | rank: 0, 7 | move: '' 8 | }, 9 | 10 | rank_up: function() { this.set('move', 'up') }, 11 | rank_down: function() { this.set('move', 'down') } 12 | }); 13 | 14 | // A Collection of AngryCats 15 | window.AngryCats = Backbone.Collection.extend({ 16 | model: AngryCat, 17 | 18 | initialize: function(cats) { 19 | _.each(cats, function(cat) { 20 | // This is the *same* line of code as is in set_rank. How do I call that here? 21 | cat.set('rank', _.max(cats, function(cat) { return cat.get('rank') }).get('rank') + 1); 22 | }); 23 | 24 | // If we are added via the 'add' method: 25 | this.on('add', this.set_rank); 26 | this.sort(); 27 | }, 28 | 29 | comparator: function(cat) { 30 | return cat.get('rank'); 31 | }, 32 | 33 | trade_rank: function(move_cat, direction) { 34 | var old_rank = move_cat.get('rank'); 35 | var new_rank = ''; 36 | (direction == 'up') ? new_rank = old_rank - 1 : new_rank = old_rank + 1; 37 | var push_cat = _.find(this.models, function(cat) { return cat.get('rank') == new_rank }); 38 | 39 | if (new_rank < 1 || new_rank > this.models.length) { 40 | return; 41 | } 42 | 43 | move_cat.set('rank', new_rank); 44 | push_cat.set('rank', old_rank); 45 | this.sort(); 46 | }, 47 | 48 | set_rank: function(cat) { 49 | cat.set('rank', _.max(this.models, function(cat) { return cat.get('rank') }).get('rank') + 1); 50 | } 51 | }); 52 | 53 | // The View for an Individual AngryCat 54 | window.AngryCatView = Backbone.View.extend({ 55 | 56 | // This is responsible for automatically updating the UI 57 | // in response to changes in the model 58 | initialize: function() { 59 | this.model.on('change', this.render, this); 60 | }, 61 | 62 | tagName: 'tr', 63 | 64 | className: 'angry_cat', 65 | 66 | render: function() { 67 | $(this.el).html(_.template($('#angry_cat-template').html(), { 68 | id: this.model.cid, 69 | rank: this.model.get('rank'), 70 | name: this.model.get('name'), 71 | image_path: this.model.get('image_path') 72 | })); 73 | return this; 74 | } 75 | }); 76 | 77 | // The Overall "App" View 78 | window.AngryCatsView = Backbone.View.extend({ 79 | 80 | el: $("div#contents"), 81 | 82 | events: { 83 | 'click img.rank_up': 'rank_up', 84 | 'click img.rank_down': 'rank_down' 85 | }, 86 | 87 | rank_up: function(event) { 88 | this.collection.trade_rank(this.find_move_cat(event, 'up'), 'up'); 89 | this.render(); 90 | }, 91 | 92 | rank_down: function(event) { 93 | this.collection.trade_rank(this.find_move_cat(event, 'down'), 'down'); 94 | this.render(); 95 | }, 96 | 97 | find_move_cat: function(event, direction) { 98 | var classes = $(event.currentTarget).attr('class').split(' '); 99 | var cid = _.find(classes, function(c) { return c != ('rank_' + direction) }); 100 | return this.collection.find(function(cat) { return cat.cid == cid }); 101 | }, 102 | 103 | // Show it! 104 | render: function() { 105 | var header = $("table#angry_cats tr.header").clone(); 106 | $("table#angry_cats > tbody:last").html('').append(header); 107 | 108 | this.collection.sort(); 109 | this.collection.each(function(cat) { 110 | var catView = new AngryCatView({model: cat}); 111 | $("table#angry_cats > tbody:last").append(catView.render().el); 112 | }); 113 | } 114 | }); 115 | }); -------------------------------------------------------------------------------- /collections3/images/cat1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/cat1.jpg -------------------------------------------------------------------------------- /collections3/images/cat2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/cat2.jpg -------------------------------------------------------------------------------- /collections3/images/cat3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/cat3.jpg -------------------------------------------------------------------------------- /collections3/images/cat4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/cat4.jpg -------------------------------------------------------------------------------- /collections3/images/down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/down.gif -------------------------------------------------------------------------------- /collections3/images/up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddellacosta/backbone.js-examples/c7d5d7f133e95fe42128fa9c7a900200acf17a36/collections3/images/up.gif -------------------------------------------------------------------------------- /collections3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BACKBONE Tutorial 3: Collections 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
RankNameImage
56 | 57 | 58 | 59 | 68 | 69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /events2/events2.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | 3 | // A simple Counting model 4 | var Counter = Backbone.Model.extend({ 5 | defaults: { 6 | count: 0 7 | }, 8 | 9 | increment: function() { this.set('count', this.get('count')+1) }, 10 | decrement: function() { this.set('count', this.get('count')-1) } 11 | }); 12 | 13 | // The View (and effectively Controller) which wraps up our Counter for the DOM 14 | var CounterView = Backbone.View.extend({ 15 | 16 | // This is responsible for automatically updating the UI 17 | // in response to changes in the model 18 | initialize: function() { 19 | this.model.on('change', this.render, this); 20 | }, 21 | 22 | // This connects events on DOM elements (WITHIN THE VIEW--IMPORTANT!) 23 | // to methods specified in this View. 24 | events: { 25 | "click #increment_button": 'increment', 26 | "click #decrement_button": 'decrement' 27 | }, 28 | 29 | // It would be nice if you could just pass model methods to the backbone events hash... 30 | increment: function() { this.model.increment() }, 31 | decrement: function() { this.model.decrement() }, 32 | 33 | // Show it! 34 | render: function() { 35 | $(this.el).html(_.template($('#count-template').html(), {count: this.model.get('count')})); 36 | return this; 37 | } 38 | }); 39 | 40 | var myCounter = new Counter(); 41 | var myCounterView = new CounterView({ model: myCounter, el: '#count_holder' }); 42 | myCounterView.render(); 43 | }); 44 | -------------------------------------------------------------------------------- /events2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BACKBONE Tutorial 2: Events 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /localstorage5/backbone-localstorage.js: -------------------------------------------------------------------------------- 1 | // A simple module to replace `Backbone.sync` with *localStorage*-based 2 | // persistence. Models are given GUIDS, and saved into a JSON object. Simple 3 | // as that. 4 | 5 | // Generate four random hex digits. 6 | function S4() { 7 | return (((1+Math.random())*0x10000)|0).toString(16).substring(1); 8 | }; 9 | 10 | // Generate a pseudo-GUID by concatenating random hexadecimal. 11 | function guid() { 12 | return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); 13 | }; 14 | 15 | // Our Store is represented by a single JS object in *localStorage*. Create it 16 | // with a meaningful name, like the name you'd give a table. 17 | var Store = function(name) { 18 | this.name = name; 19 | var store = localStorage.getItem(this.name); 20 | this.data = (store && JSON.parse(store)) || {}; 21 | }; 22 | 23 | _.extend(Store.prototype, { 24 | 25 | // Save the current state of the **Store** to *localStorage*. 26 | save: function() { 27 | localStorage.setItem(this.name, JSON.stringify(this.data)); 28 | }, 29 | 30 | // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already 31 | // have an id of it's own. 32 | create: function(model) { 33 | if (!model.id) model.id = model.attributes.id = guid(); 34 | this.data[model.id] = model; 35 | this.save(); 36 | return model; 37 | }, 38 | 39 | // Update a model by replacing its copy in `this.data`. 40 | update: function(model) { 41 | this.data[model.id] = model; 42 | this.save(); 43 | return model; 44 | }, 45 | 46 | // Retrieve a model from `this.data` by id. 47 | find: function(model) { 48 | return this.data[model.id]; 49 | }, 50 | 51 | // Return the array of all models currently in storage. 52 | findAll: function() { 53 | return _.values(this.data); 54 | }, 55 | 56 | // Delete a model from `this.data`, returning it. 57 | destroy: function(model) { 58 | delete this.data[model.id]; 59 | this.save(); 60 | return model; 61 | } 62 | 63 | }); 64 | 65 | // Override `Backbone.sync` to use delegate to the model or collection's 66 | // *localStorage* property, which should be an instance of `Store`. 67 | Backbone.sync = function(method, model, options) { 68 | 69 | var resp; 70 | var store = model.localStorage || model.collection.localStorage; 71 | 72 | switch (method) { 73 | case "read": resp = model.id ? store.find(model) : store.findAll(); break; 74 | case "create": resp = store.create(model); break; 75 | case "update": resp = store.update(model); break; 76 | case "delete": resp = store.destroy(model); break; 77 | } 78 | 79 | if (resp) { 80 | options.success(resp); 81 | } else { 82 | options.error("Record not found"); 83 | } 84 | }; -------------------------------------------------------------------------------- /localstorage5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BACKBONE Tutorial 5: Local Storage - Backbone.sync Pt. 1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 |
28 | 29 |

This example uses the backbone-localstorage.js module written for the Todos example.

30 | 31 |
32 | Description: , Link:
33 | 34 |
35 | 36 | 37 | 43 | 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /localstorage5/localstorage5.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 20px; 3 | } 4 | 5 | h4 { 6 | margin-bottom: 20px; 7 | } 8 | 9 | div#contents { 10 | margin-top: 20px; 11 | width: 900px; 12 | margin-right: auto; 13 | margin-left: auto; 14 | } 15 | 16 | div#links { 17 | width: 300px; 18 | } 19 | 20 | div.link { 21 | margin-top: 20px; 22 | } 23 | 24 | div.link button { 25 | display: block; 26 | float: right; 27 | } -------------------------------------------------------------------------------- /localstorage5/localstorage5.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | 3 | // Link Model 4 | window.Link = Backbone.Model.extend({ 5 | }); 6 | 7 | // Link Collection 8 | window.Links = Backbone.Collection.extend({ 9 | model: Link, // <-- this needs to be a function reference, not a string! 10 | 11 | localStorage: new Store("links") 12 | }); 13 | 14 | // An individual Link's View 15 | window.LinkView = Backbone.View.extend({ 16 | render: function() { 17 | return _.template($('#link-template').html(), { 18 | cid: this.model.cid, 19 | desc: this.model.get('desc'), 20 | url: this.model.get('url') 21 | }); 22 | } 23 | }); 24 | 25 | // Don't like this, seems like view and controller functionality is coupled too much. Smells! 26 | window.App = Backbone.View.extend({ 27 | el: '#app', 28 | 29 | initialize: function() { 30 | this.collection.fetch(); 31 | }, 32 | 33 | events: { 34 | "keypress input#link" : "save", 35 | "click button#delete" : "destroy" 36 | }, 37 | 38 | destroy: function(e) { 39 | // Collection Manipulation... 40 | var classes = e.currentTarget.className.split(/\s+/); 41 | var modelID = this.findModelID(classes); 42 | link = this.collection.getByCid(modelID); 43 | this.collection.localStorage.destroy(link); 44 | this.collection.remove(link); 45 | 46 | // Now reflect in the view. 47 | this.removeLink(modelID); 48 | }, 49 | 50 | // Stolen from official 'todos' example. 51 | save: function(e) { 52 | if (e.keyCode == 13) { 53 | // Collection Manipulation... 54 | var link = this.collection.create({ 55 | url: $("input#link").val(), 56 | desc: $("input#desc").val() 57 | }); 58 | 59 | // Clean 'em out 60 | $("input#desc").val(''); 61 | $("input#link").val('http://'); 62 | 63 | // Now reflect in the view. 64 | this.appendLink(link); 65 | } 66 | }, 67 | 68 | appendLink: function(link) { 69 | var linkView = new LinkView({ model: link }); 70 | $(this.el).find("div#links").append(linkView.render()); 71 | }, 72 | 73 | removeLink: function(linkID) { 74 | $('div#' + linkID).remove(); 75 | }, 76 | 77 | findModelID: function (classes) { 78 | return _.find(classes, function(className) { return className.match(/^c/); }); 79 | }, 80 | 81 | render: function() { 82 | this.collection.each(function(link) { this.appendLink(link) }, this); 83 | return this; 84 | } 85 | }); 86 | 87 | var linkApp = new App({ collection: new Links() }); 88 | linkApp.render(); 89 | }); 90 | -------------------------------------------------------------------------------- /remotestorage6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BACKBONE Tutorial 6: Remote Storage - Backbone.sync Pt. 2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 |
27 | 28 |

This example uses a very simple Sinatra app for the remote store. It assumes you have ruby installed. You'll need to start the Sinatra server up in a terminal before you get going, using:

29 | 30 | 31 | $ cd <the directory this file is in>
32 | $ ruby store.rb 33 |
34 | 35 |
36 | Description: , Link:
37 | 38 |
39 | 40 | 41 | 47 | 48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /remotestorage6/public/backbone.js: -------------------------------------------------------------------------------- 1 | // Backbone.js 0.9.2 2 | 3 | // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. 4 | // Backbone may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://backbonejs.org 7 | 8 | (function(){ 9 | 10 | // Initial Setup 11 | // ------------- 12 | 13 | // Save a reference to the global object (`window` in the browser, `global` 14 | // on the server). 15 | var root = this; 16 | 17 | // Save the previous value of the `Backbone` variable, so that it can be 18 | // restored later on, if `noConflict` is used. 19 | var previousBackbone = root.Backbone; 20 | 21 | // Create a local reference to slice/splice. 22 | var slice = Array.prototype.slice; 23 | var splice = Array.prototype.splice; 24 | 25 | // The top-level namespace. All public Backbone classes and modules will 26 | // be attached to this. Exported for both CommonJS and the browser. 27 | var Backbone; 28 | if (typeof exports !== 'undefined') { 29 | Backbone = exports; 30 | } else { 31 | Backbone = root.Backbone = {}; 32 | } 33 | 34 | // Current version of the library. Keep in sync with `package.json`. 35 | Backbone.VERSION = '0.9.2'; 36 | 37 | // Require Underscore, if we're on the server, and it's not already present. 38 | var _ = root._; 39 | if (!_ && (typeof require !== 'undefined')) _ = require('underscore'); 40 | 41 | // For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable. 42 | var $ = root.jQuery || root.Zepto || root.ender; 43 | 44 | // Set the JavaScript library that will be used for DOM manipulation and 45 | // Ajax calls (a.k.a. the `$` variable). By default Backbone will use: jQuery, 46 | // Zepto, or Ender; but the `setDomLibrary()` method lets you inject an 47 | // alternate JavaScript library (or a mock library for testing your views 48 | // outside of a browser). 49 | Backbone.setDomLibrary = function(lib) { 50 | $ = lib; 51 | }; 52 | 53 | // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable 54 | // to its previous owner. Returns a reference to this Backbone object. 55 | Backbone.noConflict = function() { 56 | root.Backbone = previousBackbone; 57 | return this; 58 | }; 59 | 60 | // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option 61 | // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and 62 | // set a `X-Http-Method-Override` header. 63 | Backbone.emulateHTTP = false; 64 | 65 | // Turn on `emulateJSON` to support legacy servers that can't deal with direct 66 | // `application/json` requests ... will encode the body as 67 | // `application/x-www-form-urlencoded` instead and will send the model in a 68 | // form param named `model`. 69 | Backbone.emulateJSON = false; 70 | 71 | // Backbone.Events 72 | // ----------------- 73 | 74 | // Regular expression used to split event strings 75 | var eventSplitter = /\s+/; 76 | 77 | // A module that can be mixed in to *any object* in order to provide it with 78 | // custom events. You may bind with `on` or remove with `off` callback functions 79 | // to an event; trigger`-ing an event fires all callbacks in succession. 80 | // 81 | // var object = {}; 82 | // _.extend(object, Backbone.Events); 83 | // object.on('expand', function(){ alert('expanded'); }); 84 | // object.trigger('expand'); 85 | // 86 | var Events = Backbone.Events = { 87 | 88 | // Bind one or more space separated events, `events`, to a `callback` 89 | // function. Passing `"all"` will bind the callback to all events fired. 90 | on: function(events, callback, context) { 91 | 92 | var calls, event, node, tail, list; 93 | if (!callback) return this; 94 | events = events.split(eventSplitter); 95 | calls = this._callbacks || (this._callbacks = {}); 96 | 97 | // Create an immutable callback list, allowing traversal during 98 | // modification. The tail is an empty object that will always be used 99 | // as the next node. 100 | while (event = events.shift()) { 101 | list = calls[event]; 102 | node = list ? list.tail : {}; 103 | node.next = tail = {}; 104 | node.context = context; 105 | node.callback = callback; 106 | calls[event] = {tail: tail, next: list ? list.next : node}; 107 | } 108 | 109 | return this; 110 | }, 111 | 112 | // Remove one or many callbacks. If `context` is null, removes all callbacks 113 | // with that function. If `callback` is null, removes all callbacks for the 114 | // event. If `events` is null, removes all bound callbacks for all events. 115 | off: function(events, callback, context) { 116 | var event, calls, node, tail, cb, ctx; 117 | 118 | // No events, or removing *all* events. 119 | if (!(calls = this._callbacks)) return this; 120 | if (!(events || callback || context)) { 121 | delete this._callbacks; 122 | return this; 123 | } 124 | 125 | // Loop through the listed events and contexts, splicing them out of the 126 | // linked list of callbacks if appropriate. 127 | events = events ? events.split(eventSplitter) : _.keys(calls); 128 | while (event = events.shift()) { 129 | node = calls[event]; 130 | delete calls[event]; 131 | if (!node || !(callback || context)) continue; 132 | // Create a new list, omitting the indicated callbacks. 133 | tail = node.tail; 134 | while ((node = node.next) !== tail) { 135 | cb = node.callback; 136 | ctx = node.context; 137 | if ((callback && cb !== callback) || (context && ctx !== context)) { 138 | this.on(event, cb, ctx); 139 | } 140 | } 141 | } 142 | 143 | return this; 144 | }, 145 | 146 | // Trigger one or many events, firing all bound callbacks. Callbacks are 147 | // passed the same arguments as `trigger` is, apart from the event name 148 | // (unless you're listening on `"all"`, which will cause your callback to 149 | // receive the true name of the event as the first argument). 150 | trigger: function(events) { 151 | var event, node, calls, tail, args, all, rest; 152 | if (!(calls = this._callbacks)) return this; 153 | all = calls.all; 154 | events = events.split(eventSplitter); 155 | rest = slice.call(arguments, 1); 156 | 157 | // For each event, walk through the linked list of callbacks twice, 158 | // first to trigger the event, then to trigger any `"all"` callbacks. 159 | while (event = events.shift()) { 160 | if (node = calls[event]) { 161 | tail = node.tail; 162 | while ((node = node.next) !== tail) { 163 | node.callback.apply(node.context || this, rest); 164 | } 165 | } 166 | if (node = all) { 167 | tail = node.tail; 168 | args = [event].concat(rest); 169 | while ((node = node.next) !== tail) { 170 | node.callback.apply(node.context || this, args); 171 | } 172 | } 173 | } 174 | 175 | return this; 176 | } 177 | 178 | }; 179 | 180 | // Aliases for backwards compatibility. 181 | Events.bind = Events.on; 182 | Events.unbind = Events.off; 183 | 184 | // Backbone.Model 185 | // -------------- 186 | 187 | // Create a new model, with defined attributes. A client id (`cid`) 188 | // is automatically generated and assigned for you. 189 | var Model = Backbone.Model = function(attributes, options) { 190 | var defaults; 191 | attributes || (attributes = {}); 192 | if (options && options.parse) attributes = this.parse(attributes); 193 | if (defaults = getValue(this, 'defaults')) { 194 | attributes = _.extend({}, defaults, attributes); 195 | } 196 | if (options && options.collection) this.collection = options.collection; 197 | this.attributes = {}; 198 | this._escapedAttributes = {}; 199 | this.cid = _.uniqueId('c'); 200 | this.changed = {}; 201 | this._silent = {}; 202 | this._pending = {}; 203 | this.set(attributes, {silent: true}); 204 | // Reset change tracking. 205 | this.changed = {}; 206 | this._silent = {}; 207 | this._pending = {}; 208 | this._previousAttributes = _.clone(this.attributes); 209 | this.initialize.apply(this, arguments); 210 | }; 211 | 212 | // Attach all inheritable methods to the Model prototype. 213 | _.extend(Model.prototype, Events, { 214 | 215 | // A hash of attributes whose current and previous value differ. 216 | changed: null, 217 | 218 | // A hash of attributes that have silently changed since the last time 219 | // `change` was called. Will become pending attributes on the next call. 220 | _silent: null, 221 | 222 | // A hash of attributes that have changed since the last `'change'` event 223 | // began. 224 | _pending: null, 225 | 226 | // The default name for the JSON `id` attribute is `"id"`. MongoDB and 227 | // CouchDB users may want to set this to `"_id"`. 228 | idAttribute: 'id', 229 | 230 | // Initialize is an empty function by default. Override it with your own 231 | // initialization logic. 232 | initialize: function(){}, 233 | 234 | // Return a copy of the model's `attributes` object. 235 | toJSON: function(options) { 236 | return _.clone(this.attributes); 237 | }, 238 | 239 | // Get the value of an attribute. 240 | get: function(attr) { 241 | return this.attributes[attr]; 242 | }, 243 | 244 | // Get the HTML-escaped value of an attribute. 245 | escape: function(attr) { 246 | var html; 247 | if (html = this._escapedAttributes[attr]) return html; 248 | var val = this.get(attr); 249 | return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val); 250 | }, 251 | 252 | // Returns `true` if the attribute contains a value that is not null 253 | // or undefined. 254 | has: function(attr) { 255 | return this.get(attr) != null; 256 | }, 257 | 258 | // Set a hash of model attributes on the object, firing `"change"` unless 259 | // you choose to silence it. 260 | set: function(key, value, options) { 261 | var attrs, attr, val; 262 | 263 | // Handle both `"key", value` and `{key: value}` -style arguments. 264 | if (_.isObject(key) || key == null) { 265 | attrs = key; 266 | options = value; 267 | } else { 268 | attrs = {}; 269 | attrs[key] = value; 270 | } 271 | 272 | // Extract attributes and options. 273 | options || (options = {}); 274 | if (!attrs) return this; 275 | if (attrs instanceof Model) attrs = attrs.attributes; 276 | if (options.unset) for (attr in attrs) attrs[attr] = void 0; 277 | 278 | // Run validation. 279 | if (!this._validate(attrs, options)) return false; 280 | 281 | // Check for changes of `id`. 282 | if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; 283 | 284 | var changes = options.changes = {}; 285 | var now = this.attributes; 286 | var escaped = this._escapedAttributes; 287 | var prev = this._previousAttributes || {}; 288 | 289 | // For each `set` attribute... 290 | for (attr in attrs) { 291 | val = attrs[attr]; 292 | 293 | // If the new and current value differ, record the change. 294 | if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) { 295 | delete escaped[attr]; 296 | (options.silent ? this._silent : changes)[attr] = true; 297 | } 298 | 299 | // Update or delete the current value. 300 | options.unset ? delete now[attr] : now[attr] = val; 301 | 302 | // If the new and previous value differ, record the change. If not, 303 | // then remove changes for this attribute. 304 | if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) { 305 | this.changed[attr] = val; 306 | if (!options.silent) this._pending[attr] = true; 307 | } else { 308 | delete this.changed[attr]; 309 | delete this._pending[attr]; 310 | } 311 | } 312 | 313 | // Fire the `"change"` events. 314 | if (!options.silent) this.change(options); 315 | return this; 316 | }, 317 | 318 | // Remove an attribute from the model, firing `"change"` unless you choose 319 | // to silence it. `unset` is a noop if the attribute doesn't exist. 320 | unset: function(attr, options) { 321 | (options || (options = {})).unset = true; 322 | return this.set(attr, null, options); 323 | }, 324 | 325 | // Clear all attributes on the model, firing `"change"` unless you choose 326 | // to silence it. 327 | clear: function(options) { 328 | (options || (options = {})).unset = true; 329 | return this.set(_.clone(this.attributes), options); 330 | }, 331 | 332 | // Fetch the model from the server. If the server's representation of the 333 | // model differs from its current attributes, they will be overriden, 334 | // triggering a `"change"` event. 335 | fetch: function(options) { 336 | options = options ? _.clone(options) : {}; 337 | var model = this; 338 | var success = options.success; 339 | options.success = function(resp, status, xhr) { 340 | if (!model.set(model.parse(resp, xhr), options)) return false; 341 | if (success) success(model, resp); 342 | }; 343 | options.error = Backbone.wrapError(options.error, model, options); 344 | return (this.sync || Backbone.sync).call(this, 'read', this, options); 345 | }, 346 | 347 | // Set a hash of model attributes, and sync the model to the server. 348 | // If the server returns an attributes hash that differs, the model's 349 | // state will be `set` again. 350 | save: function(key, value, options) { 351 | var attrs, current; 352 | 353 | // Handle both `("key", value)` and `({key: value})` -style calls. 354 | if (_.isObject(key) || key == null) { 355 | attrs = key; 356 | options = value; 357 | } else { 358 | attrs = {}; 359 | attrs[key] = value; 360 | } 361 | options = options ? _.clone(options) : {}; 362 | 363 | // If we're "wait"-ing to set changed attributes, validate early. 364 | if (options.wait) { 365 | if (!this._validate(attrs, options)) return false; 366 | current = _.clone(this.attributes); 367 | } 368 | 369 | // Regular saves `set` attributes before persisting to the server. 370 | var silentOptions = _.extend({}, options, {silent: true}); 371 | if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) { 372 | return false; 373 | } 374 | 375 | // After a successful server-side save, the client is (optionally) 376 | // updated with the server-side state. 377 | var model = this; 378 | var success = options.success; 379 | options.success = function(resp, status, xhr) { 380 | var serverAttrs = model.parse(resp, xhr); 381 | if (options.wait) { 382 | delete options.wait; 383 | serverAttrs = _.extend(attrs || {}, serverAttrs); 384 | } 385 | if (!model.set(serverAttrs, options)) return false; 386 | if (success) { 387 | success(model, resp); 388 | } else { 389 | model.trigger('sync', model, resp, options); 390 | } 391 | }; 392 | 393 | // Finish configuring and sending the Ajax request. 394 | options.error = Backbone.wrapError(options.error, model, options); 395 | var method = this.isNew() ? 'create' : 'update'; 396 | var xhr = (this.sync || Backbone.sync).call(this, method, this, options); 397 | if (options.wait) this.set(current, silentOptions); 398 | return xhr; 399 | }, 400 | 401 | // Destroy this model on the server if it was already persisted. 402 | // Optimistically removes the model from its collection, if it has one. 403 | // If `wait: true` is passed, waits for the server to respond before removal. 404 | destroy: function(options) { 405 | options = options ? _.clone(options) : {}; 406 | var model = this; 407 | var success = options.success; 408 | 409 | var triggerDestroy = function() { 410 | model.trigger('destroy', model, model.collection, options); 411 | }; 412 | 413 | if (this.isNew()) { 414 | 415 | console.log('why fail?'); 416 | 417 | triggerDestroy(); 418 | return false; 419 | } 420 | 421 | options.success = function(resp) { 422 | if (options.wait) triggerDestroy(); 423 | if (success) { 424 | success(model, resp); 425 | } else { 426 | model.trigger('sync', model, resp, options); 427 | } 428 | }; 429 | 430 | options.error = Backbone.wrapError(options.error, model, options); 431 | var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options); 432 | if (!options.wait) triggerDestroy(); 433 | return xhr; 434 | }, 435 | 436 | // Default URL for the model's representation on the server -- if you're 437 | // using Backbone's restful methods, override this to change the endpoint 438 | // that will be called. 439 | url: function() { 440 | var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError(); 441 | if (this.isNew()) return base; 442 | return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id); 443 | }, 444 | 445 | // **parse** converts a response into the hash of attributes to be `set` on 446 | // the model. The default implementation is just to pass the response along. 447 | parse: function(resp, xhr) { 448 | return resp; 449 | }, 450 | 451 | // Create a new model with identical attributes to this one. 452 | clone: function() { 453 | return new this.constructor(this.attributes); 454 | }, 455 | 456 | // A model is new if it has never been saved to the server, and lacks an id. 457 | isNew: function() { 458 | return this.id == null; 459 | }, 460 | 461 | // Call this method to manually fire a `"change"` event for this model and 462 | // a `"change:attribute"` event for each changed attribute. 463 | // Calling this will cause all objects observing the model to update. 464 | change: function(options) { 465 | options || (options = {}); 466 | var changing = this._changing; 467 | this._changing = true; 468 | 469 | // Silent changes become pending changes. 470 | for (var attr in this._silent) this._pending[attr] = true; 471 | 472 | // Silent changes are triggered. 473 | var changes = _.extend({}, options.changes, this._silent); 474 | this._silent = {}; 475 | for (var attr in changes) { 476 | this.trigger('change:' + attr, this, this.get(attr), options); 477 | } 478 | if (changing) return this; 479 | 480 | // Continue firing `"change"` events while there are pending changes. 481 | while (!_.isEmpty(this._pending)) { 482 | this._pending = {}; 483 | this.trigger('change', this, options); 484 | // Pending and silent changes still remain. 485 | for (var attr in this.changed) { 486 | if (this._pending[attr] || this._silent[attr]) continue; 487 | delete this.changed[attr]; 488 | } 489 | this._previousAttributes = _.clone(this.attributes); 490 | } 491 | 492 | this._changing = false; 493 | return this; 494 | }, 495 | 496 | // Determine if the model has changed since the last `"change"` event. 497 | // If you specify an attribute name, determine if that attribute has changed. 498 | hasChanged: function(attr) { 499 | if (!arguments.length) return !_.isEmpty(this.changed); 500 | return _.has(this.changed, attr); 501 | }, 502 | 503 | // Return an object containing all the attributes that have changed, or 504 | // false if there are no changed attributes. Useful for determining what 505 | // parts of a view need to be updated and/or what attributes need to be 506 | // persisted to the server. Unset attributes will be set to undefined. 507 | // You can also pass an attributes object to diff against the model, 508 | // determining if there *would be* a change. 509 | changedAttributes: function(diff) { 510 | if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; 511 | var val, changed = false, old = this._previousAttributes; 512 | for (var attr in diff) { 513 | if (_.isEqual(old[attr], (val = diff[attr]))) continue; 514 | (changed || (changed = {}))[attr] = val; 515 | } 516 | return changed; 517 | }, 518 | 519 | // Get the previous value of an attribute, recorded at the time the last 520 | // `"change"` event was fired. 521 | previous: function(attr) { 522 | if (!arguments.length || !this._previousAttributes) return null; 523 | return this._previousAttributes[attr]; 524 | }, 525 | 526 | // Get all of the attributes of the model at the time of the previous 527 | // `"change"` event. 528 | previousAttributes: function() { 529 | return _.clone(this._previousAttributes); 530 | }, 531 | 532 | // Check if the model is currently in a valid state. It's only possible to 533 | // get into an *invalid* state if you're using silent changes. 534 | isValid: function() { 535 | return !this.validate || !this.validate(this.attributes); 536 | }, 537 | 538 | // Run validation against the next complete set of model attributes, 539 | // returning `true` if all is well. If a specific `error` callback has 540 | // been passed, call that instead of firing the general `"error"` event. 541 | _validate: function(attrs, options) { 542 | if (options.silent || !this.validate) return true; 543 | attrs = _.extend({}, this.attributes, attrs); 544 | var error = this.validate(attrs, options); 545 | if (!error) return true; 546 | if (options && options.error) { 547 | options.error(this, error, options); 548 | } else { 549 | this.trigger('error', this, error, options); 550 | } 551 | return false; 552 | } 553 | 554 | }); 555 | 556 | // Backbone.Collection 557 | // ------------------- 558 | 559 | // Provides a standard collection class for our sets of models, ordered 560 | // or unordered. If a `comparator` is specified, the Collection will maintain 561 | // its models in sort order, as they're added and removed. 562 | var Collection = Backbone.Collection = function(models, options) { 563 | options || (options = {}); 564 | if (options.model) this.model = options.model; 565 | if (options.comparator) this.comparator = options.comparator; 566 | this._reset(); 567 | this.initialize.apply(this, arguments); 568 | if (models) this.reset(models, {silent: true, parse: options.parse}); 569 | }; 570 | 571 | // Define the Collection's inheritable methods. 572 | _.extend(Collection.prototype, Events, { 573 | 574 | // The default model for a collection is just a **Backbone.Model**. 575 | // This should be overridden in most cases. 576 | model: Model, 577 | 578 | // Initialize is an empty function by default. Override it with your own 579 | // initialization logic. 580 | initialize: function(){}, 581 | 582 | // The JSON representation of a Collection is an array of the 583 | // models' attributes. 584 | toJSON: function(options) { 585 | return this.map(function(model){ return model.toJSON(options); }); 586 | }, 587 | 588 | // Add a model, or list of models to the set. Pass **silent** to avoid 589 | // firing the `add` event for every new model. 590 | add: function(models, options) { 591 | var i, index, length, model, cid, id, cids = {}, ids = {}, dups = []; 592 | options || (options = {}); 593 | models = _.isArray(models) ? models.slice() : [models]; 594 | 595 | // Begin by turning bare objects into model references, and preventing 596 | // invalid models or duplicate models from being added. 597 | for (i = 0, length = models.length; i < length; i++) { 598 | if (!(model = models[i] = this._prepareModel(models[i], options))) { 599 | throw new Error("Can't add an invalid model to a collection"); 600 | } 601 | cid = model.cid; 602 | id = model.id; 603 | if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) { 604 | dups.push(i); 605 | continue; 606 | } 607 | cids[cid] = ids[id] = model; 608 | } 609 | 610 | // Remove duplicates. 611 | i = dups.length; 612 | while (i--) { 613 | models.splice(dups[i], 1); 614 | } 615 | 616 | // Listen to added models' events, and index models for lookup by 617 | // `id` and by `cid`. 618 | for (i = 0, length = models.length; i < length; i++) { 619 | (model = models[i]).on('all', this._onModelEvent, this); 620 | this._byCid[model.cid] = model; 621 | if (model.id != null) this._byId[model.id] = model; 622 | } 623 | 624 | // Insert models into the collection, re-sorting if needed, and triggering 625 | // `add` events unless silenced. 626 | this.length += length; 627 | index = options.at != null ? options.at : this.models.length; 628 | splice.apply(this.models, [index, 0].concat(models)); 629 | if (this.comparator && options.at == null) this.sort({silent: true}); 630 | if (options.silent) return this; 631 | for (i = 0, length = this.models.length; i < length; i++) { 632 | if (!cids[(model = this.models[i]).cid]) continue; 633 | options.index = i; 634 | model.trigger('add', model, this, options); 635 | } 636 | return this; 637 | }, 638 | 639 | // Remove a model, or a list of models from the set. Pass silent to avoid 640 | // firing the `remove` event for every model removed. 641 | remove: function(models, options) { 642 | var i, l, index, model; 643 | options || (options = {}); 644 | models = _.isArray(models) ? models.slice() : [models]; 645 | for (i = 0, l = models.length; i < l; i++) { 646 | model = this.getByCid(models[i]) || this.get(models[i]); 647 | if (!model) continue; 648 | delete this._byId[model.id]; 649 | delete this._byCid[model.cid]; 650 | index = this.indexOf(model); 651 | this.models.splice(index, 1); 652 | this.length--; 653 | if (!options.silent) { 654 | options.index = index; 655 | model.trigger('remove', model, this, options); 656 | } 657 | this._removeReference(model); 658 | } 659 | return this; 660 | }, 661 | 662 | // Add a model to the end of the collection. 663 | push: function(model, options) { 664 | model = this._prepareModel(model, options); 665 | this.add(model, options); 666 | return model; 667 | }, 668 | 669 | // Remove a model from the end of the collection. 670 | pop: function(options) { 671 | var model = this.at(this.length - 1); 672 | this.remove(model, options); 673 | return model; 674 | }, 675 | 676 | // Add a model to the beginning of the collection. 677 | unshift: function(model, options) { 678 | model = this._prepareModel(model, options); 679 | this.add(model, _.extend({at: 0}, options)); 680 | return model; 681 | }, 682 | 683 | // Remove a model from the beginning of the collection. 684 | shift: function(options) { 685 | var model = this.at(0); 686 | this.remove(model, options); 687 | return model; 688 | }, 689 | 690 | // Get a model from the set by id. 691 | get: function(id) { 692 | if (id == null) return void 0; 693 | return this._byId[id.id != null ? id.id : id]; 694 | }, 695 | 696 | // Get a model from the set by client id. 697 | getByCid: function(cid) { 698 | return cid && this._byCid[cid.cid || cid]; 699 | }, 700 | 701 | // Get the model at the given index. 702 | at: function(index) { 703 | return this.models[index]; 704 | }, 705 | 706 | // Return models with matching attributes. Useful for simple cases of `filter`. 707 | where: function(attrs) { 708 | if (_.isEmpty(attrs)) return []; 709 | return this.filter(function(model) { 710 | for (var key in attrs) { 711 | if (attrs[key] !== model.get(key)) return false; 712 | } 713 | return true; 714 | }); 715 | }, 716 | 717 | // Force the collection to re-sort itself. You don't need to call this under 718 | // normal circumstances, as the set will maintain sort order as each item 719 | // is added. 720 | sort: function(options) { 721 | options || (options = {}); 722 | if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); 723 | var boundComparator = _.bind(this.comparator, this); 724 | if (this.comparator.length == 1) { 725 | this.models = this.sortBy(boundComparator); 726 | } else { 727 | this.models.sort(boundComparator); 728 | } 729 | if (!options.silent) this.trigger('reset', this, options); 730 | return this; 731 | }, 732 | 733 | // Pluck an attribute from each model in the collection. 734 | pluck: function(attr) { 735 | return _.map(this.models, function(model){ return model.get(attr); }); 736 | }, 737 | 738 | // When you have more items than you want to add or remove individually, 739 | // you can reset the entire set with a new list of models, without firing 740 | // any `add` or `remove` events. Fires `reset` when finished. 741 | reset: function(models, options) { 742 | models || (models = []); 743 | options || (options = {}); 744 | for (var i = 0, l = this.models.length; i < l; i++) { 745 | this._removeReference(this.models[i]); 746 | } 747 | this._reset(); 748 | this.add(models, _.extend({silent: true}, options)); 749 | if (!options.silent) this.trigger('reset', this, options); 750 | return this; 751 | }, 752 | 753 | // Fetch the default set of models for this collection, resetting the 754 | // collection when they arrive. If `add: true` is passed, appends the 755 | // models to the collection instead of resetting. 756 | fetch: function(options) { 757 | options = options ? _.clone(options) : {}; 758 | if (options.parse === undefined) options.parse = true; 759 | var collection = this; 760 | var success = options.success; 761 | options.success = function(resp, status, xhr) { 762 | collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options); 763 | if (success) success(collection, resp); 764 | }; 765 | options.error = Backbone.wrapError(options.error, collection, options); 766 | return (this.sync || Backbone.sync).call(this, 'read', this, options); 767 | }, 768 | 769 | // Create a new instance of a model in this collection. Add the model to the 770 | // collection immediately, unless `wait: true` is passed, in which case we 771 | // wait for the server to agree. 772 | create: function(model, options) { 773 | var coll = this; 774 | options = options ? _.clone(options) : {}; 775 | model = this._prepareModel(model, options); 776 | if (!model) return false; 777 | if (!options.wait) coll.add(model, options); 778 | var success = options.success; 779 | options.success = function(nextModel, resp, xhr) { 780 | if (options.wait) coll.add(nextModel, options); 781 | if (success) { 782 | success(nextModel, resp); 783 | } else { 784 | nextModel.trigger('sync', model, resp, options); 785 | } 786 | }; 787 | model.save(null, options); 788 | return model; 789 | }, 790 | 791 | // **parse** converts a response into a list of models to be added to the 792 | // collection. The default implementation is just to pass it through. 793 | parse: function(resp, xhr) { 794 | return resp; 795 | }, 796 | 797 | // Proxy to _'s chain. Can't be proxied the same way the rest of the 798 | // underscore methods are proxied because it relies on the underscore 799 | // constructor. 800 | chain: function () { 801 | return _(this.models).chain(); 802 | }, 803 | 804 | // Reset all internal state. Called when the collection is reset. 805 | _reset: function(options) { 806 | this.length = 0; 807 | this.models = []; 808 | this._byId = {}; 809 | this._byCid = {}; 810 | }, 811 | 812 | // Prepare a model or hash of attributes to be added to this collection. 813 | _prepareModel: function(model, options) { 814 | options || (options = {}); 815 | if (!(model instanceof Model)) { 816 | var attrs = model; 817 | options.collection = this; 818 | model = new this.model(attrs, options); 819 | if (!model._validate(model.attributes, options)) model = false; 820 | } else if (!model.collection) { 821 | model.collection = this; 822 | } 823 | return model; 824 | }, 825 | 826 | // Internal method to remove a model's ties to a collection. 827 | _removeReference: function(model) { 828 | if (this == model.collection) { 829 | delete model.collection; 830 | } 831 | model.off('all', this._onModelEvent, this); 832 | }, 833 | 834 | // Internal method called every time a model in the set fires an event. 835 | // Sets need to update their indexes when models change ids. All other 836 | // events simply proxy through. "add" and "remove" events that originate 837 | // in other collections are ignored. 838 | _onModelEvent: function(event, model, collection, options) { 839 | if ((event == 'add' || event == 'remove') && collection != this) return; 840 | if (event == 'destroy') { 841 | this.remove(model, options); 842 | } 843 | if (model && event === 'change:' + model.idAttribute) { 844 | delete this._byId[model.previous(model.idAttribute)]; 845 | this._byId[model.id] = model; 846 | } 847 | this.trigger.apply(this, arguments); 848 | } 849 | 850 | }); 851 | 852 | // Underscore methods that we want to implement on the Collection. 853 | var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find', 854 | 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 855 | 'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex', 856 | 'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf', 857 | 'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy']; 858 | 859 | // Mix in each Underscore method as a proxy to `Collection#models`. 860 | _.each(methods, function(method) { 861 | Collection.prototype[method] = function() { 862 | return _[method].apply(_, [this.models].concat(_.toArray(arguments))); 863 | }; 864 | }); 865 | 866 | // Backbone.Router 867 | // ------------------- 868 | 869 | // Routers map faux-URLs to actions, and fire events when routes are 870 | // matched. Creating a new one sets its `routes` hash, if not set statically. 871 | var Router = Backbone.Router = function(options) { 872 | options || (options = {}); 873 | if (options.routes) this.routes = options.routes; 874 | this._bindRoutes(); 875 | this.initialize.apply(this, arguments); 876 | }; 877 | 878 | // Cached regular expressions for matching named param parts and splatted 879 | // parts of route strings. 880 | var namedParam = /:\w+/g; 881 | var splatParam = /\*\w+/g; 882 | var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g; 883 | 884 | // Set up all inheritable **Backbone.Router** properties and methods. 885 | _.extend(Router.prototype, Events, { 886 | 887 | // Initialize is an empty function by default. Override it with your own 888 | // initialization logic. 889 | initialize: function(){}, 890 | 891 | // Manually bind a single named route to a callback. For example: 892 | // 893 | // this.route('search/:query/p:num', 'search', function(query, num) { 894 | // ... 895 | // }); 896 | // 897 | route: function(route, name, callback) { 898 | Backbone.history || (Backbone.history = new History); 899 | if (!_.isRegExp(route)) route = this._routeToRegExp(route); 900 | if (!callback) callback = this[name]; 901 | Backbone.history.route(route, _.bind(function(fragment) { 902 | var args = this._extractParameters(route, fragment); 903 | callback && callback.apply(this, args); 904 | this.trigger.apply(this, ['route:' + name].concat(args)); 905 | Backbone.history.trigger('route', this, name, args); 906 | }, this)); 907 | return this; 908 | }, 909 | 910 | // Simple proxy to `Backbone.history` to save a fragment into the history. 911 | navigate: function(fragment, options) { 912 | Backbone.history.navigate(fragment, options); 913 | }, 914 | 915 | // Bind all defined routes to `Backbone.history`. We have to reverse the 916 | // order of the routes here to support behavior where the most general 917 | // routes can be defined at the bottom of the route map. 918 | _bindRoutes: function() { 919 | if (!this.routes) return; 920 | var routes = []; 921 | for (var route in this.routes) { 922 | routes.unshift([route, this.routes[route]]); 923 | } 924 | for (var i = 0, l = routes.length; i < l; i++) { 925 | this.route(routes[i][0], routes[i][1], this[routes[i][1]]); 926 | } 927 | }, 928 | 929 | // Convert a route string into a regular expression, suitable for matching 930 | // against the current location hash. 931 | _routeToRegExp: function(route) { 932 | route = route.replace(escapeRegExp, '\\$&') 933 | .replace(namedParam, '([^\/]+)') 934 | .replace(splatParam, '(.*?)'); 935 | return new RegExp('^' + route + '$'); 936 | }, 937 | 938 | // Given a route, and a URL fragment that it matches, return the array of 939 | // extracted parameters. 940 | _extractParameters: function(route, fragment) { 941 | return route.exec(fragment).slice(1); 942 | } 943 | 944 | }); 945 | 946 | // Backbone.History 947 | // ---------------- 948 | 949 | // Handles cross-browser history management, based on URL fragments. If the 950 | // browser does not support `onhashchange`, falls back to polling. 951 | var History = Backbone.History = function() { 952 | this.handlers = []; 953 | _.bindAll(this, 'checkUrl'); 954 | }; 955 | 956 | // Cached regex for cleaning leading hashes and slashes . 957 | var routeStripper = /^[#\/]/; 958 | 959 | // Cached regex for detecting MSIE. 960 | var isExplorer = /msie [\w.]+/; 961 | 962 | // Has the history handling already been started? 963 | History.started = false; 964 | 965 | // Set up all inheritable **Backbone.History** properties and methods. 966 | _.extend(History.prototype, Events, { 967 | 968 | // The default interval to poll for hash changes, if necessary, is 969 | // twenty times a second. 970 | interval: 50, 971 | 972 | // Gets the true hash value. Cannot use location.hash directly due to bug 973 | // in Firefox where location.hash will always be decoded. 974 | getHash: function(windowOverride) { 975 | var loc = windowOverride ? windowOverride.location : window.location; 976 | var match = loc.href.match(/#(.*)$/); 977 | return match ? match[1] : ''; 978 | }, 979 | 980 | // Get the cross-browser normalized URL fragment, either from the URL, 981 | // the hash, or the override. 982 | getFragment: function(fragment, forcePushState) { 983 | if (fragment == null) { 984 | if (this._hasPushState || forcePushState) { 985 | fragment = window.location.pathname; 986 | var search = window.location.search; 987 | if (search) fragment += search; 988 | } else { 989 | fragment = this.getHash(); 990 | } 991 | } 992 | if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length); 993 | return fragment.replace(routeStripper, ''); 994 | }, 995 | 996 | // Start the hash change handling, returning `true` if the current URL matches 997 | // an existing route, and `false` otherwise. 998 | start: function(options) { 999 | if (History.started) throw new Error("Backbone.history has already been started"); 1000 | History.started = true; 1001 | 1002 | // Figure out the initial configuration. Do we need an iframe? 1003 | // Is pushState desired ... is it available? 1004 | this.options = _.extend({}, {root: '/'}, this.options, options); 1005 | this._wantsHashChange = this.options.hashChange !== false; 1006 | this._wantsPushState = !!this.options.pushState; 1007 | this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState); 1008 | var fragment = this.getFragment(); 1009 | var docMode = document.documentMode; 1010 | var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); 1011 | 1012 | if (oldIE) { 1013 | this.iframe = $('