├── .gitignore ├── LICENSE.txt ├── ajax.php ├── bootstrap ├── css │ ├── bootstrap-responsive.css │ ├── bootstrap-responsive.min.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png └── js │ ├── bootstrap.js │ └── bootstrap.min.js ├── grid.css ├── grid.js ├── grid.php ├── grid.styl ├── index.html ├── jquery.js ├── lib └── nib │ ├── border.styl │ ├── box.styl │ ├── clearfix.styl │ ├── color-image.styl │ ├── config.styl │ ├── gradients.styl │ ├── iconic.styl │ ├── index.styl │ ├── overflow.styl │ ├── positions.styl │ ├── reset.styl │ ├── text │ ├── aliases.styl │ ├── ellipsis.styl │ ├── hide-text.styl │ ├── index.styl │ └── replace-text.styl │ └── vendor.styl ├── masterdetail.html ├── readme.md ├── root.js ├── sample.sql └── world-ajax.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Sean Clark Square Bracket LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ajax.php: -------------------------------------------------------------------------------- 1 | true, 12 | "delete"=>true, 13 | "where"=>"ThumbnailLocation != ''", 14 | "joins"=>array( 15 | "LEFT JOIN categories ON categories.CategoryID = tutorials.CategoryID" 16 | ), 17 | "fields"=>array( 18 | "thumb" => "CONCAT('http://cmivfx.com/images/thumbs/',ThumbnailLocation)" 19 | ), 20 | "select" => 'selectFunction' 21 | )); 22 | 23 | // drop down function 24 | // if you have anonymous function support, then you can just put this function in place of 25 | // 'selectFunction' 26 | function selectFunction($grid) { 27 | $selects = array(); 28 | 29 | // category select 30 | $grid->table = "categories"; 31 | $selects["CategoryID"] = $grid->makeSelect("CategoryID","Name"); 32 | 33 | // active select 34 | $selects["active"] = array("1"=>"true","0"=>"false"); 35 | 36 | // render data 37 | $grid->render($selects); 38 | } 39 | 40 | 41 | ?> -------------------------------------------------------------------------------- /bootstrap/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive 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 | .clearfix { 11 | *zoom: 1; 12 | } 13 | .clearfix:before, 14 | .clearfix:after { 15 | display: table; 16 | content: ""; 17 | } 18 | .clearfix:after { 19 | clear: both; 20 | } 21 | .hide-text { 22 | overflow: hidden; 23 | text-indent: 100%; 24 | white-space: nowrap; 25 | } 26 | .input-block-level { 27 | display: block; 28 | width: 100%; 29 | min-height: 28px; 30 | /* Make inputs at least the height of their button counterpart */ 31 | 32 | /* Makes inputs behave like true block-level elements */ 33 | 34 | -webkit-box-sizing: border-box; 35 | -moz-box-sizing: border-box; 36 | -ms-box-sizing: border-box; 37 | box-sizing: border-box; 38 | } 39 | .hidden { 40 | display: none; 41 | visibility: hidden; 42 | } 43 | .visible-phone { 44 | display: none; 45 | } 46 | .visible-tablet { 47 | display: none; 48 | } 49 | .visible-desktop { 50 | display: block; 51 | } 52 | .hidden-phone { 53 | display: block; 54 | } 55 | .hidden-tablet { 56 | display: block; 57 | } 58 | .hidden-desktop { 59 | display: none; 60 | } 61 | @media (max-width: 767px) { 62 | .visible-phone { 63 | display: block; 64 | } 65 | .hidden-phone { 66 | display: none; 67 | } 68 | .hidden-desktop { 69 | display: block; 70 | } 71 | .visible-desktop { 72 | display: none; 73 | } 74 | } 75 | @media (min-width: 768px) and (max-width: 979px) { 76 | .visible-tablet { 77 | display: block; 78 | } 79 | .hidden-tablet { 80 | display: none; 81 | } 82 | .hidden-desktop { 83 | display: block; 84 | } 85 | .visible-desktop { 86 | display: none; 87 | } 88 | } 89 | @media (max-width: 480px) { 90 | .nav-collapse { 91 | -webkit-transform: translate3d(0, 0, 0); 92 | } 93 | .page-header h1 small { 94 | display: block; 95 | line-height: 18px; 96 | } 97 | input[type="checkbox"], 98 | input[type="radio"] { 99 | border: 1px solid #ccc; 100 | } 101 | .form-horizontal .control-group > label { 102 | float: none; 103 | width: auto; 104 | padding-top: 0; 105 | text-align: left; 106 | } 107 | .form-horizontal .controls { 108 | margin-left: 0; 109 | } 110 | .form-horizontal .control-list { 111 | padding-top: 0; 112 | } 113 | .form-horizontal .form-actions { 114 | padding-left: 10px; 115 | padding-right: 10px; 116 | } 117 | .modal { 118 | position: absolute; 119 | top: 10px; 120 | left: 10px; 121 | right: 10px; 122 | width: auto; 123 | margin: 0; 124 | } 125 | .modal.fade.in { 126 | top: auto; 127 | } 128 | .modal-header .close { 129 | padding: 10px; 130 | margin: -10px; 131 | } 132 | .carousel-caption { 133 | position: static; 134 | } 135 | } 136 | @media (max-width: 767px) { 137 | body { 138 | padding-left: 20px; 139 | padding-right: 20px; 140 | } 141 | .navbar-fixed-top { 142 | margin-left: -20px; 143 | margin-right: -20px; 144 | } 145 | .container { 146 | width: auto; 147 | } 148 | .row-fluid { 149 | width: 100%; 150 | } 151 | .row { 152 | margin-left: 0; 153 | } 154 | .row > [class*="span"], 155 | .row-fluid > [class*="span"] { 156 | float: none; 157 | display: block; 158 | width: auto; 159 | margin: 0; 160 | } 161 | .thumbnails [class*="span"] { 162 | width: auto; 163 | } 164 | input[class*="span"], 165 | select[class*="span"], 166 | textarea[class*="span"], 167 | .uneditable-input { 168 | display: block; 169 | width: 100%; 170 | min-height: 28px; 171 | /* Make inputs at least the height of their button counterpart */ 172 | 173 | /* Makes inputs behave like true block-level elements */ 174 | 175 | -webkit-box-sizing: border-box; 176 | -moz-box-sizing: border-box; 177 | -ms-box-sizing: border-box; 178 | box-sizing: border-box; 179 | } 180 | .input-prepend input[class*="span"], 181 | .input-append input[class*="span"] { 182 | width: auto; 183 | } 184 | } 185 | @media (min-width: 768px) and (max-width: 979px) { 186 | .row { 187 | margin-left: -20px; 188 | *zoom: 1; 189 | } 190 | .row:before, 191 | .row:after { 192 | display: table; 193 | content: ""; 194 | } 195 | .row:after { 196 | clear: both; 197 | } 198 | [class*="span"] { 199 | float: left; 200 | margin-left: 20px; 201 | } 202 | .container, 203 | .navbar-fixed-top .container, 204 | .navbar-fixed-bottom .container { 205 | width: 724px; 206 | } 207 | .span12 { 208 | width: 724px; 209 | } 210 | .span11 { 211 | width: 662px; 212 | } 213 | .span10 { 214 | width: 600px; 215 | } 216 | .span9 { 217 | width: 538px; 218 | } 219 | .span8 { 220 | width: 476px; 221 | } 222 | .span7 { 223 | width: 414px; 224 | } 225 | .span6 { 226 | width: 352px; 227 | } 228 | .span5 { 229 | width: 290px; 230 | } 231 | .span4 { 232 | width: 228px; 233 | } 234 | .span3 { 235 | width: 166px; 236 | } 237 | .span2 { 238 | width: 104px; 239 | } 240 | .span1 { 241 | width: 42px; 242 | } 243 | .offset12 { 244 | margin-left: 764px; 245 | } 246 | .offset11 { 247 | margin-left: 702px; 248 | } 249 | .offset10 { 250 | margin-left: 640px; 251 | } 252 | .offset9 { 253 | margin-left: 578px; 254 | } 255 | .offset8 { 256 | margin-left: 516px; 257 | } 258 | .offset7 { 259 | margin-left: 454px; 260 | } 261 | .offset6 { 262 | margin-left: 392px; 263 | } 264 | .offset5 { 265 | margin-left: 330px; 266 | } 267 | .offset4 { 268 | margin-left: 268px; 269 | } 270 | .offset3 { 271 | margin-left: 206px; 272 | } 273 | .offset2 { 274 | margin-left: 144px; 275 | } 276 | .offset1 { 277 | margin-left: 82px; 278 | } 279 | .row-fluid { 280 | width: 100%; 281 | *zoom: 1; 282 | } 283 | .row-fluid:before, 284 | .row-fluid:after { 285 | display: table; 286 | content: ""; 287 | } 288 | .row-fluid:after { 289 | clear: both; 290 | } 291 | .row-fluid > [class*="span"] { 292 | float: left; 293 | margin-left: 2.762430939%; 294 | } 295 | .row-fluid > [class*="span"]:first-child { 296 | margin-left: 0; 297 | } 298 | .row-fluid > .span12 { 299 | width: 99.999999993%; 300 | } 301 | .row-fluid > .span11 { 302 | width: 91.436464082%; 303 | } 304 | .row-fluid > .span10 { 305 | width: 82.87292817100001%; 306 | } 307 | .row-fluid > .span9 { 308 | width: 74.30939226%; 309 | } 310 | .row-fluid > .span8 { 311 | width: 65.74585634900001%; 312 | } 313 | .row-fluid > .span7 { 314 | width: 57.182320438000005%; 315 | } 316 | .row-fluid > .span6 { 317 | width: 48.618784527%; 318 | } 319 | .row-fluid > .span5 { 320 | width: 40.055248616%; 321 | } 322 | .row-fluid > .span4 { 323 | width: 31.491712705%; 324 | } 325 | .row-fluid > .span3 { 326 | width: 22.928176794%; 327 | } 328 | .row-fluid > .span2 { 329 | width: 14.364640883%; 330 | } 331 | .row-fluid > .span1 { 332 | width: 5.801104972%; 333 | } 334 | input, 335 | textarea, 336 | .uneditable-input { 337 | margin-left: 0; 338 | } 339 | input.span12, textarea.span12, .uneditable-input.span12 { 340 | width: 714px; 341 | } 342 | input.span11, textarea.span11, .uneditable-input.span11 { 343 | width: 652px; 344 | } 345 | input.span10, textarea.span10, .uneditable-input.span10 { 346 | width: 590px; 347 | } 348 | input.span9, textarea.span9, .uneditable-input.span9 { 349 | width: 528px; 350 | } 351 | input.span8, textarea.span8, .uneditable-input.span8 { 352 | width: 466px; 353 | } 354 | input.span7, textarea.span7, .uneditable-input.span7 { 355 | width: 404px; 356 | } 357 | input.span6, textarea.span6, .uneditable-input.span6 { 358 | width: 342px; 359 | } 360 | input.span5, textarea.span5, .uneditable-input.span5 { 361 | width: 280px; 362 | } 363 | input.span4, textarea.span4, .uneditable-input.span4 { 364 | width: 218px; 365 | } 366 | input.span3, textarea.span3, .uneditable-input.span3 { 367 | width: 156px; 368 | } 369 | input.span2, textarea.span2, .uneditable-input.span2 { 370 | width: 94px; 371 | } 372 | input.span1, textarea.span1, .uneditable-input.span1 { 373 | width: 32px; 374 | } 375 | } 376 | @media (max-width: 979px) { 377 | body { 378 | padding-top: 0; 379 | } 380 | .navbar-fixed-top { 381 | position: static; 382 | margin-bottom: 18px; 383 | } 384 | .navbar-fixed-top .navbar-inner { 385 | padding: 5px; 386 | } 387 | .navbar .container { 388 | width: auto; 389 | padding: 0; 390 | } 391 | .navbar .brand { 392 | padding-left: 10px; 393 | padding-right: 10px; 394 | margin: 0 0 0 -5px; 395 | } 396 | .navbar .nav-collapse { 397 | clear: left; 398 | } 399 | .navbar .nav { 400 | float: none; 401 | margin: 0 0 9px; 402 | } 403 | .navbar .nav > li { 404 | float: none; 405 | } 406 | .navbar .nav > li > a { 407 | margin-bottom: 2px; 408 | } 409 | .navbar .nav > .divider-vertical { 410 | display: none; 411 | } 412 | .navbar .nav .nav-header { 413 | color: #999999; 414 | text-shadow: none; 415 | } 416 | .navbar .nav > li > a, 417 | .navbar .dropdown-menu a { 418 | padding: 6px 15px; 419 | font-weight: bold; 420 | color: #999999; 421 | -webkit-border-radius: 3px; 422 | -moz-border-radius: 3px; 423 | border-radius: 3px; 424 | } 425 | .navbar .dropdown-menu li + li a { 426 | margin-bottom: 2px; 427 | } 428 | .navbar .nav > li > a:hover, 429 | .navbar .dropdown-menu a:hover { 430 | background-color: #222222; 431 | } 432 | .navbar .dropdown-menu { 433 | position: static; 434 | top: auto; 435 | left: auto; 436 | float: none; 437 | display: block; 438 | max-width: none; 439 | margin: 0 15px; 440 | padding: 0; 441 | background-color: transparent; 442 | border: none; 443 | -webkit-border-radius: 0; 444 | -moz-border-radius: 0; 445 | border-radius: 0; 446 | -webkit-box-shadow: none; 447 | -moz-box-shadow: none; 448 | box-shadow: none; 449 | } 450 | .navbar .dropdown-menu:before, 451 | .navbar .dropdown-menu:after { 452 | display: none; 453 | } 454 | .navbar .dropdown-menu .divider { 455 | display: none; 456 | } 457 | .navbar-form, 458 | .navbar-search { 459 | float: none; 460 | padding: 9px 15px; 461 | margin: 9px 0; 462 | border-top: 1px solid #222222; 463 | border-bottom: 1px solid #222222; 464 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 465 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 466 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 467 | } 468 | .navbar .nav.pull-right { 469 | float: none; 470 | margin-left: 0; 471 | } 472 | .navbar-static .navbar-inner { 473 | padding-left: 10px; 474 | padding-right: 10px; 475 | } 476 | .btn-navbar { 477 | display: block; 478 | } 479 | .nav-collapse { 480 | overflow: hidden; 481 | height: 0; 482 | } 483 | } 484 | @media (min-width: 980px) { 485 | .nav-collapse.collapse { 486 | height: auto !important; 487 | overflow: visible !important; 488 | } 489 | } 490 | @media (min-width: 1200px) { 491 | .row { 492 | margin-left: -30px; 493 | *zoom: 1; 494 | } 495 | .row:before, 496 | .row:after { 497 | display: table; 498 | content: ""; 499 | } 500 | .row:after { 501 | clear: both; 502 | } 503 | [class*="span"] { 504 | float: left; 505 | margin-left: 30px; 506 | } 507 | .container, 508 | .navbar-fixed-top .container, 509 | .navbar-fixed-bottom .container { 510 | width: 1170px; 511 | } 512 | .span12 { 513 | width: 1170px; 514 | } 515 | .span11 { 516 | width: 1070px; 517 | } 518 | .span10 { 519 | width: 970px; 520 | } 521 | .span9 { 522 | width: 870px; 523 | } 524 | .span8 { 525 | width: 770px; 526 | } 527 | .span7 { 528 | width: 670px; 529 | } 530 | .span6 { 531 | width: 570px; 532 | } 533 | .span5 { 534 | width: 470px; 535 | } 536 | .span4 { 537 | width: 370px; 538 | } 539 | .span3 { 540 | width: 270px; 541 | } 542 | .span2 { 543 | width: 170px; 544 | } 545 | .span1 { 546 | width: 70px; 547 | } 548 | .offset12 { 549 | margin-left: 1230px; 550 | } 551 | .offset11 { 552 | margin-left: 1130px; 553 | } 554 | .offset10 { 555 | margin-left: 1030px; 556 | } 557 | .offset9 { 558 | margin-left: 930px; 559 | } 560 | .offset8 { 561 | margin-left: 830px; 562 | } 563 | .offset7 { 564 | margin-left: 730px; 565 | } 566 | .offset6 { 567 | margin-left: 630px; 568 | } 569 | .offset5 { 570 | margin-left: 530px; 571 | } 572 | .offset4 { 573 | margin-left: 430px; 574 | } 575 | .offset3 { 576 | margin-left: 330px; 577 | } 578 | .offset2 { 579 | margin-left: 230px; 580 | } 581 | .offset1 { 582 | margin-left: 130px; 583 | } 584 | .row-fluid { 585 | width: 100%; 586 | *zoom: 1; 587 | } 588 | .row-fluid:before, 589 | .row-fluid:after { 590 | display: table; 591 | content: ""; 592 | } 593 | .row-fluid:after { 594 | clear: both; 595 | } 596 | .row-fluid > [class*="span"] { 597 | float: left; 598 | margin-left: 2.564102564%; 599 | } 600 | .row-fluid > [class*="span"]:first-child { 601 | margin-left: 0; 602 | } 603 | .row-fluid > .span12 { 604 | width: 100%; 605 | } 606 | .row-fluid > .span11 { 607 | width: 91.45299145300001%; 608 | } 609 | .row-fluid > .span10 { 610 | width: 82.905982906%; 611 | } 612 | .row-fluid > .span9 { 613 | width: 74.358974359%; 614 | } 615 | .row-fluid > .span8 { 616 | width: 65.81196581200001%; 617 | } 618 | .row-fluid > .span7 { 619 | width: 57.264957265%; 620 | } 621 | .row-fluid > .span6 { 622 | width: 48.717948718%; 623 | } 624 | .row-fluid > .span5 { 625 | width: 40.170940171000005%; 626 | } 627 | .row-fluid > .span4 { 628 | width: 31.623931624%; 629 | } 630 | .row-fluid > .span3 { 631 | width: 23.076923077%; 632 | } 633 | .row-fluid > .span2 { 634 | width: 14.529914530000001%; 635 | } 636 | .row-fluid > .span1 { 637 | width: 5.982905983%; 638 | } 639 | input, 640 | textarea, 641 | .uneditable-input { 642 | margin-left: 0; 643 | } 644 | input.span12, textarea.span12, .uneditable-input.span12 { 645 | width: 1160px; 646 | } 647 | input.span11, textarea.span11, .uneditable-input.span11 { 648 | width: 1060px; 649 | } 650 | input.span10, textarea.span10, .uneditable-input.span10 { 651 | width: 960px; 652 | } 653 | input.span9, textarea.span9, .uneditable-input.span9 { 654 | width: 860px; 655 | } 656 | input.span8, textarea.span8, .uneditable-input.span8 { 657 | width: 760px; 658 | } 659 | input.span7, textarea.span7, .uneditable-input.span7 { 660 | width: 660px; 661 | } 662 | input.span6, textarea.span6, .uneditable-input.span6 { 663 | width: 560px; 664 | } 665 | input.span5, textarea.span5, .uneditable-input.span5 { 666 | width: 460px; 667 | } 668 | input.span4, textarea.span4, .uneditable-input.span4 { 669 | width: 360px; 670 | } 671 | input.span3, textarea.span3, .uneditable-input.span3 { 672 | width: 260px; 673 | } 674 | input.span2, textarea.span2, .uneditable-input.span2 { 675 | width: 160px; 676 | } 677 | input.span1, textarea.span1, .uneditable-input.span1 { 678 | width: 60px; 679 | } 680 | .thumbnails { 681 | margin-left: -30px; 682 | } 683 | .thumbnails > li { 684 | margin-left: 30px; 685 | } 686 | } 687 | -------------------------------------------------------------------------------- /bootstrap/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";} 2 | .clearfix:after{clear:both;} 3 | .hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;} 4 | .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} 5 | .hidden{display:none;visibility:hidden;} 6 | .visible-phone{display:none;} 7 | .visible-tablet{display:none;} 8 | .visible-desktop{display:block;} 9 | .hidden-phone{display:block;} 10 | .hidden-tablet{display:block;} 11 | .hidden-desktop{display:none;} 12 | @media (max-width:767px){.visible-phone{display:block;} .hidden-phone{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (min-width:768px) and (max-width:979px){.visible-tablet{display:block;} .hidden-tablet{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top{margin-left:-20px;margin-right:-20px;} .container{width:auto;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;} .thumbnails [class*="span"]{width:auto;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:99.999999993%;} .row-fluid > .span11{width:91.436464082%;} .row-fluid > .span10{width:82.87292817100001%;} .row-fluid > .span9{width:74.30939226%;} .row-fluid > .span8{width:65.74585634900001%;} .row-fluid > .span7{width:57.182320438000005%;} .row-fluid > .span6{width:48.618784527%;} .row-fluid > .span5{width:40.055248616%;} .row-fluid > .span4{width:31.491712705%;} .row-fluid > .span3{width:22.928176794%;} .row-fluid > .span2{width:14.364640883%;} .row-fluid > .span1{width:5.801104972%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:714px;} input.span11, textarea.span11, .uneditable-input.span11{width:652px;} input.span10, textarea.span10, .uneditable-input.span10{width:590px;} input.span9, textarea.span9, .uneditable-input.span9{width:528px;} input.span8, textarea.span8, .uneditable-input.span8{width:466px;} input.span7, textarea.span7, .uneditable-input.span7{width:404px;} input.span6, textarea.span6, .uneditable-input.span6{width:342px;} input.span5, textarea.span5, .uneditable-input.span5{width:280px;} input.span4, textarea.span4, .uneditable-input.span4{width:218px;} input.span3, textarea.span3, .uneditable-input.span3{width:156px;} input.span2, textarea.span2, .uneditable-input.span2{width:94px;} input.span1, textarea.span1, .uneditable-input.span1{width:32px;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav .nav-header{color:#999999;text-shadow:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:100%;} .row-fluid > .span11{width:91.45299145300001%;} .row-fluid > .span10{width:82.905982906%;} .row-fluid > .span9{width:74.358974359%;} .row-fluid > .span8{width:65.81196581200001%;} .row-fluid > .span7{width:57.264957265%;} .row-fluid > .span6{width:48.717948718%;} .row-fluid > .span5{width:40.170940171000005%;} .row-fluid > .span4{width:31.623931624%;} .row-fluid > .span3{width:23.076923077%;} .row-fluid > .span2{width:14.529914530000001%;} .row-fluid > .span1{width:5.982905983%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:1160px;} input.span11, textarea.span11, .uneditable-input.span11{width:1060px;} input.span10, textarea.span10, .uneditable-input.span10{width:960px;} input.span9, textarea.span9, .uneditable-input.span9{width:860px;} input.span8, textarea.span8, .uneditable-input.span8{width:760px;} input.span7, textarea.span7, .uneditable-input.span7{width:660px;} input.span6, textarea.span6, .uneditable-input.span6{width:560px;} input.span5, textarea.span5, .uneditable-input.span5{width:460px;} input.span4, textarea.span4, .uneditable-input.span4{width:360px;} input.span3, textarea.span3, .uneditable-input.span3{width:260px;} input.span2, textarea.span2, .uneditable-input.span2{width:160px;} input.span1, textarea.span1, .uneditable-input.span1{width:60px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}} 13 | -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optikalefx/OpenJS-Grid/7f5188ce79a9202f3b0f56d2dc63ac60f0f869d7/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optikalefx/OpenJS-Grid/7f5188ce79a9202f3b0f56d2dc63ac60f0f869d7/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /bootstrap/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(a){a(function(){"use strict",a.support.transition=function(){var b=document.body||document.documentElement,c=b.style,d=c.transition!==undefined||c.WebkitTransition!==undefined||c.MozTransition!==undefined||c.MsTransition!==undefined||c.OTransition!==undefined;return d&&{end:function(){var b="TransitionEnd";return a.browser.webkit?b="webkitTransitionEnd":a.browser.mozilla?b="transitionend":a.browser.opera&&(b="oTransitionEnd"),b}()}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype={constructor:c,close:function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),e.trigger("close"),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger("close").removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()}},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype={constructor:b,setState:function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},toggle:function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")}},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.carousel.defaults,c),this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(){return this.interval=setInterval(a.proxy(this.next,this),this.options.interval),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(){return clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;return!a.support.transition&&this.$element.hasClass("slide")?(this.$element.trigger("slide"),d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")):(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.trigger("slide"),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})),f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=typeof c=="object"&&c;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find(".in"),e;d&&d.length&&(e=d.data("collapse"),d.collapse("hide"),e||d.data("collapse",null)),this.$element[b](0),this.transition("addClass","show","shown"),this.$element[b](this.$element[0][c])},hide:function(){var a=this.dimension();this.reset(this.$element[a]()),this.transition("removeClass","hide","hidden"),this.$element[a](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c=="show"&&e.reset(),e.$element.trigger(d)};this.$element.trigger(c)[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e=c.attr("data-target"),f,g;return e||(e=c.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,"")),f=a(e),f.length||(f=c.parent()),g=f.hasClass("open"),d(),!g&&f.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('"); 179 | 180 | var self = this, 181 | $grid = $(this.el), 182 | table = $table[0], 183 | $ths = $table.find("th"); 184 | 185 | // so we can access all grids from the outside 186 | window.grids.push(this); 187 | 188 | // lets take the attributes from the table element and store them 189 | this._attrsToProps(table,this.opts); 190 | 191 | // take the columns you want and store them in a comma sep list (easy to send to ajax) 192 | this.cols = $table.find("th").map(function() {return $(this).attr("col")}).get().join(","); 193 | 194 | // define this object on THIS instance 195 | this.columns = {}; 196 | 197 | // loop through THs and store properties in an object 198 | for(var i=0;i<=$ths.length;i++) { 199 | if($ths.eq(i).length) { 200 | var $col = $ths.eq(i), 201 | col = $col[0], 202 | colName = col.getAttribute("col"); 203 | this.columns[colName] = {header : $col.text()}; 204 | this._attrsToProps(col,this.columns[colName]); 205 | } 206 | } 207 | 208 | // we dont need no damn tables 209 | $table.remove(); 210 | 211 | // store some stuff we need 212 | this.sbWidth = this._calculateScrollbarWidth(); 213 | 214 | // add the touch class if we have a touch devince 215 | !!('ontouchstart' in window) && $grid.addClass("touch"); 216 | 217 | // call the load when the object is built 218 | this.load(); 219 | 220 | 221 | //////////// EVENTS 222 | 223 | 224 | // save event 225 | if(this.opts.editing) { 226 | $grid._on("click",".gridSave:not(.disabled)", self.saveRow, self); 227 | $grid.on("click",".gridSave.disabled", function(){ return false }); 228 | 229 | // as you type, keep the object up to date 230 | $grid._on("keyup",".cell :input", self.markForSaving, self); 231 | 232 | // datepicker choose (datepicker is optional) 233 | $grid._on("change",".cell :input.datepicker", self.markForSaving, self); 234 | 235 | // datepicker choose (datepicker is optional) 236 | $grid._on("change",".cell select", self.markForSaving, self); 237 | } 238 | 239 | // add custom cell types if needed 240 | if(this.opts.cellTypes) { 241 | this.extend(this.cellTypes,this.opts.cellTypes); 242 | } 243 | 244 | // as you type, keep the object up to date 245 | $grid._on("click",".cell", self._handleCellClick, self); 246 | 247 | // checkbox saving 248 | $grid._on("click",".cell :checkbox", self.markForSaving, self); 249 | 250 | // as you type, keep the object up to date 251 | $grid._on("click",".headerCell", self.sort, self); 252 | 253 | // row hover 254 | //$grid._on("mouseover",".cell[data-row]",self.rowHover,self); 255 | //$grid._on("mouseout" ,".cell[data-row]",self.rowHoverOut,self); 256 | 257 | // grid resizer 258 | $grid._on("mousedown",".gridResizer", self._gridResize, self); 259 | 260 | // col resizers 261 | var rs = ".headerCell .resizer"; 262 | $grid._on("mousedown", rs, self._columnResize, self).on("click",rs, function(e) { 263 | // stop the header cell from being clicked 264 | e.stopPropagation(); 265 | }); 266 | 267 | // delete button 268 | if(this.opts.deleting) { 269 | $grid._on("click","button.gridDeleteRow", self.deleteRow, self); 270 | } 271 | }, 272 | 273 | 274 | /******* 275 | 276 | I think this function is finally done. No matter what your table padding, border, 277 | cell padding, cell border, whatever, scrollbars or not. The math should always make it perfect 278 | honestly, many days went into this math, and i'm quite proud of it. The whole grid comes down to this 279 | function, and it being fast. Trying to optimize this as much as possible 280 | 281 | *******/ 282 | _equalize : function(amt) { 283 | var $grid = $(this.el), // our grid 284 | $columns = this.$columns, // single columns container 285 | $cols = this.$cols, // collection of each column 286 | nCols = $cols.length, // how many columns 287 | totalNCols = nCols, 288 | gridHeight = this.gridHeight, // height of the grid 289 | sbWidth = this.sbWidth, // scrollbar width 290 | minAllowedColWidth = this.opts.minAllowedColWidth, // minium allowed width for columns 291 | needsScrollbar = this.aColumnHeight > gridHeight, // if 1 column height is > grid height, we need to account for scrollbar 292 | sbWidth = needsScrollbar ? sbWidth : 0, // use sbwidth or 0 if we needed a scroll bar 293 | columns = this.columns, // our columns object 294 | colName, col, i, name, customWidth, colwidth; // extra vars 295 | 296 | var originalWidth = $grid.width(); // current width of the grid 297 | this.fullWidth = originalWidth - sbWidth; // adjust width to scrollbar so we know how much space to fill 298 | var playWidth = this.fullWidth; // playWidth is how much space minus set widths do we have 299 | 300 | // adjust number of columns and full width to reflect manually set widths 301 | for(colName in columns) { 302 | col = columns[colName]; 303 | if("width" in col) { 304 | if(playWidth - parseInt(col.width) > minAllowedColWidth) { 305 | // adjust width for custom width cells 306 | playWidth -= parseInt(col.width); 307 | // no longer count this cell 308 | nCols--; 309 | } 310 | } 311 | } 312 | 313 | for(i=0, l = $cols.length; i minWidth) { 383 | // change the width 384 | colOpts.width += amt; 385 | // adjust the header cell width so it can affect the others 386 | startX = e.clientX; 387 | // adjust the rest, except the header cell 388 | self._equalize(); 389 | } 390 | }); 391 | }, 392 | 393 | // resize method for the entire grid 394 | _gridResize: function(e,el) { 395 | // starting pos 396 | var self = this, 397 | startX = e.clientX; 398 | $grid = $(self.el); 399 | 400 | // turn off selection while resizing 401 | $grid.addClass("resizing"); 402 | 403 | $(document).bind("mouseup.grid",function() { 404 | $(document).unbind("mousemove.grid"); 405 | $grid.removeClass("resizing"); 406 | self._equalize(); 407 | }); 408 | 409 | $(document).bind("mousemove.grid",function(e) { 410 | $grid.width( $grid.width() + (e.clientX - startX) ); 411 | // adjust the header cell width so it can affect the others 412 | startX = e.clientX; 413 | // if the width is tiny, add the small class 414 | if($grid.width() < 600) { 415 | $grid.addClass("small"); 416 | self.pager.slider.update(); 417 | } else if($grid.hasClass("small")) { 418 | $grid.removeClass("small"); 419 | self.pager.slider.update(); 420 | } 421 | // adjust the rest, except the header cell 422 | self._equalize(); 423 | }); 424 | }, 425 | 426 | // often will be the case that browsers have different scrollbars 427 | // this trick calculates that size 428 | _calculateScrollbarWidth : function() { 429 | var div = $('
').css({ 430 | width:50, 431 | height:50, 432 | overflow:"hidden", 433 | position:"absolute", 434 | top:-200, 435 | left:-200 436 | }); 437 | $('body').append(div); 438 | var w1 = $('div', div).innerWidth(); 439 | div.css('overflow-y', 'auto'); 440 | var w2 = $('div', div).innerWidth(); 441 | $(div).remove(); 442 | var scrollbarWidth = (w1 - w2); 443 | return scrollbarWidth; 444 | }, 445 | 446 | 447 | _attrsToProps : function(el,obj) { 448 | // takes all the attributes on some dom element and stores them 449 | // as properties onto some other object 450 | // im making this a method, cuz we will need to do this again for THs 451 | var attrs = el.attributes; 452 | for(var i=0, l=attrs.length; i"; 482 | }) 483 | } 484 | 485 | ///////////////////////// 486 | // ADD ROW NUMBER COLUMN 487 | //////////////////////// 488 | if(this.opts.rowNumbers && !Array.isArray(this.rows)) { 489 | // add the column with a width 490 | var $newCol = this.addColumn("rowNumbers", { 491 | width: 35, 492 | insertAt: 0, 493 | header : " ", 494 | cellClass : "center" 495 | }, function(i) { 496 | return i + self.start; 497 | }) 498 | } 499 | 500 | ///////////////////////// 501 | // ADD DATEPICKER STUFF 502 | //////////////////////// 503 | if($.datepicker && $(".datepicker").length) { 504 | $(".datepicker").datepicker({dateFormat: "yy-mm-dd"}); 505 | } 506 | 507 | ///////////////////////// 508 | // ADD DELETE BUTTON COLUMN 509 | //////////////////////// 510 | if(this.opts.deleting && !Array.isArray(this.rows)) { 511 | 512 | // add the column with a width 513 | var $deleteCol = this.addColumn("Delete", {width: 65, cellClass : "center"}, function() { 514 | return self._render("deleteButton")(); 515 | }) 516 | } 517 | 518 | ///////////////////////// 519 | // ADD SORTABLE BAR THING 520 | //////////////////////// 521 | var $sortBar = $(this.el).find(".headerCell[col='"+this.opts.orderBy+"']").find(".sortbar").show(); 522 | if(this.opts.sort == "desc") $sortBar.addClass("desc"); 523 | 524 | ///////////////////////// 525 | // SET THE BLANK CELL HEIGHT TO MATCH 526 | //////////////////////// 527 | var headerHeight = $grid.find(".headerCell:first").height(); 528 | $grid.find(".blankCell").css({ 529 | height: headerHeight 530 | }); 531 | 532 | // what happens after ajax, stays after ajax. 533 | this._cacheSize(); 534 | this._equalize(); 535 | 536 | // were done loading, close the notification 537 | self.loadingDialog.close(); 538 | 539 | if($grid.width() < 600) { 540 | $grid.addClass("small"); 541 | self.pager.slider.update(); 542 | } else if($grid.hasClass("small")) { 543 | $grid.removeClass("small"); 544 | self.pager.slider.update(); 545 | } 546 | 547 | // mark first load 548 | this.firstLoad = false; 549 | 550 | }, 551 | 552 | // stores up the current size and variables for equalize 553 | // only call this to recache 554 | // dont call this if the grid is gonna reload, itll get called anyway 555 | _cacheSize : function() { 556 | var $grid = $(this.el); 557 | this.$columns = $grid.children(".columns"); 558 | this.$cols = this.$columns.children(".col"); 559 | this.aColumnHeight = this.$columns.children(".col:first").height(); 560 | this.gridHeight = $grid.height(); 561 | 562 | }, 563 | 564 | // because there is no true concept of a row, 565 | // we need to run this call both rowClick and cellClick 566 | _handleCellClick : function(e,el) { 567 | var id = el.getAttribute("data-row"), 568 | rowData= this.rows["_"+id]; 569 | // row check 570 | if($(e.target).hasClass("rowCheck")) { 571 | $(this.el).trigger("rowCheck", [$(e.target),rowData]); 572 | } 573 | // trigger cell click 574 | $(this.el).trigger("cellClick", [$(el),rowData]); 575 | // trigger row click 576 | $rows = this.getRow(id); 577 | // this isn't sending the array? 578 | $(this.el).trigger("rowClick", [$rows,rowData]); 579 | }, 580 | 581 | // template render 582 | _render : function (template) { 583 | var self = this; 584 | return function (data) { 585 | // Caches the template so that it may be manipulated. 586 | // allows {!{ syntax for use with other template engines 587 | var temple, regex = /{!?{([\w\.]+)}}/g; 588 | 589 | // use template as string if its not defined 590 | if(typeof self._templates[template] == "undefined") { 591 | temple = template; 592 | 593 | // use pre defined template 594 | } else { 595 | temple = self._templates[template]; 596 | } 597 | 598 | // template replacement 599 | temple = temple.replace(regex, function(match, $1) { return data[$1] }); 600 | // Get rid of any remaining, unused variables before returning. 601 | return temple.replace(regex, ''); 602 | }; 603 | }, 604 | 605 | // html templates 606 | _templates : { 607 | deleteButton : "", 608 | cell : "
{{val}}
", 609 | columnHeader : ""+ 610 | "
\ 611 | {{header}}\ 612 |
\ 613 |
\ 614 |
\ 615 | \ 616 | ", 617 | confirm : ""+ 618 | "
\ 619 | {{msg}}\ 620 |
\ 621 | \ 622 | \ 623 |
\ 624 |
\ 625 | ", 626 | alert : ""+ 627 | "
\ 628 | {{title}}\ 629 | {{msg}}\ 630 |
\ 631 | \ 632 |
\ 633 |
\ 634 | ", 635 | notify : ""+ 636 | "
\ 637 | {{msg}}\ 638 |
\ 639 | ", 640 | pager : ""+ 641 | "\ 660 |
\ 661 | Save\ 662 |
\ 663 | " 664 | }, 665 | 666 | // ********************************************************************************* 667 | // ********************************************************************************* 668 | // ** PUBLIC METHODS 669 | // ********************************************************************************* 670 | // ********************************************************************************* 671 | 672 | // IDEA - ONLY EVER KEEP 30 ROWS ON THE DOM, REMOVE TOP AND BOTTOM ROWS AND STORE IN MEMORY 673 | // ONLY CREATE 30 ROWS AT A TIME, NEVER MORE. FILTERING IS ALREADY DONE ON MEMORY, BUT WOULD NEED 674 | // TO ADD BACK ROWS THAT ARE IN MEMORY AND NOT IN THE DOM, SHOULD BE EASY. 675 | 676 | // public methods 677 | load : function(opts) { 678 | var self = this, packet, promise, rowHtml = "", colHtml = "", 679 | col = 0, key = 0, pKey, rowCol = 0, cellValue, checked = 0, 680 | cellClass = "", type; 681 | 682 | // if we are reloading with options pass them in 683 | // if(opts) this.grid(opts); 684 | if(opts) this.opts = this.extend(this.opts,opts); 685 | 686 | // register loadStart callback 687 | $(this.el).trigger("loadStart"); 688 | 689 | // we have some more data than in this.opts that we wanna send to ajax 690 | packet = $.extend({ 691 | cols : this.cols 692 | },this.opts); 693 | 694 | // cache the el because self.el changes some where? 695 | var el = self.el 696 | var cellTypes = self.cellTypes; 697 | 698 | // show loading box 699 | this.loadingDialog = this.notify("Loading"); 700 | 701 | ///////////////////////// 702 | // LOAD SELECT BOXES 703 | //////////////////////// 704 | var selCol, colName, selectCols = [], selectPromise = $.Deferred(); 705 | for(colName in this.columns) { 706 | selCol = this.columns[colName]; 707 | if(typeof selCol.type != "undefined" && selCol.type == "select") { 708 | selectCols.push(colName); 709 | } 710 | } 711 | // get all the drop downs, store the promise in case we wanna check this 712 | if(selectCols.length && !self.selects) { 713 | selectPromise = $.post(this.opts.action,{select : true, cols : selectCols},function(data) { 714 | // by saving the data, we dont ever have to do this ajax call again til page reload 715 | self.selects = data; 716 | return true; 717 | }); 718 | } else { 719 | selectPromise.resolve(); 720 | } 721 | 722 | 723 | promise = $.post(this.opts.action,packet,function(data) { 724 | self.el = el; // fixes some problem i dont know :( 725 | self.cellTypes = cellTypes; 726 | var $grid = $(self.el), 727 | $columns = $grid.find(".columns"); 728 | 729 | // store some data we got back 730 | self.totalRows = data.nRows; 731 | self.start = data.start; 732 | self.end = Math.min(data.end,data.nRows); 733 | self.saveable = data.saveable; 734 | 735 | self.opts.orderBy = data.order_by; 736 | self.opts.sort = data.sort; 737 | 738 | // were gonna build the table in a string, then append it 739 | // this is 1000000x times faster than dom manipulation 740 | self.rows = data.rows; 741 | 742 | // when our ajax is done, move on. 743 | selectPromise.done(function() { 744 | 745 | // it will be an object if it has data 746 | if(!Array.isArray(data.rows)) { 747 | 748 | // build the table in column form, instead of row form 749 | for(col in self.columns) { 750 | 751 | // options on the column 752 | colOpts = self.columns[col]; 753 | 754 | // opening col div 755 | colHtml += "
"; 756 | 757 | // blank cells mess things up 758 | if(colOpts.header == "") colOpts.header = " " 759 | 760 | // add header cell with resizer, sortable bar and blank cell 761 | // this is only the header and not the whole column because we want the ability 762 | // to keep adding strings to the return for speed 763 | colHtml += self._render("columnHeader")(colOpts); 764 | 765 | for(key in data.rows) { 766 | pkey = key.substr(1); 767 | row = data.rows[key]; 768 | for(rowCol in row) { 769 | if(rowCol === col) { 770 | 771 | // main value 772 | cellValue = row[col], 773 | cellClass = ""; 774 | 775 | // setup some types 776 | if(typeof self.cellTypes[colOpts.type] == "function") { 777 | 778 | typeOpts = self.cellTypes[colOpts.type](cellValue,colOpts,self); 779 | 780 | // protect a no return 781 | if(typeof typeOpts == "undefined") typeOpts = {cellValue : cellValue,cellClass: ""}; 782 | 783 | cellValue = typeOpts.cellValue; 784 | cellClass = typeOpts.cellClass; 785 | } 786 | 787 | 788 | // empty cells kinda mess with things 789 | if(cellValue == "") cellValue = " "; 790 | 791 | // add linking 792 | // this is not a type because you can link anything by adding href 793 | if(colOpts.href) { 794 | // make some tokens for use in the href 795 | var linkTokens = {value : cellValue} 796 | // add all the column values, column.Title i.e. 797 | for(var aCol in row) linkTokens["columns."+aCol] = row[aCol]; 798 | // render the href with the tokens 799 | var href = self._render(colOpts.href)(linkTokens); 800 | // wrap the cell value in an a tag with the rendered href 801 | cellValue = ""+cellValue+""; 802 | } 803 | 804 | // create the cell from template 805 | colHtml += self._render("cell")({ 806 | cl : cellClass, 807 | id : pkey, 808 | col : col, 809 | val : cellValue 810 | }); 811 | } 812 | } 813 | } 814 | 815 | colHtml += "
"; 816 | } 817 | } else { 818 | colHtml = "No Rows"; 819 | } 820 | 821 | // hide our loading 822 | $grid.find(".gridLoading").hide(); 823 | 824 | // place all the content 825 | $columns.html(colHtml); 826 | 827 | // do things after ajax 828 | self._afterLoad(); 829 | 830 | // register loadComplate Callback 831 | $(self.el).trigger("loadComplete",self); 832 | 833 | }); 834 | 835 | },"json"); 836 | 837 | return promise; 838 | }, 839 | 840 | // [none | success | warning | important | info | inverse] 841 | // helper dialog alert function 842 | alert : function(type, title, msg) { 843 | return Dialog.inherit({ 844 | tmpl : "alert", 845 | type: type, 846 | title: title, 847 | msg : msg, 848 | grid: this 849 | }).show(); 850 | }, 851 | 852 | // helper dialog notify method 853 | notify : function(msg, ms) { 854 | var self = this; 855 | // our opts 856 | var opts = {msg:msg, grid:this}; 857 | // if we wanted a timer 858 | if(ms) opts.autoFadeTimer = ms; 859 | // create and show 860 | return Dialog.inherit(opts).show(); 861 | }, 862 | 863 | 864 | // shortcut error function 865 | error : function(msg) { 866 | return this.alert("important", "Error!", msg); 867 | }, 868 | 869 | // a confrim dialog box 870 | confirm : function(msg, callback) { 871 | var $grid = $(this.el); 872 | var dialog = Dialog.inherit({ 873 | tmpl : "confirm", 874 | msg : msg, 875 | grid : this 876 | }).show(); 877 | 878 | // add our confirm ok 879 | dialog.$dialog.one("click",".confirmOk",callback); 880 | 881 | return dialog; 882 | }, 883 | 884 | // debouncing the typing 885 | _filter : function(e,el) { 886 | var self = this, 887 | $el = $(el); 888 | // store on pager 889 | this.pager.query = $el.val(); 890 | // start typing timer 891 | clearTimeout(this.debounce); 892 | this.debounce = setTimeout(function() { 893 | self.filter( $el.val() ) 894 | },150); 895 | }, 896 | 897 | // finds matches in the dom as fast as i know how 898 | // do intelligent searches with column: 899 | // right click a column header and choose "search on" which would fill out the search filter 900 | filter : function(val) { 901 | var $grid = $(this.el), 902 | $all = $grid.find("[data-row]"), 903 | $cols = $grid.find(".col"); 904 | 905 | if(val) { 906 | var matches = [], 907 | val = val.toLowerCase(); 908 | for(id in this.rows) { 909 | var row = this.rows[id], 910 | id = id.substring(1); 911 | for(key in row) { 912 | var string = row[key].toLowerCase(); 913 | if(~string.indexOf(val) && !~matches.indexOf(id)) matches.push(id); 914 | } 915 | } 916 | 917 | $all.hide(); 918 | $all.removeClass("topMargin"); 919 | 920 | if(matches.length) { 921 | $(".cell.temp").remove(); 922 | for(i=0;i