diff --git a/framework/cli/views/webapp/protected/components/Controller.php b/framework/cli/views/webapp/protected/components/Controller.php
index 4d27862..083187e 100644
--- a/framework/cli/views/webapp/protected/components/Controller.php
+++ b/framework/cli/views/webapp/protected/components/Controller.php
@@ -6,10 +6,10 @@
class Controller extends CController
{
/**
- * @var string the default layout for the controller view. Defaults to '//layouts/column1',
- * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
+ * @var string the default layout for the controller view. Defaults to '//layouts/main',
+ * meaning using a single column layout. See 'protected/views/layouts/main.php'.
*/
- public $layout='//layouts/column1';
+ public $layout='//layouts/main';
/**
* @var array context menu items. This property will be assigned to {@link CMenu::items}.
*/
diff --git a/www/protected/components/Controller.php b/www/protected/components/Controller.php
index 4d27862..083187e 100644
--- a/www/protected/components/Controller.php
+++ b/www/protected/components/Controller.php
@@ -6,10 +6,10 @@
class Controller extends CController
{
/**
- * @var string the default layout for the controller view. Defaults to '//layouts/column1',
- * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
+ * @var string the default layout for the controller view. Defaults to '//layouts/main',
+ * meaning using a single column layout. See 'protected/views/layouts/main.php'.
*/
- public $layout='//layouts/column1';
+ public $layout='//layouts/main';
/**
* @var array context menu items. This property will be assigned to {@link CMenu::items}.
*/
diff --git a/www/protected/config/env/dev.php b/www/protected/config/env/dev.php
index 8ce1136..c65e806 100644
--- a/www/protected/config/env/dev.php
+++ b/www/protected/config/env/dev.php
@@ -27,6 +27,7 @@ return array(
'modules'=>array(
'gii'=>array(
'class'=>'system.gii.GiiModule',
+ 'generatorPaths' => array('bootstrap.gii'),
'password'=>'giipw',
'ipFilters'=>array('127.0.0.1','::1'),
),
diff --git a/www/protected/config/main.php b/www/protected/config/main.php
index 4057807..6000c85 100644
--- a/www/protected/config/main.php
+++ b/www/protected/config/main.php
@@ -11,27 +11,40 @@ use Yiinitializr\Helpers\ArrayX;
return ArrayX::merge(array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
- 'name'=>'My Web Application',
+ 'name'=>'Mikescher.de',
// preloading 'log' component
'preload'=>array('log'),
+ 'aliases' => array(
+ 'bootstrap' => realpath(__DIR__ . '/../extensions/bootstrap'), // change this if necessary
+ ),
+
// autoloading model and component classes
'import'=>array(
'application.models.*',
'application.components.*',
+ 'bootstrap.components.*',
+ 'bootstrap.behaviors.*',
+ 'bootstrap.helpers.*',
+
),
'modules'=>array(
-
+ //
),
// application components
'components'=>array(
+ 'bootstrap' => array(
+ 'class' => 'bootstrap.components.TbApi',
+ ),
+
'user'=>array(
// enable cookie-based authentication
'allowAutoLogin'=>true,
),
+
// uncomment the following to enable URLs in path-format
/*
'urlManager'=>array(
diff --git a/www/protected/extensions/bootstrap/.gitignore b/www/protected/extensions/bootstrap/.gitignore
new file mode 100644
index 0000000..58793a2
--- /dev/null
+++ b/www/protected/extensions/bootstrap/.gitignore
@@ -0,0 +1,29 @@
+# Composer files
+composer.phar
+vendor/*
+
+# Codeception files
+codecept.phar
+tests/_log/*
+tests/acceptance/*
+tests/functional/*
+tests/acceptance.suite.yml
+tests/functional.suite.yml
+
+# Node modules
+node_modules
+
+# releases
+releases/
+
+# project files
+.idea/*
+nbproject/*
+
+# mac deployment helpers
+switch
+
+# cache directories
+Thumbs.db
+*.DS_Store
+*.empty
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/.travis.yml b/www/protected/extensions/bootstrap/.travis.yml
new file mode 100644
index 0000000..67267d0
--- /dev/null
+++ b/www/protected/extensions/bootstrap/.travis.yml
@@ -0,0 +1,14 @@
+language: php
+
+php:
+ - 5.4
+
+before_script:
+ - composer self-update
+ - composer install --prefer-source
+
+script: vendor/bin/codecept run unit
+
+branches:
+ only:
+ - master
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/Gruntfile.js b/www/protected/extensions/bootstrap/Gruntfile.js
new file mode 100644
index 0000000..7f67289
--- /dev/null
+++ b/www/protected/extensions/bootstrap/Gruntfile.js
@@ -0,0 +1,31 @@
+// The wrapper function
+module.exports = function(grunt) {
+
+ // Project and task configuration
+ grunt.initConfig({
+ less: {
+ development: {
+ files: {
+ "assets/css/yiistrap.css": "assets/less/yiistrap.less"
+ }
+ },
+ production: {
+ options: {
+ compress: true,
+ yuicompress: true,
+ optimization: 2
+ },
+ files: {
+ "assets/css/yiistrap.min.css": "assets/less/yiistrap.less"
+ }
+ }
+ }
+ });
+
+ // Load plugins
+ grunt.loadNpmTasks('grunt-contrib-less');
+
+ // Define tasks
+ grunt.registerTask('default', ['less']);
+
+};
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/LICENSE.txt b/www/protected/extensions/bootstrap/LICENSE.txt
new file mode 100644
index 0000000..efd1221
--- /dev/null
+++ b/www/protected/extensions/bootstrap/LICENSE.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2013, Christoffer Niska
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Christoffer Niska nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/README.md b/www/protected/extensions/bootstrap/README.md
new file mode 100644
index 0000000..71b96e6
--- /dev/null
+++ b/www/protected/extensions/bootstrap/README.md
@@ -0,0 +1,10 @@
+Yiistrap
+========
+
+[![Latest Stable Version](https://poser.pugx.org/crisu83/yiistrap/v/stable.png)](https://packagist.org/packages/crisu83/yiistrap)
+[![Build Status](https://travis-ci.org/Crisu83/yiistrap.png)](https://travis-ci.org/Crisu83/yiistrap)
+
+Twitter Bootstrap for Yii.
+
+Documentation can be found here:
+[http://www.getyiistrap.com](http://www.getyiistrap.com)
diff --git a/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.css b/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.css
new file mode 100644
index 0000000..09e88ce
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.css
@@ -0,0 +1,1109 @@
+/*!
+ * Bootstrap Responsive v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+ *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.clearfix:after {
+ clear: both;
+}
+
+.hide-text {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+@-ms-viewport {
+ width: device-width;
+}
+
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+
+.visible-phone {
+ display: none !important;
+}
+
+.visible-tablet {
+ display: none !important;
+}
+
+.hidden-desktop {
+ display: none !important;
+}
+
+.visible-desktop {
+ display: inherit !important;
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+ .hidden-desktop {
+ display: inherit !important;
+ }
+ .visible-desktop {
+ display: none !important ;
+ }
+ .visible-tablet {
+ display: inherit !important;
+ }
+ .hidden-tablet {
+ display: none !important;
+ }
+}
+
+@media (max-width: 767px) {
+ .hidden-desktop {
+ display: inherit !important;
+ }
+ .visible-desktop {
+ display: none !important;
+ }
+ .visible-phone {
+ display: inherit !important;
+ }
+ .hidden-phone {
+ display: none !important;
+ }
+}
+
+.visible-print {
+ display: none !important;
+}
+
+@media print {
+ .visible-print {
+ display: inherit !important;
+ }
+ .hidden-print {
+ display: none !important;
+ }
+}
+
+@media (min-width: 1200px) {
+ .row {
+ margin-left: -30px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ line-height: 0;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ min-height: 1px;
+ margin-left: 30px;
+ }
+ .container,
+ .navbar-static-top .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 1170px;
+ }
+ .span12 {
+ width: 1170px;
+ }
+ .span11 {
+ width: 1070px;
+ }
+ .span10 {
+ width: 970px;
+ }
+ .span9 {
+ width: 870px;
+ }
+ .span8 {
+ width: 770px;
+ }
+ .span7 {
+ width: 670px;
+ }
+ .span6 {
+ width: 570px;
+ }
+ .span5 {
+ width: 470px;
+ }
+ .span4 {
+ width: 370px;
+ }
+ .span3 {
+ width: 270px;
+ }
+ .span2 {
+ width: 170px;
+ }
+ .span1 {
+ width: 70px;
+ }
+ .offset12 {
+ margin-left: 1230px;
+ }
+ .offset11 {
+ margin-left: 1130px;
+ }
+ .offset10 {
+ margin-left: 1030px;
+ }
+ .offset9 {
+ margin-left: 930px;
+ }
+ .offset8 {
+ margin-left: 830px;
+ }
+ .offset7 {
+ margin-left: 730px;
+ }
+ .offset6 {
+ margin-left: 630px;
+ }
+ .offset5 {
+ margin-left: 530px;
+ }
+ .offset4 {
+ margin-left: 430px;
+ }
+ .offset3 {
+ margin-left: 330px;
+ }
+ .offset2 {
+ margin-left: 230px;
+ }
+ .offset1 {
+ margin-left: 130px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ line-height: 0;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid [class*="span"] {
+ display: block;
+ float: left;
+ width: 100%;
+ min-height: 30px;
+ margin-left: 2.564102564102564%;
+ *margin-left: 2.5109110747408616%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .row-fluid [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 2.564102564102564%;
+ }
+ .row-fluid .span12 {
+ width: 100%;
+ *width: 99.94680851063829%;
+ }
+ .row-fluid .span11 {
+ width: 91.45299145299145%;
+ *width: 91.39979996362975%;
+ }
+ .row-fluid .span10 {
+ width: 82.90598290598291%;
+ *width: 82.8527914166212%;
+ }
+ .row-fluid .span9 {
+ width: 74.35897435897436%;
+ *width: 74.30578286961266%;
+ }
+ .row-fluid .span8 {
+ width: 65.81196581196582%;
+ *width: 65.75877432260411%;
+ }
+ .row-fluid .span7 {
+ width: 57.26495726495726%;
+ *width: 57.21176577559556%;
+ }
+ .row-fluid .span6 {
+ width: 48.717948717948715%;
+ *width: 48.664757228587014%;
+ }
+ .row-fluid .span5 {
+ width: 40.17094017094017%;
+ *width: 40.11774868157847%;
+ }
+ .row-fluid .span4 {
+ width: 31.623931623931625%;
+ *width: 31.570740134569924%;
+ }
+ .row-fluid .span3 {
+ width: 23.076923076923077%;
+ *width: 23.023731587561375%;
+ }
+ .row-fluid .span2 {
+ width: 14.52991452991453%;
+ *width: 14.476723040552828%;
+ }
+ .row-fluid .span1 {
+ width: 5.982905982905983%;
+ *width: 5.929714493544281%;
+ }
+ .row-fluid .offset12 {
+ margin-left: 105.12820512820512%;
+ *margin-left: 105.02182214948171%;
+ }
+ .row-fluid .offset12:first-child {
+ margin-left: 102.56410256410257%;
+ *margin-left: 102.45771958537915%;
+ }
+ .row-fluid .offset11 {
+ margin-left: 96.58119658119658%;
+ *margin-left: 96.47481360247316%;
+ }
+ .row-fluid .offset11:first-child {
+ margin-left: 94.01709401709402%;
+ *margin-left: 93.91071103837061%;
+ }
+ .row-fluid .offset10 {
+ margin-left: 88.03418803418803%;
+ *margin-left: 87.92780505546462%;
+ }
+ .row-fluid .offset10:first-child {
+ margin-left: 85.47008547008548%;
+ *margin-left: 85.36370249136206%;
+ }
+ .row-fluid .offset9 {
+ margin-left: 79.48717948717949%;
+ *margin-left: 79.38079650845607%;
+ }
+ .row-fluid .offset9:first-child {
+ margin-left: 76.92307692307693%;
+ *margin-left: 76.81669394435352%;
+ }
+ .row-fluid .offset8 {
+ margin-left: 70.94017094017094%;
+ *margin-left: 70.83378796144753%;
+ }
+ .row-fluid .offset8:first-child {
+ margin-left: 68.37606837606839%;
+ *margin-left: 68.26968539734497%;
+ }
+ .row-fluid .offset7 {
+ margin-left: 62.393162393162385%;
+ *margin-left: 62.28677941443899%;
+ }
+ .row-fluid .offset7:first-child {
+ margin-left: 59.82905982905982%;
+ *margin-left: 59.72267685033642%;
+ }
+ .row-fluid .offset6 {
+ margin-left: 53.84615384615384%;
+ *margin-left: 53.739770867430444%;
+ }
+ .row-fluid .offset6:first-child {
+ margin-left: 51.28205128205128%;
+ *margin-left: 51.175668303327875%;
+ }
+ .row-fluid .offset5 {
+ margin-left: 45.299145299145295%;
+ *margin-left: 45.1927623204219%;
+ }
+ .row-fluid .offset5:first-child {
+ margin-left: 42.73504273504273%;
+ *margin-left: 42.62865975631933%;
+ }
+ .row-fluid .offset4 {
+ margin-left: 36.75213675213675%;
+ *margin-left: 36.645753773413354%;
+ }
+ .row-fluid .offset4:first-child {
+ margin-left: 34.18803418803419%;
+ *margin-left: 34.081651209310785%;
+ }
+ .row-fluid .offset3 {
+ margin-left: 28.205128205128204%;
+ *margin-left: 28.0987452264048%;
+ }
+ .row-fluid .offset3:first-child {
+ margin-left: 25.641025641025642%;
+ *margin-left: 25.53464266230224%;
+ }
+ .row-fluid .offset2 {
+ margin-left: 19.65811965811966%;
+ *margin-left: 19.551736679396257%;
+ }
+ .row-fluid .offset2:first-child {
+ margin-left: 17.094017094017094%;
+ *margin-left: 16.98763411529369%;
+ }
+ .row-fluid .offset1 {
+ margin-left: 11.11111111111111%;
+ *margin-left: 11.004728132387708%;
+ }
+ .row-fluid .offset1:first-child {
+ margin-left: 8.547008547008547%;
+ *margin-left: 8.440625568285142%;
+ }
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0;
+ }
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 30px;
+ }
+ input.span12,
+ textarea.span12,
+ .uneditable-input.span12 {
+ width: 1156px;
+ }
+ input.span11,
+ textarea.span11,
+ .uneditable-input.span11 {
+ width: 1056px;
+ }
+ input.span10,
+ textarea.span10,
+ .uneditable-input.span10 {
+ width: 956px;
+ }
+ input.span9,
+ textarea.span9,
+ .uneditable-input.span9 {
+ width: 856px;
+ }
+ input.span8,
+ textarea.span8,
+ .uneditable-input.span8 {
+ width: 756px;
+ }
+ input.span7,
+ textarea.span7,
+ .uneditable-input.span7 {
+ width: 656px;
+ }
+ input.span6,
+ textarea.span6,
+ .uneditable-input.span6 {
+ width: 556px;
+ }
+ input.span5,
+ textarea.span5,
+ .uneditable-input.span5 {
+ width: 456px;
+ }
+ input.span4,
+ textarea.span4,
+ .uneditable-input.span4 {
+ width: 356px;
+ }
+ input.span3,
+ textarea.span3,
+ .uneditable-input.span3 {
+ width: 256px;
+ }
+ input.span2,
+ textarea.span2,
+ .uneditable-input.span2 {
+ width: 156px;
+ }
+ input.span1,
+ textarea.span1,
+ .uneditable-input.span1 {
+ width: 56px;
+ }
+ .thumbnails {
+ margin-left: -30px;
+ }
+ .thumbnails > li {
+ margin-left: 30px;
+ }
+ .row-fluid .thumbnails {
+ margin-left: 0;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+ .row {
+ margin-left: -20px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ line-height: 0;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ min-height: 1px;
+ margin-left: 20px;
+ }
+ .container,
+ .navbar-static-top .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 724px;
+ }
+ .span12 {
+ width: 724px;
+ }
+ .span11 {
+ width: 662px;
+ }
+ .span10 {
+ width: 600px;
+ }
+ .span9 {
+ width: 538px;
+ }
+ .span8 {
+ width: 476px;
+ }
+ .span7 {
+ width: 414px;
+ }
+ .span6 {
+ width: 352px;
+ }
+ .span5 {
+ width: 290px;
+ }
+ .span4 {
+ width: 228px;
+ }
+ .span3 {
+ width: 166px;
+ }
+ .span2 {
+ width: 104px;
+ }
+ .span1 {
+ width: 42px;
+ }
+ .offset12 {
+ margin-left: 764px;
+ }
+ .offset11 {
+ margin-left: 702px;
+ }
+ .offset10 {
+ margin-left: 640px;
+ }
+ .offset9 {
+ margin-left: 578px;
+ }
+ .offset8 {
+ margin-left: 516px;
+ }
+ .offset7 {
+ margin-left: 454px;
+ }
+ .offset6 {
+ margin-left: 392px;
+ }
+ .offset5 {
+ margin-left: 330px;
+ }
+ .offset4 {
+ margin-left: 268px;
+ }
+ .offset3 {
+ margin-left: 206px;
+ }
+ .offset2 {
+ margin-left: 144px;
+ }
+ .offset1 {
+ margin-left: 82px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ line-height: 0;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid [class*="span"] {
+ display: block;
+ float: left;
+ width: 100%;
+ min-height: 30px;
+ margin-left: 2.7624309392265194%;
+ *margin-left: 2.709239449864817%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .row-fluid [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 2.7624309392265194%;
+ }
+ .row-fluid .span12 {
+ width: 100%;
+ *width: 99.94680851063829%;
+ }
+ .row-fluid .span11 {
+ width: 91.43646408839778%;
+ *width: 91.38327259903608%;
+ }
+ .row-fluid .span10 {
+ width: 82.87292817679558%;
+ *width: 82.81973668743387%;
+ }
+ .row-fluid .span9 {
+ width: 74.30939226519337%;
+ *width: 74.25620077583166%;
+ }
+ .row-fluid .span8 {
+ width: 65.74585635359117%;
+ *width: 65.69266486422946%;
+ }
+ .row-fluid .span7 {
+ width: 57.18232044198895%;
+ *width: 57.12912895262725%;
+ }
+ .row-fluid .span6 {
+ width: 48.61878453038674%;
+ *width: 48.56559304102504%;
+ }
+ .row-fluid .span5 {
+ width: 40.05524861878453%;
+ *width: 40.00205712942283%;
+ }
+ .row-fluid .span4 {
+ width: 31.491712707182323%;
+ *width: 31.43852121782062%;
+ }
+ .row-fluid .span3 {
+ width: 22.92817679558011%;
+ *width: 22.87498530621841%;
+ }
+ .row-fluid .span2 {
+ width: 14.3646408839779%;
+ *width: 14.311449394616199%;
+ }
+ .row-fluid .span1 {
+ width: 5.801104972375691%;
+ *width: 5.747913483013988%;
+ }
+ .row-fluid .offset12 {
+ margin-left: 105.52486187845304%;
+ *margin-left: 105.41847889972962%;
+ }
+ .row-fluid .offset12:first-child {
+ margin-left: 102.76243093922652%;
+ *margin-left: 102.6560479605031%;
+ }
+ .row-fluid .offset11 {
+ margin-left: 96.96132596685082%;
+ *margin-left: 96.8549429881274%;
+ }
+ .row-fluid .offset11:first-child {
+ margin-left: 94.1988950276243%;
+ *margin-left: 94.09251204890089%;
+ }
+ .row-fluid .offset10 {
+ margin-left: 88.39779005524862%;
+ *margin-left: 88.2914070765252%;
+ }
+ .row-fluid .offset10:first-child {
+ margin-left: 85.6353591160221%;
+ *margin-left: 85.52897613729868%;
+ }
+ .row-fluid .offset9 {
+ margin-left: 79.8342541436464%;
+ *margin-left: 79.72787116492299%;
+ }
+ .row-fluid .offset9:first-child {
+ margin-left: 77.07182320441989%;
+ *margin-left: 76.96544022569647%;
+ }
+ .row-fluid .offset8 {
+ margin-left: 71.2707182320442%;
+ *margin-left: 71.16433525332079%;
+ }
+ .row-fluid .offset8:first-child {
+ margin-left: 68.50828729281768%;
+ *margin-left: 68.40190431409427%;
+ }
+ .row-fluid .offset7 {
+ margin-left: 62.70718232044199%;
+ *margin-left: 62.600799341718584%;
+ }
+ .row-fluid .offset7:first-child {
+ margin-left: 59.94475138121547%;
+ *margin-left: 59.838368402492065%;
+ }
+ .row-fluid .offset6 {
+ margin-left: 54.14364640883978%;
+ *margin-left: 54.037263430116376%;
+ }
+ .row-fluid .offset6:first-child {
+ margin-left: 51.38121546961326%;
+ *margin-left: 51.27483249088986%;
+ }
+ .row-fluid .offset5 {
+ margin-left: 45.58011049723757%;
+ *margin-left: 45.47372751851417%;
+ }
+ .row-fluid .offset5:first-child {
+ margin-left: 42.81767955801105%;
+ *margin-left: 42.71129657928765%;
+ }
+ .row-fluid .offset4 {
+ margin-left: 37.01657458563536%;
+ *margin-left: 36.91019160691196%;
+ }
+ .row-fluid .offset4:first-child {
+ margin-left: 34.25414364640884%;
+ *margin-left: 34.14776066768544%;
+ }
+ .row-fluid .offset3 {
+ margin-left: 28.45303867403315%;
+ *margin-left: 28.346655695309746%;
+ }
+ .row-fluid .offset3:first-child {
+ margin-left: 25.69060773480663%;
+ *margin-left: 25.584224756083227%;
+ }
+ .row-fluid .offset2 {
+ margin-left: 19.88950276243094%;
+ *margin-left: 19.783119783707537%;
+ }
+ .row-fluid .offset2:first-child {
+ margin-left: 17.12707182320442%;
+ *margin-left: 17.02068884448102%;
+ }
+ .row-fluid .offset1 {
+ margin-left: 11.32596685082873%;
+ *margin-left: 11.219583872105325%;
+ }
+ .row-fluid .offset1:first-child {
+ margin-left: 8.56353591160221%;
+ *margin-left: 8.457152932878806%;
+ }
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0;
+ }
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 20px;
+ }
+ input.span12,
+ textarea.span12,
+ .uneditable-input.span12 {
+ width: 710px;
+ }
+ input.span11,
+ textarea.span11,
+ .uneditable-input.span11 {
+ width: 648px;
+ }
+ input.span10,
+ textarea.span10,
+ .uneditable-input.span10 {
+ width: 586px;
+ }
+ input.span9,
+ textarea.span9,
+ .uneditable-input.span9 {
+ width: 524px;
+ }
+ input.span8,
+ textarea.span8,
+ .uneditable-input.span8 {
+ width: 462px;
+ }
+ input.span7,
+ textarea.span7,
+ .uneditable-input.span7 {
+ width: 400px;
+ }
+ input.span6,
+ textarea.span6,
+ .uneditable-input.span6 {
+ width: 338px;
+ }
+ input.span5,
+ textarea.span5,
+ .uneditable-input.span5 {
+ width: 276px;
+ }
+ input.span4,
+ textarea.span4,
+ .uneditable-input.span4 {
+ width: 214px;
+ }
+ input.span3,
+ textarea.span3,
+ .uneditable-input.span3 {
+ width: 152px;
+ }
+ input.span2,
+ textarea.span2,
+ .uneditable-input.span2 {
+ width: 90px;
+ }
+ input.span1,
+ textarea.span1,
+ .uneditable-input.span1 {
+ width: 28px;
+ }
+}
+
+@media (max-width: 767px) {
+ body {
+ padding-right: 20px;
+ padding-left: 20px;
+ }
+ .navbar-fixed-top,
+ .navbar-fixed-bottom,
+ .navbar-static-top {
+ margin-right: -20px;
+ margin-left: -20px;
+ }
+ .container-fluid {
+ padding: 0;
+ }
+ .dl-horizontal dt {
+ float: none;
+ width: auto;
+ clear: none;
+ text-align: left;
+ }
+ .dl-horizontal dd {
+ margin-left: 0;
+ }
+ .container {
+ width: auto;
+ }
+ .row-fluid {
+ width: 100%;
+ }
+ .row,
+ .thumbnails {
+ margin-left: 0;
+ }
+ .thumbnails > li {
+ float: none;
+ margin-left: 0;
+ }
+ [class*="span"],
+ .uneditable-input[class*="span"],
+ .row-fluid [class*="span"] {
+ display: block;
+ float: none;
+ width: 100%;
+ margin-left: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .span12,
+ .row-fluid .span12 {
+ width: 100%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .row-fluid [class*="offset"]:first-child {
+ margin-left: 0;
+ }
+ .input-large,
+ .input-xlarge,
+ .input-xxlarge,
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .input-prepend input,
+ .input-append input,
+ .input-prepend input[class*="span"],
+ .input-append input[class*="span"] {
+ display: inline-block;
+ width: auto;
+ }
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 0;
+ }
+ .modal {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ left: 20px;
+ width: auto;
+ margin: 0;
+ }
+ .modal.fade {
+ top: -100px;
+ }
+ .modal.fade.in {
+ top: 20px;
+ }
+}
+
+@media (max-width: 480px) {
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0);
+ }
+ .page-header h1 small {
+ display: block;
+ line-height: 20px;
+ }
+ input[type="checkbox"],
+ input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+ .form-horizontal .control-label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ .form-horizontal .controls {
+ margin-left: 0;
+ }
+ .form-horizontal .control-list {
+ padding-top: 0;
+ }
+ .form-horizontal .form-actions {
+ padding-right: 10px;
+ padding-left: 10px;
+ }
+ .media .pull-left,
+ .media .pull-right {
+ display: block;
+ float: none;
+ margin-bottom: 10px;
+ }
+ .media-object {
+ margin-right: 0;
+ margin-left: 0;
+ }
+ .modal {
+ top: 10px;
+ right: 10px;
+ left: 10px;
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+ .carousel-caption {
+ position: static;
+ }
+}
+
+@media (max-width: 979px) {
+ body {
+ padding-top: 0;
+ }
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ position: static;
+ }
+ .navbar-fixed-top {
+ margin-bottom: 20px;
+ }
+ .navbar-fixed-bottom {
+ margin-top: 20px;
+ }
+ .navbar-fixed-top .navbar-inner,
+ .navbar-fixed-bottom .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ .navbar .brand {
+ padding-right: 10px;
+ padding-left: 10px;
+ margin: 0 0 0 -5px;
+ }
+ .nav-collapse {
+ clear: both;
+ }
+ .nav-collapse .nav {
+ float: none;
+ margin: 0 0 10px;
+ }
+ .nav-collapse .nav > li {
+ float: none;
+ }
+ .nav-collapse .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .nav-collapse .nav > .divider-vertical {
+ display: none;
+ }
+ .nav-collapse .nav .nav-header {
+ color: #777777;
+ text-shadow: none;
+ }
+ .nav-collapse .nav > li > a,
+ .nav-collapse .dropdown-menu a {
+ padding: 9px 15px;
+ font-weight: bold;
+ color: #777777;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ }
+ .nav-collapse .btn {
+ padding: 4px 10px 4px;
+ font-weight: normal;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ }
+ .nav-collapse .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .nav-collapse .nav > li > a:hover,
+ .nav-collapse .nav > li > a:focus,
+ .nav-collapse .dropdown-menu a:hover,
+ .nav-collapse .dropdown-menu a:focus {
+ background-color: #f2f2f2;
+ }
+ .navbar-inverse .nav-collapse .nav > li > a,
+ .navbar-inverse .nav-collapse .dropdown-menu a {
+ color: #999999;
+ }
+ .navbar-inverse .nav-collapse .nav > li > a:hover,
+ .navbar-inverse .nav-collapse .nav > li > a:focus,
+ .navbar-inverse .nav-collapse .dropdown-menu a:hover,
+ .navbar-inverse .nav-collapse .dropdown-menu a:focus {
+ background-color: #111111;
+ }
+ .nav-collapse.in .btn-group {
+ padding: 0;
+ margin-top: 5px;
+ }
+ .nav-collapse .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ display: none;
+ float: none;
+ max-width: none;
+ padding: 0;
+ margin: 0 15px;
+ background-color: transparent;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ }
+ .nav-collapse .open > .dropdown-menu {
+ display: block;
+ }
+ .nav-collapse .dropdown-menu:before,
+ .nav-collapse .dropdown-menu:after {
+ display: none;
+ }
+ .nav-collapse .dropdown-menu .divider {
+ display: none;
+ }
+ .nav-collapse .nav > li > .dropdown-menu:before,
+ .nav-collapse .nav > li > .dropdown-menu:after {
+ display: none;
+ }
+ .nav-collapse .navbar-form,
+ .nav-collapse .navbar-search {
+ float: none;
+ padding: 10px 15px;
+ margin: 10px 0;
+ border-top: 1px solid #f2f2f2;
+ border-bottom: 1px solid #f2f2f2;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ }
+ .navbar-inverse .nav-collapse .navbar-form,
+ .navbar-inverse .nav-collapse .navbar-search {
+ border-top-color: #111111;
+ border-bottom-color: #111111;
+ }
+ .navbar .nav-collapse .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ .nav-collapse,
+ .nav-collapse.collapse {
+ height: 0;
+ overflow: hidden;
+ }
+ .navbar .btn-navbar {
+ display: block;
+ }
+ .navbar-static .navbar-inner {
+ padding-right: 10px;
+ padding-left: 10px;
+ }
+}
+
+@media (min-width: 980px) {
+ .nav-collapse.collapse {
+ height: auto !important;
+ overflow: visible !important;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.min.css b/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.min.css
new file mode 100644
index 0000000..f4ede63
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/bootstrap-responsive.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap Responsive v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
diff --git a/www/protected/extensions/bootstrap/assets/css/bootstrap.css b/www/protected/extensions/bootstrap/assets/css/bootstrap.css
new file mode 100644
index 0000000..b725064
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/bootstrap.css
@@ -0,0 +1,6167 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+ *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.clearfix:after {
+ clear: both;
+}
+
+.hide-text {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+
+audio:not([controls]) {
+ display: none;
+}
+
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+
+a:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+a:hover,
+a:active {
+ outline: 0;
+}
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+img {
+ width: auto\9;
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+
+#map_canvas img,
+.google-maps img {
+ max-width: none;
+}
+
+button,
+input,
+select,
+textarea {
+ margin: 0;
+ font-size: 100%;
+ vertical-align: middle;
+}
+
+button,
+input {
+ *overflow: visible;
+ line-height: normal;
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+}
+
+label,
+select,
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"],
+input[type="radio"],
+input[type="checkbox"] {
+ cursor: pointer;
+}
+
+input[type="search"] {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}
+
+textarea {
+ overflow: auto;
+ vertical-align: top;
+}
+
+@media print {
+ * {
+ color: #000 !important;
+ text-shadow: none !important;
+ background: transparent !important;
+ box-shadow: none !important;
+ }
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+ .ir a:after,
+ a[href^="javascript:"]:after,
+ a[href^="#"]:after {
+ content: "";
+ }
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ img {
+ max-width: 100% !important;
+ }
+ @page {
+ margin: 0.5cm;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+}
+
+body {
+ margin: 0;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 20px;
+ color: #333333;
+ background-color: #ffffff;
+}
+
+a {
+ color: #0088cc;
+ text-decoration: none;
+}
+
+a:hover,
+a:focus {
+ color: #005580;
+ text-decoration: underline;
+}
+
+.img-rounded {
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.img-polaroid {
+ padding: 4px;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.img-circle {
+ -webkit-border-radius: 500px;
+ -moz-border-radius: 500px;
+ border-radius: 500px;
+}
+
+.row {
+ margin-left: -20px;
+ *zoom: 1;
+}
+
+.row:before,
+.row:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.row:after {
+ clear: both;
+}
+
+[class*="span"] {
+ float: left;
+ min-height: 1px;
+ margin-left: 20px;
+}
+
+.container,
+.navbar-static-top .container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ width: 940px;
+}
+
+.span12 {
+ width: 940px;
+}
+
+.span11 {
+ width: 860px;
+}
+
+.span10 {
+ width: 780px;
+}
+
+.span9 {
+ width: 700px;
+}
+
+.span8 {
+ width: 620px;
+}
+
+.span7 {
+ width: 540px;
+}
+
+.span6 {
+ width: 460px;
+}
+
+.span5 {
+ width: 380px;
+}
+
+.span4 {
+ width: 300px;
+}
+
+.span3 {
+ width: 220px;
+}
+
+.span2 {
+ width: 140px;
+}
+
+.span1 {
+ width: 60px;
+}
+
+.offset12 {
+ margin-left: 980px;
+}
+
+.offset11 {
+ margin-left: 900px;
+}
+
+.offset10 {
+ margin-left: 820px;
+}
+
+.offset9 {
+ margin-left: 740px;
+}
+
+.offset8 {
+ margin-left: 660px;
+}
+
+.offset7 {
+ margin-left: 580px;
+}
+
+.offset6 {
+ margin-left: 500px;
+}
+
+.offset5 {
+ margin-left: 420px;
+}
+
+.offset4 {
+ margin-left: 340px;
+}
+
+.offset3 {
+ margin-left: 260px;
+}
+
+.offset2 {
+ margin-left: 180px;
+}
+
+.offset1 {
+ margin-left: 100px;
+}
+
+.row-fluid {
+ width: 100%;
+ *zoom: 1;
+}
+
+.row-fluid:before,
+.row-fluid:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.row-fluid:after {
+ clear: both;
+}
+
+.row-fluid [class*="span"] {
+ display: block;
+ float: left;
+ width: 100%;
+ min-height: 30px;
+ margin-left: 2.127659574468085%;
+ *margin-left: 2.074468085106383%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.row-fluid [class*="span"]:first-child {
+ margin-left: 0;
+}
+
+.row-fluid .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 2.127659574468085%;
+}
+
+.row-fluid .span12 {
+ width: 100%;
+ *width: 99.94680851063829%;
+}
+
+.row-fluid .span11 {
+ width: 91.48936170212765%;
+ *width: 91.43617021276594%;
+}
+
+.row-fluid .span10 {
+ width: 82.97872340425532%;
+ *width: 82.92553191489361%;
+}
+
+.row-fluid .span9 {
+ width: 74.46808510638297%;
+ *width: 74.41489361702126%;
+}
+
+.row-fluid .span8 {
+ width: 65.95744680851064%;
+ *width: 65.90425531914893%;
+}
+
+.row-fluid .span7 {
+ width: 57.44680851063829%;
+ *width: 57.39361702127659%;
+}
+
+.row-fluid .span6 {
+ width: 48.93617021276595%;
+ *width: 48.88297872340425%;
+}
+
+.row-fluid .span5 {
+ width: 40.42553191489362%;
+ *width: 40.37234042553192%;
+}
+
+.row-fluid .span4 {
+ width: 31.914893617021278%;
+ *width: 31.861702127659576%;
+}
+
+.row-fluid .span3 {
+ width: 23.404255319148934%;
+ *width: 23.351063829787233%;
+}
+
+.row-fluid .span2 {
+ width: 14.893617021276595%;
+ *width: 14.840425531914894%;
+}
+
+.row-fluid .span1 {
+ width: 6.382978723404255%;
+ *width: 6.329787234042553%;
+}
+
+.row-fluid .offset12 {
+ margin-left: 104.25531914893617%;
+ *margin-left: 104.14893617021275%;
+}
+
+.row-fluid .offset12:first-child {
+ margin-left: 102.12765957446808%;
+ *margin-left: 102.02127659574467%;
+}
+
+.row-fluid .offset11 {
+ margin-left: 95.74468085106382%;
+ *margin-left: 95.6382978723404%;
+}
+
+.row-fluid .offset11:first-child {
+ margin-left: 93.61702127659574%;
+ *margin-left: 93.51063829787232%;
+}
+
+.row-fluid .offset10 {
+ margin-left: 87.23404255319149%;
+ *margin-left: 87.12765957446807%;
+}
+
+.row-fluid .offset10:first-child {
+ margin-left: 85.1063829787234%;
+ *margin-left: 84.99999999999999%;
+}
+
+.row-fluid .offset9 {
+ margin-left: 78.72340425531914%;
+ *margin-left: 78.61702127659572%;
+}
+
+.row-fluid .offset9:first-child {
+ margin-left: 76.59574468085106%;
+ *margin-left: 76.48936170212764%;
+}
+
+.row-fluid .offset8 {
+ margin-left: 70.2127659574468%;
+ *margin-left: 70.10638297872339%;
+}
+
+.row-fluid .offset8:first-child {
+ margin-left: 68.08510638297872%;
+ *margin-left: 67.9787234042553%;
+}
+
+.row-fluid .offset7 {
+ margin-left: 61.70212765957446%;
+ *margin-left: 61.59574468085106%;
+}
+
+.row-fluid .offset7:first-child {
+ margin-left: 59.574468085106375%;
+ *margin-left: 59.46808510638297%;
+}
+
+.row-fluid .offset6 {
+ margin-left: 53.191489361702125%;
+ *margin-left: 53.085106382978715%;
+}
+
+.row-fluid .offset6:first-child {
+ margin-left: 51.063829787234035%;
+ *margin-left: 50.95744680851063%;
+}
+
+.row-fluid .offset5 {
+ margin-left: 44.68085106382979%;
+ *margin-left: 44.57446808510638%;
+}
+
+.row-fluid .offset5:first-child {
+ margin-left: 42.5531914893617%;
+ *margin-left: 42.4468085106383%;
+}
+
+.row-fluid .offset4 {
+ margin-left: 36.170212765957444%;
+ *margin-left: 36.06382978723405%;
+}
+
+.row-fluid .offset4:first-child {
+ margin-left: 34.04255319148936%;
+ *margin-left: 33.93617021276596%;
+}
+
+.row-fluid .offset3 {
+ margin-left: 27.659574468085104%;
+ *margin-left: 27.5531914893617%;
+}
+
+.row-fluid .offset3:first-child {
+ margin-left: 25.53191489361702%;
+ *margin-left: 25.425531914893618%;
+}
+
+.row-fluid .offset2 {
+ margin-left: 19.148936170212764%;
+ *margin-left: 19.04255319148936%;
+}
+
+.row-fluid .offset2:first-child {
+ margin-left: 17.02127659574468%;
+ *margin-left: 16.914893617021278%;
+}
+
+.row-fluid .offset1 {
+ margin-left: 10.638297872340425%;
+ *margin-left: 10.53191489361702%;
+}
+
+.row-fluid .offset1:first-child {
+ margin-left: 8.51063829787234%;
+ *margin-left: 8.404255319148938%;
+}
+
+[class*="span"].hide,
+.row-fluid [class*="span"].hide {
+ display: none;
+}
+
+[class*="span"].pull-right,
+.row-fluid [class*="span"].pull-right {
+ float: right;
+}
+
+.container {
+ margin-right: auto;
+ margin-left: auto;
+ *zoom: 1;
+}
+
+.container:before,
+.container:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.container:after {
+ clear: both;
+}
+
+.container-fluid {
+ padding-right: 20px;
+ padding-left: 20px;
+ *zoom: 1;
+}
+
+.container-fluid:before,
+.container-fluid:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.container-fluid:after {
+ clear: both;
+}
+
+p {
+ margin: 0 0 10px;
+}
+
+.lead {
+ margin-bottom: 20px;
+ font-size: 21px;
+ font-weight: 200;
+ line-height: 30px;
+}
+
+small {
+ font-size: 85%;
+}
+
+strong {
+ font-weight: bold;
+}
+
+em {
+ font-style: italic;
+}
+
+cite {
+ font-style: normal;
+}
+
+.muted {
+ color: #999999;
+}
+
+a.muted:hover,
+a.muted:focus {
+ color: #808080;
+}
+
+.text-warning {
+ color: #c09853;
+}
+
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #a47e3c;
+}
+
+.text-error {
+ color: #b94a48;
+}
+
+a.text-error:hover,
+a.text-error:focus {
+ color: #953b39;
+}
+
+.text-info {
+ color: #3a87ad;
+}
+
+a.text-info:hover,
+a.text-info:focus {
+ color: #2d6987;
+}
+
+.text-success {
+ color: #468847;
+}
+
+a.text-success:hover,
+a.text-success:focus {
+ color: #356635;
+}
+
+.text-left {
+ text-align: left;
+}
+
+.text-right {
+ text-align: right;
+}
+
+.text-center {
+ text-align: center;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin: 10px 0;
+ font-family: inherit;
+ font-weight: bold;
+ line-height: 20px;
+ color: inherit;
+ text-rendering: optimizelegibility;
+}
+
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+ font-weight: normal;
+ line-height: 1;
+ color: #999999;
+}
+
+h1,
+h2,
+h3 {
+ line-height: 40px;
+}
+
+h1 {
+ font-size: 38.5px;
+}
+
+h2 {
+ font-size: 31.5px;
+}
+
+h3 {
+ font-size: 24.5px;
+}
+
+h4 {
+ font-size: 17.5px;
+}
+
+h5 {
+ font-size: 14px;
+}
+
+h6 {
+ font-size: 11.9px;
+}
+
+h1 small {
+ font-size: 24.5px;
+}
+
+h2 small {
+ font-size: 17.5px;
+}
+
+h3 small {
+ font-size: 14px;
+}
+
+h4 small {
+ font-size: 14px;
+}
+
+.page-header {
+ padding-bottom: 9px;
+ margin: 20px 0 30px;
+ border-bottom: 1px solid #eeeeee;
+}
+
+ul,
+ol {
+ padding: 0;
+ margin: 0 0 10px 25px;
+}
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+
+li {
+ line-height: 20px;
+}
+
+ul.unstyled,
+ol.unstyled {
+ margin-left: 0;
+ list-style: none;
+}
+
+ul.inline,
+ol.inline {
+ margin-left: 0;
+ list-style: none;
+}
+
+ul.inline > li,
+ol.inline > li {
+ display: inline-block;
+ *display: inline;
+ padding-right: 5px;
+ padding-left: 5px;
+ *zoom: 1;
+}
+
+dl {
+ margin-bottom: 20px;
+}
+
+dt,
+dd {
+ line-height: 20px;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd {
+ margin-left: 10px;
+}
+
+.dl-horizontal {
+ *zoom: 1;
+}
+
+.dl-horizontal:before,
+.dl-horizontal:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.dl-horizontal:after {
+ clear: both;
+}
+
+.dl-horizontal dt {
+ float: left;
+ width: 160px;
+ overflow: hidden;
+ clear: left;
+ text-align: right;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.dl-horizontal dd {
+ margin-left: 180px;
+}
+
+hr {
+ margin: 20px 0;
+ border: 0;
+ border-top: 1px solid #eeeeee;
+ border-bottom: 1px solid #ffffff;
+}
+
+abbr[title],
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted #999999;
+}
+
+abbr.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+
+blockquote {
+ padding: 0 0 0 15px;
+ margin: 0 0 20px;
+ border-left: 5px solid #eeeeee;
+}
+
+blockquote p {
+ margin-bottom: 0;
+ font-size: 17.5px;
+ font-weight: 300;
+ line-height: 1.25;
+}
+
+blockquote small {
+ display: block;
+ line-height: 20px;
+ color: #999999;
+}
+
+blockquote small:before {
+ content: '\2014 \00A0';
+}
+
+blockquote.pull-right {
+ float: right;
+ padding-right: 15px;
+ padding-left: 0;
+ border-right: 5px solid #eeeeee;
+ border-left: 0;
+}
+
+blockquote.pull-right p,
+blockquote.pull-right small {
+ text-align: right;
+}
+
+blockquote.pull-right small:before {
+ content: '';
+}
+
+blockquote.pull-right small:after {
+ content: '\00A0 \2014';
+}
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+
+address {
+ display: block;
+ margin-bottom: 20px;
+ font-style: normal;
+ line-height: 20px;
+}
+
+code,
+pre {
+ padding: 0 3px 2px;
+ font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
+ font-size: 12px;
+ color: #333333;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+code {
+ padding: 2px 4px;
+ color: #d14;
+ white-space: nowrap;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+}
+
+pre {
+ display: block;
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ line-height: 20px;
+ word-break: break-all;
+ word-wrap: break-word;
+ white-space: pre;
+ white-space: pre-wrap;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+pre.prettyprint {
+ margin-bottom: 20px;
+}
+
+pre code {
+ padding: 0;
+ color: inherit;
+ white-space: pre;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border: 0;
+}
+
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+
+form {
+ margin: 0 0 20px;
+}
+
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 20px;
+ font-size: 21px;
+ line-height: 40px;
+ color: #333333;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+}
+
+legend small {
+ font-size: 15px;
+ color: #999999;
+}
+
+label,
+input,
+button,
+select,
+textarea {
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 20px;
+}
+
+input,
+button,
+select,
+textarea {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+label {
+ display: block;
+ margin-bottom: 5px;
+}
+
+select,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+ display: inline-block;
+ height: 20px;
+ padding: 4px 6px;
+ margin-bottom: 10px;
+ font-size: 14px;
+ line-height: 20px;
+ color: #555555;
+ vertical-align: middle;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+input,
+textarea,
+.uneditable-input {
+ width: 206px;
+}
+
+textarea {
+ height: auto;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+ transition: border linear 0.2s, box-shadow linear 0.2s;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="datetime"]:focus,
+input[type="datetime-local"]:focus,
+input[type="date"]:focus,
+input[type="month"]:focus,
+input[type="time"]:focus,
+input[type="week"]:focus,
+input[type="number"]:focus,
+input[type="email"]:focus,
+input[type="url"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="color"]:focus,
+.uneditable-input:focus {
+ border-color: rgba(82, 168, 236, 0.8);
+ outline: 0;
+ outline: thin dotted \9;
+ /* IE6-9 */
+
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9;
+ *margin-top: 0;
+ line-height: normal;
+}
+
+input[type="file"],
+input[type="image"],
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+ width: auto;
+}
+
+select,
+input[type="file"] {
+ height: 30px;
+ /* In IE7, the height of the select element cannot be changed by height, only font-size */
+
+ *margin-top: 4px;
+ /* For IE7, add top margin to align select with labels */
+
+ line-height: 30px;
+}
+
+select {
+ width: 220px;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+}
+
+select[multiple],
+select[size] {
+ height: auto;
+}
+
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+.uneditable-input,
+.uneditable-textarea {
+ color: #999999;
+ cursor: not-allowed;
+ background-color: #fcfcfc;
+ border-color: #cccccc;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+}
+
+.uneditable-input {
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.uneditable-textarea {
+ width: auto;
+ height: auto;
+}
+
+input:-moz-placeholder,
+textarea:-moz-placeholder {
+ color: #999999;
+}
+
+input:-ms-input-placeholder,
+textarea:-ms-input-placeholder {
+ color: #999999;
+}
+
+input::-webkit-input-placeholder,
+textarea::-webkit-input-placeholder {
+ color: #999999;
+}
+
+.radio,
+.checkbox {
+ min-height: 20px;
+ padding-left: 20px;
+}
+
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+ float: left;
+ margin-left: -20px;
+}
+
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+ padding-top: 5px;
+}
+
+.radio.inline,
+.checkbox.inline {
+ display: inline-block;
+ padding-top: 5px;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+ margin-left: 10px;
+}
+
+.input-mini {
+ width: 60px;
+}
+
+.input-small {
+ width: 90px;
+}
+
+.input-medium {
+ width: 150px;
+}
+
+.input-large {
+ width: 210px;
+}
+
+.input-xlarge {
+ width: 270px;
+}
+
+.input-xxlarge {
+ width: 530px;
+}
+
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"] {
+ float: none;
+ margin-left: 0;
+}
+
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
+ display: inline-block;
+}
+
+input,
+textarea,
+.uneditable-input {
+ margin-left: 0;
+}
+
+.controls-row [class*="span"] + [class*="span"] {
+ margin-left: 20px;
+}
+
+input.span12,
+textarea.span12,
+.uneditable-input.span12 {
+ width: 926px;
+}
+
+input.span11,
+textarea.span11,
+.uneditable-input.span11 {
+ width: 846px;
+}
+
+input.span10,
+textarea.span10,
+.uneditable-input.span10 {
+ width: 766px;
+}
+
+input.span9,
+textarea.span9,
+.uneditable-input.span9 {
+ width: 686px;
+}
+
+input.span8,
+textarea.span8,
+.uneditable-input.span8 {
+ width: 606px;
+}
+
+input.span7,
+textarea.span7,
+.uneditable-input.span7 {
+ width: 526px;
+}
+
+input.span6,
+textarea.span6,
+.uneditable-input.span6 {
+ width: 446px;
+}
+
+input.span5,
+textarea.span5,
+.uneditable-input.span5 {
+ width: 366px;
+}
+
+input.span4,
+textarea.span4,
+.uneditable-input.span4 {
+ width: 286px;
+}
+
+input.span3,
+textarea.span3,
+.uneditable-input.span3 {
+ width: 206px;
+}
+
+input.span2,
+textarea.span2,
+.uneditable-input.span2 {
+ width: 126px;
+}
+
+input.span1,
+textarea.span1,
+.uneditable-input.span1 {
+ width: 46px;
+}
+
+.controls-row {
+ *zoom: 1;
+}
+
+.controls-row:before,
+.controls-row:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.controls-row:after {
+ clear: both;
+}
+
+.controls-row [class*="span"],
+.row-fluid .controls-row [class*="span"] {
+ float: left;
+}
+
+.controls-row .checkbox[class*="span"],
+.controls-row .radio[class*="span"] {
+ padding-top: 5px;
+}
+
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ cursor: not-allowed;
+ background-color: #eeeeee;
+}
+
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
+ background-color: transparent;
+}
+
+.control-group.warning .control-label,
+.control-group.warning .help-block,
+.control-group.warning .help-inline {
+ color: #c09853;
+}
+
+.control-group.warning .checkbox,
+.control-group.warning .radio,
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+ color: #c09853;
+}
+
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+ border-color: #c09853;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.control-group.warning input:focus,
+.control-group.warning select:focus,
+.control-group.warning textarea:focus {
+ border-color: #a47e3c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+}
+
+.control-group.warning .input-prepend .add-on,
+.control-group.warning .input-append .add-on {
+ color: #c09853;
+ background-color: #fcf8e3;
+ border-color: #c09853;
+}
+
+.control-group.error .control-label,
+.control-group.error .help-block,
+.control-group.error .help-inline {
+ color: #b94a48;
+}
+
+.control-group.error .checkbox,
+.control-group.error .radio,
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+ color: #b94a48;
+}
+
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+ border-color: #b94a48;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.control-group.error input:focus,
+.control-group.error select:focus,
+.control-group.error textarea:focus {
+ border-color: #953b39;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+}
+
+.control-group.error .input-prepend .add-on,
+.control-group.error .input-append .add-on {
+ color: #b94a48;
+ background-color: #f2dede;
+ border-color: #b94a48;
+}
+
+.control-group.success .control-label,
+.control-group.success .help-block,
+.control-group.success .help-inline {
+ color: #468847;
+}
+
+.control-group.success .checkbox,
+.control-group.success .radio,
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+ color: #468847;
+}
+
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+ border-color: #468847;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.control-group.success input:focus,
+.control-group.success select:focus,
+.control-group.success textarea:focus {
+ border-color: #356635;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+}
+
+.control-group.success .input-prepend .add-on,
+.control-group.success .input-append .add-on {
+ color: #468847;
+ background-color: #dff0d8;
+ border-color: #468847;
+}
+
+.control-group.info .control-label,
+.control-group.info .help-block,
+.control-group.info .help-inline {
+ color: #3a87ad;
+}
+
+.control-group.info .checkbox,
+.control-group.info .radio,
+.control-group.info input,
+.control-group.info select,
+.control-group.info textarea {
+ color: #3a87ad;
+}
+
+.control-group.info input,
+.control-group.info select,
+.control-group.info textarea {
+ border-color: #3a87ad;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.control-group.info input:focus,
+.control-group.info select:focus,
+.control-group.info textarea:focus {
+ border-color: #2d6987;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+}
+
+.control-group.info .input-prepend .add-on,
+.control-group.info .input-append .add-on {
+ color: #3a87ad;
+ background-color: #d9edf7;
+ border-color: #3a87ad;
+}
+
+input:focus:invalid,
+textarea:focus:invalid,
+select:focus:invalid {
+ color: #b94a48;
+ border-color: #ee5f5b;
+}
+
+input:focus:invalid:focus,
+textarea:focus:invalid:focus,
+select:focus:invalid:focus {
+ border-color: #e9322d;
+ -webkit-box-shadow: 0 0 6px #f8b9b7;
+ -moz-box-shadow: 0 0 6px #f8b9b7;
+ box-shadow: 0 0 6px #f8b9b7;
+}
+
+.form-actions {
+ padding: 19px 20px 20px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #e5e5e5;
+ *zoom: 1;
+}
+
+.form-actions:before,
+.form-actions:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.form-actions:after {
+ clear: both;
+}
+
+.help-block,
+.help-inline {
+ color: #595959;
+}
+
+.help-block {
+ display: block;
+ margin-bottom: 10px;
+}
+
+.help-inline {
+ display: inline-block;
+ *display: inline;
+ padding-left: 5px;
+ vertical-align: middle;
+ *zoom: 1;
+}
+
+.input-append,
+.input-prepend {
+ display: inline-block;
+ margin-bottom: 10px;
+ font-size: 0;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+.input-append input,
+.input-prepend input,
+.input-append select,
+.input-prepend select,
+.input-append .uneditable-input,
+.input-prepend .uneditable-input,
+.input-append .dropdown-menu,
+.input-prepend .dropdown-menu,
+.input-append .popover,
+.input-prepend .popover {
+ font-size: 14px;
+}
+
+.input-append input,
+.input-prepend input,
+.input-append select,
+.input-prepend select,
+.input-append .uneditable-input,
+.input-prepend .uneditable-input {
+ position: relative;
+ margin-bottom: 0;
+ *margin-left: 0;
+ vertical-align: top;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.input-append input:focus,
+.input-prepend input:focus,
+.input-append select:focus,
+.input-prepend select:focus,
+.input-append .uneditable-input:focus,
+.input-prepend .uneditable-input:focus {
+ z-index: 2;
+}
+
+.input-append .add-on,
+.input-prepend .add-on {
+ display: inline-block;
+ width: auto;
+ height: 20px;
+ min-width: 16px;
+ padding: 4px 5px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 20px;
+ text-align: center;
+ text-shadow: 0 1px 0 #ffffff;
+ background-color: #eeeeee;
+ border: 1px solid #ccc;
+}
+
+.input-append .add-on,
+.input-prepend .add-on,
+.input-append .btn,
+.input-prepend .btn,
+.input-append .btn-group > .dropdown-toggle,
+.input-prepend .btn-group > .dropdown-toggle {
+ vertical-align: top;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.input-append .active,
+.input-prepend .active {
+ background-color: #a9dba9;
+ border-color: #46a546;
+}
+
+.input-prepend .add-on,
+.input-prepend .btn {
+ margin-right: -1px;
+}
+
+.input-prepend .add-on:first-child,
+.input-prepend .btn:first-child {
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+
+.input-append input,
+.input-append select,
+.input-append .uneditable-input {
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+
+.input-append input + .btn-group .btn:last-child,
+.input-append select + .btn-group .btn:last-child,
+.input-append .uneditable-input + .btn-group .btn:last-child {
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.input-append .add-on,
+.input-append .btn,
+.input-append .btn-group {
+ margin-left: -1px;
+}
+
+.input-append .add-on:last-child,
+.input-append .btn:last-child,
+.input-append .btn-group:last-child > .dropdown-toggle {
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.input-prepend.input-append input,
+.input-prepend.input-append select,
+.input-prepend.input-append .uneditable-input {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.input-prepend.input-append input + .btn-group .btn,
+.input-prepend.input-append select + .btn-group .btn,
+.input-prepend.input-append .uneditable-input + .btn-group .btn {
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.input-prepend.input-append .add-on:first-child,
+.input-prepend.input-append .btn:first-child {
+ margin-right: -1px;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+
+.input-prepend.input-append .add-on:last-child,
+.input-prepend.input-append .btn:last-child {
+ margin-left: -1px;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.input-prepend.input-append .btn-group:first-child {
+ margin-left: 0;
+}
+
+input.search-query {
+ padding-right: 14px;
+ padding-right: 4px \9;
+ padding-left: 14px;
+ padding-left: 4px \9;
+ /* IE7-8 doesn't have border-radius, so don't indent the padding */
+
+ margin-bottom: 0;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+
+/* Allow for input prepend/append in search forms */
+
+.form-search .input-append .search-query,
+.form-search .input-prepend .search-query {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.form-search .input-append .search-query {
+ -webkit-border-radius: 14px 0 0 14px;
+ -moz-border-radius: 14px 0 0 14px;
+ border-radius: 14px 0 0 14px;
+}
+
+.form-search .input-append .btn {
+ -webkit-border-radius: 0 14px 14px 0;
+ -moz-border-radius: 0 14px 14px 0;
+ border-radius: 0 14px 14px 0;
+}
+
+.form-search .input-prepend .search-query {
+ -webkit-border-radius: 0 14px 14px 0;
+ -moz-border-radius: 0 14px 14px 0;
+ border-radius: 0 14px 14px 0;
+}
+
+.form-search .input-prepend .btn {
+ -webkit-border-radius: 14px 0 0 14px;
+ -moz-border-radius: 14px 0 0 14px;
+ border-radius: 14px 0 0 14px;
+}
+
+.form-search input,
+.form-inline input,
+.form-horizontal input,
+.form-search textarea,
+.form-inline textarea,
+.form-horizontal textarea,
+.form-search select,
+.form-inline select,
+.form-horizontal select,
+.form-search .help-inline,
+.form-inline .help-inline,
+.form-horizontal .help-inline,
+.form-search .uneditable-input,
+.form-inline .uneditable-input,
+.form-horizontal .uneditable-input,
+.form-search .input-prepend,
+.form-inline .input-prepend,
+.form-horizontal .input-prepend,
+.form-search .input-append,
+.form-inline .input-append,
+.form-horizontal .input-append {
+ display: inline-block;
+ *display: inline;
+ margin-bottom: 0;
+ vertical-align: middle;
+ *zoom: 1;
+}
+
+.form-search .hide,
+.form-inline .hide,
+.form-horizontal .hide {
+ display: none;
+}
+
+.form-search label,
+.form-inline label,
+.form-search .btn-group,
+.form-inline .btn-group {
+ display: inline-block;
+}
+
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+ margin-bottom: 0;
+}
+
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+ padding-left: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+
+.form-search .radio input[type="radio"],
+.form-search .checkbox input[type="checkbox"],
+.form-inline .radio input[type="radio"],
+.form-inline .checkbox input[type="checkbox"] {
+ float: left;
+ margin-right: 3px;
+ margin-left: 0;
+}
+
+.control-group {
+ margin-bottom: 10px;
+}
+
+legend + .control-group {
+ margin-top: 20px;
+ -webkit-margin-top-collapse: separate;
+}
+
+.form-horizontal .control-group {
+ margin-bottom: 20px;
+ *zoom: 1;
+}
+
+.form-horizontal .control-group:before,
+.form-horizontal .control-group:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.form-horizontal .control-group:after {
+ clear: both;
+}
+
+.form-horizontal .control-label {
+ float: left;
+ width: 160px;
+ padding-top: 5px;
+ text-align: right;
+}
+
+.form-horizontal .controls {
+ *display: inline-block;
+ *padding-left: 20px;
+ margin-left: 180px;
+ *margin-left: 0;
+}
+
+.form-horizontal .controls:first-child {
+ *padding-left: 180px;
+}
+
+.form-horizontal .help-block {
+ margin-bottom: 0;
+}
+
+.form-horizontal input + .help-block,
+.form-horizontal select + .help-block,
+.form-horizontal textarea + .help-block,
+.form-horizontal .uneditable-input + .help-block,
+.form-horizontal .input-prepend + .help-block,
+.form-horizontal .input-append + .help-block {
+ margin-top: 10px;
+}
+
+.form-horizontal .form-actions {
+ padding-left: 180px;
+}
+
+table {
+ max-width: 100%;
+ background-color: transparent;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.table {
+ width: 100%;
+ margin-bottom: 20px;
+}
+
+.table th,
+.table td {
+ padding: 8px;
+ line-height: 20px;
+ text-align: left;
+ vertical-align: top;
+ border-top: 1px solid #dddddd;
+}
+
+.table th {
+ font-weight: bold;
+}
+
+.table thead th {
+ vertical-align: bottom;
+}
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+ border-top: 0;
+}
+
+.table tbody + tbody {
+ border-top: 2px solid #dddddd;
+}
+
+.table .table {
+ background-color: #ffffff;
+}
+
+.table-condensed th,
+.table-condensed td {
+ padding: 4px 5px;
+}
+
+.table-bordered {
+ border: 1px solid #dddddd;
+ border-collapse: separate;
+ *border-collapse: collapse;
+ border-left: 0;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.table-bordered th,
+.table-bordered td {
+ border-left: 1px solid #dddddd;
+}
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+ border-top: 0;
+}
+
+.table-bordered thead:first-child tr:first-child > th:first-child,
+.table-bordered tbody:first-child tr:first-child > td:first-child,
+.table-bordered tbody:first-child tr:first-child > th:first-child {
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered thead:first-child tr:first-child > th:last-child,
+.table-bordered tbody:first-child tr:first-child > td:last-child,
+.table-bordered tbody:first-child tr:first-child > th:last-child {
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:first-child,
+.table-bordered tbody:last-child tr:last-child > td:first-child,
+.table-bordered tbody:last-child tr:last-child > th:first-child,
+.table-bordered tfoot:last-child tr:last-child > td:first-child,
+.table-bordered tfoot:last-child tr:last-child > th:first-child {
+ -webkit-border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:last-child,
+.table-bordered tbody:last-child tr:last-child > td:last-child,
+.table-bordered tbody:last-child tr:last-child > th:last-child,
+.table-bordered tfoot:last-child tr:last-child > td:last-child,
+.table-bordered tfoot:last-child tr:last-child > th:last-child {
+ -webkit-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
+ -webkit-border-bottom-left-radius: 0;
+ border-bottom-left-radius: 0;
+ -moz-border-radius-bottomleft: 0;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
+ -webkit-border-bottom-right-radius: 0;
+ border-bottom-right-radius: 0;
+ -moz-border-radius-bottomright: 0;
+}
+
+.table-bordered caption + thead tr:first-child th:first-child,
+.table-bordered caption + tbody tr:first-child td:first-child,
+.table-bordered colgroup + thead tr:first-child th:first-child,
+.table-bordered colgroup + tbody tr:first-child td:first-child {
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered caption + thead tr:first-child th:last-child,
+.table-bordered caption + tbody tr:first-child td:last-child,
+.table-bordered colgroup + thead tr:first-child th:last-child,
+.table-bordered colgroup + tbody tr:first-child td:last-child {
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+}
+
+.table-striped tbody > tr:nth-child(odd) > td,
+.table-striped tbody > tr:nth-child(odd) > th {
+ background-color: #f9f9f9;
+}
+
+.table-hover tbody tr:hover > td,
+.table-hover tbody tr:hover > th {
+ background-color: #f5f5f5;
+}
+
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+ display: table-cell;
+ float: none;
+ margin-left: 0;
+}
+
+.table td.span1,
+.table th.span1 {
+ float: none;
+ width: 44px;
+ margin-left: 0;
+}
+
+.table td.span2,
+.table th.span2 {
+ float: none;
+ width: 124px;
+ margin-left: 0;
+}
+
+.table td.span3,
+.table th.span3 {
+ float: none;
+ width: 204px;
+ margin-left: 0;
+}
+
+.table td.span4,
+.table th.span4 {
+ float: none;
+ width: 284px;
+ margin-left: 0;
+}
+
+.table td.span5,
+.table th.span5 {
+ float: none;
+ width: 364px;
+ margin-left: 0;
+}
+
+.table td.span6,
+.table th.span6 {
+ float: none;
+ width: 444px;
+ margin-left: 0;
+}
+
+.table td.span7,
+.table th.span7 {
+ float: none;
+ width: 524px;
+ margin-left: 0;
+}
+
+.table td.span8,
+.table th.span8 {
+ float: none;
+ width: 604px;
+ margin-left: 0;
+}
+
+.table td.span9,
+.table th.span9 {
+ float: none;
+ width: 684px;
+ margin-left: 0;
+}
+
+.table td.span10,
+.table th.span10 {
+ float: none;
+ width: 764px;
+ margin-left: 0;
+}
+
+.table td.span11,
+.table th.span11 {
+ float: none;
+ width: 844px;
+ margin-left: 0;
+}
+
+.table td.span12,
+.table th.span12 {
+ float: none;
+ width: 924px;
+ margin-left: 0;
+}
+
+.table tbody tr.success > td {
+ background-color: #dff0d8;
+}
+
+.table tbody tr.error > td {
+ background-color: #f2dede;
+}
+
+.table tbody tr.warning > td {
+ background-color: #fcf8e3;
+}
+
+.table tbody tr.info > td {
+ background-color: #d9edf7;
+}
+
+.table-hover tbody tr.success:hover > td {
+ background-color: #d0e9c6;
+}
+
+.table-hover tbody tr.error:hover > td {
+ background-color: #ebcccc;
+}
+
+.table-hover tbody tr.warning:hover > td {
+ background-color: #faf2cc;
+}
+
+.table-hover tbody tr.info:hover > td {
+ background-color: #c4e3f3;
+}
+
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-top: 1px;
+ *margin-right: .3em;
+ line-height: 14px;
+ vertical-align: text-top;
+ background-image: url("../img/glyphicons-halflings.png");
+ background-position: 14px 14px;
+ background-repeat: no-repeat;
+}
+
+/* White icons with optional class, or on hover/focus/active states of certain elements */
+
+.icon-white,
+.nav-pills > .active > a > [class^="icon-"],
+.nav-pills > .active > a > [class*=" icon-"],
+.nav-list > .active > a > [class^="icon-"],
+.nav-list > .active > a > [class*=" icon-"],
+.navbar-inverse .nav > .active > a > [class^="icon-"],
+.navbar-inverse .nav > .active > a > [class*=" icon-"],
+.dropdown-menu > li > a:hover > [class^="icon-"],
+.dropdown-menu > li > a:focus > [class^="icon-"],
+.dropdown-menu > li > a:hover > [class*=" icon-"],
+.dropdown-menu > li > a:focus > [class*=" icon-"],
+.dropdown-menu > .active > a > [class^="icon-"],
+.dropdown-menu > .active > a > [class*=" icon-"],
+.dropdown-submenu:hover > a > [class^="icon-"],
+.dropdown-submenu:focus > a > [class^="icon-"],
+.dropdown-submenu:hover > a > [class*=" icon-"],
+.dropdown-submenu:focus > a > [class*=" icon-"] {
+ background-image: url("../img/glyphicons-halflings-white.png");
+}
+
+.icon-glass {
+ background-position: 0 0;
+}
+
+.icon-music {
+ background-position: -24px 0;
+}
+
+.icon-search {
+ background-position: -48px 0;
+}
+
+.icon-envelope {
+ background-position: -72px 0;
+}
+
+.icon-heart {
+ background-position: -96px 0;
+}
+
+.icon-star {
+ background-position: -120px 0;
+}
+
+.icon-star-empty {
+ background-position: -144px 0;
+}
+
+.icon-user {
+ background-position: -168px 0;
+}
+
+.icon-film {
+ background-position: -192px 0;
+}
+
+.icon-th-large {
+ background-position: -216px 0;
+}
+
+.icon-th {
+ background-position: -240px 0;
+}
+
+.icon-th-list {
+ background-position: -264px 0;
+}
+
+.icon-ok {
+ background-position: -288px 0;
+}
+
+.icon-remove {
+ background-position: -312px 0;
+}
+
+.icon-zoom-in {
+ background-position: -336px 0;
+}
+
+.icon-zoom-out {
+ background-position: -360px 0;
+}
+
+.icon-off {
+ background-position: -384px 0;
+}
+
+.icon-signal {
+ background-position: -408px 0;
+}
+
+.icon-cog {
+ background-position: -432px 0;
+}
+
+.icon-trash {
+ background-position: -456px 0;
+}
+
+.icon-home {
+ background-position: 0 -24px;
+}
+
+.icon-file {
+ background-position: -24px -24px;
+}
+
+.icon-time {
+ background-position: -48px -24px;
+}
+
+.icon-road {
+ background-position: -72px -24px;
+}
+
+.icon-download-alt {
+ background-position: -96px -24px;
+}
+
+.icon-download {
+ background-position: -120px -24px;
+}
+
+.icon-upload {
+ background-position: -144px -24px;
+}
+
+.icon-inbox {
+ background-position: -168px -24px;
+}
+
+.icon-play-circle {
+ background-position: -192px -24px;
+}
+
+.icon-repeat {
+ background-position: -216px -24px;
+}
+
+.icon-refresh {
+ background-position: -240px -24px;
+}
+
+.icon-list-alt {
+ background-position: -264px -24px;
+}
+
+.icon-lock {
+ background-position: -287px -24px;
+}
+
+.icon-flag {
+ background-position: -312px -24px;
+}
+
+.icon-headphones {
+ background-position: -336px -24px;
+}
+
+.icon-volume-off {
+ background-position: -360px -24px;
+}
+
+.icon-volume-down {
+ background-position: -384px -24px;
+}
+
+.icon-volume-up {
+ background-position: -408px -24px;
+}
+
+.icon-qrcode {
+ background-position: -432px -24px;
+}
+
+.icon-barcode {
+ background-position: -456px -24px;
+}
+
+.icon-tag {
+ background-position: 0 -48px;
+}
+
+.icon-tags {
+ background-position: -25px -48px;
+}
+
+.icon-book {
+ background-position: -48px -48px;
+}
+
+.icon-bookmark {
+ background-position: -72px -48px;
+}
+
+.icon-print {
+ background-position: -96px -48px;
+}
+
+.icon-camera {
+ background-position: -120px -48px;
+}
+
+.icon-font {
+ background-position: -144px -48px;
+}
+
+.icon-bold {
+ background-position: -167px -48px;
+}
+
+.icon-italic {
+ background-position: -192px -48px;
+}
+
+.icon-text-height {
+ background-position: -216px -48px;
+}
+
+.icon-text-width {
+ background-position: -240px -48px;
+}
+
+.icon-align-left {
+ background-position: -264px -48px;
+}
+
+.icon-align-center {
+ background-position: -288px -48px;
+}
+
+.icon-align-right {
+ background-position: -312px -48px;
+}
+
+.icon-align-justify {
+ background-position: -336px -48px;
+}
+
+.icon-list {
+ background-position: -360px -48px;
+}
+
+.icon-indent-left {
+ background-position: -384px -48px;
+}
+
+.icon-indent-right {
+ background-position: -408px -48px;
+}
+
+.icon-facetime-video {
+ background-position: -432px -48px;
+}
+
+.icon-picture {
+ background-position: -456px -48px;
+}
+
+.icon-pencil {
+ background-position: 0 -72px;
+}
+
+.icon-map-marker {
+ background-position: -24px -72px;
+}
+
+.icon-adjust {
+ background-position: -48px -72px;
+}
+
+.icon-tint {
+ background-position: -72px -72px;
+}
+
+.icon-edit {
+ background-position: -96px -72px;
+}
+
+.icon-share {
+ background-position: -120px -72px;
+}
+
+.icon-check {
+ background-position: -144px -72px;
+}
+
+.icon-move {
+ background-position: -168px -72px;
+}
+
+.icon-step-backward {
+ background-position: -192px -72px;
+}
+
+.icon-fast-backward {
+ background-position: -216px -72px;
+}
+
+.icon-backward {
+ background-position: -240px -72px;
+}
+
+.icon-play {
+ background-position: -264px -72px;
+}
+
+.icon-pause {
+ background-position: -288px -72px;
+}
+
+.icon-stop {
+ background-position: -312px -72px;
+}
+
+.icon-forward {
+ background-position: -336px -72px;
+}
+
+.icon-fast-forward {
+ background-position: -360px -72px;
+}
+
+.icon-step-forward {
+ background-position: -384px -72px;
+}
+
+.icon-eject {
+ background-position: -408px -72px;
+}
+
+.icon-chevron-left {
+ background-position: -432px -72px;
+}
+
+.icon-chevron-right {
+ background-position: -456px -72px;
+}
+
+.icon-plus-sign {
+ background-position: 0 -96px;
+}
+
+.icon-minus-sign {
+ background-position: -24px -96px;
+}
+
+.icon-remove-sign {
+ background-position: -48px -96px;
+}
+
+.icon-ok-sign {
+ background-position: -72px -96px;
+}
+
+.icon-question-sign {
+ background-position: -96px -96px;
+}
+
+.icon-info-sign {
+ background-position: -120px -96px;
+}
+
+.icon-screenshot {
+ background-position: -144px -96px;
+}
+
+.icon-remove-circle {
+ background-position: -168px -96px;
+}
+
+.icon-ok-circle {
+ background-position: -192px -96px;
+}
+
+.icon-ban-circle {
+ background-position: -216px -96px;
+}
+
+.icon-arrow-left {
+ background-position: -240px -96px;
+}
+
+.icon-arrow-right {
+ background-position: -264px -96px;
+}
+
+.icon-arrow-up {
+ background-position: -289px -96px;
+}
+
+.icon-arrow-down {
+ background-position: -312px -96px;
+}
+
+.icon-share-alt {
+ background-position: -336px -96px;
+}
+
+.icon-resize-full {
+ background-position: -360px -96px;
+}
+
+.icon-resize-small {
+ background-position: -384px -96px;
+}
+
+.icon-plus {
+ background-position: -408px -96px;
+}
+
+.icon-minus {
+ background-position: -433px -96px;
+}
+
+.icon-asterisk {
+ background-position: -456px -96px;
+}
+
+.icon-exclamation-sign {
+ background-position: 0 -120px;
+}
+
+.icon-gift {
+ background-position: -24px -120px;
+}
+
+.icon-leaf {
+ background-position: -48px -120px;
+}
+
+.icon-fire {
+ background-position: -72px -120px;
+}
+
+.icon-eye-open {
+ background-position: -96px -120px;
+}
+
+.icon-eye-close {
+ background-position: -120px -120px;
+}
+
+.icon-warning-sign {
+ background-position: -144px -120px;
+}
+
+.icon-plane {
+ background-position: -168px -120px;
+}
+
+.icon-calendar {
+ background-position: -192px -120px;
+}
+
+.icon-random {
+ width: 16px;
+ background-position: -216px -120px;
+}
+
+.icon-comment {
+ background-position: -240px -120px;
+}
+
+.icon-magnet {
+ background-position: -264px -120px;
+}
+
+.icon-chevron-up {
+ background-position: -288px -120px;
+}
+
+.icon-chevron-down {
+ background-position: -313px -119px;
+}
+
+.icon-retweet {
+ background-position: -336px -120px;
+}
+
+.icon-shopping-cart {
+ background-position: -360px -120px;
+}
+
+.icon-folder-close {
+ width: 16px;
+ background-position: -384px -120px;
+}
+
+.icon-folder-open {
+ width: 16px;
+ background-position: -408px -120px;
+}
+
+.icon-resize-vertical {
+ background-position: -432px -119px;
+}
+
+.icon-resize-horizontal {
+ background-position: -456px -118px;
+}
+
+.icon-hdd {
+ background-position: 0 -144px;
+}
+
+.icon-bullhorn {
+ background-position: -24px -144px;
+}
+
+.icon-bell {
+ background-position: -48px -144px;
+}
+
+.icon-certificate {
+ background-position: -72px -144px;
+}
+
+.icon-thumbs-up {
+ background-position: -96px -144px;
+}
+
+.icon-thumbs-down {
+ background-position: -120px -144px;
+}
+
+.icon-hand-right {
+ background-position: -144px -144px;
+}
+
+.icon-hand-left {
+ background-position: -168px -144px;
+}
+
+.icon-hand-up {
+ background-position: -192px -144px;
+}
+
+.icon-hand-down {
+ background-position: -216px -144px;
+}
+
+.icon-circle-arrow-right {
+ background-position: -240px -144px;
+}
+
+.icon-circle-arrow-left {
+ background-position: -264px -144px;
+}
+
+.icon-circle-arrow-up {
+ background-position: -288px -144px;
+}
+
+.icon-circle-arrow-down {
+ background-position: -312px -144px;
+}
+
+.icon-globe {
+ background-position: -336px -144px;
+}
+
+.icon-wrench {
+ background-position: -360px -144px;
+}
+
+.icon-tasks {
+ background-position: -384px -144px;
+}
+
+.icon-filter {
+ background-position: -408px -144px;
+}
+
+.icon-briefcase {
+ background-position: -432px -144px;
+}
+
+.icon-fullscreen {
+ background-position: -456px -144px;
+}
+
+.dropup,
+.dropdown {
+ position: relative;
+}
+
+.dropdown-toggle {
+ *margin-bottom: -3px;
+}
+
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+ outline: 0;
+}
+
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ vertical-align: top;
+ border-top: 4px solid #000000;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ content: "";
+}
+
+.dropdown .caret {
+ margin-top: 8px;
+ margin-left: 2px;
+}
+
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ list-style: none;
+ background-color: #ffffff;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ *border-right-width: 2px;
+ *border-bottom-width: 2px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+
+.dropdown-menu .divider {
+ *width: 100%;
+ height: 1px;
+ margin: 9px 1px;
+ *margin: -5px 0 5px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+}
+
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 20px;
+ color: #333333;
+ white-space: nowrap;
+}
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus,
+.dropdown-submenu:hover > a,
+.dropdown-submenu:focus > a {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #0081c2;
+ background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
+ background-image: -o-linear-gradient(top, #0088cc, #0077b3);
+ background-image: linear-gradient(to bottom, #0088cc, #0077b3);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
+}
+
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #0081c2;
+ background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
+ background-image: -o-linear-gradient(top, #0088cc, #0077b3);
+ background-image: linear-gradient(to bottom, #0088cc, #0077b3);
+ background-repeat: repeat-x;
+ outline: 0;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
+}
+
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #999999;
+}
+
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ cursor: default;
+ background-color: transparent;
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.open {
+ *z-index: 1000;
+}
+
+.open > .dropdown-menu {
+ display: block;
+}
+
+.dropdown-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 990;
+}
+
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ border-top: 0;
+ border-bottom: 4px solid #000000;
+ content: "";
+}
+
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+}
+
+.dropdown-submenu {
+ position: relative;
+}
+
+.dropdown-submenu > .dropdown-menu {
+ top: 0;
+ left: 100%;
+ margin-top: -6px;
+ margin-left: -1px;
+ -webkit-border-radius: 0 6px 6px 6px;
+ -moz-border-radius: 0 6px 6px 6px;
+ border-radius: 0 6px 6px 6px;
+}
+
+.dropdown-submenu:hover > .dropdown-menu {
+ display: block;
+}
+
+.dropup .dropdown-submenu > .dropdown-menu {
+ top: auto;
+ bottom: 0;
+ margin-top: 0;
+ margin-bottom: -2px;
+ -webkit-border-radius: 5px 5px 5px 0;
+ -moz-border-radius: 5px 5px 5px 0;
+ border-radius: 5px 5px 5px 0;
+}
+
+.dropdown-submenu > a:after {
+ display: block;
+ float: right;
+ width: 0;
+ height: 0;
+ margin-top: 5px;
+ margin-right: -10px;
+ border-color: transparent;
+ border-left-color: #cccccc;
+ border-style: solid;
+ border-width: 5px 0 5px 5px;
+ content: " ";
+}
+
+.dropdown-submenu:hover > a:after {
+ border-left-color: #ffffff;
+}
+
+.dropdown-submenu.pull-left {
+ float: none;
+}
+
+.dropdown-submenu.pull-left > .dropdown-menu {
+ left: -100%;
+ margin-left: 10px;
+ -webkit-border-radius: 6px 0 6px 6px;
+ -moz-border-radius: 6px 0 6px 6px;
+ border-radius: 6px 0 6px 6px;
+}
+
+.dropdown .dropdown-menu .nav-header {
+ padding-right: 20px;
+ padding-left: 20px;
+}
+
+.typeahead {
+ z-index: 1051;
+ margin-top: 2px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+
+.well-large {
+ padding: 24px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.well-small {
+ padding: 9px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity 0.15s linear;
+ -moz-transition: opacity 0.15s linear;
+ -o-transition: opacity 0.15s linear;
+ transition: opacity 0.15s linear;
+}
+
+.fade.in {
+ opacity: 1;
+}
+
+.collapse {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ -webkit-transition: height 0.35s ease;
+ -moz-transition: height 0.35s ease;
+ -o-transition: height 0.35s ease;
+ transition: height 0.35s ease;
+}
+
+.collapse.in {
+ height: auto;
+}
+
+.close {
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 20px;
+ color: #000000;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+
+.close:hover,
+.close:focus {
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.4;
+ filter: alpha(opacity=40);
+}
+
+button.close {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+}
+
+.btn {
+ display: inline-block;
+ *display: inline;
+ padding: 4px 12px;
+ margin-bottom: 0;
+ *margin-left: .3em;
+ font-size: 14px;
+ line-height: 20px;
+ color: #333333;
+ text-align: center;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ vertical-align: middle;
+ cursor: pointer;
+ background-color: #f5f5f5;
+ *background-color: #e6e6e6;
+ background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+ background-repeat: repeat-x;
+ border: 1px solid #cccccc;
+ *border: 0;
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ border-bottom-color: #b3b3b3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ *zoom: 1;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn:hover,
+.btn:focus,
+.btn:active,
+.btn.active,
+.btn.disabled,
+.btn[disabled] {
+ color: #333333;
+ background-color: #e6e6e6;
+ *background-color: #d9d9d9;
+}
+
+.btn:active,
+.btn.active {
+ background-color: #cccccc \9;
+}
+
+.btn:first-child {
+ *margin-left: 0;
+}
+
+.btn:hover,
+.btn:focus {
+ color: #333333;
+ text-decoration: none;
+ background-position: 0 -15px;
+ -webkit-transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear;
+}
+
+.btn:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+.btn.active,
+.btn:active {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn.disabled,
+.btn[disabled] {
+ cursor: default;
+ background-image: none;
+ opacity: 0.65;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+
+.btn-large {
+ padding: 11px 19px;
+ font-size: 17.5px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.btn-large [class^="icon-"],
+.btn-large [class*=" icon-"] {
+ margin-top: 4px;
+}
+
+.btn-small {
+ padding: 2px 10px;
+ font-size: 11.9px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.btn-small [class^="icon-"],
+.btn-small [class*=" icon-"] {
+ margin-top: 0;
+}
+
+.btn-mini [class^="icon-"],
+.btn-mini [class*=" icon-"] {
+ margin-top: -1px;
+}
+
+.btn-mini {
+ padding: 0 6px;
+ font-size: 10.5px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.btn-block {
+ display: block;
+ width: 100%;
+ padding-right: 0;
+ padding-left: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+ color: rgba(255, 255, 255, 0.75);
+}
+
+.btn-primary {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #006dcc;
+ *background-color: #0044cc;
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+ background-image: linear-gradient(to bottom, #0088cc, #0044cc);
+ background-repeat: repeat-x;
+ border-color: #0044cc #0044cc #002a80;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary.disabled,
+.btn-primary[disabled] {
+ color: #ffffff;
+ background-color: #0044cc;
+ *background-color: #003bb3;
+}
+
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #003399 \9;
+}
+
+.btn-warning {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #faa732;
+ *background-color: #f89406;
+ background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+ background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+ background-image: -o-linear-gradient(top, #fbb450, #f89406);
+ background-image: linear-gradient(to bottom, #fbb450, #f89406);
+ background-repeat: repeat-x;
+ border-color: #f89406 #f89406 #ad6704;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning:active,
+.btn-warning.active,
+.btn-warning.disabled,
+.btn-warning[disabled] {
+ color: #ffffff;
+ background-color: #f89406;
+ *background-color: #df8505;
+}
+
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #c67605 \9;
+}
+
+.btn-danger {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #da4f49;
+ *background-color: #bd362f;
+ background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
+ background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);
+ background-repeat: repeat-x;
+ border-color: #bd362f #bd362f #802420;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger:active,
+.btn-danger.active,
+.btn-danger.disabled,
+.btn-danger[disabled] {
+ color: #ffffff;
+ background-color: #bd362f;
+ *background-color: #a9302a;
+}
+
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #942a25 \9;
+}
+
+.btn-success {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #5bb75b;
+ *background-color: #51a351;
+ background-image: -moz-linear-gradient(top, #62c462, #51a351);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
+ background-image: -webkit-linear-gradient(top, #62c462, #51a351);
+ background-image: -o-linear-gradient(top, #62c462, #51a351);
+ background-image: linear-gradient(to bottom, #62c462, #51a351);
+ background-repeat: repeat-x;
+ border-color: #51a351 #51a351 #387038;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-success:hover,
+.btn-success:focus,
+.btn-success:active,
+.btn-success.active,
+.btn-success.disabled,
+.btn-success[disabled] {
+ color: #ffffff;
+ background-color: #51a351;
+ *background-color: #499249;
+}
+
+.btn-success:active,
+.btn-success.active {
+ background-color: #408140 \9;
+}
+
+.btn-info {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #49afcd;
+ *background-color: #2f96b4;
+ background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
+ background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);
+ background-repeat: repeat-x;
+ border-color: #2f96b4 #2f96b4 #1f6377;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-info:hover,
+.btn-info:focus,
+.btn-info:active,
+.btn-info.active,
+.btn-info.disabled,
+.btn-info[disabled] {
+ color: #ffffff;
+ background-color: #2f96b4;
+ *background-color: #2a85a0;
+}
+
+.btn-info:active,
+.btn-info.active {
+ background-color: #24748c \9;
+}
+
+.btn-inverse {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #363636;
+ *background-color: #222222;
+ background-image: -moz-linear-gradient(top, #444444, #222222);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
+ background-image: -webkit-linear-gradient(top, #444444, #222222);
+ background-image: -o-linear-gradient(top, #444444, #222222);
+ background-image: linear-gradient(to bottom, #444444, #222222);
+ background-repeat: repeat-x;
+ border-color: #222222 #222222 #000000;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-inverse:hover,
+.btn-inverse:focus,
+.btn-inverse:active,
+.btn-inverse.active,
+.btn-inverse.disabled,
+.btn-inverse[disabled] {
+ color: #ffffff;
+ background-color: #222222;
+ *background-color: #151515;
+}
+
+.btn-inverse:active,
+.btn-inverse.active {
+ background-color: #080808 \9;
+}
+
+button.btn,
+input[type="submit"].btn {
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+}
+
+button.btn::-moz-focus-inner,
+input[type="submit"].btn::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+button.btn.btn-large,
+input[type="submit"].btn.btn-large {
+ *padding-top: 7px;
+ *padding-bottom: 7px;
+}
+
+button.btn.btn-small,
+input[type="submit"].btn.btn-small {
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+}
+
+button.btn.btn-mini,
+input[type="submit"].btn.btn-mini {
+ *padding-top: 1px;
+ *padding-bottom: 1px;
+}
+
+.btn-link,
+.btn-link:active,
+.btn-link[disabled] {
+ background-color: transparent;
+ background-image: none;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+
+.btn-link {
+ color: #0088cc;
+ cursor: pointer;
+ border-color: transparent;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.btn-link:hover,
+.btn-link:focus {
+ color: #005580;
+ text-decoration: underline;
+ background-color: transparent;
+}
+
+.btn-link[disabled]:hover,
+.btn-link[disabled]:focus {
+ color: #333333;
+ text-decoration: none;
+}
+
+.btn-group {
+ position: relative;
+ display: inline-block;
+ *display: inline;
+ *margin-left: .3em;
+ font-size: 0;
+ white-space: nowrap;
+ vertical-align: middle;
+ *zoom: 1;
+}
+
+.btn-group:first-child {
+ *margin-left: 0;
+}
+
+.btn-group + .btn-group {
+ margin-left: 5px;
+}
+
+.btn-toolbar {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ font-size: 0;
+}
+
+.btn-toolbar > .btn + .btn,
+.btn-toolbar > .btn-group + .btn,
+.btn-toolbar > .btn + .btn-group {
+ margin-left: 5px;
+}
+
+.btn-group > .btn {
+ position: relative;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.btn-group > .btn + .btn {
+ margin-left: -1px;
+}
+
+.btn-group > .btn,
+.btn-group > .dropdown-menu,
+.btn-group > .popover {
+ font-size: 14px;
+}
+
+.btn-group > .btn-mini {
+ font-size: 10.5px;
+}
+
+.btn-group > .btn-small {
+ font-size: 11.9px;
+}
+
+.btn-group > .btn-large {
+ font-size: 17.5px;
+}
+
+.btn-group > .btn:first-child {
+ margin-left: 0;
+ -webkit-border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-topleft: 4px;
+}
+
+.btn-group > .btn:last-child,
+.btn-group > .dropdown-toggle {
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-bottomright: 4px;
+}
+
+.btn-group > .btn.large:first-child {
+ margin-left: 0;
+ -webkit-border-bottom-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+ -webkit-border-top-left-radius: 6px;
+ border-top-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ -moz-border-radius-topleft: 6px;
+}
+
+.btn-group > .btn.large:last-child,
+.btn-group > .large.dropdown-toggle {
+ -webkit-border-top-right-radius: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ -moz-border-radius-bottomright: 6px;
+}
+
+.btn-group > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group > .btn:active,
+.btn-group > .btn.active {
+ z-index: 2;
+}
+
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+
+.btn-group > .btn + .dropdown-toggle {
+ *padding-top: 5px;
+ padding-right: 8px;
+ *padding-bottom: 5px;
+ padding-left: 8px;
+ -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);
+ -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);
+ 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);
+}
+
+.btn-group > .btn-mini + .dropdown-toggle {
+ *padding-top: 2px;
+ padding-right: 5px;
+ *padding-bottom: 2px;
+ padding-left: 5px;
+}
+
+.btn-group > .btn-small + .dropdown-toggle {
+ *padding-top: 5px;
+ *padding-bottom: 4px;
+}
+
+.btn-group > .btn-large + .dropdown-toggle {
+ *padding-top: 7px;
+ padding-right: 12px;
+ *padding-bottom: 7px;
+ padding-left: 12px;
+}
+
+.btn-group.open .dropdown-toggle {
+ background-image: none;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn-group.open .btn.dropdown-toggle {
+ background-color: #e6e6e6;
+}
+
+.btn-group.open .btn-primary.dropdown-toggle {
+ background-color: #0044cc;
+}
+
+.btn-group.open .btn-warning.dropdown-toggle {
+ background-color: #f89406;
+}
+
+.btn-group.open .btn-danger.dropdown-toggle {
+ background-color: #bd362f;
+}
+
+.btn-group.open .btn-success.dropdown-toggle {
+ background-color: #51a351;
+}
+
+.btn-group.open .btn-info.dropdown-toggle {
+ background-color: #2f96b4;
+}
+
+.btn-group.open .btn-inverse.dropdown-toggle {
+ background-color: #222222;
+}
+
+.btn .caret {
+ margin-top: 8px;
+ margin-left: 0;
+}
+
+.btn-large .caret {
+ margin-top: 6px;
+}
+
+.btn-large .caret {
+ border-top-width: 5px;
+ border-right-width: 5px;
+ border-left-width: 5px;
+}
+
+.btn-mini .caret,
+.btn-small .caret {
+ margin-top: 8px;
+}
+
+.dropup .btn-large .caret {
+ border-bottom-width: 5px;
+}
+
+.btn-primary .caret,
+.btn-warning .caret,
+.btn-danger .caret,
+.btn-info .caret,
+.btn-success .caret,
+.btn-inverse .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+}
+
+.btn-group-vertical {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+}
+
+.btn-group-vertical > .btn {
+ display: block;
+ float: none;
+ max-width: 100%;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.btn-group-vertical > .btn + .btn {
+ margin-top: -1px;
+ margin-left: 0;
+}
+
+.btn-group-vertical > .btn:first-child {
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+
+.btn-group-vertical > .btn:last-child {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+
+.btn-group-vertical > .btn-large:first-child {
+ -webkit-border-radius: 6px 6px 0 0;
+ -moz-border-radius: 6px 6px 0 0;
+ border-radius: 6px 6px 0 0;
+}
+
+.btn-group-vertical > .btn-large:last-child {
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+}
+
+.alert {
+ padding: 8px 35px 8px 14px;
+ margin-bottom: 20px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ background-color: #fcf8e3;
+ border: 1px solid #fbeed5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.alert,
+.alert h4 {
+ color: #c09853;
+}
+
+.alert h4 {
+ margin: 0;
+}
+
+.alert .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ line-height: 20px;
+}
+
+.alert-success {
+ color: #468847;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+
+.alert-success h4 {
+ color: #468847;
+}
+
+.alert-danger,
+.alert-error {
+ color: #b94a48;
+ background-color: #f2dede;
+ border-color: #eed3d7;
+}
+
+.alert-danger h4,
+.alert-error h4 {
+ color: #b94a48;
+}
+
+.alert-info {
+ color: #3a87ad;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+
+.alert-info h4 {
+ color: #3a87ad;
+}
+
+.alert-block {
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+
+.alert-block > p,
+.alert-block > ul {
+ margin-bottom: 0;
+}
+
+.alert-block p + p {
+ margin-top: 5px;
+}
+
+.nav {
+ margin-bottom: 20px;
+ margin-left: 0;
+ list-style: none;
+}
+
+.nav > li > a {
+ display: block;
+}
+
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: #eeeeee;
+}
+
+.nav > li > a > img {
+ max-width: none;
+}
+
+.nav > .pull-right {
+ float: right;
+}
+
+.nav-header {
+ display: block;
+ padding: 3px 15px;
+ font-size: 11px;
+ font-weight: bold;
+ line-height: 20px;
+ color: #999999;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-transform: uppercase;
+}
+
+.nav li + .nav-header {
+ margin-top: 9px;
+}
+
+.nav-list {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-bottom: 0;
+}
+
+.nav-list > li > a,
+.nav-list .nav-header {
+ margin-right: -15px;
+ margin-left: -15px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+}
+
+.nav-list > li > a {
+ padding: 3px 15px;
+}
+
+.nav-list > .active > a,
+.nav-list > .active > a:hover,
+.nav-list > .active > a:focus {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+ background-color: #0088cc;
+}
+
+.nav-list [class^="icon-"],
+.nav-list [class*=" icon-"] {
+ margin-right: 2px;
+}
+
+.nav-list .divider {
+ *width: 100%;
+ height: 1px;
+ margin: 9px 1px;
+ *margin: -5px 0 5px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+}
+
+.nav-tabs,
+.nav-pills {
+ *zoom: 1;
+}
+
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.nav-tabs:after,
+.nav-pills:after {
+ clear: both;
+}
+
+.nav-tabs > li,
+.nav-pills > li {
+ float: left;
+}
+
+.nav-tabs > li > a,
+.nav-pills > li > a {
+ padding-right: 12px;
+ padding-left: 12px;
+ margin-right: 2px;
+ line-height: 14px;
+}
+
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+
+.nav-tabs > li {
+ margin-bottom: -1px;
+}
+
+.nav-tabs > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ line-height: 20px;
+ border: 1px solid transparent;
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+
+.nav-tabs > li > a:hover,
+.nav-tabs > li > a:focus {
+ border-color: #eeeeee #eeeeee #dddddd;
+}
+
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover,
+.nav-tabs > .active > a:focus {
+ color: #555555;
+ cursor: default;
+ background-color: #ffffff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+}
+
+.nav-pills > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover,
+.nav-pills > .active > a:focus {
+ color: #ffffff;
+ background-color: #0088cc;
+}
+
+.nav-stacked > li {
+ float: none;
+}
+
+.nav-stacked > li > a {
+ margin-right: 0;
+}
+
+.nav-tabs.nav-stacked {
+ border-bottom: 0;
+}
+
+.nav-tabs.nav-stacked > li > a {
+ border: 1px solid #ddd;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.nav-tabs.nav-stacked > li:first-child > a {
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+}
+
+.nav-tabs.nav-stacked > li:last-child > a {
+ -webkit-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -moz-border-radius-bottomleft: 4px;
+}
+
+.nav-tabs.nav-stacked > li > a:hover,
+.nav-tabs.nav-stacked > li > a:focus {
+ z-index: 2;
+ border-color: #ddd;
+}
+
+.nav-pills.nav-stacked > li > a {
+ margin-bottom: 3px;
+}
+
+.nav-pills.nav-stacked > li:last-child > a {
+ margin-bottom: 1px;
+}
+
+.nav-tabs .dropdown-menu {
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+}
+
+.nav-pills .dropdown-menu {
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.nav .dropdown-toggle .caret {
+ margin-top: 6px;
+ border-top-color: #0088cc;
+ border-bottom-color: #0088cc;
+}
+
+.nav .dropdown-toggle:hover .caret,
+.nav .dropdown-toggle:focus .caret {
+ border-top-color: #005580;
+ border-bottom-color: #005580;
+}
+
+/* move down carets for tabs */
+
+.nav-tabs .dropdown-toggle .caret {
+ margin-top: 8px;
+}
+
+.nav .active .dropdown-toggle .caret {
+ border-top-color: #fff;
+ border-bottom-color: #fff;
+}
+
+.nav-tabs .active .dropdown-toggle .caret {
+ border-top-color: #555555;
+ border-bottom-color: #555555;
+}
+
+.nav > .dropdown.active > a:hover,
+.nav > .dropdown.active > a:focus {
+ cursor: pointer;
+}
+
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > li.dropdown.open.active > a:hover,
+.nav > li.dropdown.open.active > a:focus {
+ color: #ffffff;
+ background-color: #999999;
+ border-color: #999999;
+}
+
+.nav li.dropdown.open .caret,
+.nav li.dropdown.open.active .caret,
+.nav li.dropdown.open a:hover .caret,
+.nav li.dropdown.open a:focus .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+
+.tabs-stacked .open > a:hover,
+.tabs-stacked .open > a:focus {
+ border-color: #999999;
+}
+
+.tabbable {
+ *zoom: 1;
+}
+
+.tabbable:before,
+.tabbable:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.tabbable:after {
+ clear: both;
+}
+
+.tab-content {
+ overflow: auto;
+}
+
+.tabs-below > .nav-tabs,
+.tabs-right > .nav-tabs,
+.tabs-left > .nav-tabs {
+ border-bottom: 0;
+}
+
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+ display: none;
+}
+
+.tab-content > .active,
+.pill-content > .active {
+ display: block;
+}
+
+.tabs-below > .nav-tabs {
+ border-top: 1px solid #ddd;
+}
+
+.tabs-below > .nav-tabs > li {
+ margin-top: -1px;
+ margin-bottom: 0;
+}
+
+.tabs-below > .nav-tabs > li > a {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+
+.tabs-below > .nav-tabs > li > a:hover,
+.tabs-below > .nav-tabs > li > a:focus {
+ border-top-color: #ddd;
+ border-bottom-color: transparent;
+}
+
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover,
+.tabs-below > .nav-tabs > .active > a:focus {
+ border-color: transparent #ddd #ddd #ddd;
+}
+
+.tabs-left > .nav-tabs > li,
+.tabs-right > .nav-tabs > li {
+ float: none;
+}
+
+.tabs-left > .nav-tabs > li > a,
+.tabs-right > .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+
+.tabs-left > .nav-tabs {
+ float: left;
+ margin-right: 19px;
+ border-right: 1px solid #ddd;
+}
+
+.tabs-left > .nav-tabs > li > a {
+ margin-right: -1px;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+
+.tabs-left > .nav-tabs > li > a:hover,
+.tabs-left > .nav-tabs > li > a:focus {
+ border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+
+.tabs-left > .nav-tabs .active > a,
+.tabs-left > .nav-tabs .active > a:hover,
+.tabs-left > .nav-tabs .active > a:focus {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: #ffffff;
+}
+
+.tabs-right > .nav-tabs {
+ float: right;
+ margin-left: 19px;
+ border-left: 1px solid #ddd;
+}
+
+.tabs-right > .nav-tabs > li > a {
+ margin-left: -1px;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+
+.tabs-right > .nav-tabs > li > a:hover,
+.tabs-right > .nav-tabs > li > a:focus {
+ border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+}
+
+.tabs-right > .nav-tabs .active > a,
+.tabs-right > .nav-tabs .active > a:hover,
+.tabs-right > .nav-tabs .active > a:focus {
+ border-color: #ddd #ddd #ddd transparent;
+ *border-left-color: #ffffff;
+}
+
+.nav > .disabled > a {
+ color: #999999;
+}
+
+.nav > .disabled > a:hover,
+.nav > .disabled > a:focus {
+ text-decoration: none;
+ cursor: default;
+ background-color: transparent;
+}
+
+.navbar {
+ *position: relative;
+ *z-index: 2;
+ margin-bottom: 20px;
+ overflow: visible;
+}
+
+.navbar-inner {
+ min-height: 40px;
+ padding-right: 20px;
+ padding-left: 20px;
+ background-color: #fafafa;
+ background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));
+ background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2);
+ background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);
+ background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
+ background-repeat: repeat-x;
+ border: 1px solid #d4d4d4;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
+ *zoom: 1;
+ -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+}
+
+.navbar-inner:before,
+.navbar-inner:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.navbar-inner:after {
+ clear: both;
+}
+
+.navbar .container {
+ width: auto;
+}
+
+.nav-collapse.collapse {
+ height: auto;
+ overflow: visible;
+}
+
+.navbar .brand {
+ display: block;
+ float: left;
+ padding: 10px 20px 10px;
+ margin-left: -20px;
+ font-size: 20px;
+ font-weight: 200;
+ color: #777777;
+ text-shadow: 0 1px 0 #ffffff;
+}
+
+.navbar .brand:hover,
+.navbar .brand:focus {
+ text-decoration: none;
+}
+
+.navbar-text {
+ margin-bottom: 0;
+ line-height: 40px;
+ color: #777777;
+}
+
+.navbar-link {
+ color: #777777;
+}
+
+.navbar-link:hover,
+.navbar-link:focus {
+ color: #333333;
+}
+
+.navbar .divider-vertical {
+ height: 40px;
+ margin: 0 9px;
+ border-right: 1px solid #ffffff;
+ border-left: 1px solid #f2f2f2;
+}
+
+.navbar .btn,
+.navbar .btn-group {
+ margin-top: 5px;
+}
+
+.navbar .btn-group .btn,
+.navbar .input-prepend .btn,
+.navbar .input-append .btn,
+.navbar .input-prepend .btn-group,
+.navbar .input-append .btn-group {
+ margin-top: 0;
+}
+
+.navbar-form {
+ margin-bottom: 0;
+ *zoom: 1;
+}
+
+.navbar-form:before,
+.navbar-form:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.navbar-form:after {
+ clear: both;
+}
+
+.navbar-form input,
+.navbar-form select,
+.navbar-form .radio,
+.navbar-form .checkbox {
+ margin-top: 5px;
+}
+
+.navbar-form input,
+.navbar-form select,
+.navbar-form .btn {
+ display: inline-block;
+ margin-bottom: 0;
+}
+
+.navbar-form input[type="image"],
+.navbar-form input[type="checkbox"],
+.navbar-form input[type="radio"] {
+ margin-top: 3px;
+}
+
+.navbar-form .input-append,
+.navbar-form .input-prepend {
+ margin-top: 5px;
+ white-space: nowrap;
+}
+
+.navbar-form .input-append input,
+.navbar-form .input-prepend input {
+ margin-top: 0;
+}
+
+.navbar-search {
+ position: relative;
+ float: left;
+ margin-top: 5px;
+ margin-bottom: 0;
+}
+
+.navbar-search .search-query {
+ padding: 4px 14px;
+ margin-bottom: 0;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 1;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+
+.navbar-static-top {
+ position: static;
+ margin-bottom: 0;
+}
+
+.navbar-static-top .navbar-inner {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+ margin-bottom: 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-static-top .navbar-inner {
+ border-width: 0 0 1px;
+}
+
+.navbar-fixed-bottom .navbar-inner {
+ border-width: 1px 0 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-fixed-bottom .navbar-inner {
+ padding-right: 0;
+ padding-left: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+
+.navbar-static-top .container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ width: 940px;
+}
+
+.navbar-fixed-top {
+ top: 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-static-top .navbar-inner {
+ -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+}
+
+.navbar-fixed-bottom {
+ bottom: 0;
+}
+
+.navbar-fixed-bottom .navbar-inner {
+ -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+}
+
+.navbar .nav {
+ position: relative;
+ left: 0;
+ display: block;
+ float: left;
+ margin: 0 10px 0 0;
+}
+
+.navbar .nav.pull-right {
+ float: right;
+ margin-right: 0;
+}
+
+.navbar .nav > li {
+ float: left;
+}
+
+.navbar .nav > li > a {
+ float: none;
+ padding: 10px 15px 10px;
+ color: #777777;
+ text-decoration: none;
+ text-shadow: 0 1px 0 #ffffff;
+}
+
+.navbar .nav .dropdown-toggle .caret {
+ margin-top: 8px;
+}
+
+.navbar .nav > li > a:focus,
+.navbar .nav > li > a:hover {
+ color: #333333;
+ text-decoration: none;
+ background-color: transparent;
+}
+
+.navbar .nav > .active > a,
+.navbar .nav > .active > a:hover,
+.navbar .nav > .active > a:focus {
+ color: #555555;
+ text-decoration: none;
+ background-color: #e5e5e5;
+ -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+ -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+}
+
+.navbar .btn-navbar {
+ display: none;
+ float: right;
+ padding: 7px 10px;
+ margin-right: 5px;
+ margin-left: 5px;
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #ededed;
+ *background-color: #e5e5e5;
+ background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));
+ background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5);
+ background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5);
+ background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5);
+ background-repeat: repeat-x;
+ border-color: #e5e5e5 #e5e5e5 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+}
+
+.navbar .btn-navbar:hover,
+.navbar .btn-navbar:focus,
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active,
+.navbar .btn-navbar.disabled,
+.navbar .btn-navbar[disabled] {
+ color: #ffffff;
+ background-color: #e5e5e5;
+ *background-color: #d9d9d9;
+}
+
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active {
+ background-color: #cccccc \9;
+}
+
+.navbar .btn-navbar .icon-bar {
+ display: block;
+ width: 18px;
+ height: 2px;
+ background-color: #f5f5f5;
+ -webkit-border-radius: 1px;
+ -moz-border-radius: 1px;
+ border-radius: 1px;
+ -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.btn-navbar .icon-bar + .icon-bar {
+ margin-top: 3px;
+}
+
+.navbar .nav > li > .dropdown-menu:before {
+ position: absolute;
+ top: -7px;
+ left: 9px;
+ display: inline-block;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-left: 7px solid transparent;
+ border-bottom-color: rgba(0, 0, 0, 0.2);
+ content: '';
+}
+
+.navbar .nav > li > .dropdown-menu:after {
+ position: absolute;
+ top: -6px;
+ left: 10px;
+ display: inline-block;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid #ffffff;
+ border-left: 6px solid transparent;
+ content: '';
+}
+
+.navbar-fixed-bottom .nav > li > .dropdown-menu:before {
+ top: auto;
+ bottom: -7px;
+ border-top: 7px solid #ccc;
+ border-bottom: 0;
+ border-top-color: rgba(0, 0, 0, 0.2);
+}
+
+.navbar-fixed-bottom .nav > li > .dropdown-menu:after {
+ top: auto;
+ bottom: -6px;
+ border-top: 6px solid #ffffff;
+ border-bottom: 0;
+}
+
+.navbar .nav li.dropdown > a:hover .caret,
+.navbar .nav li.dropdown > a:focus .caret {
+ border-top-color: #333333;
+ border-bottom-color: #333333;
+}
+
+.navbar .nav li.dropdown.open > .dropdown-toggle,
+.navbar .nav li.dropdown.active > .dropdown-toggle,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle {
+ color: #555555;
+ background-color: #e5e5e5;
+}
+
+.navbar .nav li.dropdown > .dropdown-toggle .caret {
+ border-top-color: #777777;
+ border-bottom-color: #777777;
+}
+
+.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.active > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {
+ border-top-color: #555555;
+ border-bottom-color: #555555;
+}
+
+.navbar .pull-right > li > .dropdown-menu,
+.navbar .nav > li > .dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu:before,
+.navbar .nav > li > .dropdown-menu.pull-right:before {
+ right: 12px;
+ left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu:after,
+.navbar .nav > li > .dropdown-menu.pull-right:after {
+ right: 13px;
+ left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu .dropdown-menu,
+.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu {
+ right: 100%;
+ left: auto;
+ margin-right: -1px;
+ margin-left: 0;
+ -webkit-border-radius: 6px 0 6px 6px;
+ -moz-border-radius: 6px 0 6px 6px;
+ border-radius: 6px 0 6px 6px;
+}
+
+.navbar-inverse .navbar-inner {
+ background-color: #1b1b1b;
+ background-image: -moz-linear-gradient(top, #222222, #111111);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));
+ background-image: -webkit-linear-gradient(top, #222222, #111111);
+ background-image: -o-linear-gradient(top, #222222, #111111);
+ background-image: linear-gradient(to bottom, #222222, #111111);
+ background-repeat: repeat-x;
+ border-color: #252525;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
+}
+
+.navbar-inverse .brand,
+.navbar-inverse .nav > li > a {
+ color: #999999;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.navbar-inverse .brand:hover,
+.navbar-inverse .nav > li > a:hover,
+.navbar-inverse .brand:focus,
+.navbar-inverse .nav > li > a:focus {
+ color: #ffffff;
+}
+
+.navbar-inverse .brand {
+ color: #999999;
+}
+
+.navbar-inverse .navbar-text {
+ color: #999999;
+}
+
+.navbar-inverse .nav > li > a:focus,
+.navbar-inverse .nav > li > a:hover {
+ color: #ffffff;
+ background-color: transparent;
+}
+
+.navbar-inverse .nav .active > a,
+.navbar-inverse .nav .active > a:hover,
+.navbar-inverse .nav .active > a:focus {
+ color: #ffffff;
+ background-color: #111111;
+}
+
+.navbar-inverse .navbar-link {
+ color: #999999;
+}
+
+.navbar-inverse .navbar-link:hover,
+.navbar-inverse .navbar-link:focus {
+ color: #ffffff;
+}
+
+.navbar-inverse .divider-vertical {
+ border-right-color: #222222;
+ border-left-color: #111111;
+}
+
+.navbar-inverse .nav li.dropdown.open > .dropdown-toggle,
+.navbar-inverse .nav li.dropdown.active > .dropdown-toggle,
+.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle {
+ color: #ffffff;
+ background-color: #111111;
+}
+
+.navbar-inverse .nav li.dropdown > a:hover .caret,
+.navbar-inverse .nav li.dropdown > a:focus .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+}
+
+.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {
+ border-top-color: #999999;
+ border-bottom-color: #999999;
+}
+
+.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
+.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret,
+.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+}
+
+.navbar-inverse .navbar-search .search-query {
+ color: #ffffff;
+ background-color: #515151;
+ border-color: #111111;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+ -webkit-transition: none;
+ -moz-transition: none;
+ -o-transition: none;
+ transition: none;
+}
+
+.navbar-inverse .navbar-search .search-query:-moz-placeholder {
+ color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {
+ color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {
+ color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query:focus,
+.navbar-inverse .navbar-search .search-query.focused {
+ padding: 5px 15px;
+ color: #333333;
+ text-shadow: 0 1px 0 #ffffff;
+ background-color: #ffffff;
+ border: 0;
+ outline: 0;
+ -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+}
+
+.navbar-inverse .btn-navbar {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #0e0e0e;
+ *background-color: #040404;
+ background-image: -moz-linear-gradient(top, #151515, #040404);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));
+ background-image: -webkit-linear-gradient(top, #151515, #040404);
+ background-image: -o-linear-gradient(top, #151515, #040404);
+ background-image: linear-gradient(to bottom, #151515, #040404);
+ background-repeat: repeat-x;
+ border-color: #040404 #040404 #000000;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.navbar-inverse .btn-navbar:hover,
+.navbar-inverse .btn-navbar:focus,
+.navbar-inverse .btn-navbar:active,
+.navbar-inverse .btn-navbar.active,
+.navbar-inverse .btn-navbar.disabled,
+.navbar-inverse .btn-navbar[disabled] {
+ color: #ffffff;
+ background-color: #040404;
+ *background-color: #000000;
+}
+
+.navbar-inverse .btn-navbar:active,
+.navbar-inverse .btn-navbar.active {
+ background-color: #000000 \9;
+}
+
+.breadcrumb {
+ padding: 8px 15px;
+ margin: 0 0 20px;
+ list-style: none;
+ background-color: #f5f5f5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.breadcrumb > li {
+ display: inline-block;
+ *display: inline;
+ text-shadow: 0 1px 0 #ffffff;
+ *zoom: 1;
+}
+
+.breadcrumb > li > .divider {
+ padding: 0 5px;
+ color: #ccc;
+}
+
+.breadcrumb > .active {
+ color: #999999;
+}
+
+.pagination {
+ margin: 20px 0;
+}
+
+.pagination ul {
+ display: inline-block;
+ *display: inline;
+ margin-bottom: 0;
+ margin-left: 0;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ *zoom: 1;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.pagination ul > li {
+ display: inline;
+}
+
+.pagination ul > li > a,
+.pagination ul > li > span {
+ float: left;
+ padding: 4px 12px;
+ line-height: 20px;
+ text-decoration: none;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ border-left-width: 0;
+}
+
+.pagination ul > li > a:hover,
+.pagination ul > li > a:focus,
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+ background-color: #f5f5f5;
+}
+
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+ color: #999999;
+ cursor: default;
+}
+
+.pagination ul > .disabled > span,
+.pagination ul > .disabled > a,
+.pagination ul > .disabled > a:hover,
+.pagination ul > .disabled > a:focus {
+ color: #999999;
+ cursor: default;
+ background-color: transparent;
+}
+
+.pagination ul > li:first-child > a,
+.pagination ul > li:first-child > span {
+ border-left-width: 1px;
+ -webkit-border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-topleft: 4px;
+}
+
+.pagination ul > li:last-child > a,
+.pagination ul > li:last-child > span {
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-bottomright: 4px;
+}
+
+.pagination-centered {
+ text-align: center;
+}
+
+.pagination-right {
+ text-align: right;
+}
+
+.pagination-large ul > li > a,
+.pagination-large ul > li > span {
+ padding: 11px 19px;
+ font-size: 17.5px;
+}
+
+.pagination-large ul > li:first-child > a,
+.pagination-large ul > li:first-child > span {
+ -webkit-border-bottom-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+ -webkit-border-top-left-radius: 6px;
+ border-top-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ -moz-border-radius-topleft: 6px;
+}
+
+.pagination-large ul > li:last-child > a,
+.pagination-large ul > li:last-child > span {
+ -webkit-border-top-right-radius: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ -moz-border-radius-bottomright: 6px;
+}
+
+.pagination-mini ul > li:first-child > a,
+.pagination-small ul > li:first-child > a,
+.pagination-mini ul > li:first-child > span,
+.pagination-small ul > li:first-child > span {
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+ -moz-border-radius-bottomleft: 3px;
+ -moz-border-radius-topleft: 3px;
+}
+
+.pagination-mini ul > li:last-child > a,
+.pagination-small ul > li:last-child > a,
+.pagination-mini ul > li:last-child > span,
+.pagination-small ul > li:last-child > span {
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ -moz-border-radius-topright: 3px;
+ -moz-border-radius-bottomright: 3px;
+}
+
+.pagination-small ul > li > a,
+.pagination-small ul > li > span {
+ padding: 2px 10px;
+ font-size: 11.9px;
+}
+
+.pagination-mini ul > li > a,
+.pagination-mini ul > li > span {
+ padding: 0 6px;
+ font-size: 10.5px;
+}
+
+.pager {
+ margin: 20px 0;
+ text-align: center;
+ list-style: none;
+ *zoom: 1;
+}
+
+.pager:before,
+.pager:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.pager:after {
+ clear: both;
+}
+
+.pager li {
+ display: inline;
+}
+
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: #999999;
+ cursor: default;
+ background-color: #fff;
+}
+
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000000;
+}
+
+.modal-backdrop.fade {
+ opacity: 0;
+}
+
+.modal-backdrop,
+.modal-backdrop.fade.in {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+
+.modal {
+ position: fixed;
+ top: 10%;
+ left: 50%;
+ z-index: 1050;
+ width: 560px;
+ margin-left: -280px;
+ background-color: #ffffff;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ *border: 1px solid #999;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ outline: none;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+
+.modal.fade {
+ top: -25%;
+ -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
+ -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
+ -o-transition: opacity 0.3s linear, top 0.3s ease-out;
+ transition: opacity 0.3s linear, top 0.3s ease-out;
+}
+
+.modal.fade.in {
+ top: 10%;
+}
+
+.modal-header {
+ padding: 9px 15px;
+ border-bottom: 1px solid #eee;
+}
+
+.modal-header .close {
+ margin-top: 2px;
+}
+
+.modal-header h3 {
+ margin: 0;
+ line-height: 30px;
+}
+
+.modal-body {
+ position: relative;
+ max-height: 400px;
+ padding: 15px;
+ overflow-y: auto;
+}
+
+.modal-form {
+ margin-bottom: 0;
+}
+
+.modal-footer {
+ padding: 14px 15px 15px;
+ margin-bottom: 0;
+ text-align: right;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+ *zoom: 1;
+ -webkit-box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+}
+
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.modal-footer:after {
+ clear: both;
+}
+
+.modal-footer .btn + .btn {
+ margin-bottom: 0;
+ margin-left: 5px;
+}
+
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+
+.tooltip {
+ position: absolute;
+ z-index: 1030;
+ display: block;
+ font-size: 11px;
+ line-height: 1.4;
+ opacity: 0;
+ filter: alpha(opacity=0);
+ visibility: visible;
+}
+
+.tooltip.in {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+
+.tooltip.top {
+ padding: 5px 0;
+ margin-top: -3px;
+}
+
+.tooltip.right {
+ padding: 0 5px;
+ margin-left: 3px;
+}
+
+.tooltip.bottom {
+ padding: 5px 0;
+ margin-top: 3px;
+}
+
+.tooltip.left {
+ padding: 0 5px;
+ margin-left: -3px;
+}
+
+.tooltip-inner {
+ max-width: 200px;
+ padding: 8px;
+ color: #ffffff;
+ text-align: center;
+ text-decoration: none;
+ background-color: #000000;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-top-color: #000000;
+ border-width: 5px 5px 0;
+}
+
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-right-color: #000000;
+ border-width: 5px 5px 5px 0;
+}
+
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-left-color: #000000;
+ border-width: 5px 0 5px 5px;
+}
+
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-bottom-color: #000000;
+ border-width: 0 5px 5px;
+}
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1010;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ text-align: left;
+ white-space: normal;
+ background-color: #ffffff;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+
+.popover.top {
+ margin-top: -10px;
+}
+
+.popover.right {
+ margin-left: 10px;
+}
+
+.popover.bottom {
+ margin-top: 10px;
+}
+
+.popover.left {
+ margin-left: -10px;
+}
+
+.popover-title {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 18px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ -webkit-border-radius: 5px 5px 0 0;
+ -moz-border-radius: 5px 5px 0 0;
+ border-radius: 5px 5px 0 0;
+}
+
+.popover-title:empty {
+ display: none;
+}
+
+.popover-content {
+ padding: 9px 14px;
+}
+
+.popover .arrow,
+.popover .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+
+.popover .arrow {
+ border-width: 11px;
+}
+
+.popover .arrow:after {
+ border-width: 10px;
+ content: "";
+}
+
+.popover.top .arrow {
+ bottom: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-color: #999;
+ border-top-color: rgba(0, 0, 0, 0.25);
+ border-bottom-width: 0;
+}
+
+.popover.top .arrow:after {
+ bottom: 1px;
+ margin-left: -10px;
+ border-top-color: #ffffff;
+ border-bottom-width: 0;
+}
+
+.popover.right .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-right-color: #999;
+ border-right-color: rgba(0, 0, 0, 0.25);
+ border-left-width: 0;
+}
+
+.popover.right .arrow:after {
+ bottom: -10px;
+ left: 1px;
+ border-right-color: #ffffff;
+ border-left-width: 0;
+}
+
+.popover.bottom .arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-bottom-color: #999;
+ border-bottom-color: rgba(0, 0, 0, 0.25);
+ border-top-width: 0;
+}
+
+.popover.bottom .arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ border-bottom-color: #ffffff;
+ border-top-width: 0;
+}
+
+.popover.left .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-left-color: #999;
+ border-left-color: rgba(0, 0, 0, 0.25);
+ border-right-width: 0;
+}
+
+.popover.left .arrow:after {
+ right: 1px;
+ bottom: -10px;
+ border-left-color: #ffffff;
+ border-right-width: 0;
+}
+
+.thumbnails {
+ margin-left: -20px;
+ list-style: none;
+ *zoom: 1;
+}
+
+.thumbnails:before,
+.thumbnails:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.thumbnails:after {
+ clear: both;
+}
+
+.row-fluid .thumbnails {
+ margin-left: 0;
+}
+
+.thumbnails > li {
+ float: left;
+ margin-bottom: 20px;
+ margin-left: 20px;
+}
+
+.thumbnail {
+ display: block;
+ padding: 4px;
+ line-height: 20px;
+ border: 1px solid #ddd;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+ -webkit-transition: all 0.2s ease-in-out;
+ -moz-transition: all 0.2s ease-in-out;
+ -o-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+}
+
+a.thumbnail:hover,
+a.thumbnail:focus {
+ border-color: #0088cc;
+ -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+}
+
+.thumbnail > img {
+ display: block;
+ max-width: 100%;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.thumbnail .caption {
+ padding: 9px;
+ color: #555555;
+}
+
+.media,
+.media-body {
+ overflow: hidden;
+ *overflow: visible;
+ zoom: 1;
+}
+
+.media,
+.media .media {
+ margin-top: 15px;
+}
+
+.media:first-child {
+ margin-top: 0;
+}
+
+.media-object {
+ display: block;
+}
+
+.media-heading {
+ margin: 0 0 5px;
+}
+
+.media > .pull-left {
+ margin-right: 10px;
+}
+
+.media > .pull-right {
+ margin-left: 10px;
+}
+
+.media-list {
+ margin-left: 0;
+ list-style: none;
+}
+
+.label,
+.badge {
+ display: inline-block;
+ padding: 2px 4px;
+ font-size: 11.844px;
+ font-weight: bold;
+ line-height: 14px;
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ white-space: nowrap;
+ vertical-align: baseline;
+ background-color: #999999;
+}
+
+.label {
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.badge {
+ padding-right: 9px;
+ padding-left: 9px;
+ -webkit-border-radius: 9px;
+ -moz-border-radius: 9px;
+ border-radius: 9px;
+}
+
+.label:empty,
+.badge:empty {
+ display: none;
+}
+
+a.label:hover,
+a.label:focus,
+a.badge:hover,
+a.badge:focus {
+ color: #ffffff;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.label-important,
+.badge-important {
+ background-color: #b94a48;
+}
+
+.label-important[href],
+.badge-important[href] {
+ background-color: #953b39;
+}
+
+.label-warning,
+.badge-warning {
+ background-color: #f89406;
+}
+
+.label-warning[href],
+.badge-warning[href] {
+ background-color: #c67605;
+}
+
+.label-success,
+.badge-success {
+ background-color: #468847;
+}
+
+.label-success[href],
+.badge-success[href] {
+ background-color: #356635;
+}
+
+.label-info,
+.badge-info {
+ background-color: #3a87ad;
+}
+
+.label-info[href],
+.badge-info[href] {
+ background-color: #2d6987;
+}
+
+.label-inverse,
+.badge-inverse {
+ background-color: #333333;
+}
+
+.label-inverse[href],
+.badge-inverse[href] {
+ background-color: #1a1a1a;
+}
+
+.btn .label,
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+
+.btn-mini .label,
+.btn-mini .badge {
+ top: 0;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@-moz-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@-ms-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 0 0;
+ }
+ to {
+ background-position: 40px 0;
+ }
+}
+
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+.progress {
+ height: 20px;
+ margin-bottom: 20px;
+ overflow: hidden;
+ background-color: #f7f7f7;
+ background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
+ background-repeat: repeat-x;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+.progress .bar {
+ float: left;
+ width: 0;
+ height: 100%;
+ font-size: 12px;
+ color: #ffffff;
+ text-align: center;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #0e90d2;
+ background-image: -moz-linear-gradient(top, #149bdf, #0480be);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
+ background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
+ background-image: -o-linear-gradient(top, #149bdf, #0480be);
+ background-image: linear-gradient(to bottom, #149bdf, #0480be);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-transition: width 0.6s ease;
+ -moz-transition: width 0.6s ease;
+ -o-transition: width 0.6s ease;
+ transition: width 0.6s ease;
+}
+
+.progress .bar + .bar {
+ -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+}
+
+.progress-striped .bar {
+ background-color: #149bdf;
+ 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));
+ 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);
+ 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);
+ 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);
+ 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);
+ -webkit-background-size: 40px 40px;
+ -moz-background-size: 40px 40px;
+ -o-background-size: 40px 40px;
+ background-size: 40px 40px;
+}
+
+.progress.active .bar {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -moz-animation: progress-bar-stripes 2s linear infinite;
+ -ms-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+
+.progress-danger .bar,
+.progress .bar-danger {
+ background-color: #dd514c;
+ background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
+ background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);
+}
+
+.progress-danger.progress-striped .bar,
+.progress-striped .bar-danger {
+ background-color: #ee5f5b;
+ 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));
+ 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);
+ 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);
+ 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);
+ 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);
+}
+
+.progress-success .bar,
+.progress .bar-success {
+ background-color: #5eb95e;
+ background-image: -moz-linear-gradient(top, #62c462, #57a957);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
+ background-image: -webkit-linear-gradient(top, #62c462, #57a957);
+ background-image: -o-linear-gradient(top, #62c462, #57a957);
+ background-image: linear-gradient(to bottom, #62c462, #57a957);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);
+}
+
+.progress-success.progress-striped .bar,
+.progress-striped .bar-success {
+ background-color: #62c462;
+ 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));
+ 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);
+ 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);
+ 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);
+ 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);
+}
+
+.progress-info .bar,
+.progress .bar-info {
+ background-color: #4bb1cf;
+ background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
+ background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);
+}
+
+.progress-info.progress-striped .bar,
+.progress-striped .bar-info {
+ background-color: #5bc0de;
+ 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));
+ 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);
+ 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);
+ 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);
+ 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);
+}
+
+.progress-warning .bar,
+.progress .bar-warning {
+ background-color: #faa732;
+ background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+ background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+ background-image: -o-linear-gradient(top, #fbb450, #f89406);
+ background-image: linear-gradient(to bottom, #fbb450, #f89406);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
+}
+
+.progress-warning.progress-striped .bar,
+.progress-striped .bar-warning {
+ background-color: #fbb450;
+ 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));
+ 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);
+ 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);
+ 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);
+ 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);
+}
+
+.accordion {
+ margin-bottom: 20px;
+}
+
+.accordion-group {
+ margin-bottom: 2px;
+ border: 1px solid #e5e5e5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.accordion-heading {
+ border-bottom: 0;
+}
+
+.accordion-heading .accordion-toggle {
+ display: block;
+ padding: 8px 15px;
+}
+
+.accordion-toggle {
+ cursor: pointer;
+}
+
+.accordion-inner {
+ padding: 9px 15px;
+ border-top: 1px solid #e5e5e5;
+}
+
+.carousel {
+ position: relative;
+ margin-bottom: 20px;
+ line-height: 1;
+}
+
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+
+.carousel-inner > .item {
+ position: relative;
+ display: none;
+ -webkit-transition: 0.6s ease-in-out left;
+ -moz-transition: 0.6s ease-in-out left;
+ -o-transition: 0.6s ease-in-out left;
+ transition: 0.6s ease-in-out left;
+}
+
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ display: block;
+ line-height: 1;
+}
+
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ display: block;
+}
+
+.carousel-inner > .active {
+ left: 0;
+}
+
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+.carousel-inner > .next {
+ left: 100%;
+}
+
+.carousel-inner > .prev {
+ left: -100%;
+}
+
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+ left: 0;
+}
+
+.carousel-inner > .active.left {
+ left: -100%;
+}
+
+.carousel-inner > .active.right {
+ left: 100%;
+}
+
+.carousel-control {
+ position: absolute;
+ top: 40%;
+ left: 15px;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ font-size: 60px;
+ font-weight: 100;
+ line-height: 30px;
+ color: #ffffff;
+ text-align: center;
+ background: #222222;
+ border: 3px solid #ffffff;
+ -webkit-border-radius: 23px;
+ -moz-border-radius: 23px;
+ border-radius: 23px;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+
+.carousel-control.right {
+ right: 15px;
+ left: auto;
+}
+
+.carousel-control:hover,
+.carousel-control:focus {
+ color: #ffffff;
+ text-decoration: none;
+ opacity: 0.9;
+ filter: alpha(opacity=90);
+}
+
+.carousel-indicators {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ z-index: 5;
+ margin: 0;
+ list-style: none;
+}
+
+.carousel-indicators li {
+ display: block;
+ float: left;
+ width: 10px;
+ height: 10px;
+ margin-left: 5px;
+ text-indent: -999px;
+ background-color: #ccc;
+ background-color: rgba(255, 255, 255, 0.25);
+ border-radius: 5px;
+}
+
+.carousel-indicators .active {
+ background-color: #fff;
+}
+
+.carousel-caption {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: 15px;
+ background: #333333;
+ background: rgba(0, 0, 0, 0.75);
+}
+
+.carousel-caption h4,
+.carousel-caption p {
+ line-height: 20px;
+ color: #ffffff;
+}
+
+.carousel-caption h4 {
+ margin: 0 0 5px;
+}
+
+.carousel-caption p {
+ margin-bottom: 0;
+}
+
+.hero-unit {
+ padding: 60px;
+ margin-bottom: 30px;
+ font-size: 18px;
+ font-weight: 200;
+ line-height: 30px;
+ color: inherit;
+ background-color: #eeeeee;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.hero-unit h1 {
+ margin-bottom: 0;
+ font-size: 60px;
+ line-height: 1;
+ letter-spacing: -1px;
+ color: inherit;
+}
+
+.hero-unit li {
+ line-height: 30px;
+}
+
+.pull-right {
+ float: right;
+}
+
+.pull-left {
+ float: left;
+}
+
+.hide {
+ display: none;
+}
+
+.show {
+ display: block;
+}
+
+.invisible {
+ visibility: hidden;
+}
+
+.affix {
+ position: fixed;
+}
diff --git a/www/protected/extensions/bootstrap/assets/css/bootstrap.min.css b/www/protected/extensions/bootstrap/assets/css/bootstrap.min.css
new file mode 100644
index 0000000..b6428e6
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/bootstrap.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-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);-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);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)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;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));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);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);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);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);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;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));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);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);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);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)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;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));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);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);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);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)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;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));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);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);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);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)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;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));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);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);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);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)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
diff --git a/www/protected/extensions/bootstrap/assets/css/yiistrap.css b/www/protected/extensions/bootstrap/assets/css/yiistrap.css
new file mode 100644
index 0000000..ccf6340
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/yiistrap.css
@@ -0,0 +1,109 @@
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.clearfix:after {
+ clear: both;
+}
+.hide-text {
+ font: NaN a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.grid-view {
+ font-size: 13px;
+}
+.grid-view .table th > .sort-link {
+ color: #333;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ position: relative;
+}
+.grid-view .table th > .sort-link:hover {
+ text-decoration: none;
+}
+.grid-view .table th > .sort-link .caret {
+ border-color: transparent;
+ border-style: solid;
+ border-width: 4px;
+ display: none;
+ position: absolute;
+ right: 5px;
+}
+.grid-view .table th > .sort-link.asc .caret {
+ border-bottom-color: #333;
+ display: block;
+ top: 4px;
+}
+.grid-view .table th > .sort-link.desc .caret {
+ border-top-color: #333;
+ display: block;
+ top: 8px;
+}
+.grid-view .table .filters > td .filter-container {
+ padding: 0 16px 0 0;
+}
+.grid-view .table .filters > td .filter-container input[type="text"],
+.grid-view .table .filters > td .filter-container select {
+ margin-bottom: 0;
+ width: 100%;
+}
+.grid-view .table tr.selected td {
+ background: #eee;
+}
+.grid-view .table td {
+ vertical-align: middle;
+}
+.grid-view .table .checkbox-column {
+ width: 15px;
+}
+.grid-view .table .number-column {
+ text-align: right;
+}
+.grid-view .table .button-column {
+ text-align: right;
+ min-width: 50px;
+}
+.grid-view .summary {
+ color: #999999;
+ font-size: 12px;
+ padding: 6px 0;
+ text-align: right;
+}
+.grid-view .empty {
+ font-style: italic;
+}
+.grid-view.grid-view-loading {
+ background: url(../img/loader.gif) no-repeat 100% 10px;
+}
+.grid-view.grid-view-loading .table {
+ opacity: 0.5;
+}
+.grid-view.grid-view-loading .table th > .sort-link .caret {
+ display: none;
+}
+.detail-view .null { color:#ffc0cb; }
+.detail-view th {
+ text-align:right;
+ width:160px;
+}
+span.required {
+ color: #b94a48;
+ font-weight: bold;
+}
diff --git a/www/protected/extensions/bootstrap/assets/css/yiistrap.min.css b/www/protected/extensions/bootstrap/assets/css/yiistrap.min.css
new file mode 100644
index 0000000..4a771fa
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/css/yiistrap.min.css
@@ -0,0 +1 @@
+.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:NaN a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.grid-view{font-size:13px}.grid-view .table th>.sort-link{color:#333;display:block;font-size:14px;font-weight:bold;position:relative}.grid-view .table th>.sort-link:hover{text-decoration:none}.grid-view .table th>.sort-link .caret{border-color:transparent;border-style:solid;border-width:4px;display:none;position:absolute;right:5px}.grid-view .table th>.sort-link.asc .caret{border-bottom-color:#333;display:block;top:4px}.grid-view .table th>.sort-link.desc .caret{border-top-color:#333;display:block;top:8px}.grid-view .table .filters>td .filter-container{padding:0 16px 0 0}.grid-view .table .filters>td .filter-container input[type="text"], .grid-view .table .filters>td .filter-container select{margin-bottom:0;width:100%}.grid-view .table tr.selected td{background:#eee}.grid-view .table td{vertical-align:middle}.grid-view .table .checkbox-column{width:15px}.grid-view .table .number-column{text-align:right}.grid-view .table .button-column{text-align:right;min-width:50px}.grid-view .summary{color:#999;font-size:12px;padding:6px 0;text-align:right}.grid-view .empty{font-style:italic}.grid-view.grid-view-loading{background:url(../img/loader.gif) no-repeat 100% 10px}.grid-view.grid-view-loading .table{opacity:.5}.grid-view.grid-view-loading .table th>.sort-link .caret{display:none}.detail-view .null{color:#ffc0cb;}.detail-view th{text-align:right;width:160px;}span.required{color:#b94a48;font-weight:bold}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings-white.png b/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000..3bf6484
Binary files /dev/null and b/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings-white.png differ
diff --git a/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings.png b/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings.png
new file mode 100644
index 0000000..a996999
Binary files /dev/null and b/www/protected/extensions/bootstrap/assets/img/glyphicons-halflings.png differ
diff --git a/www/protected/extensions/bootstrap/assets/img/loader.gif b/www/protected/extensions/bootstrap/assets/img/loader.gif
new file mode 100644
index 0000000..155fcf5
Binary files /dev/null and b/www/protected/extensions/bootstrap/assets/img/loader.gif differ
diff --git a/www/protected/extensions/bootstrap/assets/js/bootstrap.js b/www/protected/extensions/bootstrap/assets/js/bootstrap.js
new file mode 100644
index 0000000..643e71c
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/js/bootstrap.js
@@ -0,0 +1,2280 @@
+/* ===================================================
+ * bootstrap-transition.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
+ * ===================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
+ * ======================================================= */
+
+ $(function () {
+
+ $.support.transition = (function () {
+
+ var transitionEnd = (function () {
+
+ var el = document.createElement('bootstrap')
+ , transEndEventNames = {
+ 'WebkitTransition' : 'webkitTransitionEnd'
+ , 'MozTransition' : 'transitionend'
+ , 'OTransition' : 'oTransitionEnd otransitionend'
+ , 'transition' : 'transitionend'
+ }
+ , name
+
+ for (name in transEndEventNames){
+ if (el.style[name] !== undefined) {
+ return transEndEventNames[name]
+ }
+ }
+
+ }())
+
+ return transitionEnd && {
+ end: transitionEnd
+ }
+
+ })()
+
+ })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-alert.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* ALERT CLASS DEFINITION
+ * ====================== */
+
+ var dismiss = '[data-dismiss="alert"]'
+ , Alert = function (el) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.prototype.close = function (e) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+
+ e && e.preventDefault()
+
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
+
+ $parent.trigger(e = $.Event('close'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ $parent
+ .trigger('closed')
+ .remove()
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent.on($.support.transition.end, removeElement) :
+ removeElement()
+ }
+
+
+ /* ALERT PLUGIN DEFINITION
+ * ======================= */
+
+ var old = $.fn.alert
+
+ $.fn.alert = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('alert')
+ if (!data) $this.data('alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.alert.Constructor = Alert
+
+
+ /* ALERT NO CONFLICT
+ * ================= */
+
+ $.fn.alert.noConflict = function () {
+ $.fn.alert = old
+ return this
+ }
+
+
+ /* ALERT DATA-API
+ * ============== */
+
+ $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-button.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* BUTTON PUBLIC CLASS DEFINITION
+ * ============================== */
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.button.defaults, options)
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ , $el = this.$element
+ , data = $el.data()
+ , val = $el.is('input') ? 'val' : 'html'
+
+ state = state + 'Text'
+ data.resetText || $el.data('resetText', $el[val]())
+
+ $el[val](data[state] || this.options[state])
+
+ // push to event loop to allow forms to submit
+ setTimeout(function () {
+ state == 'loadingText' ?
+ $el.addClass(d).attr(d, d) :
+ $el.removeClass(d).removeAttr(d)
+ }, 0)
+ }
+
+ Button.prototype.toggle = function () {
+ var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
+
+ $parent && $parent
+ .find('.active')
+ .removeClass('active')
+
+ this.$element.toggleClass('active')
+ }
+
+
+ /* BUTTON PLUGIN DEFINITION
+ * ======================== */
+
+ var old = $.fn.button
+
+ $.fn.button = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('button')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('button', (data = new Button(this, options)))
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ $.fn.button.defaults = {
+ loadingText: 'loading...'
+ }
+
+ $.fn.button.Constructor = Button
+
+
+ /* BUTTON NO CONFLICT
+ * ================== */
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ /* BUTTON DATA-API
+ * =============== */
+
+ $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ $btn.button('toggle')
+ })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-carousel.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* CAROUSEL CLASS DEFINITION
+ * ========================= */
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.$indicators = this.$element.find('.carousel-indicators')
+ this.options = options
+ this.options.pause == 'hover' && this.$element
+ .on('mouseenter', $.proxy(this.pause, this))
+ .on('mouseleave', $.proxy(this.cycle, this))
+ }
+
+ Carousel.prototype = {
+
+ cycle: function (e) {
+ if (!e) this.paused = false
+ if (this.interval) clearInterval(this.interval);
+ this.options.interval
+ && !this.paused
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+ return this
+ }
+
+ , getActiveIndex: function () {
+ this.$active = this.$element.find('.item.active')
+ this.$items = this.$active.parent().children()
+ return this.$items.index(this.$active)
+ }
+
+ , to: function (pos) {
+ var activeIndex = this.getActiveIndex()
+ , that = this
+
+ if (pos > (this.$items.length - 1) || pos < 0) return
+
+ if (this.sliding) {
+ return this.$element.one('slid', function () {
+ that.to(pos)
+ })
+ }
+
+ if (activeIndex == pos) {
+ return this.pause().cycle()
+ }
+
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+ }
+
+ , pause: function (e) {
+ if (!e) this.paused = true
+ if (this.$element.find('.next, .prev').length && $.support.transition.end) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle(true)
+ }
+ clearInterval(this.interval)
+ this.interval = null
+ return this
+ }
+
+ , next: function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ , prev: function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ , slide: function (type, next) {
+ var $active = this.$element.find('.item.active')
+ , $next = next || $active[type]()
+ , isCycling = this.interval
+ , direction = type == 'next' ? 'left' : 'right'
+ , fallback = type == 'next' ? 'first' : 'last'
+ , that = this
+ , e
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ $next = $next.length ? $next : this.$element.find('.item')[fallback]()
+
+ e = $.Event('slide', {
+ relatedTarget: $next[0]
+ , direction: direction
+ })
+
+ if ($next.hasClass('active')) return
+
+ if (this.$indicators.length) {
+ this.$indicators.find('.active').removeClass('active')
+ this.$element.one('slid', function () {
+ var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
+ $nextIndicator && $nextIndicator.addClass('active')
+ })
+ }
+
+ if ($.support.transition && this.$element.hasClass('slide')) {
+ this.$element.trigger(e)
+ if (e.isDefaultPrevented()) return
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ this.$element.one($.support.transition.end, function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () { that.$element.trigger('slid') }, 0)
+ })
+ } else {
+ this.$element.trigger(e)
+ if (e.isDefaultPrevented()) return
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger('slid')
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+ }
+
+
+ /* CAROUSEL PLUGIN DEFINITION
+ * ========================== */
+
+ var old = $.fn.carousel
+
+ $.fn.carousel = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('carousel')
+ , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
+ , action = typeof option == 'string' ? option : options.slide
+ if (!data) $this.data('carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (action) data[action]()
+ else if (options.interval) data.pause().cycle()
+ })
+ }
+
+ $.fn.carousel.defaults = {
+ interval: 5000
+ , pause: 'hover'
+ }
+
+ $.fn.carousel.Constructor = Carousel
+
+
+ /* CAROUSEL NO CONFLICT
+ * ==================== */
+
+ $.fn.carousel.noConflict = function () {
+ $.fn.carousel = old
+ return this
+ }
+
+ /* CAROUSEL DATA-API
+ * ================= */
+
+ $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+ var $this = $(this), href
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ , options = $.extend({}, $target.data(), $this.data())
+ , slideIndex
+
+ $target.carousel(options)
+
+ if (slideIndex = $this.attr('data-slide-to')) {
+ $target.data('carousel').pause().to(slideIndex).cycle()
+ }
+
+ e.preventDefault()
+ })
+
+}(window.jQuery);/* =============================================================
+ * bootstrap-collapse.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* COLLAPSE PUBLIC CLASS DEFINITION
+ * ================================ */
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.collapse.defaults, options)
+
+ if (this.options.parent) {
+ this.$parent = $(this.options.parent)
+ }
+
+ this.options.toggle && this.toggle()
+ }
+
+ Collapse.prototype = {
+
+ constructor: Collapse
+
+ , dimension: function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ , show: function () {
+ var dimension
+ , scroll
+ , actives
+ , hasData
+
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ dimension = this.dimension()
+ scroll = $.camelCase(['scroll', dimension].join('-'))
+ actives = this.$parent && this.$parent.find('> .accordion-group > .in')
+
+ if (actives && actives.length) {
+ hasData = actives.data('collapse')
+ if (hasData && hasData.transitioning) return
+ actives.collapse('hide')
+ hasData || actives.data('collapse', null)
+ }
+
+ this.$element[dimension](0)
+ this.transition('addClass', $.Event('show'), 'shown')
+ $.support.transition && this.$element[dimension](this.$element[0][scroll])
+ }
+
+ , hide: function () {
+ var dimension
+ if (this.transitioning || !this.$element.hasClass('in')) return
+ dimension = this.dimension()
+ this.reset(this.$element[dimension]())
+ this.transition('removeClass', $.Event('hide'), 'hidden')
+ this.$element[dimension](0)
+ }
+
+ , reset: function (size) {
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ [dimension](size || 'auto')
+ [0].offsetWidth
+
+ this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
+
+ return this
+ }
+
+ , transition: function (method, startEvent, completeEvent) {
+ var that = this
+ , complete = function () {
+ if (startEvent.type == 'show') that.reset()
+ that.transitioning = 0
+ that.$element.trigger(completeEvent)
+ }
+
+ this.$element.trigger(startEvent)
+
+ if (startEvent.isDefaultPrevented()) return
+
+ this.transitioning = 1
+
+ this.$element[method]('in')
+
+ $.support.transition && this.$element.hasClass('collapse') ?
+ this.$element.one($.support.transition.end, complete) :
+ complete()
+ }
+
+ , toggle: function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+ }
+
+
+ /* COLLAPSE PLUGIN DEFINITION
+ * ========================== */
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('collapse')
+ , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
+ if (!data) $this.data('collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.collapse.defaults = {
+ toggle: true
+ }
+
+ $.fn.collapse.Constructor = Collapse
+
+
+ /* COLLAPSE NO CONFLICT
+ * ==================== */
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ /* COLLAPSE DATA-API
+ * ================= */
+
+ $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
+ var $this = $(this), href
+ , target = $this.attr('data-target')
+ || e.preventDefault()
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
+ $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
+ $(target).collapse(option)
+ })
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-dropdown.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle=dropdown]'
+ , Dropdown = function (element) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function (e) {
+ var $this = $(this)
+ , $parent
+ , isActive
+
+ if ($this.is('.disabled, :disabled')) return
+
+ $parent = getParent($this)
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement) {
+ // if mobile we we use a backdrop because click events don't delegate
+ $('
').insertBefore($(this)).on('click', clearMenus)
+ }
+ $parent.toggleClass('open')
+ }
+
+ $this.focus()
+
+ return false
+ }
+
+ , keydown: function (e) {
+ var $this
+ , $items
+ , $active
+ , $parent
+ , isActive
+ , index
+
+ if (!/(38|40|27)/.test(e.keyCode)) return
+
+ $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ $parent = getParent($this)
+
+ isActive = $parent.hasClass('open')
+
+ if (!isActive || (isActive && e.keyCode == 27)) {
+ if (e.which == 27) $parent.find(toggle).focus()
+ return $this.click()
+ }
+
+ $items = $('[role=menu] li:not(.divider):visible a', $parent)
+
+ if (!$items.length) return
+
+ index = $items.index($items.filter(':focus'))
+
+ if (e.keyCode == 38 && index > 0) index-- // up
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items
+ .eq(index)
+ .focus()
+ }
+
+ }
+
+ function clearMenus() {
+ $('.dropdown-backdrop').remove()
+ $(toggle).each(function () {
+ getParent($(this)).removeClass('open')
+ })
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+ , $parent
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = selector && $(selector)
+
+ if (!$parent || !$parent.length) $parent = $this.parent()
+
+ return $parent
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* DROPDOWN NO CONFLICT
+ * ==================== */
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(document)
+ .on('click.dropdown.data-api', clearMenus)
+ .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
+ .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
+
+}(window.jQuery);
+/* =========================================================
+ * bootstrap-modal.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#modals
+ * =========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================= */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* MODAL CLASS DEFINITION
+ * ====================== */
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$element = $(element)
+ .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+ this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
+ }
+
+ Modal.prototype = {
+
+ constructor: Modal
+
+ , toggle: function () {
+ return this[!this.isShown ? 'show' : 'hide']()
+ }
+
+ , show: function () {
+ var that = this
+ , e = $.Event('show')
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.escape()
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(document.body) //don't move modals dom position
+ }
+
+ that.$element.show()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element
+ .addClass('in')
+ .attr('aria-hidden', false)
+
+ that.enforceFocus()
+
+ transition ?
+ that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
+ that.$element.focus().trigger('shown')
+
+ })
+ }
+
+ , hide: function (e) {
+ e && e.preventDefault()
+
+ var that = this
+
+ e = $.Event('hide')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+
+ $(document).off('focusin.modal')
+
+ this.$element
+ .removeClass('in')
+ .attr('aria-hidden', true)
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.hideWithTransition() :
+ this.hideModal()
+ }
+
+ , enforceFocus: function () {
+ var that = this
+ $(document).on('focusin.modal', function (e) {
+ if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
+ that.$element.focus()
+ }
+ })
+ }
+
+ , escape: function () {
+ var that = this
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keyup.dismiss.modal', function ( e ) {
+ e.which == 27 && that.hide()
+ })
+ } else if (!this.isShown) {
+ this.$element.off('keyup.dismiss.modal')
+ }
+ }
+
+ , hideWithTransition: function () {
+ var that = this
+ , timeout = setTimeout(function () {
+ that.$element.off($.support.transition.end)
+ that.hideModal()
+ }, 500)
+
+ this.$element.one($.support.transition.end, function () {
+ clearTimeout(timeout)
+ that.hideModal()
+ })
+ }
+
+ , hideModal: function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.removeBackdrop()
+ that.$element.trigger('hidden')
+ })
+ }
+
+ , removeBackdrop: function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ , backdrop: function (callback) {
+ var that = this
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('
')
+ .appendTo(document.body)
+
+ this.$backdrop.click(
+ this.options.backdrop == 'static' ?
+ $.proxy(this.$element[0].focus, this.$element[0])
+ : $.proxy(this.hide, this)
+ )
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop.one($.support.transition.end, callback) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade')?
+ this.$backdrop.one($.support.transition.end, callback) :
+ callback()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+ }
+
+
+ /* MODAL PLUGIN DEFINITION
+ * ======================= */
+
+ var old = $.fn.modal
+
+ $.fn.modal = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('modal')
+ , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
+ if (!data) $this.data('modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option]()
+ else if (options.show) data.show()
+ })
+ }
+
+ $.fn.modal.defaults = {
+ backdrop: true
+ , keyboard: true
+ , show: true
+ }
+
+ $.fn.modal.Constructor = Modal
+
+
+ /* MODAL NO CONFLICT
+ * ================= */
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ /* MODAL DATA-API
+ * ============== */
+
+ $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ , href = $this.attr('href')
+ , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+ , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
+
+ e.preventDefault()
+
+ $target
+ .modal(option)
+ .one('hide', function () {
+ $this.focus()
+ })
+ })
+
+}(window.jQuery);
+/* ===========================================================
+ * bootstrap-tooltip.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* TOOLTIP PUBLIC CLASS DEFINITION
+ * =============================== */
+
+ var Tooltip = function (element, options) {
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.prototype = {
+
+ constructor: Tooltip
+
+ , init: function (type, element, options) {
+ var eventIn
+ , eventOut
+ , triggers
+ , trigger
+ , i
+
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.enabled = true
+
+ triggers = this.options.trigger.split(' ')
+
+ for (i = triggers.length; i--;) {
+ trigger = triggers[i]
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
+ eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ , getOptions: function (options) {
+ options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay
+ , hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ , enter: function (e) {
+ var defaults = $.fn[this.type].defaults
+ , options = {}
+ , self
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ }, this)
+
+ self = $(e.currentTarget)[this.type](options).data(this.type)
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ clearTimeout(this.timeout)
+ self.hoverState = 'in'
+ this.timeout = setTimeout(function() {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ , leave: function (e) {
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+ if (this.timeout) clearTimeout(this.timeout)
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.hoverState = 'out'
+ this.timeout = setTimeout(function() {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ , show: function () {
+ var $tip
+ , pos
+ , actualWidth
+ , actualHeight
+ , placement
+ , tp
+ , e = $.Event('show')
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+ if (e.isDefaultPrevented()) return
+ $tip = this.tip()
+ this.setContent()
+
+ if (this.options.animation) {
+ $tip.addClass('fade')
+ }
+
+ placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+ pos = this.getPosition()
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+
+ switch (placement) {
+ case 'bottom':
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
+ break
+ case 'top':
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
+ break
+ case 'left':
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
+ break
+ case 'right':
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
+ break
+ }
+
+ this.applyPlacement(tp, placement)
+ this.$element.trigger('shown')
+ }
+ }
+
+ , applyPlacement: function(offset, placement){
+ var $tip = this.tip()
+ , width = $tip[0].offsetWidth
+ , height = $tip[0].offsetHeight
+ , actualWidth
+ , actualHeight
+ , delta
+ , replace
+
+ $tip
+ .offset(offset)
+ .addClass(placement)
+ .addClass('in')
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
+ replace = true
+ }
+
+ if (placement == 'bottom' || placement == 'top') {
+ delta = 0
+
+ if (offset.left < 0){
+ delta = offset.left * -2
+ offset.left = 0
+ $tip.offset(offset)
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
+ }
+
+ , replaceArrow: function(delta, dimension, position){
+ this
+ .arrow()
+ .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
+ }
+
+ , setContent: function () {
+ var $tip = this.tip()
+ , title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ , hide: function () {
+ var that = this
+ , $tip = this.tip()
+ , e = $.Event('hide')
+
+ this.$element.trigger(e)
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ function removeWithAnimation() {
+ var timeout = setTimeout(function () {
+ $tip.off($.support.transition.end).detach()
+ }, 500)
+
+ $tip.one($.support.transition.end, function () {
+ clearTimeout(timeout)
+ $tip.detach()
+ })
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ removeWithAnimation() :
+ $tip.detach()
+
+ this.$element.trigger('hidden')
+
+ return this
+ }
+
+ , fixTitle: function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ , hasContent: function () {
+ return this.getTitle()
+ }
+
+ , getPosition: function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth
+ , height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ , getTitle: function () {
+ var title
+ , $e = this.$element
+ , o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ , tip: function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ , arrow: function(){
+ return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
+ }
+
+ , validate: function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ , enable: function () {
+ this.enabled = true
+ }
+
+ , disable: function () {
+ this.enabled = false
+ }
+
+ , toggleEnabled: function () {
+ this.enabled = !this.enabled
+ }
+
+ , toggle: function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
+ self.tip().hasClass('in') ? self.hide() : self.show()
+ }
+
+ , destroy: function () {
+ this.hide().$element.off('.' + this.type).removeData(this.type)
+ }
+
+ }
+
+
+ /* TOOLTIP PLUGIN DEFINITION
+ * ========================= */
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('tooltip')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tooltip.Constructor = Tooltip
+
+ $.fn.tooltip.defaults = {
+ animation: true
+ , placement: 'top'
+ , selector: false
+ , template: ''
+ , trigger: 'hover focus'
+ , title: ''
+ , delay: 0
+ , html: false
+ , container: false
+ }
+
+
+ /* TOOLTIP NO CONFLICT
+ * =================== */
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(window.jQuery);
+/* ===========================================================
+ * bootstrap-popover.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* POPOVER PUBLIC CLASS DEFINITION
+ * =============================== */
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+
+ /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
+ ========================================== */
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
+
+ constructor: Popover
+
+ , setContent: function () {
+ var $tip = this.tip()
+ , title = this.getTitle()
+ , content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
+
+ $tip.removeClass('fade top bottom left right in')
+ }
+
+ , hasContent: function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ , getContent: function () {
+ var content
+ , $e = this.$element
+ , o = this.options
+
+ content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
+ || $e.attr('data-content')
+
+ return content
+ }
+
+ , tip: function () {
+ if (!this.$tip) {
+ this.$tip = $(this.options.template)
+ }
+ return this.$tip
+ }
+
+ , destroy: function () {
+ this.hide().$element.off('.' + this.type).removeData(this.type)
+ }
+
+ })
+
+
+ /* POPOVER PLUGIN DEFINITION
+ * ======================= */
+
+ var old = $.fn.popover
+
+ $.fn.popover = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('popover')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.popover.Constructor = Popover
+
+ $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
+ placement: 'right'
+ , trigger: 'click'
+ , content: ''
+ , template: ''
+ })
+
+
+ /* POPOVER NO CONFLICT
+ * =================== */
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(window.jQuery);
+/* =============================================================
+ * bootstrap-scrollspy.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* SCROLLSPY CLASS DEFINITION
+ * ========================== */
+
+ function ScrollSpy(element, options) {
+ var process = $.proxy(this.process, this)
+ , $element = $(element).is('body') ? $(window) : $(element)
+ , href
+ this.options = $.extend({}, $.fn.scrollspy.defaults, options)
+ this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
+ this.selector = (this.options.target
+ || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ || '') + ' .nav li > a'
+ this.$body = $('body')
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.prototype = {
+
+ constructor: ScrollSpy
+
+ , refresh: function () {
+ var self = this
+ , $targets
+
+ this.offsets = $([])
+ this.targets = $([])
+
+ $targets = this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ , href = $el.data('target') || $el.attr('href')
+ , $href = /^#\w/.test(href) && $(href)
+ return ( $href
+ && $href.length
+ && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ self.offsets.push(this[0])
+ self.targets.push(this[1])
+ })
+ }
+
+ , process: function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
+ , maxScroll = scrollHeight - this.$scrollElement.height()
+ , offsets = this.offsets
+ , targets = this.targets
+ , activeTarget = this.activeTarget
+ , i
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets.last()[0])
+ && this.activate ( i )
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+ && this.activate( targets[i] )
+ }
+ }
+
+ , activate: function (target) {
+ var active
+ , selector
+
+ this.activeTarget = target
+
+ $(this.selector)
+ .parent('.active')
+ .removeClass('active')
+
+ selector = this.selector
+ + '[data-target="' + target + '"],'
+ + this.selector + '[href="' + target + '"]'
+
+ active = $(selector)
+ .parent('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active.closest('li.dropdown').addClass('active')
+ }
+
+ active.trigger('activate')
+ }
+
+ }
+
+
+ /* SCROLLSPY PLUGIN DEFINITION
+ * =========================== */
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('scrollspy')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+ $.fn.scrollspy.defaults = {
+ offset: 10
+ }
+
+
+ /* SCROLLSPY NO CONFLICT
+ * ===================== */
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ /* SCROLLSPY DATA-API
+ * ================== */
+
+ $(window).on('load', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ $spy.scrollspy($spy.data())
+ })
+ })
+
+}(window.jQuery);/* ========================================================
+ * bootstrap-tab.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* TAB CLASS DEFINITION
+ * ==================== */
+
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+
+ Tab.prototype = {
+
+ constructor: Tab
+
+ , show: function () {
+ var $this = this.element
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
+ , selector = $this.attr('data-target')
+ , previous
+ , $target
+ , e
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ if ( $this.parent('li').hasClass('active') ) return
+
+ previous = $ul.find('.active:last a')[0]
+
+ e = $.Event('show', {
+ relatedTarget: previous
+ })
+
+ $this.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $target = $(selector)
+
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ , activate: function ( element, container, callback) {
+ var $active = container.find('> .active')
+ , transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if ( element.parent('.dropdown-menu') ) {
+ element.closest('li.dropdown').addClass('active')
+ }
+
+ callback && callback()
+ }
+
+ transition ?
+ $active.one($.support.transition.end, next) :
+ next()
+
+ $active.removeClass('in')
+ }
+ }
+
+
+ /* TAB PLUGIN DEFINITION
+ * ===================== */
+
+ var old = $.fn.tab
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('tab')
+ if (!data) $this.data('tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ /* TAB NO CONFLICT
+ * =============== */
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ /* TAB DATA-API
+ * ============ */
+
+ $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
+ })
+
+}(window.jQuery);/* =============================================================
+ * bootstrap-typeahead.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function($){
+
+ "use strict"; // jshint ;_;
+
+
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
+ * ================================= */
+
+ var Typeahead = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.typeahead.defaults, options)
+ this.matcher = this.options.matcher || this.matcher
+ this.sorter = this.options.sorter || this.sorter
+ this.highlighter = this.options.highlighter || this.highlighter
+ this.updater = this.options.updater || this.updater
+ this.source = this.options.source
+ this.$menu = $(this.options.menu)
+ this.shown = false
+ this.listen()
+ }
+
+ Typeahead.prototype = {
+
+ constructor: Typeahead
+
+ , select: function () {
+ var val = this.$menu.find('.active').attr('data-value')
+ this.$element
+ .val(this.updater(val))
+ .change()
+ return this.hide()
+ }
+
+ , updater: function (item) {
+ return item
+ }
+
+ , show: function () {
+ var pos = $.extend({}, this.$element.position(), {
+ height: this.$element[0].offsetHeight
+ })
+
+ this.$menu
+ .insertAfter(this.$element)
+ .css({
+ top: pos.top + pos.height
+ , left: pos.left
+ })
+ .show()
+
+ this.shown = true
+ return this
+ }
+
+ , hide: function () {
+ this.$menu.hide()
+ this.shown = false
+ return this
+ }
+
+ , lookup: function (event) {
+ var items
+
+ this.query = this.$element.val()
+
+ if (!this.query || this.query.length < this.options.minLength) {
+ return this.shown ? this.hide() : this
+ }
+
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
+
+ return items ? this.process(items) : this
+ }
+
+ , process: function (items) {
+ var that = this
+
+ items = $.grep(items, function (item) {
+ return that.matcher(item)
+ })
+
+ items = this.sorter(items)
+
+ if (!items.length) {
+ return this.shown ? this.hide() : this
+ }
+
+ return this.render(items.slice(0, this.options.items)).show()
+ }
+
+ , matcher: function (item) {
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase())
+ }
+
+ , sorter: function (items) {
+ var beginswith = []
+ , caseSensitive = []
+ , caseInsensitive = []
+ , item
+
+ while (item = items.shift()) {
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
+ else if (~item.indexOf(this.query)) caseSensitive.push(item)
+ else caseInsensitive.push(item)
+ }
+
+ return beginswith.concat(caseSensitive, caseInsensitive)
+ }
+
+ , highlighter: function (item) {
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
+ return '' + match + ' '
+ })
+ }
+
+ , render: function (items) {
+ var that = this
+
+ items = $(items).map(function (i, item) {
+ i = $(that.options.item).attr('data-value', item)
+ i.find('a').html(that.highlighter(item))
+ return i[0]
+ })
+
+ items.first().addClass('active')
+ this.$menu.html(items)
+ return this
+ }
+
+ , next: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , next = active.next()
+
+ if (!next.length) {
+ next = $(this.$menu.find('li')[0])
+ }
+
+ next.addClass('active')
+ }
+
+ , prev: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , prev = active.prev()
+
+ if (!prev.length) {
+ prev = this.$menu.find('li').last()
+ }
+
+ prev.addClass('active')
+ }
+
+ , listen: function () {
+ this.$element
+ .on('focus', $.proxy(this.focus, this))
+ .on('blur', $.proxy(this.blur, this))
+ .on('keypress', $.proxy(this.keypress, this))
+ .on('keyup', $.proxy(this.keyup, this))
+
+ if (this.eventSupported('keydown')) {
+ this.$element.on('keydown', $.proxy(this.keydown, this))
+ }
+
+ this.$menu
+ .on('click', $.proxy(this.click, this))
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
+ }
+
+ , eventSupported: function(eventName) {
+ var isSupported = eventName in this.$element
+ if (!isSupported) {
+ this.$element.setAttribute(eventName, 'return;')
+ isSupported = typeof this.$element[eventName] === 'function'
+ }
+ return isSupported
+ }
+
+ , move: function (e) {
+ if (!this.shown) return
+
+ switch(e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ e.preventDefault()
+ break
+
+ case 38: // up arrow
+ e.preventDefault()
+ this.prev()
+ break
+
+ case 40: // down arrow
+ e.preventDefault()
+ this.next()
+ break
+ }
+
+ e.stopPropagation()
+ }
+
+ , keydown: function (e) {
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
+ this.move(e)
+ }
+
+ , keypress: function (e) {
+ if (this.suppressKeyPressRepeat) return
+ this.move(e)
+ }
+
+ , keyup: function (e) {
+ switch(e.keyCode) {
+ case 40: // down arrow
+ case 38: // up arrow
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ break
+
+ case 9: // tab
+ case 13: // enter
+ if (!this.shown) return
+ this.select()
+ break
+
+ case 27: // escape
+ if (!this.shown) return
+ this.hide()
+ break
+
+ default:
+ this.lookup()
+ }
+
+ e.stopPropagation()
+ e.preventDefault()
+ }
+
+ , focus: function (e) {
+ this.focused = true
+ }
+
+ , blur: function (e) {
+ this.focused = false
+ if (!this.mousedover && this.shown) this.hide()
+ }
+
+ , click: function (e) {
+ e.stopPropagation()
+ e.preventDefault()
+ this.select()
+ this.$element.focus()
+ }
+
+ , mouseenter: function (e) {
+ this.mousedover = true
+ this.$menu.find('.active').removeClass('active')
+ $(e.currentTarget).addClass('active')
+ }
+
+ , mouseleave: function (e) {
+ this.mousedover = false
+ if (!this.focused && this.shown) this.hide()
+ }
+
+ }
+
+
+ /* TYPEAHEAD PLUGIN DEFINITION
+ * =========================== */
+
+ var old = $.fn.typeahead
+
+ $.fn.typeahead = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('typeahead')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.typeahead.defaults = {
+ source: []
+ , items: 8
+ , menu: ''
+ , item: ' '
+ , minLength: 1
+ }
+
+ $.fn.typeahead.Constructor = Typeahead
+
+
+ /* TYPEAHEAD NO CONFLICT
+ * =================== */
+
+ $.fn.typeahead.noConflict = function () {
+ $.fn.typeahead = old
+ return this
+ }
+
+
+ /* TYPEAHEAD DATA-API
+ * ================== */
+
+ $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
+ var $this = $(this)
+ if ($this.data('typeahead')) return
+ $this.typeahead($this.data())
+ })
+
+}(window.jQuery);
+/* ==========================================================
+ * bootstrap-affix.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#affix
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+ "use strict"; // jshint ;_;
+
+
+ /* AFFIX CLASS DEFINITION
+ * ====================== */
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, $.fn.affix.defaults, options)
+ this.$window = $(window)
+ .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
+ this.$element = $(element)
+ this.checkPosition()
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var scrollHeight = $(document).height()
+ , scrollTop = this.$window.scrollTop()
+ , position = this.$element.offset()
+ , offset = this.options.offset
+ , offsetBottom = offset.bottom
+ , offsetTop = offset.top
+ , reset = 'affix affix-top affix-bottom'
+ , affix
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top()
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
+
+ affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
+ false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
+ 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
+ 'top' : false
+
+ if (this.affixed === affix) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? position.top - scrollTop : null
+
+ this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
+ }
+
+
+ /* AFFIX PLUGIN DEFINITION
+ * ======================= */
+
+ var old = $.fn.affix
+
+ $.fn.affix = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('affix')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.affix.Constructor = Affix
+
+ $.fn.affix.defaults = {
+ offset: 0
+ }
+
+
+ /* AFFIX NO CONFLICT
+ * ================= */
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ /* AFFIX DATA-API
+ * ============== */
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ , data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ data.offsetBottom && (data.offset.bottom = data.offsetBottom)
+ data.offsetTop && (data.offset.top = data.offsetTop)
+
+ $spy.affix(data)
+ })
+ })
+
+
+}(window.jQuery);
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/js/bootstrap.min.js b/www/protected/extensions/bootstrap/assets/js/bootstrap.min.js
new file mode 100644
index 0000000..f9cbdae
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/js/bootstrap.min.js
@@ -0,0 +1,6 @@
+/*!
+* Bootstrap.js by @fat & @mdo
+* Copyright 2012 Twitter, Inc.
+* http://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('
').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f ').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:''}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:' ',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/less/accordion.less b/www/protected/extensions/bootstrap/assets/less/accordion.less
new file mode 100644
index 0000000..d63523b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/accordion.less
@@ -0,0 +1,34 @@
+//
+// Accordion
+// --------------------------------------------------
+
+
+// Parent container
+.accordion {
+ margin-bottom: @baseLineHeight;
+}
+
+// Group == heading + body
+.accordion-group {
+ margin-bottom: 2px;
+ border: 1px solid #e5e5e5;
+ .border-radius(@baseBorderRadius);
+}
+.accordion-heading {
+ border-bottom: 0;
+}
+.accordion-heading .accordion-toggle {
+ display: block;
+ padding: 8px 15px;
+}
+
+// General toggle styles
+.accordion-toggle {
+ cursor: pointer;
+}
+
+// Inner needs the styles because you can't animate properly with any styles on the element
+.accordion-inner {
+ padding: 9px 15px;
+ border-top: 1px solid #e5e5e5;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/alerts.less b/www/protected/extensions/bootstrap/assets/less/alerts.less
new file mode 100644
index 0000000..0116b19
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/alerts.less
@@ -0,0 +1,79 @@
+//
+// Alerts
+// --------------------------------------------------
+
+
+// Base styles
+// -------------------------
+
+.alert {
+ padding: 8px 35px 8px 14px;
+ margin-bottom: @baseLineHeight;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+ background-color: @warningBackground;
+ border: 1px solid @warningBorder;
+ .border-radius(@baseBorderRadius);
+}
+.alert,
+.alert h4 {
+ // Specified for the h4 to prevent conflicts of changing @headingsColor
+ color: @warningText;
+}
+.alert h4 {
+ margin: 0;
+}
+
+// Adjust close link position
+.alert .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ line-height: @baseLineHeight;
+}
+
+
+// Alternate styles
+// -------------------------
+
+.alert-success {
+ background-color: @successBackground;
+ border-color: @successBorder;
+ color: @successText;
+}
+.alert-success h4 {
+ color: @successText;
+}
+.alert-danger,
+.alert-error {
+ background-color: @errorBackground;
+ border-color: @errorBorder;
+ color: @errorText;
+}
+.alert-danger h4,
+.alert-error h4 {
+ color: @errorText;
+}
+.alert-info {
+ background-color: @infoBackground;
+ border-color: @infoBorder;
+ color: @infoText;
+}
+.alert-info h4 {
+ color: @infoText;
+}
+
+
+// Block alerts
+// -------------------------
+
+.alert-block {
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+.alert-block > p,
+.alert-block > ul {
+ margin-bottom: 0;
+}
+.alert-block p + p {
+ margin-top: 5px;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/bootstrap.less b/www/protected/extensions/bootstrap/assets/less/bootstrap.less
new file mode 100644
index 0000000..49fdef1
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/bootstrap.less
@@ -0,0 +1,63 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+// Core variables and mixins
+@import "variables"; // Modify this for custom colors, font-sizes, etc
+@import "mixins";
+
+// CSS Reset
+@import "reset";
+
+// Grid system and page structure
+@import "scaffolding";
+@import "grid";
+@import "layouts";
+
+// Base CSS
+@import "type";
+@import "code";
+@import "forms";
+@import "tables";
+
+// Components: common
+@import "sprites";
+@import "dropdowns";
+@import "wells";
+@import "component-animations";
+@import "close";
+
+// Components: Buttons & Alerts
+@import "buttons";
+@import "button-groups";
+@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
+
+// Components: Nav
+@import "navs";
+@import "navbar";
+@import "breadcrumbs";
+@import "pagination";
+@import "pager";
+
+// Components: Popovers
+@import "modals";
+@import "tooltip";
+@import "popovers";
+
+// Components: Misc
+@import "thumbnails";
+@import "media";
+@import "labels-badges";
+@import "progress-bars";
+@import "accordion.less";
+@import "carousel";
+@import "hero-unit";
+
+// Utility classes
+@import "utilities"; // Has to be last to override when necessary
diff --git a/www/protected/extensions/bootstrap/assets/less/breadcrumbs.less b/www/protected/extensions/bootstrap/assets/less/breadcrumbs.less
new file mode 100644
index 0000000..f753df6
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/breadcrumbs.less
@@ -0,0 +1,24 @@
+//
+// Breadcrumbs
+// --------------------------------------------------
+
+
+.breadcrumb {
+ padding: 8px 15px;
+ margin: 0 0 @baseLineHeight;
+ list-style: none;
+ background-color: #f5f5f5;
+ .border-radius(@baseBorderRadius);
+ > li {
+ display: inline-block;
+ .ie7-inline-block();
+ text-shadow: 0 1px 0 @white;
+ > .divider {
+ padding: 0 5px;
+ color: #ccc;
+ }
+ }
+ > .active {
+ color: @grayLight;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/button-groups.less b/www/protected/extensions/bootstrap/assets/less/button-groups.less
new file mode 100644
index 0000000..55cdc60
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/button-groups.less
@@ -0,0 +1,229 @@
+//
+// Button groups
+// --------------------------------------------------
+
+
+// Make the div behave like a button
+.btn-group {
+ position: relative;
+ display: inline-block;
+ .ie7-inline-block();
+ font-size: 0; // remove as part 1 of font-size inline-block hack
+ vertical-align: middle; // match .btn alignment given font-size hack above
+ white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page)
+ .ie7-restore-left-whitespace();
+}
+
+// Space out series of button groups
+.btn-group + .btn-group {
+ margin-left: 5px;
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+ font-size: 0; // Hack to remove whitespace that results from using inline-block
+ margin-top: @baseLineHeight / 2;
+ margin-bottom: @baseLineHeight / 2;
+ > .btn + .btn,
+ > .btn-group + .btn,
+ > .btn + .btn-group {
+ margin-left: 5px;
+ }
+}
+
+// Float them, remove border radius, then re-add to first and last elements
+.btn-group > .btn {
+ position: relative;
+ .border-radius(0);
+}
+.btn-group > .btn + .btn {
+ margin-left: -1px;
+}
+.btn-group > .btn,
+.btn-group > .dropdown-menu,
+.btn-group > .popover {
+ font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack
+}
+
+// Reset fonts for other sizes
+.btn-group > .btn-mini {
+ font-size: @fontSizeMini;
+}
+.btn-group > .btn-small {
+ font-size: @fontSizeSmall;
+}
+.btn-group > .btn-large {
+ font-size: @fontSizeLarge;
+}
+
+// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
+.btn-group > .btn:first-child {
+ margin-left: 0;
+ .border-top-left-radius(@baseBorderRadius);
+ .border-bottom-left-radius(@baseBorderRadius);
+}
+// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
+.btn-group > .btn:last-child,
+.btn-group > .dropdown-toggle {
+ .border-top-right-radius(@baseBorderRadius);
+ .border-bottom-right-radius(@baseBorderRadius);
+}
+// Reset corners for large buttons
+.btn-group > .btn.large:first-child {
+ margin-left: 0;
+ .border-top-left-radius(@borderRadiusLarge);
+ .border-bottom-left-radius(@borderRadiusLarge);
+}
+.btn-group > .btn.large:last-child,
+.btn-group > .large.dropdown-toggle {
+ .border-top-right-radius(@borderRadiusLarge);
+ .border-bottom-right-radius(@borderRadiusLarge);
+}
+
+// On hover/focus/active, bring the proper btn to front
+.btn-group > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group > .btn:active,
+.btn-group > .btn.active {
+ z-index: 2;
+}
+
+// On active and open, don't show outline
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+
+
+
+// Split button dropdowns
+// ----------------------
+
+// Give the line between buttons some depth
+.btn-group > .btn + .dropdown-toggle {
+ padding-left: 8px;
+ padding-right: 8px;
+ .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
+ *padding-top: 5px;
+ *padding-bottom: 5px;
+}
+.btn-group > .btn-mini + .dropdown-toggle {
+ padding-left: 5px;
+ padding-right: 5px;
+ *padding-top: 2px;
+ *padding-bottom: 2px;
+}
+.btn-group > .btn-small + .dropdown-toggle {
+ *padding-top: 5px;
+ *padding-bottom: 4px;
+}
+.btn-group > .btn-large + .dropdown-toggle {
+ padding-left: 12px;
+ padding-right: 12px;
+ *padding-top: 7px;
+ *padding-bottom: 7px;
+}
+
+.btn-group.open {
+
+ // The clickable button for toggling the menu
+ // Remove the gradient and set the same inset shadow as the :active state
+ .dropdown-toggle {
+ background-image: none;
+ .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
+ }
+
+ // Keep the hover's background when dropdown is open
+ .btn.dropdown-toggle {
+ background-color: @btnBackgroundHighlight;
+ }
+ .btn-primary.dropdown-toggle {
+ background-color: @btnPrimaryBackgroundHighlight;
+ }
+ .btn-warning.dropdown-toggle {
+ background-color: @btnWarningBackgroundHighlight;
+ }
+ .btn-danger.dropdown-toggle {
+ background-color: @btnDangerBackgroundHighlight;
+ }
+ .btn-success.dropdown-toggle {
+ background-color: @btnSuccessBackgroundHighlight;
+ }
+ .btn-info.dropdown-toggle {
+ background-color: @btnInfoBackgroundHighlight;
+ }
+ .btn-inverse.dropdown-toggle {
+ background-color: @btnInverseBackgroundHighlight;
+ }
+}
+
+
+// Reposition the caret
+.btn .caret {
+ margin-top: 8px;
+ margin-left: 0;
+}
+// Carets in other button sizes
+.btn-large .caret {
+ margin-top: 6px;
+}
+.btn-large .caret {
+ border-left-width: 5px;
+ border-right-width: 5px;
+ border-top-width: 5px;
+}
+.btn-mini .caret,
+.btn-small .caret {
+ margin-top: 8px;
+}
+// Upside down carets for .dropup
+.dropup .btn-large .caret {
+ border-bottom-width: 5px;
+}
+
+
+
+// Account for other colors
+.btn-primary,
+.btn-warning,
+.btn-danger,
+.btn-info,
+.btn-success,
+.btn-inverse {
+ .caret {
+ border-top-color: @white;
+ border-bottom-color: @white;
+ }
+}
+
+
+
+// Vertical button groups
+// ----------------------
+
+.btn-group-vertical {
+ display: inline-block; // makes buttons only take up the width they need
+ .ie7-inline-block();
+}
+.btn-group-vertical > .btn {
+ display: block;
+ float: none;
+ max-width: 100%;
+ .border-radius(0);
+}
+.btn-group-vertical > .btn + .btn {
+ margin-left: 0;
+ margin-top: -1px;
+}
+.btn-group-vertical > .btn:first-child {
+ .border-radius(@baseBorderRadius @baseBorderRadius 0 0);
+}
+.btn-group-vertical > .btn:last-child {
+ .border-radius(0 0 @baseBorderRadius @baseBorderRadius);
+}
+.btn-group-vertical > .btn-large:first-child {
+ .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0);
+}
+.btn-group-vertical > .btn-large:last-child {
+ .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge);
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/buttons.less b/www/protected/extensions/bootstrap/assets/less/buttons.less
new file mode 100644
index 0000000..4cd4d86
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/buttons.less
@@ -0,0 +1,228 @@
+//
+// Buttons
+// --------------------------------------------------
+
+
+// Base styles
+// --------------------------------------------------
+
+// Core
+.btn {
+ display: inline-block;
+ .ie7-inline-block();
+ padding: 4px 12px;
+ margin-bottom: 0; // For input.btn
+ font-size: @baseFontSize;
+ line-height: @baseLineHeight;
+ text-align: center;
+ vertical-align: middle;
+ cursor: pointer;
+ .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75));
+ border: 1px solid @btnBorder;
+ *border: 0; // Remove the border to prevent IE7's black border on input:focus
+ border-bottom-color: darken(@btnBorder, 10%);
+ .border-radius(@baseBorderRadius);
+ .ie7-restore-left-whitespace(); // Give IE7 some love
+ .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
+
+ // Hover/focus state
+ &:hover,
+ &:focus {
+ color: @grayDark;
+ text-decoration: none;
+ background-position: 0 -15px;
+
+ // transition is only when going to hover/focus, otherwise the background
+ // behind the gradient (there for IE<=9 fallback) gets mismatched
+ .transition(background-position .1s linear);
+ }
+
+ // Focus state for keyboard and accessibility
+ &:focus {
+ .tab-focus();
+ }
+
+ // Active state
+ &.active,
+ &:active {
+ background-image: none;
+ outline: 0;
+ .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
+ }
+
+ // Disabled state
+ &.disabled,
+ &[disabled] {
+ cursor: default;
+ background-image: none;
+ .opacity(65);
+ .box-shadow(none);
+ }
+
+}
+
+
+
+// Button Sizes
+// --------------------------------------------------
+
+// Large
+.btn-large {
+ padding: @paddingLarge;
+ font-size: @fontSizeLarge;
+ .border-radius(@borderRadiusLarge);
+}
+.btn-large [class^="icon-"],
+.btn-large [class*=" icon-"] {
+ margin-top: 4px;
+}
+
+// Small
+.btn-small {
+ padding: @paddingSmall;
+ font-size: @fontSizeSmall;
+ .border-radius(@borderRadiusSmall);
+}
+.btn-small [class^="icon-"],
+.btn-small [class*=" icon-"] {
+ margin-top: 0;
+}
+.btn-mini [class^="icon-"],
+.btn-mini [class*=" icon-"] {
+ margin-top: -1px;
+}
+
+// Mini
+.btn-mini {
+ padding: @paddingMini;
+ font-size: @fontSizeMini;
+ .border-radius(@borderRadiusSmall);
+}
+
+
+// Block button
+// -------------------------
+
+.btn-block {
+ display: block;
+ width: 100%;
+ padding-left: 0;
+ padding-right: 0;
+ .box-sizing(border-box);
+}
+
+// Vertically space out multiple block buttons
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+
+// Specificity overrides
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ &.btn-block {
+ width: 100%;
+ }
+}
+
+
+
+// Alternate buttons
+// --------------------------------------------------
+
+// Provide *some* extra contrast for those who can get it
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+ color: rgba(255,255,255,.75);
+}
+
+// Set the backgrounds
+// -------------------------
+.btn-primary {
+ .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight);
+}
+// Warning appears are orange
+.btn-warning {
+ .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight);
+}
+// Danger and error appear as red
+.btn-danger {
+ .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight);
+}
+// Success appears as green
+.btn-success {
+ .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight);
+}
+// Info appears as a neutral blue
+.btn-info {
+ .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight);
+}
+// Inverse appears as dark gray
+.btn-inverse {
+ .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight);
+}
+
+
+// Cross-browser Jank
+// --------------------------------------------------
+
+button.btn,
+input[type="submit"].btn {
+
+ // Firefox 3.6 only I believe
+ &::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+ }
+
+ // IE7 has some default padding on button controls
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+
+ &.btn-large {
+ *padding-top: 7px;
+ *padding-bottom: 7px;
+ }
+ &.btn-small {
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+ }
+ &.btn-mini {
+ *padding-top: 1px;
+ *padding-bottom: 1px;
+ }
+}
+
+
+// Link buttons
+// --------------------------------------------------
+
+// Make a button look and behave like a link
+.btn-link,
+.btn-link:active,
+.btn-link[disabled] {
+ background-color: transparent;
+ background-image: none;
+ .box-shadow(none);
+}
+.btn-link {
+ border-color: transparent;
+ cursor: pointer;
+ color: @linkColor;
+ .border-radius(0);
+}
+.btn-link:hover,
+.btn-link:focus {
+ color: @linkColorHover;
+ text-decoration: underline;
+ background-color: transparent;
+}
+.btn-link[disabled]:hover,
+.btn-link[disabled]:focus {
+ color: @grayDark;
+ text-decoration: none;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/carousel.less b/www/protected/extensions/bootstrap/assets/less/carousel.less
new file mode 100644
index 0000000..55bc050
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/carousel.less
@@ -0,0 +1,158 @@
+//
+// Carousel
+// --------------------------------------------------
+
+
+.carousel {
+ position: relative;
+ margin-bottom: @baseLineHeight;
+ line-height: 1;
+}
+
+.carousel-inner {
+ overflow: hidden;
+ width: 100%;
+ position: relative;
+}
+
+.carousel-inner {
+
+ > .item {
+ display: none;
+ position: relative;
+ .transition(.6s ease-in-out left);
+
+ // Account for jankitude on images
+ > img,
+ > a > img {
+ display: block;
+ line-height: 1;
+ }
+ }
+
+ > .active,
+ > .next,
+ > .prev { display: block; }
+
+ > .active {
+ left: 0;
+ }
+
+ > .next,
+ > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+
+ > .next {
+ left: 100%;
+ }
+ > .prev {
+ left: -100%;
+ }
+ > .next.left,
+ > .prev.right {
+ left: 0;
+ }
+
+ > .active.left {
+ left: -100%;
+ }
+ > .active.right {
+ left: 100%;
+ }
+
+}
+
+// Left/right controls for nav
+// ---------------------------
+
+.carousel-control {
+ position: absolute;
+ top: 40%;
+ left: 15px;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ font-size: 60px;
+ font-weight: 100;
+ line-height: 30px;
+ color: @white;
+ text-align: center;
+ background: @grayDarker;
+ border: 3px solid @white;
+ .border-radius(23px);
+ .opacity(50);
+
+ // we can't have this transition here
+ // because webkit cancels the carousel
+ // animation if you trip this while
+ // in the middle of another animation
+ // ;_;
+ // .transition(opacity .2s linear);
+
+ // Reposition the right one
+ &.right {
+ left: auto;
+ right: 15px;
+ }
+
+ // Hover/focus state
+ &:hover,
+ &:focus {
+ color: @white;
+ text-decoration: none;
+ .opacity(90);
+ }
+}
+
+// Carousel indicator pips
+// -----------------------------
+.carousel-indicators {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ z-index: 5;
+ margin: 0;
+ list-style: none;
+
+ li {
+ display: block;
+ float: left;
+ width: 10px;
+ height: 10px;
+ margin-left: 5px;
+ text-indent: -999px;
+ background-color: #ccc;
+ background-color: rgba(255,255,255,.25);
+ border-radius: 5px;
+ }
+ .active {
+ background-color: #fff;
+ }
+}
+
+// Caption for text below images
+// -----------------------------
+
+.carousel-caption {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 15px;
+ background: @grayDark;
+ background: rgba(0,0,0,.75);
+}
+.carousel-caption h4,
+.carousel-caption p {
+ color: @white;
+ line-height: @baseLineHeight;
+}
+.carousel-caption h4 {
+ margin: 0 0 5px;
+}
+.carousel-caption p {
+ margin-bottom: 0;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/close.less b/www/protected/extensions/bootstrap/assets/less/close.less
new file mode 100644
index 0000000..4c626bd
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/close.less
@@ -0,0 +1,32 @@
+//
+// Close icons
+// --------------------------------------------------
+
+
+.close {
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: @baseLineHeight;
+ color: @black;
+ text-shadow: 0 1px 0 rgba(255,255,255,1);
+ .opacity(20);
+ &:hover,
+ &:focus {
+ color: @black;
+ text-decoration: none;
+ cursor: pointer;
+ .opacity(40);
+ }
+}
+
+// Additional properties for button version
+// iOS requires the button element instead of an anchor tag.
+// If you want the anchor version, it requires `href="#"`.
+button.close {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/less/code.less b/www/protected/extensions/bootstrap/assets/less/code.less
new file mode 100644
index 0000000..266a926
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/code.less
@@ -0,0 +1,61 @@
+//
+// Code (inline and blocK)
+// --------------------------------------------------
+
+
+// Inline and block code styles
+code,
+pre {
+ padding: 0 3px 2px;
+ #font > #family > .monospace;
+ font-size: @baseFontSize - 2;
+ color: @grayDark;
+ .border-radius(3px);
+}
+
+// Inline code
+code {
+ padding: 2px 4px;
+ color: #d14;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+ white-space: nowrap;
+}
+
+// Blocks of code
+pre {
+ display: block;
+ padding: (@baseLineHeight - 1) / 2;
+ margin: 0 0 @baseLineHeight / 2;
+ font-size: @baseFontSize - 1; // 14px to 13px
+ line-height: @baseLineHeight;
+ word-break: break-all;
+ word-wrap: break-word;
+ white-space: pre;
+ white-space: pre-wrap;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc; // fallback for IE7-8
+ border: 1px solid rgba(0,0,0,.15);
+ .border-radius(@baseBorderRadius);
+
+ // Make prettyprint styles more spaced out for readability
+ &.prettyprint {
+ margin-bottom: @baseLineHeight;
+ }
+
+ // Account for some code outputs that place code tags in pre tags
+ code {
+ padding: 0;
+ color: inherit;
+ white-space: pre;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border: 0;
+ }
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/less/component-animations.less b/www/protected/extensions/bootstrap/assets/less/component-animations.less
new file mode 100644
index 0000000..d614263
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/component-animations.less
@@ -0,0 +1,22 @@
+//
+// Component animations
+// --------------------------------------------------
+
+
+.fade {
+ opacity: 0;
+ .transition(opacity .15s linear);
+ &.in {
+ opacity: 1;
+ }
+}
+
+.collapse {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ .transition(height .35s ease);
+ &.in {
+ height: auto;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/dropdowns.less b/www/protected/extensions/bootstrap/assets/less/dropdowns.less
new file mode 100644
index 0000000..9e47b47
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/dropdowns.less
@@ -0,0 +1,248 @@
+//
+// Dropdown menus
+// --------------------------------------------------
+
+
+// Use the .menu class on any element within the topbar or ul.tabs and you'll get some superfancy dropdowns
+.dropup,
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle {
+ // The caret makes the toggle a bit too tall in IE7
+ *margin-bottom: -3px;
+}
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+ outline: 0;
+}
+
+// Dropdown arrow/caret
+// --------------------
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ vertical-align: top;
+ border-top: 4px solid @black;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ content: "";
+}
+
+// Place the caret
+.dropdown .caret {
+ margin-top: 8px;
+ margin-left: 2px;
+}
+
+// The dropdown menu (ul)
+// ----------------------
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: @zindexDropdown;
+ display: none; // none by default, but block on "open" of the menu
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0; // override default ul
+ list-style: none;
+ background-color: @dropdownBackground;
+ border: 1px solid #ccc; // Fallback for IE7-8
+ border: 1px solid @dropdownBorder;
+ *border-right-width: 2px;
+ *border-bottom-width: 2px;
+ .border-radius(6px);
+ .box-shadow(0 5px 10px rgba(0,0,0,.2));
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+
+ // Aligns the dropdown menu to right
+ &.pull-right {
+ right: 0;
+ left: auto;
+ }
+
+ // Dividers (basically an hr) within the dropdown
+ .divider {
+ .nav-divider(@dropdownDividerTop, @dropdownDividerBottom);
+ }
+
+ // Links within the dropdown menu
+ > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: @baseLineHeight;
+ color: @dropdownLinkColor;
+ white-space: nowrap;
+ }
+}
+
+// Hover/Focus state
+// -----------
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus,
+.dropdown-submenu:hover > a,
+.dropdown-submenu:focus > a {
+ text-decoration: none;
+ color: @dropdownLinkColorHover;
+ #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%));
+}
+
+// Active state
+// ------------
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: @dropdownLinkColorActive;
+ text-decoration: none;
+ outline: 0;
+ #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%));
+}
+
+// Disabled state
+// --------------
+// Gray out text and ensure the hover/focus state remains gray
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: @grayLight;
+}
+// Nuke hover/focus effects
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ background-color: transparent;
+ background-image: none; // Remove CSS gradient
+ .reset-filter();
+ cursor: default;
+}
+
+// Open state for the dropdown
+// ---------------------------
+.open {
+ // IE7's z-index only goes to the nearest positioned ancestor, which would
+ // make the menu appear below buttons that appeared later on the page
+ *z-index: @zindexDropdown;
+
+ & > .dropdown-menu {
+ display: block;
+ }
+}
+
+// Backdrop to catch body clicks on mobile, etc.
+// ---------------------------
+.dropdown-backdrop {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ z-index: @zindexDropdown - 10;
+}
+
+// Right aligned dropdowns
+// ---------------------------
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+
+// Allow for dropdowns to go bottom up (aka, dropup-menu)
+// ------------------------------------------------------
+// Just add .dropup after the standard .dropdown class and you're set, bro.
+// TODO: abstract this so that the navbar fixed styles are not placed here?
+.dropup,
+.navbar-fixed-bottom .dropdown {
+ // Reverse the caret
+ .caret {
+ border-top: 0;
+ border-bottom: 4px solid @black;
+ content: "";
+ }
+ // Different positioning for bottom up menu
+ .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+ }
+}
+
+// Sub menus
+// ---------------------------
+.dropdown-submenu {
+ position: relative;
+}
+// Default dropdowns
+.dropdown-submenu > .dropdown-menu {
+ top: 0;
+ left: 100%;
+ margin-top: -6px;
+ margin-left: -1px;
+ .border-radius(0 6px 6px 6px);
+}
+.dropdown-submenu:hover > .dropdown-menu {
+ display: block;
+}
+
+// Dropups
+.dropup .dropdown-submenu > .dropdown-menu {
+ top: auto;
+ bottom: 0;
+ margin-top: 0;
+ margin-bottom: -2px;
+ .border-radius(5px 5px 5px 0);
+}
+
+// Caret to indicate there is a submenu
+.dropdown-submenu > a:after {
+ display: block;
+ content: " ";
+ float: right;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ border-width: 5px 0 5px 5px;
+ border-left-color: darken(@dropdownBackground, 20%);
+ margin-top: 5px;
+ margin-right: -10px;
+}
+.dropdown-submenu:hover > a:after {
+ border-left-color: @dropdownLinkColorHover;
+}
+
+// Left aligned submenus
+.dropdown-submenu.pull-left {
+ // Undo the float
+ // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere.
+ float: none;
+
+ // Positioning the submenu
+ > .dropdown-menu {
+ left: -100%;
+ margin-left: 10px;
+ .border-radius(6px 0 6px 6px);
+ }
+}
+
+// Tweak nav headers
+// -----------------
+// Increase padding from 15px to 20px on sides
+.dropdown .dropdown-menu .nav-header {
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+// Typeahead
+// ---------
+.typeahead {
+ z-index: 1051;
+ margin-top: 2px; // give it some space to breathe
+ .border-radius(@baseBorderRadius);
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/forms.less b/www/protected/extensions/bootstrap/assets/less/forms.less
new file mode 100644
index 0000000..06767bd
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/forms.less
@@ -0,0 +1,690 @@
+//
+// Forms
+// --------------------------------------------------
+
+
+// GENERAL STYLES
+// --------------
+
+// Make all forms have space below them
+form {
+ margin: 0 0 @baseLineHeight;
+}
+
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+// Groups of fields with labels on top (legends)
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: @baseLineHeight;
+ font-size: @baseFontSize * 1.5;
+ line-height: @baseLineHeight * 2;
+ color: @grayDark;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+
+ // Small
+ small {
+ font-size: @baseLineHeight * .75;
+ color: @grayLight;
+ }
+}
+
+// Set font for forms
+label,
+input,
+button,
+select,
+textarea {
+ #font > .shorthand(@baseFontSize,normal,@baseLineHeight); // Set size, weight, line-height here
+}
+input,
+button,
+select,
+textarea {
+ font-family: @baseFontFamily; // And only set font-family here for those that need it (note the missing label element)
+}
+
+// Identify controls by their labels
+label {
+ display: block;
+ margin-bottom: 5px;
+}
+
+// Form controls
+// -------------------------
+
+// Shared size and type resets
+select,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+ display: inline-block;
+ height: @baseLineHeight;
+ padding: 4px 6px;
+ margin-bottom: @baseLineHeight / 2;
+ font-size: @baseFontSize;
+ line-height: @baseLineHeight;
+ color: @gray;
+ .border-radius(@inputBorderRadius);
+ vertical-align: middle;
+}
+
+// Reset appearance properties for textual inputs and textarea
+// Declare width for legacy (can't be on input[type=*] selectors or it's too specific)
+input,
+textarea,
+.uneditable-input {
+ width: 206px; // plus 12px padding and 2px border
+}
+// Reset height since textareas have rows
+textarea {
+ height: auto;
+}
+// Everything else
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+ background-color: @inputBackground;
+ border: 1px solid @inputBorder;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
+ .transition(~"border linear .2s, box-shadow linear .2s");
+
+ // Focus state
+ &:focus {
+ border-color: rgba(82,168,236,.8);
+ outline: 0;
+ outline: thin dotted \9; /* IE6-9 */
+ .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)");
+ }
+}
+
+// Position radios and checkboxes better
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ *margin-top: 0; /* IE7 */
+ margin-top: 1px \9; /* IE8-9 */
+ line-height: normal;
+}
+
+// Reset width of input images, buttons, radios, checkboxes
+input[type="file"],
+input[type="image"],
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+ width: auto; // Override of generic input selector
+}
+
+// Set the height of select and file controls to match text inputs
+select,
+input[type="file"] {
+ height: @inputHeight; /* In IE7, the height of the select element cannot be changed by height, only font-size */
+ *margin-top: 4px; /* For IE7, add top margin to align select with labels */
+ line-height: @inputHeight;
+}
+
+// Make select elements obey height by applying a border
+select {
+ width: 220px; // default input width + 10px of padding that doesn't get applied
+ border: 1px solid @inputBorder;
+ background-color: @inputBackground; // Chrome on Linux and Mobile Safari need background-color
+}
+
+// Make multiple select elements height not fixed
+select[multiple],
+select[size] {
+ height: auto;
+}
+
+// Focus for select, file, radio, and checkbox
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ .tab-focus();
+}
+
+
+// Uneditable inputs
+// -------------------------
+
+// Make uneditable inputs look inactive
+.uneditable-input,
+.uneditable-textarea {
+ color: @grayLight;
+ background-color: darken(@inputBackground, 1%);
+ border-color: @inputBorder;
+ .box-shadow(inset 0 1px 2px rgba(0,0,0,.025));
+ cursor: not-allowed;
+}
+
+// For text that needs to appear as an input but should not be an input
+.uneditable-input {
+ overflow: hidden; // prevent text from wrapping, but still cut it off like an input does
+ white-space: nowrap;
+}
+
+// Make uneditable textareas behave like a textarea
+.uneditable-textarea {
+ width: auto;
+ height: auto;
+}
+
+
+// Placeholder
+// -------------------------
+
+// Placeholder text gets special styles because when browsers invalidate entire lines if it doesn't understand a selector
+input,
+textarea {
+ .placeholder();
+}
+
+
+// CHECKBOXES & RADIOS
+// -------------------
+
+// Indent the labels to position radios/checkboxes as hanging
+.radio,
+.checkbox {
+ min-height: @baseLineHeight; // clear the floating input if there is no label text
+ padding-left: 20px;
+}
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+ float: left;
+ margin-left: -20px;
+}
+
+// Move the options list down to align with labels
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+ padding-top: 5px; // has to be padding because margin collaspes
+}
+
+// Radios and checkboxes on same line
+// TODO v3: Convert .inline to .control-inline
+.radio.inline,
+.checkbox.inline {
+ display: inline-block;
+ padding-top: 5px;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+ margin-left: 10px; // space out consecutive inline controls
+}
+
+
+
+// INPUT SIZES
+// -----------
+
+// General classes for quick sizes
+.input-mini { width: 60px; }
+.input-small { width: 90px; }
+.input-medium { width: 150px; }
+.input-large { width: 210px; }
+.input-xlarge { width: 270px; }
+.input-xxlarge { width: 530px; }
+
+// Grid style input sizes
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input[class*="span"],
+// Redeclare since the fluid row class is more specific
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"] {
+ float: none;
+ margin-left: 0;
+}
+// Ensure input-prepend/append never wraps
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
+ display: inline-block;
+}
+
+
+
+// GRID SIZING FOR INPUTS
+// ----------------------
+
+// Grid sizes
+#grid > .input(@gridColumnWidth, @gridGutterWidth);
+
+// Control row for multiple inputs per line
+.controls-row {
+ .clearfix(); // Clear the float from controls
+}
+
+// Float to collapse white-space for proper grid alignment
+.controls-row [class*="span"],
+// Redeclare the fluid grid collapse since we undo the float for inputs
+.row-fluid .controls-row [class*="span"] {
+ float: left;
+}
+// Explicity set top padding on all checkboxes/radios, not just first-child
+.controls-row .checkbox[class*="span"],
+.controls-row .radio[class*="span"] {
+ padding-top: 5px;
+}
+
+
+
+
+// DISABLED STATE
+// --------------
+
+// Disabled and read-only inputs
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ cursor: not-allowed;
+ background-color: @inputDisabledBackground;
+}
+// Explicitly reset the colors here
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
+ background-color: transparent;
+}
+
+
+
+
+// FORM FIELD FEEDBACK STATES
+// --------------------------
+
+// Warning
+.control-group.warning {
+ .formFieldState(@warningText, @warningText, @warningBackground);
+}
+// Error
+.control-group.error {
+ .formFieldState(@errorText, @errorText, @errorBackground);
+}
+// Success
+.control-group.success {
+ .formFieldState(@successText, @successText, @successBackground);
+}
+// Success
+.control-group.info {
+ .formFieldState(@infoText, @infoText, @infoBackground);
+}
+
+// HTML5 invalid states
+// Shares styles with the .control-group.error above
+input:focus:invalid,
+textarea:focus:invalid,
+select:focus:invalid {
+ color: #b94a48;
+ border-color: #ee5f5b;
+ &:focus {
+ border-color: darken(#ee5f5b, 10%);
+ @shadow: 0 0 6px lighten(#ee5f5b, 20%);
+ .box-shadow(@shadow);
+ }
+}
+
+
+
+// FORM ACTIONS
+// ------------
+
+.form-actions {
+ padding: (@baseLineHeight - 1) 20px @baseLineHeight;
+ margin-top: @baseLineHeight;
+ margin-bottom: @baseLineHeight;
+ background-color: @formActionsBackground;
+ border-top: 1px solid #e5e5e5;
+ .clearfix(); // Adding clearfix to allow for .pull-right button containers
+}
+
+
+
+// HELP TEXT
+// ---------
+
+.help-block,
+.help-inline {
+ color: lighten(@textColor, 15%); // lighten the text some for contrast
+}
+
+.help-block {
+ display: block; // account for any element using help-block
+ margin-bottom: @baseLineHeight / 2;
+}
+
+.help-inline {
+ display: inline-block;
+ .ie7-inline-block();
+ vertical-align: middle;
+ padding-left: 5px;
+}
+
+
+
+// INPUT GROUPS
+// ------------
+
+// Allow us to put symbols and text within the input field for a cleaner look
+.input-append,
+.input-prepend {
+ display: inline-block;
+ margin-bottom: @baseLineHeight / 2;
+ vertical-align: middle;
+ font-size: 0; // white space collapse hack
+ white-space: nowrap; // Prevent span and input from separating
+
+ // Reset the white space collapse hack
+ input,
+ select,
+ .uneditable-input,
+ .dropdown-menu,
+ .popover {
+ font-size: @baseFontSize;
+ }
+
+ input,
+ select,
+ .uneditable-input {
+ position: relative; // placed here by default so that on :focus we can place the input above the .add-on for full border and box-shadow goodness
+ margin-bottom: 0; // prevent bottom margin from screwing up alignment in stacked forms
+ *margin-left: 0;
+ vertical-align: top;
+ .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+ // Make input on top when focused so blue border and shadow always show
+ &:focus {
+ z-index: 2;
+ }
+ }
+ .add-on {
+ display: inline-block;
+ width: auto;
+ height: @baseLineHeight;
+ min-width: 16px;
+ padding: 4px 5px;
+ font-size: @baseFontSize;
+ font-weight: normal;
+ line-height: @baseLineHeight;
+ text-align: center;
+ text-shadow: 0 1px 0 @white;
+ background-color: @grayLighter;
+ border: 1px solid #ccc;
+ }
+ .add-on,
+ .btn,
+ .btn-group > .dropdown-toggle {
+ vertical-align: top;
+ .border-radius(0);
+ }
+ .active {
+ background-color: lighten(@green, 30);
+ border-color: @green;
+ }
+}
+
+.input-prepend {
+ .add-on,
+ .btn {
+ margin-right: -1px;
+ }
+ .add-on:first-child,
+ .btn:first-child {
+ // FYI, `.btn:first-child` accounts for a button group that's prepended
+ .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+ }
+}
+
+.input-append {
+ input,
+ select,
+ .uneditable-input {
+ .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+ + .btn-group .btn:last-child {
+ .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+ }
+ }
+ .add-on,
+ .btn,
+ .btn-group {
+ margin-left: -1px;
+ }
+ .add-on:last-child,
+ .btn:last-child,
+ .btn-group:last-child > .dropdown-toggle {
+ .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+ }
+}
+
+// Remove all border-radius for inputs with both prepend and append
+.input-prepend.input-append {
+ input,
+ select,
+ .uneditable-input {
+ .border-radius(0);
+ + .btn-group .btn {
+ .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+ }
+ }
+ .add-on:first-child,
+ .btn:first-child {
+ margin-right: -1px;
+ .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+ }
+ .add-on:last-child,
+ .btn:last-child {
+ margin-left: -1px;
+ .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+ }
+ .btn-group:first-child {
+ margin-left: 0;
+ }
+}
+
+
+
+
+// SEARCH FORM
+// -----------
+
+input.search-query {
+ padding-right: 14px;
+ padding-right: 4px \9;
+ padding-left: 14px;
+ padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */
+ margin-bottom: 0; // Remove the default margin on all inputs
+ .border-radius(15px);
+}
+
+/* Allow for input prepend/append in search forms */
+.form-search .input-append .search-query,
+.form-search .input-prepend .search-query {
+ .border-radius(0); // Override due to specificity
+}
+.form-search .input-append .search-query {
+ .border-radius(14px 0 0 14px);
+}
+.form-search .input-append .btn {
+ .border-radius(0 14px 14px 0);
+}
+.form-search .input-prepend .search-query {
+ .border-radius(0 14px 14px 0);
+}
+.form-search .input-prepend .btn {
+ .border-radius(14px 0 0 14px);
+}
+
+
+
+
+// HORIZONTAL & VERTICAL FORMS
+// ---------------------------
+
+// Common properties
+// -----------------
+
+.form-search,
+.form-inline,
+.form-horizontal {
+ input,
+ textarea,
+ select,
+ .help-inline,
+ .uneditable-input,
+ .input-prepend,
+ .input-append {
+ display: inline-block;
+ .ie7-inline-block();
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ // Re-hide hidden elements due to specifity
+ .hide {
+ display: none;
+ }
+}
+.form-search label,
+.form-inline label,
+.form-search .btn-group,
+.form-inline .btn-group {
+ display: inline-block;
+}
+// Remove margin for input-prepend/-append
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+ margin-bottom: 0;
+}
+// Inline checkbox/radio labels (remove padding on left)
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+ padding-left: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+// Remove float and margin, set to inline-block
+.form-search .radio input[type="radio"],
+.form-search .checkbox input[type="checkbox"],
+.form-inline .radio input[type="radio"],
+.form-inline .checkbox input[type="checkbox"] {
+ float: left;
+ margin-right: 3px;
+ margin-left: 0;
+}
+
+
+// Margin to space out fieldsets
+.control-group {
+ margin-bottom: @baseLineHeight / 2;
+}
+
+// Legend collapses margin, so next element is responsible for spacing
+legend + .control-group {
+ margin-top: @baseLineHeight;
+ -webkit-margin-top-collapse: separate;
+}
+
+// Horizontal-specific styles
+// --------------------------
+
+.form-horizontal {
+ // Increase spacing between groups
+ .control-group {
+ margin-bottom: @baseLineHeight;
+ .clearfix();
+ }
+ // Float the labels left
+ .control-label {
+ float: left;
+ width: @horizontalComponentOffset - 20;
+ padding-top: 5px;
+ text-align: right;
+ }
+ // Move over all input controls and content
+ .controls {
+ // 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
+ *display: inline-block;
+ *padding-left: 20px;
+ margin-left: @horizontalComponentOffset;
+ *margin-left: 0;
+ &:first-child {
+ *padding-left: @horizontalComponentOffset;
+ }
+ }
+ // Remove bottom margin on block level help text since that's accounted for on .control-group
+ .help-block {
+ margin-bottom: 0;
+ }
+ // And apply it only to .help-block instances that follow a form control
+ input,
+ select,
+ textarea,
+ .uneditable-input,
+ .input-prepend,
+ .input-append {
+ + .help-block {
+ margin-top: @baseLineHeight / 2;
+ }
+ }
+ // Move over buttons in .form-actions to align with .controls
+ .form-actions {
+ padding-left: @horizontalComponentOffset;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/grid.less b/www/protected/extensions/bootstrap/assets/less/grid.less
new file mode 100644
index 0000000..750d203
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/grid.less
@@ -0,0 +1,21 @@
+//
+// Grid system
+// --------------------------------------------------
+
+
+// Fixed (940px)
+#grid > .core(@gridColumnWidth, @gridGutterWidth);
+
+// Fluid (940px)
+#grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
+
+// Reset utility classes due to specificity
+[class*="span"].hide,
+.row-fluid [class*="span"].hide {
+ display: none;
+}
+
+[class*="span"].pull-right,
+.row-fluid [class*="span"].pull-right {
+ float: right;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/hero-unit.less b/www/protected/extensions/bootstrap/assets/less/hero-unit.less
new file mode 100644
index 0000000..763d86a
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/hero-unit.less
@@ -0,0 +1,25 @@
+//
+// Hero unit
+// --------------------------------------------------
+
+
+.hero-unit {
+ padding: 60px;
+ margin-bottom: 30px;
+ font-size: 18px;
+ font-weight: 200;
+ line-height: @baseLineHeight * 1.5;
+ color: @heroUnitLeadColor;
+ background-color: @heroUnitBackground;
+ .border-radius(6px);
+ h1 {
+ margin-bottom: 0;
+ font-size: 60px;
+ line-height: 1;
+ color: @heroUnitHeadingColor;
+ letter-spacing: -1px;
+ }
+ li {
+ line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/labels-badges.less b/www/protected/extensions/bootstrap/assets/less/labels-badges.less
new file mode 100644
index 0000000..bc321fe
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/labels-badges.less
@@ -0,0 +1,84 @@
+//
+// Labels and badges
+// --------------------------------------------------
+
+
+// Base classes
+.label,
+.badge {
+ display: inline-block;
+ padding: 2px 4px;
+ font-size: @baseFontSize * .846;
+ font-weight: bold;
+ line-height: 14px; // ensure proper line-height if floated
+ color: @white;
+ vertical-align: baseline;
+ white-space: nowrap;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ background-color: @grayLight;
+}
+// Set unique padding and border-radii
+.label {
+ .border-radius(3px);
+}
+.badge {
+ padding-left: 9px;
+ padding-right: 9px;
+ .border-radius(9px);
+}
+
+// Empty labels/badges collapse
+.label,
+.badge {
+ &:empty {
+ display: none;
+ }
+}
+
+// Hover/focus state, but only for links
+a {
+ &.label:hover,
+ &.label:focus,
+ &.badge:hover,
+ &.badge:focus {
+ color: @white;
+ text-decoration: none;
+ cursor: pointer;
+ }
+}
+
+// Colors
+// Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute)
+.label,
+.badge {
+ // Important (red)
+ &-important { background-color: @errorText; }
+ &-important[href] { background-color: darken(@errorText, 10%); }
+ // Warnings (orange)
+ &-warning { background-color: @orange; }
+ &-warning[href] { background-color: darken(@orange, 10%); }
+ // Success (green)
+ &-success { background-color: @successText; }
+ &-success[href] { background-color: darken(@successText, 10%); }
+ // Info (turquoise)
+ &-info { background-color: @infoText; }
+ &-info[href] { background-color: darken(@infoText, 10%); }
+ // Inverse (black)
+ &-inverse { background-color: @grayDark; }
+ &-inverse[href] { background-color: darken(@grayDark, 10%); }
+}
+
+// Quick fix for labels/badges in buttons
+.btn {
+ .label,
+ .badge {
+ position: relative;
+ top: -1px;
+ }
+}
+.btn-mini {
+ .label,
+ .badge {
+ top: 0;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/layouts.less b/www/protected/extensions/bootstrap/assets/less/layouts.less
new file mode 100644
index 0000000..24a2062
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/layouts.less
@@ -0,0 +1,16 @@
+//
+// Layouts
+// --------------------------------------------------
+
+
+// Container (centered, fixed-width layouts)
+.container {
+ .container-fixed();
+}
+
+// Fluid layouts (left aligned, with sidebar, min- & max-width content)
+.container-fluid {
+ padding-right: @gridGutterWidth;
+ padding-left: @gridGutterWidth;
+ .clearfix();
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/less/media.less b/www/protected/extensions/bootstrap/assets/less/media.less
new file mode 100644
index 0000000..e461e44
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/media.less
@@ -0,0 +1,55 @@
+// Media objects
+// Source: http://stubbornella.org/content/?p=497
+// --------------------------------------------------
+
+
+// Common styles
+// -------------------------
+
+// Clear the floats
+.media,
+.media-body {
+ overflow: hidden;
+ *overflow: visible;
+ zoom: 1;
+}
+
+// Proper spacing between instances of .media
+.media,
+.media .media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+
+// For images and videos, set to block
+.media-object {
+ display: block;
+}
+
+// Reset margins on headings for tighter default spacing
+.media-heading {
+ margin: 0 0 5px;
+}
+
+
+// Media image alignment
+// -------------------------
+
+.media > .pull-left {
+ margin-right: 10px;
+}
+.media > .pull-right {
+ margin-left: 10px;
+}
+
+
+// Media list variation
+// -------------------------
+
+// Undo default ul/ol styles
+.media-list {
+ margin-left: 0;
+ list-style: none;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/mixins.less b/www/protected/extensions/bootstrap/assets/less/mixins.less
new file mode 100644
index 0000000..79d8892
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/mixins.less
@@ -0,0 +1,702 @@
+//
+// Mixins
+// --------------------------------------------------
+
+
+// UTILITY MIXINS
+// --------------------------------------------------
+
+// Clearfix
+// --------
+// For clearing floats like a boss h5bp.com/q
+.clearfix {
+ *zoom: 1;
+ &:before,
+ &:after {
+ display: table;
+ content: "";
+ // Fixes Opera/contenteditable bug:
+ // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952
+ line-height: 0;
+ }
+ &:after {
+ clear: both;
+ }
+}
+
+// Webkit-style focus
+// ------------------
+.tab-focus() {
+ // Default
+ outline: thin dotted #333;
+ // Webkit
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+// Center-align a block level element
+// ----------------------------------
+.center-block() {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+// IE7 inline-block
+// ----------------
+.ie7-inline-block() {
+ *display: inline; /* IE7 inline-block hack */
+ *zoom: 1;
+}
+
+// IE7 likes to collapse whitespace on either side of the inline-block elements.
+// Ems because we're attempting to match the width of a space character. Left
+// version is for form buttons, which typically come after other elements, and
+// right version is for icons, which come before. Applying both is ok, but it will
+// mean that space between those elements will be .6em (~2 space characters) in IE7,
+// instead of the 1 space in other browsers.
+.ie7-restore-left-whitespace() {
+ *margin-left: .3em;
+
+ &:first-child {
+ *margin-left: 0;
+ }
+}
+
+.ie7-restore-right-whitespace() {
+ *margin-right: .3em;
+}
+
+// Sizing shortcuts
+// -------------------------
+.size(@height, @width) {
+ width: @width;
+ height: @height;
+}
+.square(@size) {
+ .size(@size, @size);
+}
+
+// Placeholder text
+// -------------------------
+.placeholder(@color: @placeholderText) {
+ &:-moz-placeholder {
+ color: @color;
+ }
+ &:-ms-input-placeholder {
+ color: @color;
+ }
+ &::-webkit-input-placeholder {
+ color: @color;
+ }
+}
+
+// Text overflow
+// -------------------------
+// Requires inline-block or block for proper styling
+.text-overflow() {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+// CSS image replacement
+// -------------------------
+// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
+.hide-text {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+
+
+// FONTS
+// --------------------------------------------------
+
+#font {
+ #family {
+ .serif() {
+ font-family: @serifFontFamily;
+ }
+ .sans-serif() {
+ font-family: @sansFontFamily;
+ }
+ .monospace() {
+ font-family: @monoFontFamily;
+ }
+ }
+ .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
+ font-size: @size;
+ font-weight: @weight;
+ line-height: @lineHeight;
+ }
+ .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
+ #font > #family > .serif;
+ #font > .shorthand(@size, @weight, @lineHeight);
+ }
+ .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
+ #font > #family > .sans-serif;
+ #font > .shorthand(@size, @weight, @lineHeight);
+ }
+ .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) {
+ #font > #family > .monospace;
+ #font > .shorthand(@size, @weight, @lineHeight);
+ }
+}
+
+
+// FORMS
+// --------------------------------------------------
+
+// Block level inputs
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: @inputHeight; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
+ .box-sizing(border-box); // Makes inputs behave like true block-level elements
+}
+
+
+
+// Mixin for form field states
+.formFieldState(@textColor: #555, @borderColor: #ccc, @backgroundColor: #f5f5f5) {
+ // Set the text color
+ .control-label,
+ .help-block,
+ .help-inline {
+ color: @textColor;
+ }
+ // Style inputs accordingly
+ .checkbox,
+ .radio,
+ input,
+ select,
+ textarea {
+ color: @textColor;
+ }
+ input,
+ select,
+ textarea {
+ border-color: @borderColor;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
+ &:focus {
+ border-color: darken(@borderColor, 10%);
+ @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@borderColor, 20%);
+ .box-shadow(@shadow);
+ }
+ }
+ // Give a small background color for input-prepend/-append
+ .input-prepend .add-on,
+ .input-append .add-on {
+ color: @textColor;
+ background-color: @backgroundColor;
+ border-color: @textColor;
+ }
+}
+
+
+
+// CSS3 PROPERTIES
+// --------------------------------------------------
+
+// Border Radius
+.border-radius(@radius) {
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+ border-radius: @radius;
+}
+
+// Single Corner Border Radius
+.border-top-left-radius(@radius) {
+ -webkit-border-top-left-radius: @radius;
+ -moz-border-radius-topleft: @radius;
+ border-top-left-radius: @radius;
+}
+.border-top-right-radius(@radius) {
+ -webkit-border-top-right-radius: @radius;
+ -moz-border-radius-topright: @radius;
+ border-top-right-radius: @radius;
+}
+.border-bottom-right-radius(@radius) {
+ -webkit-border-bottom-right-radius: @radius;
+ -moz-border-radius-bottomright: @radius;
+ border-bottom-right-radius: @radius;
+}
+.border-bottom-left-radius(@radius) {
+ -webkit-border-bottom-left-radius: @radius;
+ -moz-border-radius-bottomleft: @radius;
+ border-bottom-left-radius: @radius;
+}
+
+// Single Side Border Radius
+.border-top-radius(@radius) {
+ .border-top-right-radius(@radius);
+ .border-top-left-radius(@radius);
+}
+.border-right-radius(@radius) {
+ .border-top-right-radius(@radius);
+ .border-bottom-right-radius(@radius);
+}
+.border-bottom-radius(@radius) {
+ .border-bottom-right-radius(@radius);
+ .border-bottom-left-radius(@radius);
+}
+.border-left-radius(@radius) {
+ .border-top-left-radius(@radius);
+ .border-bottom-left-radius(@radius);
+}
+
+// Drop shadows
+.box-shadow(@shadow) {
+ -webkit-box-shadow: @shadow;
+ -moz-box-shadow: @shadow;
+ box-shadow: @shadow;
+}
+
+// Transitions
+.transition(@transition) {
+ -webkit-transition: @transition;
+ -moz-transition: @transition;
+ -o-transition: @transition;
+ transition: @transition;
+}
+.transition-delay(@transition-delay) {
+ -webkit-transition-delay: @transition-delay;
+ -moz-transition-delay: @transition-delay;
+ -o-transition-delay: @transition-delay;
+ transition-delay: @transition-delay;
+}
+.transition-duration(@transition-duration) {
+ -webkit-transition-duration: @transition-duration;
+ -moz-transition-duration: @transition-duration;
+ -o-transition-duration: @transition-duration;
+ transition-duration: @transition-duration;
+}
+
+// Transformations
+.rotate(@degrees) {
+ -webkit-transform: rotate(@degrees);
+ -moz-transform: rotate(@degrees);
+ -ms-transform: rotate(@degrees);
+ -o-transform: rotate(@degrees);
+ transform: rotate(@degrees);
+}
+.scale(@ratio) {
+ -webkit-transform: scale(@ratio);
+ -moz-transform: scale(@ratio);
+ -ms-transform: scale(@ratio);
+ -o-transform: scale(@ratio);
+ transform: scale(@ratio);
+}
+.translate(@x, @y) {
+ -webkit-transform: translate(@x, @y);
+ -moz-transform: translate(@x, @y);
+ -ms-transform: translate(@x, @y);
+ -o-transform: translate(@x, @y);
+ transform: translate(@x, @y);
+}
+.skew(@x, @y) {
+ -webkit-transform: skew(@x, @y);
+ -moz-transform: skew(@x, @y);
+ -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twitter/bootstrap/issues/4885
+ -o-transform: skew(@x, @y);
+ transform: skew(@x, @y);
+ -webkit-backface-visibility: hidden; // See https://github.com/twitter/bootstrap/issues/5319
+}
+.translate3d(@x, @y, @z) {
+ -webkit-transform: translate3d(@x, @y, @z);
+ -moz-transform: translate3d(@x, @y, @z);
+ -o-transform: translate3d(@x, @y, @z);
+ transform: translate3d(@x, @y, @z);
+}
+
+// Backface visibility
+// Prevent browsers from flickering when using CSS 3D transforms.
+// Default value is `visible`, but can be changed to `hidden
+// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples
+.backface-visibility(@visibility){
+ -webkit-backface-visibility: @visibility;
+ -moz-backface-visibility: @visibility;
+ backface-visibility: @visibility;
+}
+
+// Background clipping
+// Heads up: FF 3.6 and under need "padding" instead of "padding-box"
+.background-clip(@clip) {
+ -webkit-background-clip: @clip;
+ -moz-background-clip: @clip;
+ background-clip: @clip;
+}
+
+// Background sizing
+.background-size(@size) {
+ -webkit-background-size: @size;
+ -moz-background-size: @size;
+ -o-background-size: @size;
+ background-size: @size;
+}
+
+
+// Box sizing
+.box-sizing(@boxmodel) {
+ -webkit-box-sizing: @boxmodel;
+ -moz-box-sizing: @boxmodel;
+ box-sizing: @boxmodel;
+}
+
+// User select
+// For selecting text on the page
+.user-select(@select) {
+ -webkit-user-select: @select;
+ -moz-user-select: @select;
+ -ms-user-select: @select;
+ -o-user-select: @select;
+ user-select: @select;
+}
+
+// Resize anything
+.resizable(@direction) {
+ resize: @direction; // Options: horizontal, vertical, both
+ overflow: auto; // Safari fix
+}
+
+// CSS3 Content Columns
+.content-columns(@columnCount, @columnGap: @gridGutterWidth) {
+ -webkit-column-count: @columnCount;
+ -moz-column-count: @columnCount;
+ column-count: @columnCount;
+ -webkit-column-gap: @columnGap;
+ -moz-column-gap: @columnGap;
+ column-gap: @columnGap;
+}
+
+// Optional hyphenation
+.hyphens(@mode: auto) {
+ word-wrap: break-word;
+ -webkit-hyphens: @mode;
+ -moz-hyphens: @mode;
+ -ms-hyphens: @mode;
+ -o-hyphens: @mode;
+ hyphens: @mode;
+}
+
+// Opacity
+.opacity(@opacity) {
+ opacity: @opacity / 100;
+ filter: ~"alpha(opacity=@{opacity})";
+}
+
+
+
+// BACKGROUNDS
+// --------------------------------------------------
+
+// Add an alphatransparency value to any background or border color (via Elyse Holladay)
+#translucent {
+ .background(@color: @white, @alpha: 1) {
+ background-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha);
+ }
+ .border(@color: @white, @alpha: 1) {
+ border-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha);
+ .background-clip(padding-box);
+ }
+}
+
+// Gradient Bar Colors for buttons and alerts
+.gradientBar(@primaryColor, @secondaryColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) {
+ color: @textColor;
+ text-shadow: @textShadow;
+ #gradient > .vertical(@primaryColor, @secondaryColor);
+ border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%);
+ border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%);
+}
+
+// Gradients
+#gradient {
+ .horizontal(@startColor: #555, @endColor: #333) {
+ background-color: @endColor;
+ background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+
+ background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10
+ background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10
+ background-repeat: repeat-x;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down
+ }
+ .vertical(@startColor: #555, @endColor: #333) {
+ background-color: mix(@startColor, @endColor, 60%);
+ background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10
+ background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10
+ background-repeat: repeat-x;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down
+ }
+ .directional(@startColor: #555, @endColor: #333, @deg: 45deg) {
+ background-color: @endColor;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+
+ background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10
+ background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10
+ }
+ .horizontal-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) {
+ background-color: mix(@midColor, @endColor, 80%);
+ background-image: -webkit-gradient(left, linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor));
+ background-image: -webkit-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
+ background-image: -moz-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
+ background-image: -o-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
+ background-image: linear-gradient(to right, @startColor, @midColor @colorStop, @endColor);
+ background-repeat: no-repeat;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback
+ }
+
+ .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) {
+ background-color: mix(@midColor, @endColor, 80%);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor));
+ background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor);
+ background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor);
+ background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor);
+ background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor);
+ background-repeat: no-repeat;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback
+ }
+ .radial(@innerColor: #555, @outerColor: #333) {
+ background-color: @outerColor;
+ background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor));
+ background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor);
+ background-image: -moz-radial-gradient(circle, @innerColor, @outerColor);
+ background-image: -o-radial-gradient(circle, @innerColor, @outerColor);
+ background-repeat: no-repeat;
+ }
+ .striped(@color: #555, @angle: 45deg) {
+ background-color: @color;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
+ }
+}
+// Reset filters for IE
+.reset-filter() {
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
+}
+
+
+
+// COMPONENT MIXINS
+// --------------------------------------------------
+
+// Horizontal dividers
+// -------------------------
+// Dividers (basically an hr) within dropdowns and nav lists
+.nav-divider(@top: #e5e5e5, @bottom: @white) {
+ // IE7 needs a set width since we gave a height. Restricting just
+ // to IE7 to keep the 1px left/right space in other browsers.
+ // It is unclear where IE is getting the extra space that we need
+ // to negative-margin away, but so it goes.
+ *width: 100%;
+ height: 1px;
+ margin: ((@baseLineHeight / 2) - 1) 1px; // 8px 1px
+ *margin: -5px 0 5px;
+ overflow: hidden;
+ background-color: @top;
+ border-bottom: 1px solid @bottom;
+}
+
+// Button backgrounds
+// ------------------
+.buttonBackground(@startColor, @endColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) {
+ // gradientBar will set the background to a pleasing blend of these, to support IE<=9
+ .gradientBar(@startColor, @endColor, @textColor, @textShadow);
+ *background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ .reset-filter();
+
+ // in these cases the gradient won't cover the background, so we override
+ &:hover, &:focus, &:active, &.active, &.disabled, &[disabled] {
+ color: @textColor;
+ background-color: @endColor;
+ *background-color: darken(@endColor, 5%);
+ }
+
+ // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves
+ &:active,
+ &.active {
+ background-color: darken(@endColor, 10%) e("\9");
+ }
+}
+
+// Navbar vertical align
+// -------------------------
+// Vertically center elements in the navbar.
+// Example: an element has a height of 30px, so write out `.navbarVerticalAlign(30px);` to calculate the appropriate top margin.
+.navbarVerticalAlign(@elementHeight) {
+ margin-top: (@navbarHeight - @elementHeight) / 2;
+}
+
+
+
+// Grid System
+// -----------
+
+// Centered container element
+.container-fixed() {
+ margin-right: auto;
+ margin-left: auto;
+ .clearfix();
+}
+
+// Table columns
+.tableColumns(@columnSpan: 1) {
+ float: none; // undo default grid column styles
+ width: ((@gridColumnWidth) * @columnSpan) + (@gridGutterWidth * (@columnSpan - 1)) - 16; // 16 is total padding on left and right of table cells
+ margin-left: 0; // undo default grid column styles
+}
+
+// Make a Grid
+// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior
+.makeRow() {
+ margin-left: @gridGutterWidth * -1;
+ .clearfix();
+}
+.makeColumn(@columns: 1, @offset: 0) {
+ float: left;
+ margin-left: (@gridColumnWidth * @offset) + (@gridGutterWidth * (@offset - 1)) + (@gridGutterWidth * 2);
+ width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
+}
+
+// The Grid
+#grid {
+
+ .core (@gridColumnWidth, @gridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ .span@{index} { .span(@index); }
+ .spanX(@index - 1);
+ }
+ .spanX (0) {}
+
+ .offsetX (@index) when (@index > 0) {
+ .offset@{index} { .offset(@index); }
+ .offsetX(@index - 1);
+ }
+ .offsetX (0) {}
+
+ .offset (@columns) {
+ margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1));
+ }
+
+ .span (@columns) {
+ width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
+ }
+
+ .row {
+ margin-left: @gridGutterWidth * -1;
+ .clearfix();
+ }
+
+ [class*="span"] {
+ float: left;
+ min-height: 1px; // prevent collapsing columns
+ margin-left: @gridGutterWidth;
+ }
+
+ // Set the container width, and override it for fixed navbars in media queries
+ .container,
+ .navbar-static-top .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container { .span(@gridColumns); }
+
+ // generate .spanX and .offsetX
+ .spanX (@gridColumns);
+ .offsetX (@gridColumns);
+
+ }
+
+ .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ .span@{index} { .span(@index); }
+ .spanX(@index - 1);
+ }
+ .spanX (0) {}
+
+ .offsetX (@index) when (@index > 0) {
+ .offset@{index} { .offset(@index); }
+ .offset@{index}:first-child { .offsetFirstChild(@index); }
+ .offsetX(@index - 1);
+ }
+ .offsetX (0) {}
+
+ .offset (@columns) {
+ margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2);
+ *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .offsetFirstChild (@columns) {
+ margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth);
+ *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .span (@columns) {
+ width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
+ *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .row-fluid {
+ width: 100%;
+ .clearfix();
+ [class*="span"] {
+ .input-block-level();
+ float: left;
+ margin-left: @fluidGridGutterWidth;
+ *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
+ }
+ [class*="span"]:first-child {
+ margin-left: 0;
+ }
+
+ // Space grid-sized controls properly if multiple per line
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: @fluidGridGutterWidth;
+ }
+
+ // generate .spanX and .offsetX
+ .spanX (@gridColumns);
+ .offsetX (@gridColumns);
+ }
+
+ }
+
+ .input(@gridColumnWidth, @gridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index} { .span(@index); }
+ .spanX(@index - 1);
+ }
+ .spanX (0) {}
+
+ .span(@columns) {
+ width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 14;
+ }
+
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0; // override margin-left from core grid system
+ }
+
+ // Space grid-sized controls properly if multiple per line
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: @gridGutterWidth;
+ }
+
+ // generate .spanX
+ .spanX (@gridColumns);
+
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/modals.less b/www/protected/extensions/bootstrap/assets/less/modals.less
new file mode 100644
index 0000000..8e272d4
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/modals.less
@@ -0,0 +1,95 @@
+//
+// Modals
+// --------------------------------------------------
+
+// Background
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: @zindexModalBackdrop;
+ background-color: @black;
+ // Fade for backdrop
+ &.fade { opacity: 0; }
+}
+
+.modal-backdrop,
+.modal-backdrop.fade.in {
+ .opacity(80);
+}
+
+// Base modal
+.modal {
+ position: fixed;
+ top: 10%;
+ left: 50%;
+ z-index: @zindexModal;
+ width: 560px;
+ margin-left: -280px;
+ background-color: @white;
+ border: 1px solid #999;
+ border: 1px solid rgba(0,0,0,.3);
+ *border: 1px solid #999; /* IE6-7 */
+ .border-radius(6px);
+ .box-shadow(0 3px 7px rgba(0,0,0,0.3));
+ .background-clip(padding-box);
+ // Remove focus outline from opened modal
+ outline: none;
+
+ &.fade {
+ .transition(e('opacity .3s linear, top .3s ease-out'));
+ top: -25%;
+ }
+ &.fade.in { top: 10%; }
+}
+.modal-header {
+ padding: 9px 15px;
+ border-bottom: 1px solid #eee;
+ // Close icon
+ .close { margin-top: 2px; }
+ // Heading
+ h3 {
+ margin: 0;
+ line-height: 30px;
+ }
+}
+
+// Body (where all modal content resides)
+.modal-body {
+ position: relative;
+ overflow-y: auto;
+ max-height: 400px;
+ padding: 15px;
+}
+// Remove bottom margin if need be
+.modal-form {
+ margin-bottom: 0;
+}
+
+// Footer (for actions)
+.modal-footer {
+ padding: 14px 15px 15px;
+ margin-bottom: 0;
+ text-align: right; // right align buttons
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ .border-radius(0 0 6px 6px);
+ .box-shadow(inset 0 1px 0 @white);
+ .clearfix(); // clear it in case folks use .pull-* classes on buttons
+
+ // Properly space out buttons
+ .btn + .btn {
+ margin-left: 5px;
+ margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
+ }
+ // but override that for button groups
+ .btn-group .btn + .btn {
+ margin-left: -1px;
+ }
+ // and override it for block buttons as well
+ .btn-block + .btn-block {
+ margin-left: 0;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/navbar.less b/www/protected/extensions/bootstrap/assets/less/navbar.less
new file mode 100644
index 0000000..93d09bc
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/navbar.less
@@ -0,0 +1,497 @@
+//
+// Navbars (Redux)
+// --------------------------------------------------
+
+
+// COMMON STYLES
+// -------------
+
+// Base class and wrapper
+.navbar {
+ overflow: visible;
+ margin-bottom: @baseLineHeight;
+
+ // Fix for IE7's bad z-indexing so dropdowns don't appear below content that follows the navbar
+ *position: relative;
+ *z-index: 2;
+}
+
+// Inner for background effects
+// Gradient is applied to its own element because overflow visible is not honored by IE when filter is present
+.navbar-inner {
+ min-height: @navbarHeight;
+ padding-left: 20px;
+ padding-right: 20px;
+ #gradient > .vertical(@navbarBackgroundHighlight, @navbarBackground);
+ border: 1px solid @navbarBorder;
+ .border-radius(@baseBorderRadius);
+ .box-shadow(0 1px 4px rgba(0,0,0,.065));
+
+ // Prevent floats from breaking the navbar
+ .clearfix();
+}
+
+// Set width to auto for default container
+// We then reset it for fixed navbars in the #gridSystem mixin
+.navbar .container {
+ width: auto;
+}
+
+// Override the default collapsed state
+.nav-collapse.collapse {
+ height: auto;
+ overflow: visible;
+}
+
+
+// Brand: website or project name
+// -------------------------
+.navbar .brand {
+ float: left;
+ display: block;
+ // Vertically center the text given @navbarHeight
+ padding: ((@navbarHeight - @baseLineHeight) / 2) 20px ((@navbarHeight - @baseLineHeight) / 2);
+ margin-left: -20px; // negative indent to left-align the text down the page
+ font-size: 20px;
+ font-weight: 200;
+ color: @navbarBrandColor;
+ text-shadow: 0 1px 0 @navbarBackgroundHighlight;
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ }
+}
+
+// Plain text in topbar
+// -------------------------
+.navbar-text {
+ margin-bottom: 0;
+ line-height: @navbarHeight;
+ color: @navbarText;
+}
+
+// Janky solution for now to account for links outside the .nav
+// -------------------------
+.navbar-link {
+ color: @navbarLinkColor;
+ &:hover,
+ &:focus {
+ color: @navbarLinkColorHover;
+ }
+}
+
+// Dividers in navbar
+// -------------------------
+.navbar .divider-vertical {
+ height: @navbarHeight;
+ margin: 0 9px;
+ border-left: 1px solid @navbarBackground;
+ border-right: 1px solid @navbarBackgroundHighlight;
+}
+
+// Buttons in navbar
+// -------------------------
+.navbar .btn,
+.navbar .btn-group {
+ .navbarVerticalAlign(30px); // Vertically center in navbar
+}
+.navbar .btn-group .btn,
+.navbar .input-prepend .btn,
+.navbar .input-append .btn,
+.navbar .input-prepend .btn-group,
+.navbar .input-append .btn-group {
+ margin-top: 0; // then undo the margin here so we don't accidentally double it
+}
+
+// Navbar forms
+// -------------------------
+.navbar-form {
+ margin-bottom: 0; // remove default bottom margin
+ .clearfix();
+ input,
+ select,
+ .radio,
+ .checkbox {
+ .navbarVerticalAlign(30px); // Vertically center in navbar
+ }
+ input,
+ select,
+ .btn {
+ display: inline-block;
+ margin-bottom: 0;
+ }
+ input[type="image"],
+ input[type="checkbox"],
+ input[type="radio"] {
+ margin-top: 3px;
+ }
+ .input-append,
+ .input-prepend {
+ margin-top: 5px;
+ white-space: nowrap; // preven two items from separating within a .navbar-form that has .pull-left
+ input {
+ margin-top: 0; // remove the margin on top since it's on the parent
+ }
+ }
+}
+
+// Navbar search
+// -------------------------
+.navbar-search {
+ position: relative;
+ float: left;
+ .navbarVerticalAlign(30px); // Vertically center in navbar
+ margin-bottom: 0;
+ .search-query {
+ margin-bottom: 0;
+ padding: 4px 14px;
+ #font > .sans-serif(13px, normal, 1);
+ .border-radius(15px); // redeclare because of specificity of the type attribute
+ }
+}
+
+
+
+// Static navbar
+// -------------------------
+
+.navbar-static-top {
+ position: static;
+ margin-bottom: 0; // remove 18px margin for default navbar
+ .navbar-inner {
+ .border-radius(0);
+ }
+}
+
+
+
+// Fixed navbar
+// -------------------------
+
+// Shared (top/bottom) styles
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: @zindexFixedNavbar;
+ margin-bottom: 0; // remove 18px margin for default navbar
+}
+.navbar-fixed-top .navbar-inner,
+.navbar-static-top .navbar-inner {
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom .navbar-inner {
+ border-width: 1px 0 0;
+}
+.navbar-fixed-top .navbar-inner,
+.navbar-fixed-bottom .navbar-inner {
+ padding-left: 0;
+ padding-right: 0;
+ .border-radius(0);
+}
+
+// Reset container width
+// Required here as we reset the width earlier on and the grid mixins don't override early enough
+.navbar-static-top .container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ #grid > .core > .span(@gridColumns);
+}
+
+// Fixed to top
+.navbar-fixed-top {
+ top: 0;
+}
+.navbar-fixed-top,
+.navbar-static-top {
+ .navbar-inner {
+ .box-shadow(~"0 1px 10px rgba(0,0,0,.1)");
+ }
+}
+
+// Fixed to bottom
+.navbar-fixed-bottom {
+ bottom: 0;
+ .navbar-inner {
+ .box-shadow(~"0 -1px 10px rgba(0,0,0,.1)");
+ }
+}
+
+
+
+// NAVIGATION
+// ----------
+
+.navbar .nav {
+ position: relative;
+ left: 0;
+ display: block;
+ float: left;
+ margin: 0 10px 0 0;
+}
+.navbar .nav.pull-right {
+ float: right; // redeclare due to specificity
+ margin-right: 0; // remove margin on float right nav
+}
+.navbar .nav > li {
+ float: left;
+}
+
+// Links
+.navbar .nav > li > a {
+ float: none;
+ // Vertically center the text given @navbarHeight
+ padding: ((@navbarHeight - @baseLineHeight) / 2) 15px ((@navbarHeight - @baseLineHeight) / 2);
+ color: @navbarLinkColor;
+ text-decoration: none;
+ text-shadow: 0 1px 0 @navbarBackgroundHighlight;
+}
+.navbar .nav .dropdown-toggle .caret {
+ margin-top: 8px;
+}
+
+// Hover/focus
+.navbar .nav > li > a:focus,
+.navbar .nav > li > a:hover {
+ background-color: @navbarLinkBackgroundHover; // "transparent" is default to differentiate :hover/:focus from .active
+ color: @navbarLinkColorHover;
+ text-decoration: none;
+}
+
+// Active nav items
+.navbar .nav > .active > a,
+.navbar .nav > .active > a:hover,
+.navbar .nav > .active > a:focus {
+ color: @navbarLinkColorActive;
+ text-decoration: none;
+ background-color: @navbarLinkBackgroundActive;
+ .box-shadow(inset 0 3px 8px rgba(0,0,0,.125));
+}
+
+// Navbar button for toggling navbar items in responsive layouts
+// These definitions need to come after '.navbar .btn'
+.navbar .btn-navbar {
+ display: none;
+ float: right;
+ padding: 7px 10px;
+ margin-left: 5px;
+ margin-right: 5px;
+ .buttonBackground(darken(@navbarBackgroundHighlight, 5%), darken(@navbarBackground, 5%));
+ .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)");
+}
+.navbar .btn-navbar .icon-bar {
+ display: block;
+ width: 18px;
+ height: 2px;
+ background-color: #f5f5f5;
+ .border-radius(1px);
+ .box-shadow(0 1px 0 rgba(0,0,0,.25));
+}
+.btn-navbar .icon-bar + .icon-bar {
+ margin-top: 3px;
+}
+
+
+
+// Dropdown menus
+// --------------
+
+// Menu position and menu carets
+.navbar .nav > li > .dropdown-menu {
+ &:before {
+ content: '';
+ display: inline-block;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-bottom-color: @dropdownBorder;
+ position: absolute;
+ top: -7px;
+ left: 9px;
+ }
+ &:after {
+ content: '';
+ display: inline-block;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid @dropdownBackground;
+ position: absolute;
+ top: -6px;
+ left: 10px;
+ }
+}
+// Menu position and menu caret support for dropups via extra dropup class
+.navbar-fixed-bottom .nav > li > .dropdown-menu {
+ &:before {
+ border-top: 7px solid #ccc;
+ border-top-color: @dropdownBorder;
+ border-bottom: 0;
+ bottom: -7px;
+ top: auto;
+ }
+ &:after {
+ border-top: 6px solid @dropdownBackground;
+ border-bottom: 0;
+ bottom: -6px;
+ top: auto;
+ }
+}
+
+// Caret should match text color on hover/focus
+.navbar .nav li.dropdown > a:hover .caret,
+.navbar .nav li.dropdown > a:focus .caret {
+ border-top-color: @navbarLinkColorHover;
+ border-bottom-color: @navbarLinkColorHover;
+}
+
+// Remove background color from open dropdown
+.navbar .nav li.dropdown.open > .dropdown-toggle,
+.navbar .nav li.dropdown.active > .dropdown-toggle,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle {
+ background-color: @navbarLinkBackgroundActive;
+ color: @navbarLinkColorActive;
+}
+.navbar .nav li.dropdown > .dropdown-toggle .caret {
+ border-top-color: @navbarLinkColor;
+ border-bottom-color: @navbarLinkColor;
+}
+.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.active > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {
+ border-top-color: @navbarLinkColorActive;
+ border-bottom-color: @navbarLinkColorActive;
+}
+
+// Right aligned menus need alt position
+.navbar .pull-right > li > .dropdown-menu,
+.navbar .nav > li > .dropdown-menu.pull-right {
+ left: auto;
+ right: 0;
+ &:before {
+ left: auto;
+ right: 12px;
+ }
+ &:after {
+ left: auto;
+ right: 13px;
+ }
+ .dropdown-menu {
+ left: auto;
+ right: 100%;
+ margin-left: 0;
+ margin-right: -1px;
+ .border-radius(6px 0 6px 6px);
+ }
+}
+
+
+// Inverted navbar
+// -------------------------
+
+.navbar-inverse {
+
+ .navbar-inner {
+ #gradient > .vertical(@navbarInverseBackgroundHighlight, @navbarInverseBackground);
+ border-color: @navbarInverseBorder;
+ }
+
+ .brand,
+ .nav > li > a {
+ color: @navbarInverseLinkColor;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ &:hover,
+ &:focus {
+ color: @navbarInverseLinkColorHover;
+ }
+ }
+
+ .brand {
+ color: @navbarInverseBrandColor;
+ }
+
+ .navbar-text {
+ color: @navbarInverseText;
+ }
+
+ .nav > li > a:focus,
+ .nav > li > a:hover {
+ background-color: @navbarInverseLinkBackgroundHover;
+ color: @navbarInverseLinkColorHover;
+ }
+
+ .nav .active > a,
+ .nav .active > a:hover,
+ .nav .active > a:focus {
+ color: @navbarInverseLinkColorActive;
+ background-color: @navbarInverseLinkBackgroundActive;
+ }
+
+ // Inline text links
+ .navbar-link {
+ color: @navbarInverseLinkColor;
+ &:hover,
+ &:focus {
+ color: @navbarInverseLinkColorHover;
+ }
+ }
+
+ // Dividers in navbar
+ .divider-vertical {
+ border-left-color: @navbarInverseBackground;
+ border-right-color: @navbarInverseBackgroundHighlight;
+ }
+
+ // Dropdowns
+ .nav li.dropdown.open > .dropdown-toggle,
+ .nav li.dropdown.active > .dropdown-toggle,
+ .nav li.dropdown.open.active > .dropdown-toggle {
+ background-color: @navbarInverseLinkBackgroundActive;
+ color: @navbarInverseLinkColorActive;
+ }
+ .nav li.dropdown > a:hover .caret,
+ .nav li.dropdown > a:focus .caret {
+ border-top-color: @navbarInverseLinkColorActive;
+ border-bottom-color: @navbarInverseLinkColorActive;
+ }
+ .nav li.dropdown > .dropdown-toggle .caret {
+ border-top-color: @navbarInverseLinkColor;
+ border-bottom-color: @navbarInverseLinkColor;
+ }
+ .nav li.dropdown.open > .dropdown-toggle .caret,
+ .nav li.dropdown.active > .dropdown-toggle .caret,
+ .nav li.dropdown.open.active > .dropdown-toggle .caret {
+ border-top-color: @navbarInverseLinkColorActive;
+ border-bottom-color: @navbarInverseLinkColorActive;
+ }
+
+ // Navbar search
+ .navbar-search {
+ .search-query {
+ color: @white;
+ background-color: @navbarInverseSearchBackground;
+ border-color: @navbarInverseSearchBorder;
+ .box-shadow(~"inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15)");
+ .transition(none);
+ .placeholder(@navbarInverseSearchPlaceholderColor);
+
+ // Focus states (we use .focused since IE7-8 and down doesn't support :focus)
+ &:focus,
+ &.focused {
+ padding: 5px 15px;
+ color: @grayDark;
+ text-shadow: 0 1px 0 @white;
+ background-color: @navbarInverseSearchBackgroundFocus;
+ border: 0;
+ .box-shadow(0 0 3px rgba(0,0,0,.15));
+ outline: 0;
+ }
+ }
+ }
+
+ // Navbar collapse button
+ .btn-navbar {
+ .buttonBackground(darken(@navbarInverseBackgroundHighlight, 5%), darken(@navbarInverseBackground, 5%));
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/navs.less b/www/protected/extensions/bootstrap/assets/less/navs.less
new file mode 100644
index 0000000..01cd805
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/navs.less
@@ -0,0 +1,409 @@
+//
+// Navs
+// --------------------------------------------------
+
+
+// BASE CLASS
+// ----------
+
+.nav {
+ margin-left: 0;
+ margin-bottom: @baseLineHeight;
+ list-style: none;
+}
+
+// Make links block level
+.nav > li > a {
+ display: block;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: @grayLighter;
+}
+
+// Prevent IE8 from misplacing imgs
+// See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989
+.nav > li > a > img {
+ max-width: none;
+}
+
+// Redeclare pull classes because of specifity
+.nav > .pull-right {
+ float: right;
+}
+
+// Nav headers (for dropdowns and lists)
+.nav-header {
+ display: block;
+ padding: 3px 15px;
+ font-size: 11px;
+ font-weight: bold;
+ line-height: @baseLineHeight;
+ color: @grayLight;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+ text-transform: uppercase;
+}
+// Space them out when they follow another list item (link)
+.nav li + .nav-header {
+ margin-top: 9px;
+}
+
+
+
+// NAV LIST
+// --------
+
+.nav-list {
+ padding-left: 15px;
+ padding-right: 15px;
+ margin-bottom: 0;
+}
+.nav-list > li > a,
+.nav-list .nav-header {
+ margin-left: -15px;
+ margin-right: -15px;
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
+}
+.nav-list > li > a {
+ padding: 3px 15px;
+}
+.nav-list > .active > a,
+.nav-list > .active > a:hover,
+.nav-list > .active > a:focus {
+ color: @white;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.2);
+ background-color: @linkColor;
+}
+.nav-list [class^="icon-"],
+.nav-list [class*=" icon-"] {
+ margin-right: 2px;
+}
+// Dividers (basically an hr) within the dropdown
+.nav-list .divider {
+ .nav-divider();
+}
+
+
+
+// TABS AND PILLS
+// -------------
+
+// Common styles
+.nav-tabs,
+.nav-pills {
+ .clearfix();
+}
+.nav-tabs > li,
+.nav-pills > li {
+ float: left;
+}
+.nav-tabs > li > a,
+.nav-pills > li > a {
+ padding-right: 12px;
+ padding-left: 12px;
+ margin-right: 2px;
+ line-height: 14px; // keeps the overall height an even number
+}
+
+// TABS
+// ----
+
+// Give the tabs something to sit on
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+// Make the list-items overlay the bottom border
+.nav-tabs > li {
+ margin-bottom: -1px;
+}
+// Actual tabs (as links)
+.nav-tabs > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ line-height: @baseLineHeight;
+ border: 1px solid transparent;
+ .border-radius(4px 4px 0 0);
+ &:hover,
+ &:focus {
+ border-color: @grayLighter @grayLighter #ddd;
+ }
+}
+// Active state, and it's :hover/:focus to override normal :hover/:focus
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover,
+.nav-tabs > .active > a:focus {
+ color: @gray;
+ background-color: @bodyBackground;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+
+
+// PILLS
+// -----
+
+// Links rendered as pills
+.nav-pills > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ .border-radius(5px);
+}
+
+// Active state
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover,
+.nav-pills > .active > a:focus {
+ color: @white;
+ background-color: @linkColor;
+}
+
+
+
+// STACKED NAV
+// -----------
+
+// Stacked tabs and pills
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li > a {
+ margin-right: 0; // no need for the gap between nav items
+}
+
+// Tabs
+.nav-tabs.nav-stacked {
+ border-bottom: 0;
+}
+.nav-tabs.nav-stacked > li > a {
+ border: 1px solid #ddd;
+ .border-radius(0);
+}
+.nav-tabs.nav-stacked > li:first-child > a {
+ .border-top-radius(4px);
+}
+.nav-tabs.nav-stacked > li:last-child > a {
+ .border-bottom-radius(4px);
+}
+.nav-tabs.nav-stacked > li > a:hover,
+.nav-tabs.nav-stacked > li > a:focus {
+ border-color: #ddd;
+ z-index: 2;
+}
+
+// Pills
+.nav-pills.nav-stacked > li > a {
+ margin-bottom: 3px;
+}
+.nav-pills.nav-stacked > li:last-child > a {
+ margin-bottom: 1px; // decrease margin to match sizing of stacked tabs
+}
+
+
+
+// DROPDOWNS
+// ---------
+
+.nav-tabs .dropdown-menu {
+ .border-radius(0 0 6px 6px); // remove the top rounded corners here since there is a hard edge above the menu
+}
+.nav-pills .dropdown-menu {
+ .border-radius(6px); // make rounded corners match the pills
+}
+
+// Default dropdown links
+// -------------------------
+// Make carets use linkColor to start
+.nav .dropdown-toggle .caret {
+ border-top-color: @linkColor;
+ border-bottom-color: @linkColor;
+ margin-top: 6px;
+}
+.nav .dropdown-toggle:hover .caret,
+.nav .dropdown-toggle:focus .caret {
+ border-top-color: @linkColorHover;
+ border-bottom-color: @linkColorHover;
+}
+/* move down carets for tabs */
+.nav-tabs .dropdown-toggle .caret {
+ margin-top: 8px;
+}
+
+// Active dropdown links
+// -------------------------
+.nav .active .dropdown-toggle .caret {
+ border-top-color: #fff;
+ border-bottom-color: #fff;
+}
+.nav-tabs .active .dropdown-toggle .caret {
+ border-top-color: @gray;
+ border-bottom-color: @gray;
+}
+
+// Active:hover/:focus dropdown links
+// -------------------------
+.nav > .dropdown.active > a:hover,
+.nav > .dropdown.active > a:focus {
+ cursor: pointer;
+}
+
+// Open dropdowns
+// -------------------------
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > li.dropdown.open.active > a:hover,
+.nav > li.dropdown.open.active > a:focus {
+ color: @white;
+ background-color: @grayLight;
+ border-color: @grayLight;
+}
+.nav li.dropdown.open .caret,
+.nav li.dropdown.open.active .caret,
+.nav li.dropdown.open a:hover .caret,
+.nav li.dropdown.open a:focus .caret {
+ border-top-color: @white;
+ border-bottom-color: @white;
+ .opacity(100);
+}
+
+// Dropdowns in stacked tabs
+.tabs-stacked .open > a:hover,
+.tabs-stacked .open > a:focus {
+ border-color: @grayLight;
+}
+
+
+
+// TABBABLE
+// --------
+
+
+// COMMON STYLES
+// -------------
+
+// Clear any floats
+.tabbable {
+ .clearfix();
+}
+.tab-content {
+ overflow: auto; // prevent content from running below tabs
+}
+
+// Remove border on bottom, left, right
+.tabs-below > .nav-tabs,
+.tabs-right > .nav-tabs,
+.tabs-left > .nav-tabs {
+ border-bottom: 0;
+}
+
+// Show/hide tabbable areas
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+ display: none;
+}
+.tab-content > .active,
+.pill-content > .active {
+ display: block;
+}
+
+
+// BOTTOM
+// ------
+
+.tabs-below > .nav-tabs {
+ border-top: 1px solid #ddd;
+}
+.tabs-below > .nav-tabs > li {
+ margin-top: -1px;
+ margin-bottom: 0;
+}
+.tabs-below > .nav-tabs > li > a {
+ .border-radius(0 0 4px 4px);
+ &:hover,
+ &:focus {
+ border-bottom-color: transparent;
+ border-top-color: #ddd;
+ }
+}
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover,
+.tabs-below > .nav-tabs > .active > a:focus {
+ border-color: transparent #ddd #ddd #ddd;
+}
+
+// LEFT & RIGHT
+// ------------
+
+// Common styles
+.tabs-left > .nav-tabs > li,
+.tabs-right > .nav-tabs > li {
+ float: none;
+}
+.tabs-left > .nav-tabs > li > a,
+.tabs-right > .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+
+// Tabs on the left
+.tabs-left > .nav-tabs {
+ float: left;
+ margin-right: 19px;
+ border-right: 1px solid #ddd;
+}
+.tabs-left > .nav-tabs > li > a {
+ margin-right: -1px;
+ .border-radius(4px 0 0 4px);
+}
+.tabs-left > .nav-tabs > li > a:hover,
+.tabs-left > .nav-tabs > li > a:focus {
+ border-color: @grayLighter #ddd @grayLighter @grayLighter;
+}
+.tabs-left > .nav-tabs .active > a,
+.tabs-left > .nav-tabs .active > a:hover,
+.tabs-left > .nav-tabs .active > a:focus {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: @white;
+}
+
+// Tabs on the right
+.tabs-right > .nav-tabs {
+ float: right;
+ margin-left: 19px;
+ border-left: 1px solid #ddd;
+}
+.tabs-right > .nav-tabs > li > a {
+ margin-left: -1px;
+ .border-radius(0 4px 4px 0);
+}
+.tabs-right > .nav-tabs > li > a:hover,
+.tabs-right > .nav-tabs > li > a:focus {
+ border-color: @grayLighter @grayLighter @grayLighter #ddd;
+}
+.tabs-right > .nav-tabs .active > a,
+.tabs-right > .nav-tabs .active > a:hover,
+.tabs-right > .nav-tabs .active > a:focus {
+ border-color: #ddd #ddd #ddd transparent;
+ *border-left-color: @white;
+}
+
+
+
+// DISABLED STATES
+// ---------------
+
+// Gray out text
+.nav > .disabled > a {
+ color: @grayLight;
+}
+// Nuke hover/focus effects
+.nav > .disabled > a:hover,
+.nav > .disabled > a:focus {
+ text-decoration: none;
+ background-color: transparent;
+ cursor: default;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/pager.less b/www/protected/extensions/bootstrap/assets/less/pager.less
new file mode 100644
index 0000000..1476188
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/pager.less
@@ -0,0 +1,43 @@
+//
+// Pager pagination
+// --------------------------------------------------
+
+
+.pager {
+ margin: @baseLineHeight 0;
+ list-style: none;
+ text-align: center;
+ .clearfix();
+}
+.pager li {
+ display: inline;
+}
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ .border-radius(15px);
+}
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: @grayLight;
+ background-color: #fff;
+ cursor: default;
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/assets/less/pagination.less b/www/protected/extensions/bootstrap/assets/less/pagination.less
new file mode 100644
index 0000000..a789db2
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/pagination.less
@@ -0,0 +1,123 @@
+//
+// Pagination (multiple pages)
+// --------------------------------------------------
+
+// Space out pagination from surrounding content
+.pagination {
+ margin: @baseLineHeight 0;
+}
+
+.pagination ul {
+ // Allow for text-based alignment
+ display: inline-block;
+ .ie7-inline-block();
+ // Reset default ul styles
+ margin-left: 0;
+ margin-bottom: 0;
+ // Visuals
+ .border-radius(@baseBorderRadius);
+ .box-shadow(0 1px 2px rgba(0,0,0,.05));
+}
+.pagination ul > li {
+ display: inline; // Remove list-style and block-level defaults
+}
+.pagination ul > li > a,
+.pagination ul > li > span {
+ float: left; // Collapse white-space
+ padding: 4px 12px;
+ line-height: @baseLineHeight;
+ text-decoration: none;
+ background-color: @paginationBackground;
+ border: 1px solid @paginationBorder;
+ border-left-width: 0;
+}
+.pagination ul > li > a:hover,
+.pagination ul > li > a:focus,
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+ background-color: @paginationActiveBackground;
+}
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+ color: @grayLight;
+ cursor: default;
+}
+.pagination ul > .disabled > span,
+.pagination ul > .disabled > a,
+.pagination ul > .disabled > a:hover,
+.pagination ul > .disabled > a:focus {
+ color: @grayLight;
+ background-color: transparent;
+ cursor: default;
+}
+.pagination ul > li:first-child > a,
+.pagination ul > li:first-child > span {
+ border-left-width: 1px;
+ .border-left-radius(@baseBorderRadius);
+}
+.pagination ul > li:last-child > a,
+.pagination ul > li:last-child > span {
+ .border-right-radius(@baseBorderRadius);
+}
+
+
+// Alignment
+// --------------------------------------------------
+
+.pagination-centered {
+ text-align: center;
+}
+.pagination-right {
+ text-align: right;
+}
+
+
+// Sizing
+// --------------------------------------------------
+
+// Large
+.pagination-large {
+ ul > li > a,
+ ul > li > span {
+ padding: @paddingLarge;
+ font-size: @fontSizeLarge;
+ }
+ ul > li:first-child > a,
+ ul > li:first-child > span {
+ .border-left-radius(@borderRadiusLarge);
+ }
+ ul > li:last-child > a,
+ ul > li:last-child > span {
+ .border-right-radius(@borderRadiusLarge);
+ }
+}
+
+// Small and mini
+.pagination-mini,
+.pagination-small {
+ ul > li:first-child > a,
+ ul > li:first-child > span {
+ .border-left-radius(@borderRadiusSmall);
+ }
+ ul > li:last-child > a,
+ ul > li:last-child > span {
+ .border-right-radius(@borderRadiusSmall);
+ }
+}
+
+// Small
+.pagination-small {
+ ul > li > a,
+ ul > li > span {
+ padding: @paddingSmall;
+ font-size: @fontSizeSmall;
+ }
+}
+// Mini
+.pagination-mini {
+ ul > li > a,
+ ul > li > span {
+ padding: @paddingMini;
+ font-size: @fontSizeMini;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/popovers.less b/www/protected/extensions/bootstrap/assets/less/popovers.less
new file mode 100644
index 0000000..aae35c8
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/popovers.less
@@ -0,0 +1,133 @@
+//
+// Popovers
+// --------------------------------------------------
+
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: @zindexPopover;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ text-align: left; // Reset given new insertion method
+ background-color: @popoverBackground;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0,0,0,.2);
+ .border-radius(6px);
+ .box-shadow(0 5px 10px rgba(0,0,0,.2));
+
+ // Overrides for proper insertion
+ white-space: normal;
+
+ // Offset the popover to account for the popover arrow
+ &.top { margin-top: -10px; }
+ &.right { margin-left: 10px; }
+ &.bottom { margin-top: 10px; }
+ &.left { margin-left: -10px; }
+}
+
+.popover-title {
+ margin: 0; // reset heading margin
+ padding: 8px 14px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 18px;
+ background-color: @popoverTitleBackground;
+ border-bottom: 1px solid darken(@popoverTitleBackground, 5%);
+ .border-radius(5px 5px 0 0);
+
+ &:empty {
+ display: none;
+ }
+}
+
+.popover-content {
+ padding: 9px 14px;
+}
+
+// Arrows
+//
+// .arrow is outer, .arrow:after is inner
+
+.popover .arrow,
+.popover .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover .arrow {
+ border-width: @popoverArrowOuterWidth;
+}
+.popover .arrow:after {
+ border-width: @popoverArrowWidth;
+ content: "";
+}
+
+.popover {
+ &.top .arrow {
+ left: 50%;
+ margin-left: -@popoverArrowOuterWidth;
+ border-bottom-width: 0;
+ border-top-color: #999; // IE8 fallback
+ border-top-color: @popoverArrowOuterColor;
+ bottom: -@popoverArrowOuterWidth;
+ &:after {
+ bottom: 1px;
+ margin-left: -@popoverArrowWidth;
+ border-bottom-width: 0;
+ border-top-color: @popoverArrowColor;
+ }
+ }
+ &.right .arrow {
+ top: 50%;
+ left: -@popoverArrowOuterWidth;
+ margin-top: -@popoverArrowOuterWidth;
+ border-left-width: 0;
+ border-right-color: #999; // IE8 fallback
+ border-right-color: @popoverArrowOuterColor;
+ &:after {
+ left: 1px;
+ bottom: -@popoverArrowWidth;
+ border-left-width: 0;
+ border-right-color: @popoverArrowColor;
+ }
+ }
+ &.bottom .arrow {
+ left: 50%;
+ margin-left: -@popoverArrowOuterWidth;
+ border-top-width: 0;
+ border-bottom-color: #999; // IE8 fallback
+ border-bottom-color: @popoverArrowOuterColor;
+ top: -@popoverArrowOuterWidth;
+ &:after {
+ top: 1px;
+ margin-left: -@popoverArrowWidth;
+ border-top-width: 0;
+ border-bottom-color: @popoverArrowColor;
+ }
+ }
+
+ &.left .arrow {
+ top: 50%;
+ right: -@popoverArrowOuterWidth;
+ margin-top: -@popoverArrowOuterWidth;
+ border-right-width: 0;
+ border-left-color: #999; // IE8 fallback
+ border-left-color: @popoverArrowOuterColor;
+ &:after {
+ right: 1px;
+ border-right-width: 0;
+ border-left-color: @popoverArrowColor;
+ bottom: -@popoverArrowWidth;
+ }
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/progress-bars.less b/www/protected/extensions/bootstrap/assets/less/progress-bars.less
new file mode 100644
index 0000000..5e0c3dd
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/progress-bars.less
@@ -0,0 +1,122 @@
+//
+// Progress bars
+// --------------------------------------------------
+
+
+// ANIMATIONS
+// ----------
+
+// Webkit
+@-webkit-keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+// Firefox
+@-moz-keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+// IE9
+@-ms-keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+// Opera
+@-o-keyframes progress-bar-stripes {
+ from { background-position: 0 0; }
+ to { background-position: 40px 0; }
+}
+
+// Spec
+@keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+
+
+// THE BARS
+// --------
+
+// Outer container
+.progress {
+ overflow: hidden;
+ height: @baseLineHeight;
+ margin-bottom: @baseLineHeight;
+ #gradient > .vertical(#f5f5f5, #f9f9f9);
+ .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
+ .border-radius(@baseBorderRadius);
+}
+
+// Bar of progress
+.progress .bar {
+ width: 0%;
+ height: 100%;
+ color: @white;
+ float: left;
+ font-size: 12px;
+ text-align: center;
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ #gradient > .vertical(#149bdf, #0480be);
+ .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
+ .box-sizing(border-box);
+ .transition(width .6s ease);
+}
+.progress .bar + .bar {
+ .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)");
+}
+
+// Striped bars
+.progress-striped .bar {
+ #gradient > .striped(#149bdf);
+ .background-size(40px 40px);
+}
+
+// Call animation for the active one
+.progress.active .bar {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -moz-animation: progress-bar-stripes 2s linear infinite;
+ -ms-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+
+
+
+// COLORS
+// ------
+
+// Danger (red)
+.progress-danger .bar, .progress .bar-danger {
+ #gradient > .vertical(#ee5f5b, #c43c35);
+}
+.progress-danger.progress-striped .bar, .progress-striped .bar-danger {
+ #gradient > .striped(#ee5f5b);
+}
+
+// Success (green)
+.progress-success .bar, .progress .bar-success {
+ #gradient > .vertical(#62c462, #57a957);
+}
+.progress-success.progress-striped .bar, .progress-striped .bar-success {
+ #gradient > .striped(#62c462);
+}
+
+// Info (teal)
+.progress-info .bar, .progress .bar-info {
+ #gradient > .vertical(#5bc0de, #339bb9);
+}
+.progress-info.progress-striped .bar, .progress-striped .bar-info {
+ #gradient > .striped(#5bc0de);
+}
+
+// Warning (orange)
+.progress-warning .bar, .progress .bar-warning {
+ #gradient > .vertical(lighten(@orange, 15%), @orange);
+}
+.progress-warning.progress-striped .bar, .progress-striped .bar-warning {
+ #gradient > .striped(lighten(@orange, 15%));
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/reset.less b/www/protected/extensions/bootstrap/assets/less/reset.less
new file mode 100644
index 0000000..4806bd5
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/reset.less
@@ -0,0 +1,216 @@
+//
+// Reset CSS
+// Adapted from http://github.com/necolas/normalize.css
+// --------------------------------------------------
+
+
+// Display in IE6-9 and FF3
+// -------------------------
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+
+// Display block in IE6-9 and FF3
+// -------------------------
+
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+
+// Prevents modern browsers from displaying 'audio' without controls
+// -------------------------
+
+audio:not([controls]) {
+ display: none;
+}
+
+// Base settings
+// -------------------------
+
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+// Focus states
+a:focus {
+ .tab-focus();
+}
+// Hover & Active
+a:hover,
+a:active {
+ outline: 0;
+}
+
+// Prevents sub and sup affecting line-height in all browsers
+// -------------------------
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+
+// Img border in a's and image quality
+// -------------------------
+
+img {
+ /* Responsive images (ensure images don't scale beyond their parents) */
+ max-width: 100%; /* Part 1: Set a maxium relative to the parent */
+ width: auto\9; /* IE7-8 need help adjusting responsive images */
+ height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */
+
+ vertical-align: middle;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+
+// Prevent max-width from affecting Google Maps
+#map_canvas img,
+.google-maps img {
+ max-width: none;
+}
+
+// Forms
+// -------------------------
+
+// Font size in all browsers, margin changes, misc consistency
+button,
+input,
+select,
+textarea {
+ margin: 0;
+ font-size: 100%;
+ vertical-align: middle;
+}
+button,
+input {
+ *overflow: visible; // Inner spacing ie IE6/7
+ line-height: normal; // FF3/4 have !important on line-height in UA stylesheet
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
+ padding: 0;
+ border: 0;
+}
+button,
+html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls.
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS.
+ cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others.
+}
+label,
+select,
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"],
+input[type="radio"],
+input[type="checkbox"] {
+ cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others.
+}
+input[type="search"] { // Appearance in Safari/Chrome
+ .box-sizing(content-box);
+ -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
+}
+textarea {
+ overflow: auto; // Remove vertical scrollbar in IE6-9
+ vertical-align: top; // Readability and alignment cross-browser
+}
+
+
+// Printing
+// -------------------------
+// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css
+
+@media print {
+
+ * {
+ text-shadow: none !important;
+ color: #000 !important; // Black prints faster: h5bp.com/s
+ background: transparent !important;
+ box-shadow: none !important;
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+
+ // Don't show links for images, or javascript/internal links
+ .ir a:after,
+ a[href^="javascript:"]:after,
+ a[href^="#"]:after {
+ content: "";
+ }
+
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+
+ thead {
+ display: table-header-group; // h5bp.com/t
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+
+ img {
+ max-width: 100% !important;
+ }
+
+ @page {
+ margin: 0.5cm;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive-1200px-min.less b/www/protected/extensions/bootstrap/assets/less/responsive-1200px-min.less
new file mode 100644
index 0000000..4f35ba6
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive-1200px-min.less
@@ -0,0 +1,28 @@
+//
+// Responsive: Large desktop and up
+// --------------------------------------------------
+
+
+@media (min-width: 1200px) {
+
+ // Fixed grid
+ #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);
+
+ // Fluid grid
+ #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);
+
+ // Input grid
+ #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);
+
+ // Thumbnails
+ .thumbnails {
+ margin-left: -@gridGutterWidth1200;
+ }
+ .thumbnails > li {
+ margin-left: @gridGutterWidth1200;
+ }
+ .row-fluid .thumbnails {
+ margin-left: 0;
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive-767px-max.less b/www/protected/extensions/bootstrap/assets/less/responsive-767px-max.less
new file mode 100644
index 0000000..128f4ce
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive-767px-max.less
@@ -0,0 +1,193 @@
+//
+// Responsive: Landscape phone to desktop/tablet
+// --------------------------------------------------
+
+
+@media (max-width: 767px) {
+
+ // Padding to set content in a bit
+ body {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ // Negative indent the now static "fixed" navbar
+ .navbar-fixed-top,
+ .navbar-fixed-bottom,
+ .navbar-static-top {
+ margin-left: -20px;
+ margin-right: -20px;
+ }
+ // Remove padding on container given explicit padding set on body
+ .container-fluid {
+ padding: 0;
+ }
+
+ // TYPOGRAPHY
+ // ----------
+ // Reset horizontal dl
+ .dl-horizontal {
+ dt {
+ float: none;
+ clear: none;
+ width: auto;
+ text-align: left;
+ }
+ dd {
+ margin-left: 0;
+ }
+ }
+
+ // GRID & CONTAINERS
+ // -----------------
+ // Remove width from containers
+ .container {
+ width: auto;
+ }
+ // Fluid rows
+ .row-fluid {
+ width: 100%;
+ }
+ // Undo negative margin on rows and thumbnails
+ .row,
+ .thumbnails {
+ margin-left: 0;
+ }
+ .thumbnails > li {
+ float: none;
+ margin-left: 0; // Reset the default margin for all li elements when no .span* classes are present
+ }
+ // Make all grid-sized elements block level again
+ [class*="span"],
+ .uneditable-input[class*="span"], // Makes uneditable inputs full-width when using grid sizing
+ .row-fluid [class*="span"] {
+ float: none;
+ display: block;
+ width: 100%;
+ margin-left: 0;
+ .box-sizing(border-box);
+ }
+ .span12,
+ .row-fluid .span12 {
+ width: 100%;
+ .box-sizing(border-box);
+ }
+ .row-fluid [class*="offset"]:first-child {
+ margin-left: 0;
+ }
+
+ // FORM FIELDS
+ // -----------
+ // Make span* classes full width
+ .input-large,
+ .input-xlarge,
+ .input-xxlarge,
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ .input-block-level();
+ }
+ // But don't let it screw up prepend/append inputs
+ .input-prepend input,
+ .input-append input,
+ .input-prepend input[class*="span"],
+ .input-append input[class*="span"] {
+ display: inline-block; // redeclare so they don't wrap to new lines
+ width: auto;
+ }
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 0;
+ }
+
+ // Modals
+ .modal {
+ position: fixed;
+ top: 20px;
+ left: 20px;
+ right: 20px;
+ width: auto;
+ margin: 0;
+ &.fade { top: -100px; }
+ &.fade.in { top: 20px; }
+ }
+
+}
+
+
+
+// UP TO LANDSCAPE PHONE
+// ---------------------
+
+@media (max-width: 480px) {
+
+ // Smooth out the collapsing/expanding nav
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0); // activate the GPU
+ }
+
+ // Block level the page header small tag for readability
+ .page-header h1 small {
+ display: block;
+ line-height: @baseLineHeight;
+ }
+
+ // Update checkboxes for iOS
+ input[type="checkbox"],
+ input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+
+ // Remove the horizontal form styles
+ .form-horizontal {
+ .control-label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ // Move over all input controls and content
+ .controls {
+ margin-left: 0;
+ }
+ // Move the options list down to align with labels
+ .control-list {
+ padding-top: 0; // has to be padding because margin collaspes
+ }
+ // Move over buttons in .form-actions to align with .controls
+ .form-actions {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ }
+
+ // Medias
+ // Reset float and spacing to stack
+ .media .pull-left,
+ .media .pull-right {
+ float: none;
+ display: block;
+ margin-bottom: 10px;
+ }
+ // Remove side margins since we stack instead of indent
+ .media-object {
+ margin-right: 0;
+ margin-left: 0;
+ }
+
+ // Modals
+ .modal {
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+
+ // Carousel
+ .carousel-caption {
+ position: static;
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive-768px-979px.less b/www/protected/extensions/bootstrap/assets/less/responsive-768px-979px.less
new file mode 100644
index 0000000..8e8c486
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive-768px-979px.less
@@ -0,0 +1,19 @@
+//
+// Responsive: Tablet to desktop
+// --------------------------------------------------
+
+
+@media (min-width: 768px) and (max-width: 979px) {
+
+ // Fixed grid
+ #grid > .core(@gridColumnWidth768, @gridGutterWidth768);
+
+ // Fluid grid
+ #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768);
+
+ // Input grid
+ #grid > .input(@gridColumnWidth768, @gridGutterWidth768);
+
+ // No need to reset .thumbnails here since it's the same @gridGutterWidth
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive-navbar.less b/www/protected/extensions/bootstrap/assets/less/responsive-navbar.less
new file mode 100644
index 0000000..21cd3ba
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive-navbar.less
@@ -0,0 +1,189 @@
+//
+// Responsive: Navbar
+// --------------------------------------------------
+
+
+// TABLETS AND BELOW
+// -----------------
+@media (max-width: @navbarCollapseWidth) {
+
+ // UNFIX THE TOPBAR
+ // ----------------
+ // Remove any padding from the body
+ body {
+ padding-top: 0;
+ }
+ // Unfix the navbars
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ position: static;
+ }
+ .navbar-fixed-top {
+ margin-bottom: @baseLineHeight;
+ }
+ .navbar-fixed-bottom {
+ margin-top: @baseLineHeight;
+ }
+ .navbar-fixed-top .navbar-inner,
+ .navbar-fixed-bottom .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ // Account for brand name
+ .navbar .brand {
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0 0 0 -5px;
+ }
+
+ // COLLAPSIBLE NAVBAR
+ // ------------------
+ // Nav collapse clears brand
+ .nav-collapse {
+ clear: both;
+ }
+ // Block-level the nav
+ .nav-collapse .nav {
+ float: none;
+ margin: 0 0 (@baseLineHeight / 2);
+ }
+ .nav-collapse .nav > li {
+ float: none;
+ }
+ .nav-collapse .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .nav-collapse .nav > .divider-vertical {
+ display: none;
+ }
+ .nav-collapse .nav .nav-header {
+ color: @navbarText;
+ text-shadow: none;
+ }
+ // Nav and dropdown links in navbar
+ .nav-collapse .nav > li > a,
+ .nav-collapse .dropdown-menu a {
+ padding: 9px 15px;
+ font-weight: bold;
+ color: @navbarLinkColor;
+ .border-radius(3px);
+ }
+ // Buttons
+ .nav-collapse .btn {
+ padding: 4px 10px 4px;
+ font-weight: normal;
+ .border-radius(@baseBorderRadius);
+ }
+ .nav-collapse .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .nav-collapse .nav > li > a:hover,
+ .nav-collapse .nav > li > a:focus,
+ .nav-collapse .dropdown-menu a:hover,
+ .nav-collapse .dropdown-menu a:focus {
+ background-color: @navbarBackground;
+ }
+ .navbar-inverse .nav-collapse .nav > li > a,
+ .navbar-inverse .nav-collapse .dropdown-menu a {
+ color: @navbarInverseLinkColor;
+ }
+ .navbar-inverse .nav-collapse .nav > li > a:hover,
+ .navbar-inverse .nav-collapse .nav > li > a:focus,
+ .navbar-inverse .nav-collapse .dropdown-menu a:hover,
+ .navbar-inverse .nav-collapse .dropdown-menu a:focus {
+ background-color: @navbarInverseBackground;
+ }
+ // Buttons in the navbar
+ .nav-collapse.in .btn-group {
+ margin-top: 5px;
+ padding: 0;
+ }
+ // Dropdowns in the navbar
+ .nav-collapse .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ float: none;
+ display: none;
+ max-width: none;
+ margin: 0 15px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ .border-radius(0);
+ .box-shadow(none);
+ }
+ .nav-collapse .open > .dropdown-menu {
+ display: block;
+ }
+
+ .nav-collapse .dropdown-menu:before,
+ .nav-collapse .dropdown-menu:after {
+ display: none;
+ }
+ .nav-collapse .dropdown-menu .divider {
+ display: none;
+ }
+ .nav-collapse .nav > li > .dropdown-menu {
+ &:before,
+ &:after {
+ display: none;
+ }
+ }
+ // Forms in navbar
+ .nav-collapse .navbar-form,
+ .nav-collapse .navbar-search {
+ float: none;
+ padding: (@baseLineHeight / 2) 15px;
+ margin: (@baseLineHeight / 2) 0;
+ border-top: 1px solid @navbarBackground;
+ border-bottom: 1px solid @navbarBackground;
+ .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)");
+ }
+ .navbar-inverse .nav-collapse .navbar-form,
+ .navbar-inverse .nav-collapse .navbar-search {
+ border-top-color: @navbarInverseBackground;
+ border-bottom-color: @navbarInverseBackground;
+ }
+ // Pull right (secondary) nav content
+ .navbar .nav-collapse .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ // Hide everything in the navbar save .brand and toggle button */
+ .nav-collapse,
+ .nav-collapse.collapse {
+ overflow: hidden;
+ height: 0;
+ }
+ // Navbar button
+ .navbar .btn-navbar {
+ display: block;
+ }
+
+ // STATIC NAVBAR
+ // -------------
+ .navbar-static .navbar-inner {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+
+
+}
+
+
+// DEFAULT DESKTOP
+// ---------------
+
+@media (min-width: @navbarCollapseDesktopWidth) {
+
+ // Required to make the collapsing navbar work on regular desktops
+ .nav-collapse.collapse {
+ height: auto !important;
+ overflow: visible !important;
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive-utilities.less b/www/protected/extensions/bootstrap/assets/less/responsive-utilities.less
new file mode 100644
index 0000000..bf43e8e
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive-utilities.less
@@ -0,0 +1,59 @@
+//
+// Responsive: Utility classes
+// --------------------------------------------------
+
+
+// IE10 Metro responsive
+// Required for Windows 8 Metro split-screen snapping with IE10
+// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/
+@-ms-viewport{
+ width: device-width;
+}
+
+// Hide from screenreaders and browsers
+// Credit: HTML5 Boilerplate
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+
+// Visibility utilities
+
+// For desktops
+.visible-phone { display: none !important; }
+.visible-tablet { display: none !important; }
+.hidden-phone { }
+.hidden-tablet { }
+.hidden-desktop { display: none !important; }
+.visible-desktop { display: inherit !important; }
+
+// Tablets & small desktops only
+@media (min-width: 768px) and (max-width: 979px) {
+ // Hide everything else
+ .hidden-desktop { display: inherit !important; }
+ .visible-desktop { display: none !important ; }
+ // Show
+ .visible-tablet { display: inherit !important; }
+ // Hide
+ .hidden-tablet { display: none !important; }
+}
+
+// Phones only
+@media (max-width: 767px) {
+ // Hide everything else
+ .hidden-desktop { display: inherit !important; }
+ .visible-desktop { display: none !important; }
+ // Show
+ .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior
+ // Hide
+ .hidden-phone { display: none !important; }
+}
+
+// Print utilities
+.visible-print { display: none !important; }
+.hidden-print { }
+
+@media print {
+ .visible-print { display: inherit !important; }
+ .hidden-print { display: none !important; }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/responsive.less b/www/protected/extensions/bootstrap/assets/less/responsive.less
new file mode 100644
index 0000000..9e5f9b1
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/responsive.less
@@ -0,0 +1,48 @@
+/*!
+ * Bootstrap Responsive v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+
+// Responsive.less
+// For phone and tablet devices
+// -------------------------------------------------------------
+
+
+// REPEAT VARIABLES & MIXINS
+// -------------------------
+// Required since we compile the responsive stuff separately
+
+@import "variables.less"; // Modify this for custom colors, font-sizes, etc
+@import "mixins.less";
+
+
+// RESPONSIVE CLASSES
+// ------------------
+
+@import "responsive-utilities.less";
+
+
+// MEDIA QUERIES
+// ------------------
+
+// Large desktops
+@import "responsive-1200px-min.less";
+
+// Tablets to regular desktops
+@import "responsive-768px-979px.less";
+
+// Phones to portrait tablets and narrow desktops
+@import "responsive-767px-max.less";
+
+
+// RESPONSIVE NAVBAR
+// ------------------
+
+// From 979px and below, show a button to toggle navbar contents
+@import "responsive-navbar.less";
diff --git a/www/protected/extensions/bootstrap/assets/less/scaffolding.less b/www/protected/extensions/bootstrap/assets/less/scaffolding.less
new file mode 100644
index 0000000..f17e8ca
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/scaffolding.less
@@ -0,0 +1,53 @@
+//
+// Scaffolding
+// --------------------------------------------------
+
+
+// Body reset
+// -------------------------
+
+body {
+ margin: 0;
+ font-family: @baseFontFamily;
+ font-size: @baseFontSize;
+ line-height: @baseLineHeight;
+ color: @textColor;
+ background-color: @bodyBackground;
+}
+
+
+// Links
+// -------------------------
+
+a {
+ color: @linkColor;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: @linkColorHover;
+ text-decoration: underline;
+}
+
+
+// Images
+// -------------------------
+
+// Rounded corners
+.img-rounded {
+ .border-radius(6px);
+}
+
+// Add polaroid-esque trim
+.img-polaroid {
+ padding: 4px;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0,0,0,.2);
+ .box-shadow(0 1px 3px rgba(0,0,0,.1));
+}
+
+// Perfect circle
+.img-circle {
+ .border-radius(500px); // crank the border-radius so it works with most reasonably sized images
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/sprites.less b/www/protected/extensions/bootstrap/assets/less/sprites.less
new file mode 100644
index 0000000..1812bf7
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/sprites.less
@@ -0,0 +1,197 @@
+//
+// Sprites
+// --------------------------------------------------
+
+
+// ICONS
+// -----
+
+// All icons receive the styles of the tag with a base class
+// of .i and are then given a unique class to add width, height,
+// and background-position. Your resulting HTML will look like
+// .
+
+// For the white version of the icons, just add the .icon-white class:
+//
+
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ .ie7-restore-right-whitespace();
+ line-height: 14px;
+ vertical-align: text-top;
+ background-image: url("@{iconSpritePath}");
+ background-position: 14px 14px;
+ background-repeat: no-repeat;
+ margin-top: 1px;
+}
+
+/* White icons with optional class, or on hover/focus/active states of certain elements */
+.icon-white,
+.nav-pills > .active > a > [class^="icon-"],
+.nav-pills > .active > a > [class*=" icon-"],
+.nav-list > .active > a > [class^="icon-"],
+.nav-list > .active > a > [class*=" icon-"],
+.navbar-inverse .nav > .active > a > [class^="icon-"],
+.navbar-inverse .nav > .active > a > [class*=" icon-"],
+.dropdown-menu > li > a:hover > [class^="icon-"],
+.dropdown-menu > li > a:focus > [class^="icon-"],
+.dropdown-menu > li > a:hover > [class*=" icon-"],
+.dropdown-menu > li > a:focus > [class*=" icon-"],
+.dropdown-menu > .active > a > [class^="icon-"],
+.dropdown-menu > .active > a > [class*=" icon-"],
+.dropdown-submenu:hover > a > [class^="icon-"],
+.dropdown-submenu:focus > a > [class^="icon-"],
+.dropdown-submenu:hover > a > [class*=" icon-"],
+.dropdown-submenu:focus > a > [class*=" icon-"] {
+ background-image: url("@{iconWhiteSpritePath}");
+}
+
+.icon-glass { background-position: 0 0; }
+.icon-music { background-position: -24px 0; }
+.icon-search { background-position: -48px 0; }
+.icon-envelope { background-position: -72px 0; }
+.icon-heart { background-position: -96px 0; }
+.icon-star { background-position: -120px 0; }
+.icon-star-empty { background-position: -144px 0; }
+.icon-user { background-position: -168px 0; }
+.icon-film { background-position: -192px 0; }
+.icon-th-large { background-position: -216px 0; }
+.icon-th { background-position: -240px 0; }
+.icon-th-list { background-position: -264px 0; }
+.icon-ok { background-position: -288px 0; }
+.icon-remove { background-position: -312px 0; }
+.icon-zoom-in { background-position: -336px 0; }
+.icon-zoom-out { background-position: -360px 0; }
+.icon-off { background-position: -384px 0; }
+.icon-signal { background-position: -408px 0; }
+.icon-cog { background-position: -432px 0; }
+.icon-trash { background-position: -456px 0; }
+
+.icon-home { background-position: 0 -24px; }
+.icon-file { background-position: -24px -24px; }
+.icon-time { background-position: -48px -24px; }
+.icon-road { background-position: -72px -24px; }
+.icon-download-alt { background-position: -96px -24px; }
+.icon-download { background-position: -120px -24px; }
+.icon-upload { background-position: -144px -24px; }
+.icon-inbox { background-position: -168px -24px; }
+.icon-play-circle { background-position: -192px -24px; }
+.icon-repeat { background-position: -216px -24px; }
+.icon-refresh { background-position: -240px -24px; }
+.icon-list-alt { background-position: -264px -24px; }
+.icon-lock { background-position: -287px -24px; } // 1px off
+.icon-flag { background-position: -312px -24px; }
+.icon-headphones { background-position: -336px -24px; }
+.icon-volume-off { background-position: -360px -24px; }
+.icon-volume-down { background-position: -384px -24px; }
+.icon-volume-up { background-position: -408px -24px; }
+.icon-qrcode { background-position: -432px -24px; }
+.icon-barcode { background-position: -456px -24px; }
+
+.icon-tag { background-position: 0 -48px; }
+.icon-tags { background-position: -25px -48px; } // 1px off
+.icon-book { background-position: -48px -48px; }
+.icon-bookmark { background-position: -72px -48px; }
+.icon-print { background-position: -96px -48px; }
+.icon-camera { background-position: -120px -48px; }
+.icon-font { background-position: -144px -48px; }
+.icon-bold { background-position: -167px -48px; } // 1px off
+.icon-italic { background-position: -192px -48px; }
+.icon-text-height { background-position: -216px -48px; }
+.icon-text-width { background-position: -240px -48px; }
+.icon-align-left { background-position: -264px -48px; }
+.icon-align-center { background-position: -288px -48px; }
+.icon-align-right { background-position: -312px -48px; }
+.icon-align-justify { background-position: -336px -48px; }
+.icon-list { background-position: -360px -48px; }
+.icon-indent-left { background-position: -384px -48px; }
+.icon-indent-right { background-position: -408px -48px; }
+.icon-facetime-video { background-position: -432px -48px; }
+.icon-picture { background-position: -456px -48px; }
+
+.icon-pencil { background-position: 0 -72px; }
+.icon-map-marker { background-position: -24px -72px; }
+.icon-adjust { background-position: -48px -72px; }
+.icon-tint { background-position: -72px -72px; }
+.icon-edit { background-position: -96px -72px; }
+.icon-share { background-position: -120px -72px; }
+.icon-check { background-position: -144px -72px; }
+.icon-move { background-position: -168px -72px; }
+.icon-step-backward { background-position: -192px -72px; }
+.icon-fast-backward { background-position: -216px -72px; }
+.icon-backward { background-position: -240px -72px; }
+.icon-play { background-position: -264px -72px; }
+.icon-pause { background-position: -288px -72px; }
+.icon-stop { background-position: -312px -72px; }
+.icon-forward { background-position: -336px -72px; }
+.icon-fast-forward { background-position: -360px -72px; }
+.icon-step-forward { background-position: -384px -72px; }
+.icon-eject { background-position: -408px -72px; }
+.icon-chevron-left { background-position: -432px -72px; }
+.icon-chevron-right { background-position: -456px -72px; }
+
+.icon-plus-sign { background-position: 0 -96px; }
+.icon-minus-sign { background-position: -24px -96px; }
+.icon-remove-sign { background-position: -48px -96px; }
+.icon-ok-sign { background-position: -72px -96px; }
+.icon-question-sign { background-position: -96px -96px; }
+.icon-info-sign { background-position: -120px -96px; }
+.icon-screenshot { background-position: -144px -96px; }
+.icon-remove-circle { background-position: -168px -96px; }
+.icon-ok-circle { background-position: -192px -96px; }
+.icon-ban-circle { background-position: -216px -96px; }
+.icon-arrow-left { background-position: -240px -96px; }
+.icon-arrow-right { background-position: -264px -96px; }
+.icon-arrow-up { background-position: -289px -96px; } // 1px off
+.icon-arrow-down { background-position: -312px -96px; }
+.icon-share-alt { background-position: -336px -96px; }
+.icon-resize-full { background-position: -360px -96px; }
+.icon-resize-small { background-position: -384px -96px; }
+.icon-plus { background-position: -408px -96px; }
+.icon-minus { background-position: -433px -96px; }
+.icon-asterisk { background-position: -456px -96px; }
+
+.icon-exclamation-sign { background-position: 0 -120px; }
+.icon-gift { background-position: -24px -120px; }
+.icon-leaf { background-position: -48px -120px; }
+.icon-fire { background-position: -72px -120px; }
+.icon-eye-open { background-position: -96px -120px; }
+.icon-eye-close { background-position: -120px -120px; }
+.icon-warning-sign { background-position: -144px -120px; }
+.icon-plane { background-position: -168px -120px; }
+.icon-calendar { background-position: -192px -120px; }
+.icon-random { background-position: -216px -120px; width: 16px; }
+.icon-comment { background-position: -240px -120px; }
+.icon-magnet { background-position: -264px -120px; }
+.icon-chevron-up { background-position: -288px -120px; }
+.icon-chevron-down { background-position: -313px -119px; } // 1px, 1px off
+.icon-retweet { background-position: -336px -120px; }
+.icon-shopping-cart { background-position: -360px -120px; }
+.icon-folder-close { background-position: -384px -120px; width: 16px; }
+.icon-folder-open { background-position: -408px -120px; width: 16px; }
+.icon-resize-vertical { background-position: -432px -119px; } // 1px, 1px off
+.icon-resize-horizontal { background-position: -456px -118px; } // 1px, 2px off
+
+.icon-hdd { background-position: 0 -144px; }
+.icon-bullhorn { background-position: -24px -144px; }
+.icon-bell { background-position: -48px -144px; }
+.icon-certificate { background-position: -72px -144px; }
+.icon-thumbs-up { background-position: -96px -144px; }
+.icon-thumbs-down { background-position: -120px -144px; }
+.icon-hand-right { background-position: -144px -144px; }
+.icon-hand-left { background-position: -168px -144px; }
+.icon-hand-up { background-position: -192px -144px; }
+.icon-hand-down { background-position: -216px -144px; }
+.icon-circle-arrow-right { background-position: -240px -144px; }
+.icon-circle-arrow-left { background-position: -264px -144px; }
+.icon-circle-arrow-up { background-position: -288px -144px; }
+.icon-circle-arrow-down { background-position: -312px -144px; }
+.icon-globe { background-position: -336px -144px; }
+.icon-wrench { background-position: -360px -144px; }
+.icon-tasks { background-position: -384px -144px; }
+.icon-filter { background-position: -408px -144px; }
+.icon-briefcase { background-position: -432px -144px; }
+.icon-fullscreen { background-position: -456px -144px; }
diff --git a/www/protected/extensions/bootstrap/assets/less/tables.less b/www/protected/extensions/bootstrap/assets/less/tables.less
new file mode 100644
index 0000000..0e35271
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/tables.less
@@ -0,0 +1,244 @@
+//
+// Tables
+// --------------------------------------------------
+
+
+// BASE TABLES
+// -----------------
+
+table {
+ max-width: 100%;
+ background-color: @tableBackground;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+// BASELINE STYLES
+// ---------------
+
+.table {
+ width: 100%;
+ margin-bottom: @baseLineHeight;
+ // Cells
+ th,
+ td {
+ padding: 8px;
+ line-height: @baseLineHeight;
+ text-align: left;
+ vertical-align: top;
+ border-top: 1px solid @tableBorder;
+ }
+ th {
+ font-weight: bold;
+ }
+ // Bottom align for column headings
+ thead th {
+ vertical-align: bottom;
+ }
+ // Remove top border from thead by default
+ caption + thead tr:first-child th,
+ caption + thead tr:first-child td,
+ colgroup + thead tr:first-child th,
+ colgroup + thead tr:first-child td,
+ thead:first-child tr:first-child th,
+ thead:first-child tr:first-child td {
+ border-top: 0;
+ }
+ // Account for multiple tbody instances
+ tbody + tbody {
+ border-top: 2px solid @tableBorder;
+ }
+
+ // Nesting
+ .table {
+ background-color: @bodyBackground;
+ }
+}
+
+
+
+// CONDENSED TABLE W/ HALF PADDING
+// -------------------------------
+
+.table-condensed {
+ th,
+ td {
+ padding: 4px 5px;
+ }
+}
+
+
+// BORDERED VERSION
+// ----------------
+
+.table-bordered {
+ border: 1px solid @tableBorder;
+ border-collapse: separate; // Done so we can round those corners!
+ *border-collapse: collapse; // IE7 can't round corners anyway
+ border-left: 0;
+ .border-radius(@baseBorderRadius);
+ th,
+ td {
+ border-left: 1px solid @tableBorder;
+ }
+ // Prevent a double border
+ caption + thead tr:first-child th,
+ caption + tbody tr:first-child th,
+ caption + tbody tr:first-child td,
+ colgroup + thead tr:first-child th,
+ colgroup + tbody tr:first-child th,
+ colgroup + tbody tr:first-child td,
+ thead:first-child tr:first-child th,
+ tbody:first-child tr:first-child th,
+ tbody:first-child tr:first-child td {
+ border-top: 0;
+ }
+ // For first th/td in the first row in the first thead or tbody
+ thead:first-child tr:first-child > th:first-child,
+ tbody:first-child tr:first-child > td:first-child,
+ tbody:first-child tr:first-child > th:first-child {
+ .border-top-left-radius(@baseBorderRadius);
+ }
+ // For last th/td in the first row in the first thead or tbody
+ thead:first-child tr:first-child > th:last-child,
+ tbody:first-child tr:first-child > td:last-child,
+ tbody:first-child tr:first-child > th:last-child {
+ .border-top-right-radius(@baseBorderRadius);
+ }
+ // For first th/td (can be either) in the last row in the last thead, tbody, and tfoot
+ thead:last-child tr:last-child > th:first-child,
+ tbody:last-child tr:last-child > td:first-child,
+ tbody:last-child tr:last-child > th:first-child,
+ tfoot:last-child tr:last-child > td:first-child,
+ tfoot:last-child tr:last-child > th:first-child {
+ .border-bottom-left-radius(@baseBorderRadius);
+ }
+ // For last th/td (can be either) in the last row in the last thead, tbody, and tfoot
+ thead:last-child tr:last-child > th:last-child,
+ tbody:last-child tr:last-child > td:last-child,
+ tbody:last-child tr:last-child > th:last-child,
+ tfoot:last-child tr:last-child > td:last-child,
+ tfoot:last-child tr:last-child > th:last-child {
+ .border-bottom-right-radius(@baseBorderRadius);
+ }
+
+ // Clear border-radius for first and last td in the last row in the last tbody for table with tfoot
+ tfoot + tbody:last-child tr:last-child td:first-child {
+ .border-bottom-left-radius(0);
+ }
+ tfoot + tbody:last-child tr:last-child td:last-child {
+ .border-bottom-right-radius(0);
+ }
+
+ // Special fixes to round the left border on the first td/th
+ caption + thead tr:first-child th:first-child,
+ caption + tbody tr:first-child td:first-child,
+ colgroup + thead tr:first-child th:first-child,
+ colgroup + tbody tr:first-child td:first-child {
+ .border-top-left-radius(@baseBorderRadius);
+ }
+ caption + thead tr:first-child th:last-child,
+ caption + tbody tr:first-child td:last-child,
+ colgroup + thead tr:first-child th:last-child,
+ colgroup + tbody tr:first-child td:last-child {
+ .border-top-right-radius(@baseBorderRadius);
+ }
+
+}
+
+
+
+
+// ZEBRA-STRIPING
+// --------------
+
+// Default zebra-stripe styles (alternating gray and transparent backgrounds)
+.table-striped {
+ tbody {
+ > tr:nth-child(odd) > td,
+ > tr:nth-child(odd) > th {
+ background-color: @tableBackgroundAccent;
+ }
+ }
+}
+
+
+// HOVER EFFECT
+// ------------
+// Placed here since it has to come after the potential zebra striping
+.table-hover {
+ tbody {
+ tr:hover > td,
+ tr:hover > th {
+ background-color: @tableBackgroundHover;
+ }
+ }
+}
+
+
+// TABLE CELL SIZING
+// -----------------
+
+// Reset default grid behavior
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+ display: table-cell;
+ float: none; // undo default grid column styles
+ margin-left: 0; // undo default grid column styles
+}
+
+// Change the column widths to account for td/th padding
+.table td,
+.table th {
+ &.span1 { .tableColumns(1); }
+ &.span2 { .tableColumns(2); }
+ &.span3 { .tableColumns(3); }
+ &.span4 { .tableColumns(4); }
+ &.span5 { .tableColumns(5); }
+ &.span6 { .tableColumns(6); }
+ &.span7 { .tableColumns(7); }
+ &.span8 { .tableColumns(8); }
+ &.span9 { .tableColumns(9); }
+ &.span10 { .tableColumns(10); }
+ &.span11 { .tableColumns(11); }
+ &.span12 { .tableColumns(12); }
+}
+
+
+
+// TABLE BACKGROUNDS
+// -----------------
+// Exact selectors below required to override .table-striped
+
+.table tbody tr {
+ &.success > td {
+ background-color: @successBackground;
+ }
+ &.error > td {
+ background-color: @errorBackground;
+ }
+ &.warning > td {
+ background-color: @warningBackground;
+ }
+ &.info > td {
+ background-color: @infoBackground;
+ }
+}
+
+// Hover states for .table-hover
+.table-hover tbody tr {
+ &.success:hover > td {
+ background-color: darken(@successBackground, 5%);
+ }
+ &.error:hover > td {
+ background-color: darken(@errorBackground, 5%);
+ }
+ &.warning:hover > td {
+ background-color: darken(@warningBackground, 5%);
+ }
+ &.info:hover > td {
+ background-color: darken(@infoBackground, 5%);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/thumbnails.less b/www/protected/extensions/bootstrap/assets/less/thumbnails.less
new file mode 100644
index 0000000..4fd07d2
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/thumbnails.less
@@ -0,0 +1,53 @@
+//
+// Thumbnails
+// --------------------------------------------------
+
+
+// Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files
+
+// Make wrapper ul behave like the grid
+.thumbnails {
+ margin-left: -@gridGutterWidth;
+ list-style: none;
+ .clearfix();
+}
+// Fluid rows have no left margin
+.row-fluid .thumbnails {
+ margin-left: 0;
+}
+
+// Float li to make thumbnails appear in a row
+.thumbnails > li {
+ float: left; // Explicity set the float since we don't require .span* classes
+ margin-bottom: @baseLineHeight;
+ margin-left: @gridGutterWidth;
+}
+
+// The actual thumbnail (can be `a` or `div`)
+.thumbnail {
+ display: block;
+ padding: 4px;
+ line-height: @baseLineHeight;
+ border: 1px solid #ddd;
+ .border-radius(@baseBorderRadius);
+ .box-shadow(0 1px 3px rgba(0,0,0,.055));
+ .transition(all .2s ease-in-out);
+}
+// Add a hover/focus state for linked versions only
+a.thumbnail:hover,
+a.thumbnail:focus {
+ border-color: @linkColor;
+ .box-shadow(0 1px 4px rgba(0,105,214,.25));
+}
+
+// Images and captions
+.thumbnail > img {
+ display: block;
+ max-width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+}
+.thumbnail .caption {
+ padding: 9px;
+ color: @gray;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/tooltip.less b/www/protected/extensions/bootstrap/assets/less/tooltip.less
new file mode 100644
index 0000000..83d5f2b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/tooltip.less
@@ -0,0 +1,70 @@
+//
+// Tooltips
+// --------------------------------------------------
+
+
+// Base class
+.tooltip {
+ position: absolute;
+ z-index: @zindexTooltip;
+ display: block;
+ visibility: visible;
+ font-size: 11px;
+ line-height: 1.4;
+ .opacity(0);
+ &.in { .opacity(80); }
+ &.top { margin-top: -3px; padding: 5px 0; }
+ &.right { margin-left: 3px; padding: 0 5px; }
+ &.bottom { margin-top: 3px; padding: 5px 0; }
+ &.left { margin-left: -3px; padding: 0 5px; }
+}
+
+// Wrapper for the tooltip content
+.tooltip-inner {
+ max-width: 200px;
+ padding: 8px;
+ color: @tooltipColor;
+ text-align: center;
+ text-decoration: none;
+ background-color: @tooltipBackground;
+ .border-radius(@baseBorderRadius);
+}
+
+// Arrows
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip {
+ &.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -@tooltipArrowWidth;
+ border-width: @tooltipArrowWidth @tooltipArrowWidth 0;
+ border-top-color: @tooltipArrowColor;
+ }
+ &.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -@tooltipArrowWidth;
+ border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0;
+ border-right-color: @tooltipArrowColor;
+ }
+ &.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -@tooltipArrowWidth;
+ border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth;
+ border-left-color: @tooltipArrowColor;
+ }
+ &.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -@tooltipArrowWidth;
+ border-width: 0 @tooltipArrowWidth @tooltipArrowWidth;
+ border-bottom-color: @tooltipArrowColor;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/type.less b/www/protected/extensions/bootstrap/assets/less/type.less
new file mode 100644
index 0000000..337138a
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/type.less
@@ -0,0 +1,247 @@
+//
+// Typography
+// --------------------------------------------------
+
+
+// Body text
+// -------------------------
+
+p {
+ margin: 0 0 @baseLineHeight / 2;
+}
+.lead {
+ margin-bottom: @baseLineHeight;
+ font-size: @baseFontSize * 1.5;
+ font-weight: 200;
+ line-height: @baseLineHeight * 1.5;
+}
+
+
+// Emphasis & misc
+// -------------------------
+
+// Ex: 14px base font * 85% = about 12px
+small { font-size: 85%; }
+
+strong { font-weight: bold; }
+em { font-style: italic; }
+cite { font-style: normal; }
+
+// Utility classes
+.muted { color: @grayLight; }
+a.muted:hover,
+a.muted:focus { color: darken(@grayLight, 10%); }
+
+.text-warning { color: @warningText; }
+a.text-warning:hover,
+a.text-warning:focus { color: darken(@warningText, 10%); }
+
+.text-error { color: @errorText; }
+a.text-error:hover,
+a.text-error:focus { color: darken(@errorText, 10%); }
+
+.text-info { color: @infoText; }
+a.text-info:hover,
+a.text-info:focus { color: darken(@infoText, 10%); }
+
+.text-success { color: @successText; }
+a.text-success:hover,
+a.text-success:focus { color: darken(@successText, 10%); }
+
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+.text-center { text-align: center; }
+
+
+// Headings
+// -------------------------
+
+h1, h2, h3, h4, h5, h6 {
+ margin: (@baseLineHeight / 2) 0;
+ font-family: @headingsFontFamily;
+ font-weight: @headingsFontWeight;
+ line-height: @baseLineHeight;
+ color: @headingsColor;
+ text-rendering: optimizelegibility; // Fix the character spacing for headings
+ small {
+ font-weight: normal;
+ line-height: 1;
+ color: @grayLight;
+ }
+}
+
+h1,
+h2,
+h3 { line-height: @baseLineHeight * 2; }
+
+h1 { font-size: @baseFontSize * 2.75; } // ~38px
+h2 { font-size: @baseFontSize * 2.25; } // ~32px
+h3 { font-size: @baseFontSize * 1.75; } // ~24px
+h4 { font-size: @baseFontSize * 1.25; } // ~18px
+h5 { font-size: @baseFontSize; }
+h6 { font-size: @baseFontSize * 0.85; } // ~12px
+
+h1 small { font-size: @baseFontSize * 1.75; } // ~24px
+h2 small { font-size: @baseFontSize * 1.25; } // ~18px
+h3 small { font-size: @baseFontSize; }
+h4 small { font-size: @baseFontSize; }
+
+
+// Page header
+// -------------------------
+
+.page-header {
+ padding-bottom: (@baseLineHeight / 2) - 1;
+ margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
+ border-bottom: 1px solid @grayLighter;
+}
+
+
+
+// Lists
+// --------------------------------------------------
+
+// Unordered and Ordered lists
+ul, ol {
+ padding: 0;
+ margin: 0 0 @baseLineHeight / 2 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+li {
+ line-height: @baseLineHeight;
+}
+
+// Remove default list styles
+ul.unstyled,
+ol.unstyled {
+ margin-left: 0;
+ list-style: none;
+}
+
+// Single-line list items
+ul.inline,
+ol.inline {
+ margin-left: 0;
+ list-style: none;
+ > li {
+ display: inline-block;
+ .ie7-inline-block();
+ padding-left: 5px;
+ padding-right: 5px;
+ }
+}
+
+// Description Lists
+dl {
+ margin-bottom: @baseLineHeight;
+}
+dt,
+dd {
+ line-height: @baseLineHeight;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: @baseLineHeight / 2;
+}
+// Horizontal layout (like forms)
+.dl-horizontal {
+ .clearfix(); // Ensure dl clears floats if empty dd elements present
+ dt {
+ float: left;
+ width: @horizontalComponentOffset - 20;
+ clear: left;
+ text-align: right;
+ .text-overflow();
+ }
+ dd {
+ margin-left: @horizontalComponentOffset;
+ }
+}
+
+// MISC
+// ----
+
+// Horizontal rules
+hr {
+ margin: @baseLineHeight 0;
+ border: 0;
+ border-top: 1px solid @hrBorder;
+ border-bottom: 1px solid @white;
+}
+
+// Abbreviations and acronyms
+abbr[title],
+// Added data-* attribute to help out our tooltip plugin, per https://github.com/twitter/bootstrap/issues/5257
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted @grayLight;
+}
+abbr.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+
+// Blockquotes
+blockquote {
+ padding: 0 0 0 15px;
+ margin: 0 0 @baseLineHeight;
+ border-left: 5px solid @grayLighter;
+ p {
+ margin-bottom: 0;
+ font-size: @baseFontSize * 1.25;
+ font-weight: 300;
+ line-height: 1.25;
+ }
+ small {
+ display: block;
+ line-height: @baseLineHeight;
+ color: @grayLight;
+ &:before {
+ content: '\2014 \00A0';
+ }
+ }
+
+ // Float right with text-align: right
+ &.pull-right {
+ float: right;
+ padding-right: 15px;
+ padding-left: 0;
+ border-right: 5px solid @grayLighter;
+ border-left: 0;
+ p,
+ small {
+ text-align: right;
+ }
+ small {
+ &:before {
+ content: '';
+ }
+ &:after {
+ content: '\00A0 \2014';
+ }
+ }
+ }
+}
+
+// Quotes
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+
+// Addresses
+address {
+ display: block;
+ margin-bottom: @baseLineHeight;
+ font-style: normal;
+ line-height: @baseLineHeight;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/utilities.less b/www/protected/extensions/bootstrap/assets/less/utilities.less
new file mode 100644
index 0000000..314b4ff
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/utilities.less
@@ -0,0 +1,30 @@
+//
+// Utility classes
+// --------------------------------------------------
+
+
+// Quick floats
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+
+// Toggling content
+.hide {
+ display: none;
+}
+.show {
+ display: block;
+}
+
+// Visibility
+.invisible {
+ visibility: hidden;
+}
+
+// For Affix plugin
+.affix {
+ position: fixed;
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/variables.less b/www/protected/extensions/bootstrap/assets/less/variables.less
new file mode 100644
index 0000000..31c131b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/variables.less
@@ -0,0 +1,301 @@
+//
+// Variables
+// --------------------------------------------------
+
+
+// Global values
+// --------------------------------------------------
+
+
+// Grays
+// -------------------------
+@black: #000;
+@grayDarker: #222;
+@grayDark: #333;
+@gray: #555;
+@grayLight: #999;
+@grayLighter: #eee;
+@white: #fff;
+
+
+// Accent colors
+// -------------------------
+@blue: #049cdb;
+@blueDark: #0064cd;
+@green: #46a546;
+@red: #9d261d;
+@yellow: #ffc40d;
+@orange: #f89406;
+@pink: #c3325f;
+@purple: #7a43b6;
+
+
+// Scaffolding
+// -------------------------
+@bodyBackground: @white;
+@textColor: @grayDark;
+
+
+// Links
+// -------------------------
+@linkColor: #08c;
+@linkColorHover: darken(@linkColor, 15%);
+
+
+// Typography
+// -------------------------
+@sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif;
+@serifFontFamily: Georgia, "Times New Roman", Times, serif;
+@monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace;
+
+@baseFontSize: 14px;
+@baseFontFamily: @sansFontFamily;
+@baseLineHeight: 20px;
+@altFontFamily: @serifFontFamily;
+
+@headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily
+@headingsFontWeight: bold; // instead of browser default, bold
+@headingsColor: inherit; // empty to use BS default, @textColor
+
+
+// Component sizing
+// -------------------------
+// Based on 14px font-size and 20px line-height
+
+@fontSizeLarge: @baseFontSize * 1.25; // ~18px
+@fontSizeSmall: @baseFontSize * 0.85; // ~12px
+@fontSizeMini: @baseFontSize * 0.75; // ~11px
+
+@paddingLarge: 11px 19px; // 44px
+@paddingSmall: 2px 10px; // 26px
+@paddingMini: 0 6px; // 22px
+
+@baseBorderRadius: 4px;
+@borderRadiusLarge: 6px;
+@borderRadiusSmall: 3px;
+
+
+// Tables
+// -------------------------
+@tableBackground: transparent; // overall background-color
+@tableBackgroundAccent: #f9f9f9; // for striping
+@tableBackgroundHover: #f5f5f5; // for hover
+@tableBorder: #ddd; // table and cell border
+
+// Buttons
+// -------------------------
+@btnBackground: @white;
+@btnBackgroundHighlight: darken(@white, 10%);
+@btnBorder: #ccc;
+
+@btnPrimaryBackground: @linkColor;
+@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%);
+
+@btnInfoBackground: #5bc0de;
+@btnInfoBackgroundHighlight: #2f96b4;
+
+@btnSuccessBackground: #62c462;
+@btnSuccessBackgroundHighlight: #51a351;
+
+@btnWarningBackground: lighten(@orange, 15%);
+@btnWarningBackgroundHighlight: @orange;
+
+@btnDangerBackground: #ee5f5b;
+@btnDangerBackgroundHighlight: #bd362f;
+
+@btnInverseBackground: #444;
+@btnInverseBackgroundHighlight: @grayDarker;
+
+
+// Forms
+// -------------------------
+@inputBackground: @white;
+@inputBorder: #ccc;
+@inputBorderRadius: @baseBorderRadius;
+@inputDisabledBackground: @grayLighter;
+@formActionsBackground: #f5f5f5;
+@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border
+
+
+// Dropdowns
+// -------------------------
+@dropdownBackground: @white;
+@dropdownBorder: rgba(0,0,0,.2);
+@dropdownDividerTop: #e5e5e5;
+@dropdownDividerBottom: @white;
+
+@dropdownLinkColor: @grayDark;
+@dropdownLinkColorHover: @white;
+@dropdownLinkColorActive: @white;
+
+@dropdownLinkBackgroundActive: @linkColor;
+@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive;
+
+
+
+// COMPONENT VARIABLES
+// --------------------------------------------------
+
+
+// Z-index master list
+// -------------------------
+// Used for a bird's eye view of components dependent on the z-axis
+// Try to avoid customizing these :)
+@zindexDropdown: 1000;
+@zindexPopover: 1010;
+@zindexTooltip: 1030;
+@zindexFixedNavbar: 1030;
+@zindexModalBackdrop: 1040;
+@zindexModal: 1050;
+
+
+// Sprite icons path
+// -------------------------
+@iconSpritePath: "../img/glyphicons-halflings.png";
+@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png";
+
+
+// Input placeholder text color
+// -------------------------
+@placeholderText: @grayLight;
+
+
+// Hr border color
+// -------------------------
+@hrBorder: @grayLighter;
+
+
+// Horizontal forms & lists
+// -------------------------
+@horizontalComponentOffset: 180px;
+
+
+// Wells
+// -------------------------
+@wellBackground: #f5f5f5;
+
+
+// Navbar
+// -------------------------
+@navbarCollapseWidth: 979px;
+@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1;
+
+@navbarHeight: 40px;
+@navbarBackgroundHighlight: #ffffff;
+@navbarBackground: darken(@navbarBackgroundHighlight, 5%);
+@navbarBorder: darken(@navbarBackground, 12%);
+
+@navbarText: #777;
+@navbarLinkColor: #777;
+@navbarLinkColorHover: @grayDark;
+@navbarLinkColorActive: @gray;
+@navbarLinkBackgroundHover: transparent;
+@navbarLinkBackgroundActive: darken(@navbarBackground, 5%);
+
+@navbarBrandColor: @navbarLinkColor;
+
+// Inverted navbar
+@navbarInverseBackground: #111111;
+@navbarInverseBackgroundHighlight: #222222;
+@navbarInverseBorder: #252525;
+
+@navbarInverseText: @grayLight;
+@navbarInverseLinkColor: @grayLight;
+@navbarInverseLinkColorHover: @white;
+@navbarInverseLinkColorActive: @navbarInverseLinkColorHover;
+@navbarInverseLinkBackgroundHover: transparent;
+@navbarInverseLinkBackgroundActive: @navbarInverseBackground;
+
+@navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%);
+@navbarInverseSearchBackgroundFocus: @white;
+@navbarInverseSearchBorder: @navbarInverseBackground;
+@navbarInverseSearchPlaceholderColor: #ccc;
+
+@navbarInverseBrandColor: @navbarInverseLinkColor;
+
+
+// Pagination
+// -------------------------
+@paginationBackground: #fff;
+@paginationBorder: #ddd;
+@paginationActiveBackground: #f5f5f5;
+
+
+// Hero unit
+// -------------------------
+@heroUnitBackground: @grayLighter;
+@heroUnitHeadingColor: inherit;
+@heroUnitLeadColor: inherit;
+
+
+// Form states and alerts
+// -------------------------
+@warningText: #c09853;
+@warningBackground: #fcf8e3;
+@warningBorder: darken(spin(@warningBackground, -10), 3%);
+
+@errorText: #b94a48;
+@errorBackground: #f2dede;
+@errorBorder: darken(spin(@errorBackground, -10), 3%);
+
+@successText: #468847;
+@successBackground: #dff0d8;
+@successBorder: darken(spin(@successBackground, -10), 5%);
+
+@infoText: #3a87ad;
+@infoBackground: #d9edf7;
+@infoBorder: darken(spin(@infoBackground, -10), 7%);
+
+
+// Tooltips and popovers
+// -------------------------
+@tooltipColor: #fff;
+@tooltipBackground: #000;
+@tooltipArrowWidth: 5px;
+@tooltipArrowColor: @tooltipBackground;
+
+@popoverBackground: #fff;
+@popoverArrowWidth: 10px;
+@popoverArrowColor: #fff;
+@popoverTitleBackground: darken(@popoverBackground, 3%);
+
+// Special enhancement for popovers
+@popoverArrowOuterWidth: @popoverArrowWidth + 1;
+@popoverArrowOuterColor: rgba(0,0,0,.25);
+
+
+
+// GRID
+// --------------------------------------------------
+
+
+// Default 940px grid
+// -------------------------
+@gridColumns: 12;
+@gridColumnWidth: 60px;
+@gridGutterWidth: 20px;
+@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
+
+// 1200px min
+@gridColumnWidth1200: 70px;
+@gridGutterWidth1200: 30px;
+@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1));
+
+// 768px-979px
+@gridColumnWidth768: 42px;
+@gridGutterWidth768: 20px;
+@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1));
+
+
+// Fluid grid
+// -------------------------
+@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth);
+@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth);
+
+// 1200px min
+@fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200);
+@fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200);
+
+// 768px-979px
+@fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768);
+@fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768);
diff --git a/www/protected/extensions/bootstrap/assets/less/wells.less b/www/protected/extensions/bootstrap/assets/less/wells.less
new file mode 100644
index 0000000..84a744b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/wells.less
@@ -0,0 +1,29 @@
+//
+// Wells
+// --------------------------------------------------
+
+
+// Base class
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: @wellBackground;
+ border: 1px solid darken(@wellBackground, 7%);
+ .border-radius(@baseBorderRadius);
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
+ blockquote {
+ border-color: #ddd;
+ border-color: rgba(0,0,0,.15);
+ }
+}
+
+// Sizes
+.well-large {
+ padding: 24px;
+ .border-radius(@borderRadiusLarge);
+}
+.well-small {
+ padding: 9px;
+ .border-radius(@borderRadiusSmall);
+}
diff --git a/www/protected/extensions/bootstrap/assets/less/yiistrap.less b/www/protected/extensions/bootstrap/assets/less/yiistrap.less
new file mode 100644
index 0000000..200d16e
--- /dev/null
+++ b/www/protected/extensions/bootstrap/assets/less/yiistrap.less
@@ -0,0 +1,122 @@
+@import "variables.less";
+@import "mixins.less";
+
+// Grid view
+// -------------------------
+
+.grid-view {
+ font-size: 13px;
+
+ .table {
+ th > .sort-link {
+ color: #333;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ position: relative;
+
+ &:hover {
+ text-decoration: none;
+ }
+
+ .caret {
+ border-color: transparent;
+ border-style: solid;
+ border-width: 4px;
+ display: none;
+ position: absolute;
+ right: 5px;
+ }
+
+ &.asc .caret {
+ border-bottom-color: #333;
+ display: block;
+ top: 4px;
+ }
+
+ &.desc .caret {
+ border-top-color: #333;
+ display: block;
+ top: 8px;
+ }
+ }
+
+ .filters {
+ > td {
+ .filter-container {
+ padding: 0 16px 0 0; // compensate for the margin on the input
+
+ input[type="text"], select {
+ margin-bottom: 0;
+ width: 100%;
+ }
+ }
+ }
+ }
+
+ tr.selected td {
+ background: #eee;
+ }
+
+ td {
+ vertical-align: middle;
+ }
+
+ .checkbox-column {
+ width: 15px;
+ }
+
+ .number-column {
+ text-align: right;
+ }
+
+ .button-column {
+ text-align: right;
+ min-width: 50px;
+ }
+ }
+
+ .summary {
+ color: @grayLight;
+ font-size: 12px;
+ padding: 6px 0;
+ text-align: right;
+ }
+
+ .empty {
+ font-style: italic;
+ }
+
+ &.grid-view-loading {
+ background: url(../img/loader.gif) no-repeat 100% 10px;
+
+ .table {
+ opacity: 0.5;
+
+ th > .sort-link .caret {
+ display: none;
+ }
+ }
+ }
+}
+
+// Detail view
+// -------------------------
+.detail-view {
+ .null {
+ color: #FFC0CB;
+ }
+
+ th {
+ text-align: right;
+ width: 160px;
+ }
+}
+
+// Form
+// -------------------------
+
+span.required {
+ color: #b94a48;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/behaviors/TbWidget.php b/www/protected/extensions/bootstrap/behaviors/TbWidget.php
new file mode 100644
index 0000000..8c3c8b8
--- /dev/null
+++ b/www/protected/extensions/bootstrap/behaviors/TbWidget.php
@@ -0,0 +1,169 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.behaviors
+ */
+
+/**
+ * Bootstrap widget behavior.
+ * @property $owner CWidget
+ */
+class TbWidget extends CBehavior
+{
+ private $_api;
+ private $_assetsUrl;
+ private $_clientScript;
+
+ /**
+ * Returns the widget id and copies it to HTML attributes or vice versa.
+ * @param string $id the widget id.
+ * @return string the widget id.
+ */
+ public function resolveId($id = null)
+ {
+ if ($id === null) {
+ $id = $this->owner->getId();
+ }
+ if (isset($this->owner->htmlOptions['id'])) {
+ $id = $this->owner->htmlOptions['id'];
+ } else {
+ $this->owner->htmlOptions['id'] = $id;
+ }
+ return $id;
+ }
+
+ /**
+ * Copies the id to the widget HTML attributes or vise versa.
+ * @deprecated by TbWidget::resolveId
+ */
+ public function copyId()
+ {
+ // todo: remove this when it's safe to do so.
+ if (!isset($this->owner->htmlOptions['id'])) {
+ $this->owner->htmlOptions['id'] = $this->owner->id;
+ } else {
+ $this->owner->id = $this->owner->htmlOptions['id'];
+ }
+ }
+
+ /**
+ * Publishes an asset path.
+ * @param string $path the assets path.
+ * @param boolean $forceCopy whether we should copy the asset files even if they are already published before.
+ * @return string the url.
+ * @throws CException if the asset manager cannot be located.
+ */
+ public function publishAssets($path, $forceCopy = false)
+ {
+ if (!Yii::app()->hasComponent('assetManager')) {
+ throw new CException('Failed to locate the asset manager component.');
+ }
+ /* @var CAssetManager $assetManager */
+ $assetManager = Yii::app()->getComponent('assetManager');
+ $assetsUrl = $assetManager->publish($path, false, -1, $forceCopy);
+ return $this->_assetsUrl = $assetsUrl;
+ }
+
+ /**
+ * Registers a CSS file.
+ * @param string $url URL of the CSS file.
+ * @param string $media media that the CSS file should be applied to.
+ */
+ public function registerCssFile($url, $media = '')
+ {
+ if (isset($this->_assetsUrl)) {
+ $url = $this->_assetsUrl . '/' . ltrim($url, '/');
+ }
+ $this->getClientScript()->registerCssFile($url, $media);
+ }
+
+ /**
+ * Registers a JavaScript file.
+ * @param string $url URL of the javascript file.
+ * @param integer $position the position of the JavaScript code.
+ */
+ public function registerScriptFile($url, $position = null)
+ {
+ if (isset($this->_assetsUrl)) {
+ $url = $this->_assetsUrl . '/' . ltrim($url, '/');
+ }
+ $this->getClientScript()->registerScriptFile($url, $position);
+ }
+
+ /**
+ * Returns the name of the correct script file to use.
+ * @param string $filename the base file name.
+ * @param boolean $minified whether to include the minified version (defaults to false).
+ * @return string the full filename.
+ */
+ public function resolveScriptVersion($filename, $minified = false)
+ {
+ list($name, $extension) = str_split($filename, strrpos($filename, '.') + 1);
+ return !$minified ? $name . $extension : $name . 'min.' . $extension;
+ }
+
+ /**
+ * Registers the given plugin with the API.
+ * @param string $name the plugin name.
+ * @param string $selector the CSS selector.
+ * @param array $options the JavaScript options for the plugin.
+ * @param int $position the position of the JavaScript code.
+ * @return boolean whether the plugin was registered.
+ */
+ public function registerPlugin($name, $selector, $options = array(), $position = CClientScript::POS_END)
+ {
+ if (($api = $this->getApi()) !== null) {
+ $api->registerPlugin($name, $selector, $options, $position);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Registers plugin events with the API.
+ * @param string $selector the CSS selector.
+ * @param string[] $events the JavaScript event configuration (name=>handler).
+ * @param int $position the position of the JavaScript code.
+ * @return boolean whether the events were registered.
+ */
+ public function registerEvents($selector, $events, $position = CClientScript::POS_END)
+ {
+ if (($api = $this->getApi()) !== null) {
+ $api->registerEvents($selector, $events, $position);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the API instance.
+ * @return TbApi the api.
+ */
+ protected function getApi()
+ {
+ if (isset($this->_api)) {
+ return $this->_api;
+ } else {
+ return $this->_api = Yii::app()->getComponent('bootstrap');
+ }
+ }
+
+ /**
+ * Returns the client script component.
+ * @return CClientScript the component.
+ */
+ protected function getClientScript()
+ {
+ if (isset($this->_clientScript)) {
+ return $this->_clientScript;
+ } else {
+ if (!Yii::app()->hasComponent('clientScript')) {
+ return false;
+ }
+ return $this->_clientScript = Yii::app()->getComponent('clientScript');
+ }
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/codeception.yml b/www/protected/extensions/bootstrap/codeception.yml
new file mode 100644
index 0000000..55e1fa8
--- /dev/null
+++ b/www/protected/extensions/bootstrap/codeception.yml
@@ -0,0 +1,15 @@
+paths:
+ tests: tests
+ log: tests/_log
+ data: tests/_data
+ helpers: tests/_helpers
+settings:
+ bootstrap: _bootstrap.php
+ suite_class: \PHPUnit_Framework_TestSuite
+ colors: false
+ memory_limit: 1024M
+ log: true
+coverage:
+ enabled: true
+ include:
+ - helpers/*
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/components/TbApi.php b/www/protected/extensions/bootstrap/components/TbApi.php
new file mode 100644
index 0000000..873d848
--- /dev/null
+++ b/www/protected/extensions/bootstrap/components/TbApi.php
@@ -0,0 +1,221 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.components
+ * @version 1.2.0
+ */
+
+/**
+ * Bootstrap API component.
+ */
+class TbApi extends CApplicationComponent
+{
+ // Bootstrap plugins
+ const PLUGIN_AFFIX = 'affix';
+ const PLUGIN_ALERT = 'alert';
+ const PLUGIN_BUTTON = 'button';
+ const PLUGIN_CAROUSEL = 'carousel';
+ const PLUGIN_COLLAPSE = 'collapse';
+ const PLUGIN_DROPDOWN = 'dropdown';
+ const PLUGIN_MODAL = 'modal';
+ const PLUGIN_POPOVER = 'popover';
+ const PLUGIN_SCROLLSPY = 'scrollspy';
+ const PLUGIN_TAB = 'tab';
+ const PLUGIN_TOOLTIP = 'tooltip';
+ const PLUGIN_TRANSITION = 'transition';
+ const PLUGIN_TYPEAHEAD = 'typeahead';
+
+ /**
+ * @var int static counter, used for determining script identifiers
+ */
+ public static $counter = 0;
+
+ /**
+ * @var bool whether we should copy the asset file or directory even if it is already published before.
+ */
+ public $forceCopyAssets = false;
+
+ private $_assetsUrl;
+
+ /**
+ * Registers the Bootstrap CSS.
+ * @param string $url the URL to the CSS file to register.
+ * @param string $media the media type.
+ */
+ public function registerCoreCss($url = null, $media = '')
+ {
+ if ($url === null) {
+ $fileName = YII_DEBUG ? 'bootstrap.css' : 'bootstrap.min.css';
+ $url = $this->getAssetsUrl() . '/css/' . $fileName;
+ }
+ Yii::app()->clientScript->registerCssFile($url, $media);
+ }
+
+ /**
+ * Registers the responsive Bootstrap CSS.
+ * @param string $url the URL to the CSS file to register.
+ * @param string $media the media type (defaults to 'screen').
+ */
+ public function registerResponsiveCss($url = null, $media = 'screen')
+ {
+ if ($url === null) {
+ $fileName = YII_DEBUG ? 'bootstrap-responsive.css' : 'bootstrap-responsive.min.css';
+ $url = $this->getAssetsUrl() . '/css/' . $fileName;
+ }
+ /** @var CClientScript $cs */
+ $cs = Yii::app()->getClientScript();
+ $cs->registerMetaTag('width=device-width, initial-scale=1.0', 'viewport');
+ $cs->registerCssFile($url, $media);
+ }
+
+ /**
+ * Registers the Yiistrap CSS.
+ * @param string $url the URL to the CSS file to register.
+ * @param string $media the media type.
+ */
+ public function registerYiistrapCss($url = null, $media = '')
+ {
+ if ($url === null) {
+ $fileName = YII_DEBUG ? 'yiistrap.css' : 'yiistrap.min.css';
+ $url = $this->getAssetsUrl() . '/css/' . $fileName;
+ }
+ Yii::app()->getClientScript()->registerCssFile($url, $media);
+ }
+
+ /**
+ * Registers all Bootstrap CSS files.
+ */
+ public function registerAllCss()
+ {
+ $this->registerCoreCss();
+ $this->registerResponsiveCss();
+ $this->registerYiistrapCss();
+ }
+
+ /**
+ * Registers jQuery and Bootstrap JavaScript.
+ * @param string $url the URL to the JavaScript file to register.
+ * @param int $position the position of the JavaScript code.
+ */
+ public function registerCoreScripts($url = null, $position = CClientScript::POS_END)
+ {
+ if ($url === null) {
+ $fileName = YII_DEBUG ? 'bootstrap.js' : 'bootstrap.min.js';
+ $url = $this->getAssetsUrl() . '/js/' . $fileName;
+ }
+ /** @var CClientScript $cs */
+ $cs = Yii::app()->getClientScript();
+ $cs->registerCoreScript('jquery');
+ $cs->registerScriptFile($url, $position);
+ }
+
+ /**
+ * Registers the Tooltip and Popover plugins.
+ */
+ public function registerTooltipAndPopover()
+ {
+ $this->registerPopover();
+ $this->registerTooltip();
+ }
+
+ /**
+ * Registers all Bootstrap JavaScript files.
+ */
+ public function registerAllScripts()
+ {
+ $this->registerCoreScripts();
+ $this->registerTooltipAndPopover();
+ }
+
+ /**
+ * Registers all assets.
+ */
+ public function register()
+ {
+ $this->registerAllCss();
+ $this->registerAllScripts();
+ }
+
+ /**
+ * Registers the Bootstrap Popover plugin.
+ * @param string $selector the CSS selector.
+ * @param array $options the JavaScript options for the plugin.
+ * @see http://twitter.github.com/bootstrap/javascript.html#popover
+ */
+ public function registerPopover($selector = 'body', $options = array())
+ {
+ if (!isset($options['selector'])) {
+ $options['selector'] = 'a[rel=popover]';
+ }
+ $this->registerPlugin(self::PLUGIN_POPOVER, $selector, $options);
+ }
+
+ /**
+ * Registers the Bootstrap Tooltip plugin.
+ * @param string $selector the CSS selector.
+ * @param array $options the JavaScript options for the plugin.
+ * @see http://twitter.github.com/bootstrap/javascript.html#tooltip
+ */
+ public function registerTooltip($selector = 'body', $options = array())
+ {
+ if (!isset($options['selector'])) {
+ $options['selector'] = 'a[rel=tooltip]';
+ }
+ $this->registerPlugin(self::PLUGIN_TOOLTIP, $selector, $options);
+ }
+
+ /**
+ * Registers a specific Bootstrap plugin using the given selector and options.
+ * @param string $name the plugin name.
+ * @param string $selector the CSS selector.
+ * @param array $options the JavaScript options for the plugin.
+ * @param int $position the position of the JavaScript code.
+ */
+ public function registerPlugin($name, $selector, $options = array(), $position = CClientScript::POS_END)
+ {
+ $options = !empty($options) ? CJavaScript::encode($options) : '';
+ $script = "jQuery('{$selector}').{$name}({$options});";
+ $id = __CLASS__ . '#Plugin' . self::$counter++;
+ Yii::app()->clientScript->registerScript($id, $script, $position);
+ }
+
+ /**
+ * Registers events using the given selector.
+ * @param string $selector the CSS selector.
+ * @param string[] $events the JavaScript event configuration (name=>handler).
+ * @param int $position the position of the JavaScript code.
+ */
+ public function registerEvents($selector, $events, $position = CClientScript::POS_END)
+ {
+ if (!empty($events)) {
+ $script = '';
+ foreach ($events as $name => $handler) {
+ if (!$handler instanceof CJavaScriptExpression) {
+ $handler = new CJavaScriptExpression($handler);
+ }
+ $script .= "jQuery('{$selector}').on('{$name}', {$handler});";
+ }
+ $id = __CLASS__ . '#Events' . self::$counter++;
+ Yii::app()->clientScript->registerScript($id, $script, $position);
+ }
+ }
+
+ /**
+ * Returns the url to the published assets folder.
+ * @return string the url.
+ */
+ protected function getAssetsUrl()
+ {
+ if (isset($this->_assetsUrl)) {
+ return $this->_assetsUrl;
+ } else {
+ $assetsPath = Yii::getPathOfAlias('bootstrap.assets');
+ $assetsUrl = Yii::app()->assetManager->publish($assetsPath, false, -1, $this->forceCopyAssets);
+ return $this->_assetsUrl = $assetsUrl;
+ }
+ }
+
+}
diff --git a/www/protected/extensions/bootstrap/composer.json b/www/protected/extensions/bootstrap/composer.json
new file mode 100644
index 0000000..fc5fa40
--- /dev/null
+++ b/www/protected/extensions/bootstrap/composer.json
@@ -0,0 +1,43 @@
+{
+ "name": "crisu83/yiistrap",
+ "description": "Twitter Bootstrap for the Yii PHP framework.",
+ "keywords": ["bootstrap", "yii"],
+ "type": "library",
+ "license": "BSD-3-Clause",
+ "authors": [
+ {
+ "name": "Christoffer Niska",
+ "email": "christoffer.niska@gmail.com",
+ "homepage": "http://www.cniska.net/"
+ },
+ {
+ "name": "Antonio Ramirez",
+ "email": "ramirez.cobos@gmail.com",
+ "homepage": "http://www.ramirezcobos.com/"
+ }
+ ],
+ "require-dev": {
+ "codeception/codeception": "@stable",
+ "crisu83/yii-composer": ">=1.0.0",
+ "yiisoft/yii": ">=1.1.13"
+ },
+ "scripts": {
+ "post-install-cmd": [
+ "Crisu83\\YiiComposer\\InstallHandler::setPermissions"
+ ]
+ },
+ "extra": {
+ "yii-install-writable": [
+ "tests/_log"
+ ]
+ },
+ "autoload": {
+ "classmap": [
+ "behaviors/",
+ "components/",
+ "form/",
+ "helpers/",
+ "widgets/"
+ ]
+ }
+}
diff --git a/www/protected/extensions/bootstrap/composer.lock b/www/protected/extensions/bootstrap/composer.lock
new file mode 100644
index 0000000..5e1243f
--- /dev/null
+++ b/www/protected/extensions/bootstrap/composer.lock
@@ -0,0 +1,1585 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+ ],
+ "hash": "def7a851789259f03bb96995ba352025",
+ "packages": [
+
+ ],
+ "packages-dev": [
+ {
+ "name": "behat/mink",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Behat/Mink.git",
+ "reference": "0769e6d9726c140a54dbf827a438c0f9912749fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Behat/Mink/zipball/0769e6d9726c140a54dbf827a438c0f9912749fe",
+ "reference": "0769e6d9726c140a54dbf827a438c0f9912749fe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.1",
+ "symfony/css-selector": "~2.0"
+ },
+ "suggest": {
+ "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
+ "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
+ "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
+ "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "1.5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Behat\\Mink": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ }
+ ],
+ "description": "Web acceptance testing framework for PHP 5.3",
+ "homepage": "http://mink.behat.org/",
+ "keywords": [
+ "browser",
+ "testing",
+ "web"
+ ],
+ "time": "2013-04-13 23:39:27"
+ },
+ {
+ "name": "behat/mink-browserkit-driver",
+ "version": "v1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Behat/MinkBrowserKitDriver.git",
+ "reference": "63960c8fcad4529faad1ff33e950217980baa64c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Behat/MinkBrowserKitDriver/zipball/63960c8fcad4529faad1ff33e950217980baa64c",
+ "reference": "63960c8fcad4529faad1ff33e950217980baa64c",
+ "shasum": ""
+ },
+ "require": {
+ "behat/mink": "~1.5.0",
+ "php": ">=5.3.1",
+ "symfony/browser-kit": "~2.0",
+ "symfony/dom-crawler": "~2.0"
+ },
+ "require-dev": {
+ "silex/silex": "@dev"
+ },
+ "type": "mink-driver",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Behat\\Mink\\Driver": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ }
+ ],
+ "description": "Symfony2 BrowserKit driver for Mink framework",
+ "homepage": "http://mink.behat.org/",
+ "keywords": [
+ "Mink",
+ "Symfony2",
+ "browser",
+ "testing"
+ ],
+ "time": "2013-04-13 23:46:30"
+ },
+ {
+ "name": "behat/mink-goutte-driver",
+ "version": "v1.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Behat/MinkGoutteDriver.git",
+ "reference": "fa1b073b48761464feb0b05e6825da44b20118d8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Behat/MinkGoutteDriver/zipball/fa1b073b48761464feb0b05e6825da44b20118d8",
+ "reference": "fa1b073b48761464feb0b05e6825da44b20118d8",
+ "shasum": ""
+ },
+ "require": {
+ "behat/mink-browserkit-driver": ">=1.0.5,<1.2.0",
+ "fabpot/goutte": "~1.0.1",
+ "php": ">=5.3.1"
+ },
+ "type": "mink-driver",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Behat\\Mink\\Driver": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ }
+ ],
+ "description": "Goutte driver for Mink framework",
+ "homepage": "http://mink.behat.org/",
+ "keywords": [
+ "browser",
+ "goutte",
+ "headless",
+ "testing"
+ ],
+ "time": "2013-07-03 18:43:54"
+ },
+ {
+ "name": "behat/mink-selenium2-driver",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Behat/MinkSelenium2Driver.git",
+ "reference": "bcf1b537de37db6db0822d9e7bd97e600fd7a476"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Behat/MinkSelenium2Driver/zipball/bcf1b537de37db6db0822d9e7bd97e600fd7a476",
+ "reference": "bcf1b537de37db6db0822d9e7bd97e600fd7a476",
+ "shasum": ""
+ },
+ "require": {
+ "behat/mink": "~1.5.0",
+ "instaclick/php-webdriver": "~1.0.12",
+ "php": ">=5.3.1"
+ },
+ "type": "mink-driver",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Behat\\Mink\\Driver": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Pete Otaqui",
+ "email": "pete@otaqui.com",
+ "homepage": "https://github.com/pete-otaqui"
+ }
+ ],
+ "description": "Selenium2 (WebDriver) driver for Mink framework",
+ "homepage": "http://mink.behat.org/",
+ "keywords": [
+ "ajax",
+ "browser",
+ "javascript",
+ "selenium",
+ "testing",
+ "webdriver"
+ ],
+ "time": "2013-06-02 19:09:45"
+ },
+ {
+ "name": "codeception/codeception",
+ "version": "1.7.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Codeception/Codeception.git",
+ "reference": "a6f6413bab11a631c9c767a76c80e942b3ec8a6e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Codeception/Codeception/zipball/a6f6413bab11a631c9c767a76c80e942b3ec8a6e",
+ "reference": "a6f6413bab11a631c9c767a76c80e942b3ec8a6e",
+ "shasum": ""
+ },
+ "require": {
+ "behat/mink": "1.5.*",
+ "behat/mink-goutte-driver": "1.0.*",
+ "behat/mink-selenium2-driver": "1.1.*",
+ "facebook/webdriver": "*",
+ "monolog/monolog": "*",
+ "php": ">=5.3.3",
+ "phpunit/phpunit": "3.7.*",
+ "symfony/console": "~2.3",
+ "symfony/event-dispatcher": "~2.3",
+ "symfony/finder": "~2.3",
+ "symfony/yaml": "~2.3"
+ },
+ "require-dev": {
+ "behat/mink-selenium-driver": "1.1.*",
+ "behat/mink-zombie-driver": "1.1.*",
+ "facebook/php-sdk": "3.*",
+ "videlalvaro/php-amqplib": "*"
+ },
+ "bin": [
+ "codecept"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Codeception": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Bodnarchuk",
+ "email": "davert@mail.ua",
+ "homepage": "http://codegyre.com"
+ }
+ ],
+ "description": "BDD-style testing framework",
+ "homepage": "http://codeception.com/",
+ "keywords": [
+ "BDD",
+ "TDD",
+ "acceptance testing",
+ "functional testing",
+ "unit testing"
+ ],
+ "time": "2013-10-16 22:56:44"
+ },
+ {
+ "name": "crisu83/yii-composer",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Crisu83/yii-composer.git",
+ "reference": "de7c43d26752319b1b54e16db4c911820896fb7e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Crisu83/yii-composer/zipball/de7c43d26752319b1b54e16db4c911820896fb7e",
+ "reference": "de7c43d26752319b1b54e16db4c911820896fb7e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "yiisoft/yii": ">=1.1.13"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Crisu83": "/src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Christoffer Niska",
+ "email": "christoffer.niska@gmail.com",
+ "homepage": "http://www.cniska.net/"
+ }
+ ],
+ "description": "Composer callbacks for the Yii PHP framework.",
+ "keywords": [
+ "composer",
+ "yii"
+ ],
+ "time": "2013-08-20 18:50:34"
+ },
+ {
+ "name": "fabpot/goutte",
+ "version": "v1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/fabpot/Goutte.git",
+ "reference": "75c9f23c4122caf4ea3e87a42a00b471366e707f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/fabpot/Goutte/zipball/75c9f23c4122caf4ea3e87a42a00b471366e707f",
+ "reference": "75c9f23c4122caf4ea3e87a42a00b471366e707f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "guzzle/http": ">=3.0.5,<3.8-dev",
+ "php": ">=5.3.0",
+ "symfony/browser-kit": "~2.1",
+ "symfony/css-selector": "~2.1",
+ "symfony/dom-crawler": "~2.1",
+ "symfony/finder": "~2.1",
+ "symfony/process": "~2.1"
+ },
+ "require-dev": {
+ "guzzle/plugin-history": ">=3.0.5,<3.8-dev",
+ "guzzle/plugin-mock": ">=3.0.5,<3.8-dev"
+ },
+ "type": "application",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Goutte": "."
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "A simple PHP Web Scraper",
+ "homepage": "https://github.com/fabpot/Goutte",
+ "keywords": [
+ "scraper"
+ ],
+ "time": "2013-08-16 06:03:22"
+ },
+ {
+ "name": "facebook/webdriver",
+ "version": "v0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/facebook/php-webdriver.git",
+ "reference": "b720b6aafb667a463c7e7cafcdebf3210ddc5ef7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/b720b6aafb667a463c7e7cafcdebf3210ddc5ef7",
+ "reference": "b720b6aafb667a463c7e7cafcdebf3210ddc5ef7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "description": "A php client for WebDriver",
+ "homepage": "https://github.com/facebook/php-webdriver",
+ "time": "2013-10-10 02:34:59"
+ },
+ {
+ "name": "guzzle/common",
+ "version": "v3.7.4",
+ "target-dir": "Guzzle/Common",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/common.git",
+ "reference": "5126e268446c7e7df961b89128d71878e0652432"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/common/zipball/5126e268446c7e7df961b89128d71878e0652432",
+ "reference": "5126e268446c7e7df961b89128d71878e0652432",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/event-dispatcher": ">=2.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Guzzle\\Common": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Common libraries used by Guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "collection",
+ "common",
+ "event",
+ "exception"
+ ],
+ "time": "2013-10-02 20:47:00"
+ },
+ {
+ "name": "guzzle/http",
+ "version": "v3.7.4",
+ "target-dir": "Guzzle/Http",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/http.git",
+ "reference": "3420035adcf312d62a2e64f3e6b3e3e590121786"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/http/zipball/3420035adcf312d62a2e64f3e6b3e3e590121786",
+ "reference": "3420035adcf312d62a2e64f3e6b3e3e590121786",
+ "shasum": ""
+ },
+ "require": {
+ "guzzle/common": "self.version",
+ "guzzle/parser": "self.version",
+ "guzzle/stream": "self.version",
+ "php": ">=5.3.2"
+ },
+ "suggest": {
+ "ext-curl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Guzzle\\Http": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "HTTP libraries used by Guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "Guzzle",
+ "client",
+ "curl",
+ "http",
+ "http client"
+ ],
+ "time": "2013-09-20 22:05:53"
+ },
+ {
+ "name": "guzzle/parser",
+ "version": "v3.7.4",
+ "target-dir": "Guzzle/Parser",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/parser.git",
+ "reference": "a25c2ddda1c52fb69a4ee56eb530b13ddd9573c2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/parser/zipball/a25c2ddda1c52fb69a4ee56eb530b13ddd9573c2",
+ "reference": "a25c2ddda1c52fb69a4ee56eb530b13ddd9573c2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Guzzle\\Parser": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Interchangeable parsers used by Guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "URI Template",
+ "cookie",
+ "http",
+ "message",
+ "url"
+ ],
+ "time": "2013-07-11 22:46:03"
+ },
+ {
+ "name": "guzzle/stream",
+ "version": "v3.7.4",
+ "target-dir": "Guzzle/Stream",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/stream.git",
+ "reference": "a86111d9ac7db31d65a053c825869409fe8fc83f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/stream/zipball/a86111d9ac7db31d65a053c825869409fe8fc83f",
+ "reference": "a86111d9ac7db31d65a053c825869409fe8fc83f",
+ "shasum": ""
+ },
+ "require": {
+ "guzzle/common": "self.version",
+ "php": ">=5.3.2"
+ },
+ "suggest": {
+ "guzzle/http": "To convert Guzzle request objects to PHP streams"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Guzzle\\Stream": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle stream wrapper component",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "Guzzle",
+ "component",
+ "stream"
+ ],
+ "time": "2013-07-30 22:07:23"
+ },
+ {
+ "name": "instaclick/php-webdriver",
+ "version": "1.0.17",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/instaclick/php-webdriver.git",
+ "reference": "47a6019553a7a5b42d35493276ffc2c9252c53d5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/47a6019553a7a5b42d35493276ffc2c9252c53d5",
+ "reference": "47a6019553a7a5b42d35493276ffc2c9252c53d5",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "php": ">=5.3.2"
+ },
+ "bin": [
+ "bin/webunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "WebDriver": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Justin Bishop",
+ "email": "jubishop@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anthon Pang",
+ "email": "apang@softwaredevelopment.ca",
+ "role": "Fork Maintainer"
+ }
+ ],
+ "description": "PHP WebDriver for Selenium 2",
+ "homepage": "http://instaclick.com/",
+ "keywords": [
+ "browser",
+ "selenium",
+ "webdriver",
+ "webtest"
+ ],
+ "time": "2013-10-04 15:03:51"
+ },
+ {
+ "name": "monolog/monolog",
+ "version": "1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f72392d0e6eb855118f5a84e89ac2d257c704abd",
+ "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "doctrine/couchdb": "dev-master",
+ "mlehner/gelf-php": "1.0.*",
+ "raven/raven": "0.5.*"
+ },
+ "suggest": {
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "raven/raven": "Allow sending log messages to a Sentry server"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Monolog": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be",
+ "role": "Developer"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "http://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ],
+ "time": "2013-07-28 22:38:30"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "1.2.13",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
+ "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-file-iterator": ">=1.3.0@stable",
+ "phpunit/php-text-template": ">=1.1.1@stable",
+ "phpunit/php-token-stream": ">=1.1.3@stable"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*@dev"
+ },
+ "suggest": {
+ "ext-dom": "*",
+ "ext-xdebug": ">=2.0.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-09-10 08:14:32"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
+ "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "File/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2013-10-10 15:34:57"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "5180896f51c5b3648ac946b05f9ec02be78a0b23"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5180896f51c5b3648ac946b05f9ec02be78a0b23",
+ "reference": "5180896f51c5b3648ac946b05f9ec02be78a0b23",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "Text/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2012-10-31 18:15:28"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
+ "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2013-08-02 07:42:54"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5220af2a7929aa35cf663d97c89ad3d50cf5fa3e",
+ "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2013-09-13 04:58:23"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "3.7.28",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d",
+ "reference": "3b97c8492bcafbabe6b6fbd2ab35f2f04d932a8d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=5.3.3",
+ "phpunit/php-code-coverage": "~1.2.1",
+ "phpunit/php-file-iterator": ">=1.3.1",
+ "phpunit/php-text-template": ">=1.1.1",
+ "phpunit/php-timer": ">=1.0.4",
+ "phpunit/phpunit-mock-objects": "~1.2.0",
+ "symfony/yaml": "~2.0"
+ },
+ "require-dev": {
+ "pear-pear/pear": "1.9.4"
+ },
+ "suggest": {
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "phpunit/php-invoker": ">=1.1.0,<1.2.0"
+ },
+ "bin": [
+ "composer/bin/phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ "",
+ "../../symfony/yaml/"
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-10-17 07:27:40"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875",
+ "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-text-template": ">=1.1.1@stable"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "time": "2013-01-13 10:24:48"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "shasum": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Psr\\Log\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2012-12-21 11:40:51"
+ },
+ {
+ "name": "symfony/browser-kit",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/BrowserKit",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/BrowserKit.git",
+ "reference": "7fc66ea3b9438080d79246cd8e5d88950c7fe4a4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/7fc66ea3b9438080d79246cd8e5d88950c7fe4a4",
+ "reference": "7fc66ea3b9438080d79246cd8e5d88950c7fe4a4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/dom-crawler": "~2.0"
+ },
+ "require-dev": {
+ "symfony/css-selector": "~2.0",
+ "symfony/process": "~2.0"
+ },
+ "suggest": {
+ "symfony/process": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\BrowserKit\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony BrowserKit Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-26 12:37:59"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/Console",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Console.git",
+ "reference": "f880062d56edefb25b36f2defa65aafe65959dc7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Console/zipball/f880062d56edefb25b36f2defa65aafe65959dc7",
+ "reference": "f880062d56edefb25b36f2defa65aafe65959dc7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "~2.1"
+ },
+ "suggest": {
+ "symfony/event-dispatcher": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Console\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Console Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-25 06:04:15"
+ },
+ {
+ "name": "symfony/css-selector",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/CssSelector",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/CssSelector.git",
+ "reference": "4e01c74f19ea049773fa3ee9fb2bb5bf5e14f7eb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/CssSelector/zipball/4e01c74f19ea049773fa3ee9fb2bb5bf5e14f7eb",
+ "reference": "4e01c74f19ea049773fa3ee9fb2bb5bf5e14f7eb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\CssSelector\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ },
+ {
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ }
+ ],
+ "description": "Symfony CssSelector Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-19 09:45:20"
+ },
+ {
+ "name": "symfony/dom-crawler",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/DomCrawler",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/DomCrawler.git",
+ "reference": "f3c321861994f5a1882b4045ea1f8759be47601a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/f3c321861994f5a1882b4045ea1f8759be47601a",
+ "reference": "f3c321861994f5a1882b4045ea1f8759be47601a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/css-selector": "~2.0"
+ },
+ "suggest": {
+ "symfony/css-selector": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\DomCrawler\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony DomCrawler Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-25 09:22:53"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/EventDispatcher",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/EventDispatcher.git",
+ "reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/7fc72a7a346a1887d3968cc1ce5642a15cd182e9",
+ "reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/dependency-injection": "~2.0"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony EventDispatcher Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-19 09:45:20"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/Finder",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Finder.git",
+ "reference": "a175521f680b178e63c5d0ab87c6b046c0990c3f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/a175521f680b178e63c5d0ab87c6b046c0990c3f",
+ "reference": "a175521f680b178e63c5d0ab87c6b046c0990c3f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Finder\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-19 09:45:20"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/Process",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Process.git",
+ "reference": "81191e354fe9dad0451036ccf0fdf283649d3f1e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/81191e354fe9dad0451036ccf0fdf283649d3f1e",
+ "reference": "81191e354fe9dad0451036ccf0fdf283649d3f1e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Process\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-10-09 21:17:57"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v2.3.6",
+ "target-dir": "Symfony/Component/Yaml",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Yaml.git",
+ "reference": "6bb881b948368482e1abf1a75c08bcf88a1c5fc3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/6bb881b948368482e1abf1a75c08bcf88a1c5fc3",
+ "reference": "6bb881b948368482e1abf1a75c08bcf88a1c5fc3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Yaml\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Yaml Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-09-22 18:04:39"
+ },
+ {
+ "name": "yiisoft/yii",
+ "version": "1.1.14",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii.git",
+ "reference": "f0fee98ee84f70f1f3652f65562c9670e919cb4e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/yiisoft/yii/archive/f0fee98ee84f70f1f3652f65562c9670e919cb4e.zip",
+ "reference": null,
+ "shasum": null
+ },
+ "type": "library",
+ "description": "Yii PHP Framework",
+ "homepage": "https://github.com/yiisoft/yii"
+ }
+ ],
+ "aliases": [
+
+ ],
+ "minimum-stability": "stable",
+ "stability-flags": {
+ "codeception/codeception": 0
+ },
+ "platform": [
+
+ ],
+ "platform-dev": {
+ "php": ">=5.3.0"
+ }
+}
diff --git a/www/protected/extensions/bootstrap/form/TbForm.php b/www/protected/extensions/bootstrap/form/TbForm.php
new file mode 100644
index 0000000..56b6b1b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/form/TbForm.php
@@ -0,0 +1,80 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.form
+ */
+
+/**
+ * Bootstrap form object that contains form input specifications.
+ */
+class TbForm extends CForm
+{
+ /**
+ * @var string the form layout.
+ */
+ public $layout = TbHtml::FORM_LAYOUT_VERTICAL;
+
+ /**
+ * @var string the name of the class for representing a form input element.
+ */
+ public $inputElementClass = 'TbFormInputElement';
+
+ /**
+ * @var string the name of the class for representing a form button element.
+ */
+ public $buttonElementClass = 'TbFormButtonElement';
+
+ /**
+ * @var array the configuration used to create the active form widget.
+ */
+ public $activeForm = array('class' => 'TbActiveForm');
+
+ /**
+ * Initializes this form.
+ */
+ public function init()
+ {
+ TbArray::defaultValue('layout', $this->layout, $this->activeForm);
+ }
+
+ /**
+ * Renders a single element which could be an input element, a sub-form, a string, or a button.
+ * @param mixed $element the form element to be rendered.
+ * @return string the rendering result
+ */
+ public function renderElement($element)
+ {
+ if (is_string($element)) {
+ if (($e = $this[$element]) === null && ($e = $this->getButtons()->itemAt($element)) === null) {
+ return $element;
+ } else {
+ $element = $e;
+ }
+ }
+ if ($element->getVisible()) {
+ if ($element instanceof CFormInputElement) {
+ if ($element->type === 'hidden') {
+ return TbHtml::tag('div', array('class' => 'hidden'), $element->render());
+ }
+ }
+ return $element->render();
+ }
+ return '';
+ }
+
+ /**
+ * Renders the buttons in this form.
+ * @return string the rendering result.
+ */
+ public function renderButtons()
+ {
+ $buttons = array();
+ foreach ($this->getButtons() as $button) {
+ $buttons[] = $this->renderElement($button);
+ }
+ return !empty($buttons) ? TbHtml::tag('div', array('class' => 'form-actions'), implode("\n", $buttons)) : '';
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/form/TbFormButtonElement.php b/www/protected/extensions/bootstrap/form/TbFormButtonElement.php
new file mode 100644
index 0000000..d61cace
--- /dev/null
+++ b/www/protected/extensions/bootstrap/form/TbFormButtonElement.php
@@ -0,0 +1,58 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.form
+ */
+
+/**
+ * Bootstrap form button element.
+ */
+class TbFormButtonElement extends CFormButtonElement
+{
+ /**
+ * Renders this button.
+ * @return string the rendering result.
+ */
+ public function render()
+ {
+ if (isset(self::$coreTypes[$this->type]))
+ {
+ return $this->renderCore();
+ }
+ else
+ {
+ return parent::render();
+ }
+ }
+
+ /**
+ * This function renders a built in button type.
+ * The implementation is essentially a direct copy from
+ * CFormButtonElement::render, the only difference is it uses TbHtml.
+ * @return string the rendering result.
+ */
+ public function renderCore()
+ {
+ $attributes=$this->attributes;
+ $method=self::$coreTypes[$this->type];
+ if($method==='linkButton')
+ {
+ if(!isset($attributes['params'][$this->name]))
+ $attributes['params'][$this->name]=1;
+ }
+ elseif($method==='htmlButton')
+ {
+ $attributes['type']=$this->type==='htmlSubmit' ? 'submit' : ($this->type==='htmlReset' ? 'reset' : 'button');
+ $attributes['name']=$this->name;
+ }
+ else
+ $attributes['name']=$this->name;
+ if($method==='imageButton')
+ return TbHtml::imageButton(isset($attributes['src']) ? $attributes['src'] : '',$attributes);
+ else
+ return TbHtml::$method($this->label,$attributes);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/form/TbFormInputElement.php b/www/protected/extensions/bootstrap/form/TbFormInputElement.php
new file mode 100644
index 0000000..9327ec7
--- /dev/null
+++ b/www/protected/extensions/bootstrap/form/TbFormInputElement.php
@@ -0,0 +1,53 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.form
+ */
+
+/**
+ * Bootstrap form input element.
+ */
+class TbFormInputElement extends CFormInputElement
+{
+ /**
+ * Renders everything for this input.
+ * @return string the complete rendering result for this input, including label, input field, hint, and error.
+ */
+ public function render()
+ {
+ if (isset(self::$coreTypes[$this->type]))
+ {
+ return $this->renderCore();
+ }
+ else
+ {
+ return $this->renderWidget();
+ }
+ }
+
+ protected function renderCore()
+ {
+ // Remove the "active" prefix.
+ $method = substr(self::$coreTypes[$this->type], 6) . 'ControlGroup';
+ if(strpos($method,'List')!==false)
+ {
+ return $this->getParent()->getActiveFormWidget()->$method($this->getParent()->getModel(), $this->name, $this->items, $this->attributes);
+ }
+ else
+ {
+ return $this->getParent()->getActiveFormWidget()->$method($this->getParent()->getModel(), $this->name, $this->attributes);
+ }
+ }
+
+ /**
+ * Renders a form control that is implemented via a widget.
+ */
+ protected function renderWidget()
+ {
+ $input = parent::renderInput();
+ return TbHtml::activeControlGroup(null, $this->getParent()->getModel(), $this->name, array('input' => $input));
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapCode.php b/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapCode.php
new file mode 100644
index 0000000..352d18d
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapCode.php
@@ -0,0 +1,62 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.gii
+ */
+
+Yii::import('gii.generators.crud.CrudCode');
+
+class BootstrapCode extends CrudCode
+{
+ public function generateControlGroup($modelClass, $column)
+ {
+ if ($column->type === 'boolean') {
+ return "TbHtml::activeCheckBoxControlGroup(\$model,'{$column->name}')";
+ } else {
+ if (stripos($column->dbType, 'text') !== false) {
+ return "TbHtml::activeTextAreaControlGroup(\$model,'{$column->name}',array('rows'=>6,'span'=>8))";
+ } else {
+ if (preg_match('/^(password|pass|passwd|passcode)$/i', $column->name)) {
+ $inputField = 'activePasswordControlGroup';
+ } else {
+ $inputField = 'activeTextFieldControlGroup';
+ }
+
+ if ($column->type !== 'string' || $column->size === null) {
+ return "TbHtml::{$inputField}(\$model,'{$column->name}')";
+ } else {
+ if (($size = $maxLength = $column->size) > 60) {
+ $size = 60;
+ }
+ return "TbHtml::{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";
+ }
+ }
+ }
+ }
+
+ public function generateActiveControlGroup($modelClass, $column)
+ {
+ if ($column->type === 'boolean') {
+ return "\$form->checkBoxControlGroup(\$model,'{$column->name}')";
+ } else {
+ if (stripos($column->dbType, 'text') !== false) {
+ return "\$form->textAreaControlGroup(\$model,'{$column->name}',array('rows'=>6,'span'=>8))";
+ } else {
+ if (preg_match('/^(password|pass|passwd|passcode)$/i', $column->name)) {
+ $inputField = 'passwordFieldControlGroup';
+ } else {
+ $inputField = 'textFieldControlGroup';
+ }
+
+ if ($column->type !== 'string' || $column->size === null) {
+ return "\$form->{$inputField}(\$model,'{$column->name}',array('span'=>5))";
+ } else {
+ return "\$form->{$inputField}(\$model,'{$column->name}',array('span'=>5,'maxlength'=>$column->size))";
+ }
+ }
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapGenerator.php b/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapGenerator.php
new file mode 100644
index 0000000..7af7b40
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/BootstrapGenerator.php
@@ -0,0 +1,15 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.gii
+ */
+
+Yii::import('gii.generators.crud.CrudGenerator');
+
+class BootstrapGenerator extends CrudGenerator
+{
+ public $codeModel = 'bootstrap.gii.bootstrap.BootstrapCode';
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_form.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_form.php
new file mode 100644
index 0000000..d14957c
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_form.php
@@ -0,0 +1,48 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+/* @var $form TbActiveForm */
+\n"; ?>
+
+
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_search.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_search.php
new file mode 100644
index 0000000..868b764
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_search.php
@@ -0,0 +1,36 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+/* @var $form CActiveForm */
+\n"; ?>
+
+
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_view.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_view.php
new file mode 100644
index 0000000..ad15c67
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/_view.php
@@ -0,0 +1,33 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $data getModelClass(); ?> */
+\n"; ?>
+
+
+
+ getAttributeLabel('{$this->tableSchema->primaryKey}')); ?>:\n";
+ echo "\t{$this->tableSchema->primaryKey}),array('view','id'=>\$data->{$this->tableSchema->primaryKey})); ?>\n\t \n\n";
+ $count = 0;
+ foreach ($this->tableSchema->columns as $column) {
+ if ($column->isPrimaryKey) {
+ continue;
+ }
+ if (++$count == 7) {
+ echo "\tgetAttributeLabel('{$column->name}')); ?>:\n";
+ echo "\t{$column->name}); ?>\n\t \n\n";
+ }
+ if ($count >= 7) {
+ echo "\t*/ ?>\n";
+ }
+ ?>
+
+
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/admin.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/admin.php
new file mode 100644
index 0000000..89865f5
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/admin.php
@@ -0,0 +1,76 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+
+pluralize($this->class2name($this->modelClass));
+echo "\$this->breadcrumbs=array(
+ '$label'=>array('index'),
+ 'Manage',
+);\n";
+?>
+
+$this->menu=array(
+ array('label'=>'List modelClass; ?>', 'url'=>array('index')),
+ array('label'=>'Create modelClass; ?>', 'url'=>array('create')),
+);
+
+Yii::app()->clientScript->registerScript('search', "
+$('.search-button').click(function(){
+ $('.search-form').toggle();
+ return false;
+});
+$('.search-form form').submit(function(){
+ $('#class2id($this->modelClass); ?>-grid').yiiGridView('update', {
+ data: $(this).serialize()
+ });
+ return false;
+});
+");
+?>
+
+Manage pluralize($this->class2name($this->modelClass)); ?>
+
+
+ You may optionally enter a comparison operator (< , <= , > , >= ,
+ <>
+or = ) at the beginning of each of your search values to specify how the comparison should be done.
+
+
+'search-button btn')); ?>"; ?>
+
+
+renderPartial('_search',array(
+ 'model'=>\$model,
+)); ?>\n"; ?>
+
+
+ $this->widget('bootstrap.widgets.TbGridView',array(
+ 'id'=>'class2id($this->modelClass); ?>-grid',
+ 'dataProvider'=>$model->search(),
+ 'filter'=>$model,
+ 'columns'=>array(
+tableSchema->columns as $column) {
+ if (++$count == 7) {
+ echo "\t\t/*\n";
+ }
+ echo "\t\t'" . $column->name . "',\n";
+}
+if ($count >= 7) {
+ echo "\t\t*/\n";
+}
+?>
+ array(
+ 'class'=>'bootstrap.widgets.TbButtonColumn',
+ ),
+ ),
+)); ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/controller.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/controller.php
new file mode 100644
index 0000000..2c09f38
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/controller.php
@@ -0,0 +1,187 @@
+
+
+
+class controllerClass; ?> extends baseControllerClass . "\n"; ?>
+{
+ /**
+ * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
+ * using two-column layout. See 'protected/views/layouts/column2.php'.
+ */
+ public $layout='//layouts/column2';
+
+ /**
+ * @return array action filters
+ */
+ public function filters()
+ {
+ return array(
+ 'accessControl', // perform access control for CRUD operations
+ 'postOnly + delete', // we only allow deletion via POST request
+ );
+ }
+
+ /**
+ * Specifies the access control rules.
+ * This method is used by the 'accessControl' filter.
+ * @return array access control rules
+ */
+ public function accessRules()
+ {
+ return array(
+ array('allow', // allow all users to perform 'index' and 'view' actions
+ 'actions'=>array('index','view'),
+ 'users'=>array('*'),
+ ),
+ array('allow', // allow authenticated user to perform 'create' and 'update' actions
+ 'actions'=>array('create','update'),
+ 'users'=>array('@'),
+ ),
+ array('allow', // allow admin user to perform 'admin' and 'delete' actions
+ 'actions'=>array('admin','delete'),
+ 'users'=>array('admin'),
+ ),
+ array('deny', // deny all users
+ 'users'=>array('*'),
+ ),
+ );
+ }
+
+ /**
+ * Displays a particular model.
+ * @param integer $id the ID of the model to be displayed
+ */
+ public function actionView($id)
+ {
+ $this->render('view',array(
+ 'model'=>$this->loadModel($id),
+ ));
+ }
+
+ /**
+ * Creates a new model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ */
+ public function actionCreate()
+ {
+ $model=new modelClass; ?>;
+
+ // Uncomment the following line if AJAX validation is needed
+ // $this->performAjaxValidation($model);
+
+ if (isset($_POST['modelClass; ?>'])) {
+ $model->attributes=$_POST['modelClass; ?>'];
+ if ($model->save()) {
+ $this->redirect(array('view','id'=>$model->tableSchema->primaryKey; ?>));
+ }
+ }
+
+ $this->render('create',array(
+ 'model'=>$model,
+ ));
+ }
+
+ /**
+ * Updates a particular model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id the ID of the model to be updated
+ */
+ public function actionUpdate($id)
+ {
+ $model=$this->loadModel($id);
+
+ // Uncomment the following line if AJAX validation is needed
+ // $this->performAjaxValidation($model);
+
+ if (isset($_POST['modelClass; ?>'])) {
+ $model->attributes=$_POST['modelClass; ?>'];
+ if ($model->save()) {
+ $this->redirect(array('view','id'=>$model->tableSchema->primaryKey; ?>));
+ }
+ }
+
+ $this->render('update',array(
+ 'model'=>$model,
+ ));
+ }
+
+ /**
+ * Deletes a particular model.
+ * If deletion is successful, the browser will be redirected to the 'admin' page.
+ * @param integer $id the ID of the model to be deleted
+ */
+ public function actionDelete($id)
+ {
+ if (Yii::app()->request->isPostRequest) {
+ // we only allow deletion via POST request
+ $this->loadModel($id)->delete();
+
+ // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
+ if (!isset($_GET['ajax'])) {
+ $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
+ }
+ } else {
+ throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
+ }
+ }
+
+ /**
+ * Lists all models.
+ */
+ public function actionIndex()
+ {
+ $dataProvider=new CActiveDataProvider('modelClass; ?>');
+ $this->render('index',array(
+ 'dataProvider'=>$dataProvider,
+ ));
+ }
+
+ /**
+ * Manages all models.
+ */
+ public function actionAdmin()
+ {
+ $model=new modelClass; ?>('search');
+ $model->unsetAttributes(); // clear any default values
+ if (isset($_GET['modelClass; ?>'])) {
+ $model->attributes=$_GET['modelClass; ?>'];
+ }
+
+ $this->render('admin',array(
+ 'model'=>$model,
+ ));
+ }
+
+ /**
+ * Returns the data model based on the primary key given in the GET variable.
+ * If the data model is not found, an HTTP exception will be raised.
+ * @param integer $id the ID of the model to be loaded
+ * @return modelClass; ?> the loaded model
+ * @throws CHttpException
+ */
+ public function loadModel($id)
+ {
+ $model=modelClass; ?>::model()->findByPk($id);
+ if ($model===null) {
+ throw new CHttpException(404,'The requested page does not exist.');
+ }
+ return $model;
+ }
+
+ /**
+ * Performs the AJAX validation.
+ * @param modelClass; ?> $model the model to be validated
+ */
+ protected function performAjaxValidation($model)
+ {
+ if (isset($_POST['ajax']) && $_POST['ajax']==='class2id($this->modelClass); ?>-form') {
+ echo CActiveForm::validate($model);
+ Yii::app()->end();
+ }
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/create.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/create.php
new file mode 100644
index 0000000..191a301
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/create.php
@@ -0,0 +1,29 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+\n"; ?>
+
+pluralize($this->class2name($this->modelClass));
+echo "\$this->breadcrumbs=array(
+ '$label'=>array('index'),
+ 'Create',
+);\n";
+?>
+
+$this->menu=array(
+ array('label'=>'List modelClass; ?>', 'url'=>array('index')),
+ array('label'=>'Manage modelClass; ?>', 'url'=>array('admin')),
+);
+?>
+
+Create modelClass; ?>
+
+renderPartial('_form', array('model'=>\$model)); ?>"; ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/index.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/index.php
new file mode 100644
index 0000000..6bcd1c1
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/index.php
@@ -0,0 +1,31 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $dataProvider CActiveDataProvider */
+\n"; ?>
+
+pluralize($this->class2name($this->modelClass));
+echo "\$this->breadcrumbs=array(
+ '$label',
+);\n";
+?>
+
+$this->menu=array(
+ array('label'=>'Create modelClass; ?>','url'=>array('create')),
+ array('label'=>'Manage modelClass; ?>','url'=>array('admin')),
+);
+?>
+
+
+
+ $this->widget('bootstrap.widgets.TbListView',array(
+ 'dataProvider'=>$dataProvider,
+ 'itemView'=>'_view',
+)); ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/update.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/update.php
new file mode 100644
index 0000000..3ed3aaa
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/update.php
@@ -0,0 +1,33 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+\n"; ?>
+
+guessNameColumn($this->tableSchema->columns);
+$label = $this->pluralize($this->class2name($this->modelClass));
+echo "\$this->breadcrumbs=array(
+ '$label'=>array('index'),
+ \$model->{$nameColumn}=>array('view','id'=>\$model->{$this->tableSchema->primaryKey}),
+ 'Update',
+);\n";
+?>
+
+$this->menu=array(
+ array('label'=>'List modelClass; ?>', 'url'=>array('index')),
+ array('label'=>'Create modelClass; ?>', 'url'=>array('create')),
+ array('label'=>'View modelClass; ?>', 'url'=>array('view', 'id'=>$model->tableSchema->primaryKey; ?>)),
+ array('label'=>'Manage modelClass; ?>', 'url'=>array('admin')),
+);
+?>
+
+ Update modelClass . " {$this->tableSchema->primaryKey}; ?>"; ?>
+
+renderPartial('_form', array('model'=>\$model)); ?>"; ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/view.php b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/view.php
new file mode 100644
index 0000000..00a41b1
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/templates/default/view.php
@@ -0,0 +1,45 @@
+
+
+/* @var $this getControllerClass(); ?> */
+/* @var $model getModelClass(); ?> */
+\n"; ?>
+
+guessNameColumn($this->tableSchema->columns);
+$label = $this->pluralize($this->class2name($this->modelClass));
+echo "\$this->breadcrumbs=array(
+ '$label'=>array('index'),
+ \$model->{$nameColumn},
+);\n";
+?>
+
+$this->menu=array(
+ array('label'=>'List modelClass; ?>', 'url'=>array('index')),
+ array('label'=>'Create modelClass; ?>', 'url'=>array('create')),
+ array('label'=>'Update modelClass; ?>', 'url'=>array('update', 'id'=>$model->tableSchema->primaryKey; ?>)),
+ array('label'=>'Delete modelClass; ?>', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->tableSchema->primaryKey; ?>),'confirm'=>'Are you sure you want to delete this item?')),
+ array('label'=>'Manage modelClass; ?>', 'url'=>array('admin')),
+);
+?>
+
+View modelClass . " #{$this->tableSchema->primaryKey}; ?>"; ?>
+
+ $this->widget('zii.widgets.CDetailView',array(
+ 'htmlOptions' => array(
+ 'class' => 'table table-striped table-condensed table-hover',
+ ),
+ 'data'=>$model,
+ 'attributes'=>array(
+tableSchema->columns as $column) {
+ echo "\t\t'" . $column->name . "',\n";
+}
+?>
+ ),
+)); ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/gii/bootstrap/views/index.php b/www/protected/extensions/bootstrap/gii/bootstrap/views/index.php
new file mode 100644
index 0000000..7c8628b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/gii/bootstrap/views/index.php
@@ -0,0 +1,67 @@
+clientScript->registerScript(
+ 'gii.crud',
+ "
+$('#{$class}_controller').change(function(){
+ $(this).data('changed',$(this).val()!='');
+});
+$('#{$class}_model').bind('keyup change', function(){
+ var controller=$('#{$class}_controller');
+ if(!controller.data('changed')) {
+ var id=new String($(this).val().match(/\\w*$/));
+ if(id.length>0)
+ id=id.substring(0,1).toLowerCase()+id.substring(1);
+ controller.val(id);
+ }
+});
+"
+);
+?>
+ Bootstrap Generator
+
+ This generator generates a controller and views that implement CRUD operations for the specified data model.
+
+beginWidget('CCodeForm', array('model' => $model)); ?>
+
+
+ labelEx($model, 'model'); ?>
+ textField($model, 'model', array('size' => 65)); ?>
+
+ Model class is case-sensitive. It can be either a class name (e.g. Post
)
+ or the path alias of the class file (e.g. application.models.Post
).
+ Note that if the former, the class must be auto-loadable.
+
+ error($model, 'model'); ?>
+
+
+
+ labelEx($model, 'controller'); ?>
+ textField($model, 'controller', array('size' => 65)); ?>
+
+ error($model, 'controller'); ?>
+
+
+
+ labelEx($model, 'baseControllerClass'); ?>
+ textField($model, 'baseControllerClass', array('size' => 65)); ?>
+
+ This is the class that the new CRUD controller class will extend from.
+ Please make sure the class exists and can be autoloaded.
+
+ error($model, 'baseControllerClass'); ?>
+
+
+endWidget(); ?>
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/helpers/TbArray.php b/www/protected/extensions/bootstrap/helpers/TbArray.php
new file mode 100644
index 0000000..4c6b046
--- /dev/null
+++ b/www/protected/extensions/bootstrap/helpers/TbArray.php
@@ -0,0 +1,151 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.helpers
+ */
+
+/**
+ * Array helper class.
+ */
+class TbArray
+{
+ /**
+ * Returns a specific value from the given array (or the default value if not set).
+ * @param string $key the item key.
+ * @param array $array the array to get from.
+ * @param mixed $defaultValue the default value.
+ * @return mixed the value.
+ */
+ public static function getValue($key, array $array, $defaultValue = null)
+ {
+ return isset($array[$key]) ? $array[$key] : $defaultValue;
+ }
+
+ /**
+ * Removes and returns a specific value from the given array (or the default value if not set).
+ * @param string $key the item key.
+ * @param array $array the array to pop the item from.
+ * @param mixed $defaultValue the default value.
+ * @return mixed the value.
+ */
+ public static function popValue($key, array &$array, $defaultValue = null)
+ {
+ $value = self::getValue($key, $array, $defaultValue);
+ unset($array[$key]);
+ return $value;
+ }
+
+ /**
+ * Sets the default value for a specific key in the given array.
+ * @param string $key the item key.
+ * @param mixed $value the default value.
+ * @param array $array the array.
+ */
+ public static function defaultValue($key, $value, array &$array)
+ {
+ if (!isset($array[$key])) {
+ $array[$key] = $value;
+ }
+ }
+
+ /**
+ * Sets a set of default values for the given array.
+ * @param array $array the array to set values for.
+ * @param array $values the default values.
+ */
+ public static function defaultValues(array $values, array &$array)
+ {
+ foreach ($values as $name => $value) {
+ self::defaultValue($name, $value, $array);
+ }
+ }
+
+ /**
+ * Removes a specific value from the given array.
+ * @param string $key the item key.
+ */
+ public static function removeValue($key, array &$array)
+ {
+ unset($array[$key]);
+ }
+
+ /**
+ * Removes a set of items from the given array.
+ * @param array $keys the keys to remove.
+ * @param array $array the array to remove from.
+ */
+ public static function removeValues(array $keys, array &$array)
+ {
+ $array = array_diff_key($array, array_flip($keys));
+ }
+
+ /**
+ * Copies the given values from one array to another.
+ * @param array $keys the keys to copy.
+ * @param array $from the array to copy from.
+ * @param array $to the array to copy to.
+ * @param boolean $force whether to allow overriding of existing values.
+ * @return array the options.
+ */
+ public static function copyValues(array $keys, array $from, array $to, $force = false)
+ {
+ foreach ($keys as $key) {
+ if (isset($from[$key])) {
+ if ($force || !isset($to[$key])) {
+ $to[$key] = self::getValue($key, $from);
+ }
+ }
+ }
+ return $to;
+ }
+
+ /**
+ * Moves the given values from one array to another.
+ * @param array $keys the keys to move.
+ * @param array $from the array to move from.
+ * @param array $to the array to move to.
+ * @param boolean $force whether to allow overriding of existing values.
+ * @return array the options.
+ */
+ public static function moveValues(array $keys, array &$from, array $to, $force = false)
+ {
+ foreach ($keys as $key) {
+ if (isset($from[$key])) {
+ $value = self::popValue($key, $from);
+ if ($force || !isset($to[$key])) {
+ $to[$key] = $value;
+ unset($from[$key]);
+ }
+ }
+ }
+ return $to;
+ }
+
+ /**
+ * Merges two arrays.
+ * @param array $to array to be merged to.
+ * @param array $from array to be merged from.
+ * @return array the merged array.
+ */
+ public static function merge(array $to, array $from)
+ {
+ $args = func_get_args();
+ $res = array_shift($args);
+ while (!empty($args)) {
+ $next = array_shift($args);
+ foreach ($next as $k => $v) {
+ if (is_integer($k)) {
+ isset($res[$k]) ? $res[] = $v : $res[$k] = $v;
+ } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) {
+ $res[$k] = self::merge($res[$k], $v);
+ } else {
+ $res[$k] = $v;
+ }
+ }
+ }
+ return $res;
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/helpers/TbHtml.php b/www/protected/extensions/bootstrap/helpers/TbHtml.php
new file mode 100644
index 0000000..c749f75
--- /dev/null
+++ b/www/protected/extensions/bootstrap/helpers/TbHtml.php
@@ -0,0 +1,4355 @@
+
+ * @author Christoffer Niska
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.helpers
+ */
+
+/**
+ * Bootstrap HTML helper.
+ */
+class TbHtml extends CHtml // required in order to access the protected methods in CHtml
+{
+ //
+ // TYPOGRAPHY
+ // --------------------------------------------------
+
+ const TEXT_ALIGN_LEFT = 'left';
+ const TEXT_ALIGN_CENTER = 'center';
+ const TEXT_ALIGN_RIGHT = 'right';
+
+ const TEXT_COLOR_DEFAULT = '';
+ const TEXT_COLOR_WARNING = 'warning';
+ const TEXT_COLOR_ERROR = 'error';
+ const TEXT_COLOR_INFO = 'info';
+ const TEXT_COLOR_SUCCESS = 'success';
+
+ const HELP_TYPE_INLINE = 'inline';
+ const HELP_TYPE_BLOCK = 'block';
+
+ //
+ // FORM
+ // --------------------------------------------------
+
+ const FORM_LAYOUT_VERTICAL = 'vertical';
+ const FORM_LAYOUT_HORIZONTAL = 'horizontal';
+ const FORM_LAYOUT_INLINE = 'inline';
+ const FORM_LAYOUT_SEARCH = 'search';
+
+ const INPUT_TYPE_TEXT = 'textField';
+ const INPUT_TYPE_PASSWORD = 'passwordField';
+ const INPUT_TYPE_URL = 'urlField';
+ const INPUT_TYPE_EMAIL = 'emailField';
+ const INPUT_TYPE_NUMBER = 'numberField';
+ const INPUT_TYPE_RANGE = 'rangeField';
+ const INPUT_TYPE_DATE = 'dateField';
+ const INPUT_TYPE_TEXTAREA = 'textArea';
+ const INPUT_TYPE_FILE = 'fileField';
+ const INPUT_TYPE_RADIOBUTTON = 'radioButton';
+ const INPUT_TYPE_CHECKBOX = 'checkBox';
+ const INPUT_TYPE_DROPDOWNLIST = 'dropDownList';
+ const INPUT_TYPE_LISTBOX = 'listBox';
+ const INPUT_TYPE_CHECKBOXLIST = 'checkBoxList';
+ const INPUT_TYPE_INLINECHECKBOXLIST = 'inlineCheckBoxList';
+ const INPUT_TYPE_RADIOBUTTONLIST = 'radioButtonList';
+ const INPUT_TYPE_INLINERADIOBUTTONLIST = 'inlineRadioButtonList';
+ const INPUT_TYPE_UNEDITABLE = 'uneditableField';
+ const INPUT_TYPE_SEARCH = 'searchQuery';
+ const INPUT_TYPE_CUSTOM = 'widget';
+
+ const INPUT_SIZE_MINI = 'mini';
+ const INPUT_SIZE_SMALL = 'small';
+ const INPUT_SIZE_DEFAULT = '';
+ const INPUT_SIZE_MEDIUM = 'medium';
+ const INPUT_SIZE_LARGE = 'large';
+ const INPUT_SIZE_XLARGE = 'xlarge';
+ const INPUT_SIZE_XXLARGE = 'xxlarge';
+
+ const INPUT_COLOR_DEFAULT = '';
+ const INPUT_COLOR_WARNING = 'warning';
+ const INPUT_COLOR_ERROR = 'error';
+ const INPUT_COLOR_INFO = 'info';
+ const INPUT_COLOR_SUCCESS = 'success';
+
+ //
+ // BUTTONS
+ // --------------------------------------------------
+
+ const BUTTON_TYPE_LINK = 'link';
+ const BUTTON_TYPE_HTML = 'htmlButton';
+ const BUTTON_TYPE_SUBMIT = 'submitButton';
+ const BUTTON_TYPE_RESET = 'resetButton';
+ const BUTTON_TYPE_IMAGE = 'imageButton';
+ const BUTTON_TYPE_LINKBUTTON = 'linkButton';
+ const BUTTON_TYPE_AJAXLINK = 'ajaxLink';
+ const BUTTON_TYPE_AJAXBUTTON = 'ajaxButton';
+ const BUTTON_TYPE_INPUTBUTTON = 'inputButton';
+ const BUTTON_TYPE_INPUTSUBMIT = 'inputSubmit';
+
+ const BUTTON_COLOR_DEFAULT = '';
+ const BUTTON_COLOR_PRIMARY = 'primary';
+ const BUTTON_COLOR_INFO = 'info';
+ const BUTTON_COLOR_SUCCESS = 'success';
+ const BUTTON_COLOR_WARNING = 'warning';
+ const BUTTON_COLOR_DANGER = 'danger';
+ const BUTTON_COLOR_INVERSE = 'inverse';
+ const BUTTON_COLOR_LINK = 'link';
+
+ const BUTTON_SIZE_MINI = 'mini';
+ const BUTTON_SIZE_SMALL = 'small';
+ const BUTTON_SIZE_DEFAULT = '';
+ const BUTTON_SIZE_LARGE = 'large';
+
+ const BUTTON_TOGGLE_CHECKBOX = 'checkbox';
+ const BUTTON_TOGGLE_RADIO = 'radio';
+
+ //
+ // IMAGES
+ // --------------------------------------------------
+
+ const IMAGE_TYPE_ROUNDED = 'rounded';
+ const IMAGE_TYPE_CIRCLE = 'circle';
+ const IMAGE_TYPE_POLAROID = 'polaroid';
+
+ //
+ // NAV
+ // --------------------------------------------------
+
+ const NAV_TYPE_NONE = '';
+ const NAV_TYPE_TABS = 'tabs';
+ const NAV_TYPE_PILLS = 'pills';
+ const NAV_TYPE_LIST = 'list';
+
+ const TABS_PLACEMENT_ABOVE = '';
+ const TABS_PLACEMENT_BELOW = 'below';
+ const TABS_PLACEMENT_LEFT = 'left';
+ const TABS_PLACEMENT_RIGHT = 'right';
+
+ //
+ // NAVBAR
+ // --------------------------------------------------
+
+ const NAVBAR_DISPLAY_NONE = '';
+ const NAVBAR_DISPLAY_FIXEDTOP = 'fixed-top';
+ const NAVBAR_DISPLAY_FIXEDBOTTOM = 'fixed-bottom';
+ const NAVBAR_DISPLAY_STATICTOP = 'static-top';
+
+ const NAVBAR_COLOR_INVERSE = 'inverse';
+
+ //
+ // PAGINATION
+ // --------------------------------------------------
+
+ const PAGINATION_SIZE_MINI = 'mini';
+ const PAGINATION_SIZE_SMALL = 'small';
+ const PAGINATION_SIZE_DEFAULT = '';
+ const PAGINATION_SIZE_LARGE = 'large';
+
+ const PAGINATION_ALIGN_LEFT = 'left';
+ const PAGINATION_ALIGN_CENTER = 'centered';
+ const PAGINATION_ALIGN_RIGHT = 'right';
+
+ //
+ // LABELS AND BADGES
+ // --------------------------------------------------
+
+ const LABEL_COLOR_DEFAULT = '';
+ const LABEL_COLOR_SUCCESS = 'success';
+ const LABEL_COLOR_WARNING = 'warning';
+ const LABEL_COLOR_IMPORTANT = 'important';
+ const LABEL_COLOR_INFO = 'info';
+ const LABEL_COLOR_INVERSE = 'inverse';
+
+ const BADGE_COLOR_DEFAULT = '';
+ const BADGE_COLOR_SUCCESS = 'success';
+ const BADGE_COLOR_WARNING = 'warning';
+ const BADGE_COLOR_IMPORTANT = 'important';
+ const BADGE_COLOR_INFO = 'info';
+ const BADGE_COLOR_INVERSE = 'inverse';
+
+ //
+ // TOOLTIPS AND POPOVERS
+ // --------------------------------------------------
+
+ const TOOLTIP_PLACEMENT_TOP = 'top';
+ const TOOLTIP_PLACEMENT_BOTTOM = 'bottom';
+ const TOOLTIP_PLACEMENT_LEFT = 'left';
+ const TOOLTIP_PLACEMENT_RIGHT = 'right';
+
+ const TOOLTIP_TRIGGER_CLICK = 'click';
+ const TOOLTIP_TRIGGER_HOVER = 'hover';
+ const TOOLTIP_TRIGGER_FOCUS = 'focus';
+ const TOOLTIP_TRIGGER_MANUAL = 'manual';
+
+ const POPOVER_PLACEMENT_TOP = 'top';
+ const POPOVER_PLACEMENT_BOTTOM = 'bottom';
+ const POPOVER_PLACEMENT_LEFT = 'left';
+ const POPOVER_PLACEMENT_RIGHT = 'right';
+
+ const POPOVER_TRIGGER_CLICK = 'click';
+ const POPOVER_TRIGGER_HOVER = 'hover';
+ const POPOVER_TRIGGER_FOCUS = 'focus';
+ const POPOVER_TRIGGER_MANUAL = 'manual';
+
+ //
+ // ALERT
+ // --------------------------------------------------
+
+ const ALERT_COLOR_DEFAULT = '';
+ const ALERT_COLOR_INFO = 'info';
+ const ALERT_COLOR_SUCCESS = 'success';
+ const ALERT_COLOR_WARNING = 'warning';
+ const ALERT_COLOR_ERROR = 'error';
+ const ALERT_COLOR_DANGER = 'danger';
+
+ //
+ // PROGRESS BARS
+ // --------------------------------------------------
+
+ const PROGRESS_COLOR_DEFAULT = '';
+ const PROGRESS_COLOR_INFO = 'info';
+ const PROGRESS_COLOR_SUCCESS = 'success';
+ const PROGRESS_COLOR_WARNING = 'warning';
+ const PROGRESS_COLOR_DANGER = 'danger';
+
+ //
+ // MISC
+ // --------------------------------------------------
+
+ const WELL_SIZE_SMALL = 'small';
+ const WELL_SIZE_DEFAULT = '';
+ const WELL_SIZE_LARGE = 'large';
+
+ const PULL_LEFT = 'left';
+ const PULL_RIGHT = 'right';
+
+ const CLOSE_DISMISS_ALERT = 'alert';
+ const CLOSE_DISMISS_MODAL = 'modal';
+
+ //
+ // DETAIL VIEW
+ // --------------------------------------------------
+
+ const DETAIL_TYPE_STRIPED = 'striped';
+ const DETAIL_TYPE_BORDERED = 'bordered';
+ const DETAIL_TYPE_CONDENSED = 'condensed';
+ const DETAIL_TYPE_HOVER = 'hover';
+
+ //
+ // GRID VIEW
+ // --------------------------------------------------
+
+ const GRID_TYPE_STRIPED = 'striped';
+ const GRID_TYPE_BORDERED = 'bordered';
+ const GRID_TYPE_CONDENSED = 'condensed';
+ const GRID_TYPE_HOVER = 'hover';
+
+ //
+ // AFFIX
+ // --------------------------------------------------
+
+ const AFFIX_POSITION_TOP = 'top';
+ const AFFIX_POSITION_BOTTOM = 'bottom';
+
+ //
+ // ICON
+ // --------------------------------------------------
+
+ const ICON_COLOR_DEFAULT = '';
+ const ICON_COLOR_WHITE = 'white';
+
+ const ICON_GLASS = 'icon-glass';
+ const ICON_MUSIC = 'icon-music';
+ const ICON_SEARCH = 'icon-search';
+ const ICON_ENVELOPE = 'icon-envelope';
+ const ICON_HEART = 'icon-heart';
+ const ICON_STAR = 'icon-star';
+ const ICON_STAR_EMPTY = 'icon-star-empty';
+ const ICON_USER = 'icon-user';
+ const ICON_FILM = 'icon-film';
+ const ICON_TH_LARGE = 'icon-th-large';
+ const ICON_TH = 'icon-th';
+ const ICON_TH_LIST = 'icon-th-list';
+ const ICON_OK = 'icon-ok';
+ const ICON_REMOVE = 'icon-remove';
+ const ICON_ZOOM_IN = 'icon-zoom-in';
+ const ICON_ZOOM_OUT = 'icon-zoom-out';
+ const ICON_OFF = 'icon-off';
+ const ICON_SIGNAL = 'icon-signal';
+ const ICON_COG = 'icon-cog';
+ const ICON_TRASH = 'icon-trash';
+ const ICON_HOME = 'icon-home';
+ const ICON_FILE = 'icon-file';
+ const ICON_TIME = 'icon-time';
+ const ICON_ROAD = 'icon-road';
+ const ICON_DOWNLOAD_ALT = 'icon-download-alt';
+ const ICON_DOWNLOAD = 'icon-download';
+ const ICON_UPLOAD = 'icon-upload';
+ const ICON_INBOX = 'icon-inbox';
+ const ICON_PLAY_CIRCLE = 'icon-play-circle';
+ const ICON_REPEAT = 'icon-repeat';
+ const ICON_REFRESH = 'icon-refresh';
+ const ICON_LIST_ALT = 'icon-list-alt';
+ const ICON_LOCK = 'icon-lock';
+ const ICON_FLAG = 'icon-flag';
+ const ICON_HEADPHONES = 'icon-headphones';
+ const ICON_VOLUME_OFF = 'icon-volume-off';
+ const ICON_VOLUME_DOWN = 'icon-volume-down';
+ const ICON_VOLUME_UP = 'icon-volume-up';
+ const ICON_QRCODE = 'icon-qrcode';
+ const ICON_BARCODE = 'icon-barcode';
+ const ICON_TAG = 'icon-tag';
+ const ICON_TAGS = 'icon-tags';
+ const ICON_BOOK = 'icon-book';
+ const ICON_BOOKMARK = 'icon-bookmark';
+ const ICON_PRINT = 'icon-print';
+ const ICON_CAMERA = 'icon-camera';
+ const ICON_FONT = 'icon-font';
+ const ICON_BOLD = 'icon-bold';
+ const ICON_ITALIC = 'icon-italic';
+ const ICON_TEXT_HEIGHT = 'icon-text-height';
+ const ICON_TEXT_WIDTH = 'icon-text-width';
+ const ICON_ALIGN_LEFT = 'icon-align-left';
+ const ICON_ALIGN_CENTER = 'icon-align-center';
+ const ICON_ALIGN_RIGHT = 'icon-align-right';
+ const ICON_ALIGN_JUSTIFY = 'icon-align-justify';
+ const ICON_LIST = 'icon-list';
+ const ICON_INDENT_LEFT = 'icon-indent-left';
+ const ICON_INDENT_RIGHT = 'icon-indent-right';
+ const ICON_FACETIME_VIDEO = 'icon-facetime-video';
+ const ICON_PICTURE = 'icon-picture';
+ const ICON_PENCIL = 'icon-pencil';
+ const ICON_MAP_MARKER = 'icon-map-marker';
+ const ICON_ADJUST = 'icon-adjust';
+ const ICON_TINT = 'icon-tint';
+ const ICON_EDIT = 'icon-edit';
+ const ICON_SHARE = 'icon-share';
+ const ICON_CHECK = 'icon-check';
+ const ICON_MOVE = 'icon-move';
+ const ICON_STEP_BACKWARD = 'icon-step-backward';
+ const ICON_FAST_BACKWARD = 'icon-fast-backward';
+ const ICON_BACKWARD = 'icon-backward';
+ const ICON_PLAY = 'icon-play';
+ const ICON_PAUSE = 'icon-pause';
+ const ICON_STOP = 'icon-pause';
+ const ICON_FORWARD = 'icon-forward';
+ const ICON_FAST_FORWARD = 'icon-fast-forward';
+ const ICON_STEP_FORWARD = 'icon-step-forward';
+ const ICON_EJECT = 'icon-eject';
+ const ICON_CHEVRON_LEFT = 'icon-chevron-left';
+ const ICON_CHEVRON_RIGHT = 'icon-chevron-right';
+ const ICON_PLUS_SIGN = 'icon-plus-sign';
+ const ICON_MINUS_SIGN = 'icon-minus-sign';
+ const ICON_REMOVE_SIGN = 'icon-remove-sign';
+ const ICON_OK_SIGN = 'icon-ok-sign';
+ const ICON_QUESTION_SIGN = 'icon-question-sign';
+ const ICON_INFO_SIGN = 'icon-info-sign';
+ const ICON_SCREENSHOT = 'icon-screenshot';
+ const ICON_REMOVE_CIRCLE = 'icon-remove-circle';
+ const ICON_OK_CIRCLE = 'icon-ok-circle';
+ const ICON_BAN_CIRCLE = 'icon-ban-circle';
+ const ICON_ARROW_LEFT = 'icon-arrow-left';
+ const ICON_ARROW_RIGHT = 'icon-arrow-right';
+ const ICON_ARROW_UP = 'icon-arrow-up';
+ const ICON_ARROW_DOWN = 'icon-arrow-down';
+ const ICON_SHARE_ALT = 'icon-share-alt';
+ const ICON_RESIZE_FULL = 'icon-resize-full';
+ const ICON_RESIZE_SMALL = 'icon-resize-small';
+ const ICON_PLUS = 'icon-plus';
+ const ICON_MINUS = 'icon-minus';
+ const ICON_ASTERISK = 'icon-asterisk';
+ const ICON_EXCLAMATION_SIGN = 'icon-exclamation-sign';
+ const ICON_GIFT = 'icon-gift';
+ const ICON_LEAF = 'icon-leaf';
+ const ICON_FIRE = 'icon-fire';
+ const ICON_EYE_OPEN = 'icon-eye-open';
+ const ICON_EYE_CLOSE = 'icon-eye-close';
+ const ICON_WARNING_SIGN = 'icon-warning-sign';
+ const ICON_PLANE = 'icon-plane';
+ const ICON_CALENDAR = 'icon-calendar';
+ const ICON_RANDOM = 'icon-random';
+ const ICON_COMMENT = 'icon-comment';
+ const ICON_MAGNET = 'icon-magnet';
+ const ICON_CHEVRON_UP = 'icon-chevron-up';
+ const ICON_CHEVRON_DOWN = 'icon-chevron-down';
+ const ICON_RETWEET = 'icon-retweet';
+ const ICON_SHOPPING_CART = 'icon-shopping-cart';
+ const ICON_FOLDER_CLOSE = 'icon-folder-close';
+ const ICON_FOLDER_OPEN = 'icon-folder-open';
+ const ICON_RESIZE_VERTICAL = 'icon-resize-vertical';
+ const ICON_RESIZE_HORIZONTAL = 'icon-resize-horizontal';
+ const ICON_HDD = 'icon-hdd';
+ const ICON_BULLHORN = 'icon-bullhorn';
+ const ICON_BELL = 'icon-bell';
+ const ICON_CERTFICATE = 'icon-certificate';
+ const ICON_THUMBS_UP = 'icon-thumbs-up';
+ const ICON_THUMBS_DOWN = 'icon-thumbs-down';
+ const ICON_HAND_RIGHT = 'icon-hand-right';
+ const ICON_HAND_LEFT = 'icon-hand-left';
+ const ICON_HAND_UP = 'icon-hand-up';
+ const ICON_HAND_DOWN = 'icon-hand-down';
+ const ICON_CIRCLE_ARROW_RIGHT = 'icon-circle-arrow-right';
+ const ICON_CIRCLE_ARROW_LEFT = 'icon-circle-arrow-left';
+ const ICON_CIRCLE_ARROW_UP = 'icon-circle-arrow-up';
+ const ICON_CIRCLE_ARROW_DOWN = 'icon-circle-arrow-down';
+ const ICON_GLOBE = 'icon-globe';
+ const ICON_WRENCH = 'icon-wrench';
+ const ICON_TASKS = 'icon-tasks';
+ const ICON_FILTER = 'icon-filter';
+ const ICON_BRIEFCASE = 'icon-briefcase';
+ const ICON_FULLSCREEN = 'icon-fullscreen';
+
+ // Default close text.
+ const CLOSE_TEXT = '×';
+
+ /**
+ * @var string the CSS class for displaying error summaries.
+ */
+ public static $errorSummaryCss = 'alert alert-block alert-error';
+
+ //
+ // BASE CSS
+ // --------------------------------------------------
+
+ // Typography
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#typography
+ // --------------------------------------------------
+
+ /**
+ * Generates a paragraph that stands out.
+ * @param string $text the lead text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated paragraph.
+ */
+ public static function lead($text, $htmlOptions = array())
+ {
+ self::addCssClass('lead', $htmlOptions);
+ return self::tag('p', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates small text.
+ * @param string $text the text to style.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text.
+ */
+ public static function small($text, $htmlOptions = array())
+ {
+ return self::tag('small', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates bold text.
+ * @param string $text the text to style.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text.
+ */
+ public static function b($text, $htmlOptions = array())
+ {
+ return self::tag('strong', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates italic text.
+ * @param string $text the text to style.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text.
+ */
+ public static function i($text, $htmlOptions = array())
+ {
+ return self::tag('em', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates an emphasized text.
+ * @param string $style the text style.
+ * @param string $text the text to emphasize.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param string $tag the HTML tag.
+ * @return string the generated text.
+ */
+ public static function em($text, $htmlOptions = array(), $tag = 'p')
+ {
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (TbArray::popValue('muted', $htmlOptions, false)) {
+ self::addCssClass('muted', $htmlOptions);
+ } else {
+ if (!empty($color)) {
+ self::addCssClass('text-' . $color, $htmlOptions);
+ }
+ }
+ return self::tag($tag, $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a muted text block.
+ * @param string $text the text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param string $tag the HTML tag.
+ * @return string the generated text block.
+ */
+ public static function muted($text, $htmlOptions = array(), $tag = 'p')
+ {
+ $htmlOptions['muted'] = true;
+ return self::em($text, $htmlOptions, $tag);
+ }
+
+ /**
+ * Generates a muted span.
+ * @param string $text the text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param string $tag the HTML tag.
+ * @return string the generated span.
+ */
+ public static function mutedSpan($text, $htmlOptions = array())
+ {
+ return self::muted($text, $htmlOptions, 'span');
+ }
+
+ /**
+ * Generates an abbreviation with a help text.
+ * @param string $text the abbreviation.
+ * @param string $word the word the abbreviation is for.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated abbreviation.
+ */
+ public static function abbr($text, $word, $htmlOptions = array())
+ {
+ if (TbArray::popValue('small', $htmlOptions, false)) {
+ self::addCssClass('initialism', $htmlOptions);
+ }
+ $htmlOptions['title'] = $word;
+ return self::tag('abbr', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a small abbreviation with a help text.
+ * @param string $text the abbreviation.
+ * @param string $word the word the abbreviation is for.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated abbreviation.
+ */
+ public static function smallAbbr($text, $word, $htmlOptions = array())
+ {
+ $htmlOptions['small'] = true;
+ return self::abbr($text, $word, $htmlOptions);
+ }
+
+ /**
+ * Generates an address block.
+ * @param string $quote the address text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated block.
+ */
+ public static function address($text, $htmlOptions = array())
+ {
+ return self::tag('address', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a quote.
+ * @param string $text the quoted text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated quote.
+ */
+ public static function quote($text, $htmlOptions = array())
+ {
+ $paragraphOptions = TbArray::popValue('paragraphOptions', $htmlOptions, array());
+ $source = TbArray::popValue('source', $htmlOptions);
+ $sourceOptions = TbArray::popValue('sourceOptions', $htmlOptions, array());
+ $cite = TbArray::popValue('cite', $htmlOptions);
+ $citeOptions = TbArray::popValue('citeOptions', $htmlOptions, array());
+ $cite = isset($cite) ? ' ' . self::tag('cite', $citeOptions, $cite) : '';
+ $source = isset($source) ? self::tag('small', $sourceOptions, $source . $cite) : '';
+ $text = self::tag('p', $paragraphOptions, $text) . $source;
+ return self::tag('blockquote', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a help text.
+ * @param string $text the help text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text.
+ */
+ public static function help($text, $htmlOptions = array())
+ {
+ $type = TbArray::popValue('type', $htmlOptions, self::HELP_TYPE_INLINE);
+ self::addCssClass('help-' . $type, $htmlOptions);
+ return self::tag($type === self::HELP_TYPE_INLINE ? 'span' : 'p', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a help block.
+ * @param string $text the help text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated block.
+ */
+ public static function helpBlock($text, $htmlOptions = array())
+ {
+ $htmlOptions['type'] = self::HELP_TYPE_BLOCK;
+ return self::help($text, $htmlOptions);
+ }
+
+ // Code
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#code
+ // --------------------------------------------------
+
+ /**
+ * Generates inline code.
+ * @param string $code the code.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated code.
+ */
+ public static function code($code, $htmlOptions = array())
+ {
+ return self::tag('code', $htmlOptions, $code);
+ }
+
+ /**
+ * Generates a code block.
+ * @param string $code the code.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated block.
+ */
+ public static function codeBlock($code, $htmlOptions = array())
+ {
+ return self::tag('pre', $htmlOptions, $code);
+ }
+
+ /**
+ * Generates an HTML element.
+ * @param string $tag the tag name.
+ * @param array $htmlOptions the element attributes.
+ * @param mixed $content the content to be enclosed between open and close element tags.
+ * @param boolean $closeTag whether to generate the close tag.
+ * @return string the generated HTML element tag.
+ */
+ public static function tag($tag, $htmlOptions = array(), $content = false, $closeTag = true)
+ {
+ self::addSpanClass($htmlOptions);
+ self::addPullClass($htmlOptions);
+ self::addTextAlignClass($htmlOptions);
+ return parent::tag($tag, $htmlOptions, $content, $closeTag);
+ }
+
+ /**
+ * Generates an open HTML element.
+ * @param string $tag the tag name.
+ * @param array $htmlOptions the element attributes.
+ * @return string the generated HTML element tag.
+ */
+ public static function openTag($tag, $htmlOptions = array())
+ {
+ return self::tag($tag, $htmlOptions, false, false);
+ }
+
+ // Tables
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#forms
+ // --------------------------------------------------
+
+ // todo: create table methods here.
+
+ // Forms
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#tables
+ // --------------------------------------------------
+
+ /**
+ * Generates a form tag.
+ * @param string $layout the form layout.
+ * @param string $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated tag.
+ */
+ public static function formTb(
+ $layout = self::FORM_LAYOUT_VERTICAL,
+ $action = '',
+ $method = 'post',
+ $htmlOptions = array()
+ ) {
+ return self::beginFormTb($layout, $action, $method, $htmlOptions);
+ }
+
+ /**
+ * Generates an open form tag.
+ * @param string $layout the form layout.
+ * @param string $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated tag.
+ */
+ public static function beginFormTb(
+ $layout = self::FORM_LAYOUT_VERTICAL,
+ $action = '',
+ $method = 'post',
+ $htmlOptions = array()
+ ) {
+ if (!empty($layout)) {
+ self::addCssClass('form-' . $layout, $htmlOptions);
+ }
+ return parent::beginForm($action, $method, $htmlOptions);
+ }
+
+ /**
+ * Generates a stateful form tag.
+ * @param mixed $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated form tag.
+ */
+ public static function statefulFormTb(
+ $layout = self::FORM_LAYOUT_VERTICAL,
+ $action = '',
+ $method = 'post',
+ $htmlOptions = array()
+ ) {
+ return self::formTb($layout, $action, $method, $htmlOptions)
+ . self::tag('div', array('style' => 'display: none'), parent::pageStateField(''));
+ }
+
+ /**
+ * Generates a text field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function textField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('text', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a password field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function passwordField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('password', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates an url field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function urlField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('url', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates an email field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function emailField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('email', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a number field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function numberField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('number', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a range field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function rangeField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('range', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a date field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::textInputField
+ */
+ public static function dateField($name, $value = '', $htmlOptions = array())
+ {
+ return self::textInputField('date', $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a file field input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see CHtml::fileField
+ */
+ public static function fileField($name, $value = '', $htmlOptions = array())
+ {
+ return parent::fileField($name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a text area input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text area.
+ */
+ public static function textArea($name, $value = '', $htmlOptions = array())
+ {
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+ return parent::textArea($name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a radio button.
+ * @param string $name the input name.
+ * @param boolean $checked whether the radio button is checked.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated radio button.
+ */
+ public static function radioButton($name, $checked = false, $htmlOptions = array())
+ {
+ $label = TbArray::popValue('label', $htmlOptions, false);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+ self::addCssClass('radio', $labelOptions);
+ $input = parent::radioButton($name, $checked, $htmlOptions);
+ return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
+ }
+
+ /**
+ * Generates a check box.
+ * @param string $name the input name.
+ * @param boolean $checked whether the check box is checked.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated check box.
+ */
+ public static function checkBox($name, $checked = false, $htmlOptions = array())
+ {
+ $label = TbArray::popValue('label', $htmlOptions, false);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+ self::addCssClass('checkbox', $labelOptions);
+ $input = parent::checkBox($name, $checked, $htmlOptions);
+ return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
+ }
+
+ /**
+ * Generates a drop down list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @return string the generated drop down list.
+ */
+ public static function dropDownList($name, $select, $data, $htmlOptions = array())
+ {
+ $displaySize = TbArray::popValue('displaySize', $htmlOptions);
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+ if (!empty($displaySize)) {
+ $htmlOptions['size'] = $displaySize;
+ }
+ return parent::dropDownList($name, $select, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a list box.
+ * @param string $name the input name.
+ * @param mixed $select the selected value(s).
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list box
+ */
+ public static function listBox($name, $select, $data, $htmlOptions = array())
+ {
+ if (isset($htmlOptions['multiple'])) {
+ if (substr($name, -2) !== '[]') {
+ $name .= '[]';
+ }
+ }
+ TbArray::defaultValue('displaySize', 4, $htmlOptions);
+ return self::dropDownList($name, $select, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a radio button list.
+ * @param string $name name of the radio button list.
+ * @param mixed $select selection of the radio buttons.
+ * @param array $data $data value-label pairs used to generate the radio button list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function radioButtonList($name, $select, $data, $htmlOptions = array())
+ {
+ $inline = TbArray::popValue('inline', $htmlOptions, false);
+ $separator = TbArray::popValue('separator', $htmlOptions, ' ');
+ $container = TbArray::popValue('container', $htmlOptions, 'span');
+ $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array());
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+
+ $items = array();
+ $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name));
+
+ $id = 0;
+ foreach ($data as $value => $label) {
+ $checked = !strcmp($value, $select);
+ $htmlOptions['value'] = $value;
+ $htmlOptions['id'] = $baseID . '_' . $id++;
+ if ($inline) {
+ $htmlOptions['label'] = $label;
+ self::addCssClass('inline', $labelOptions);
+ $htmlOptions['labelOptions'] = $labelOptions;
+ $items[] = self::radioButton($name, $checked, $htmlOptions);
+ } else {
+ $option = self::radioButton($name, $checked, $htmlOptions);
+ self::addCssClass('radio', $labelOptions);
+ $items[] = self::label($option . ' ' . $label, false, $labelOptions);
+ }
+ }
+
+ $inputs = implode($separator, $items);
+ return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
+ }
+
+ /**
+ * Generates an inline radio button list.
+ * @param string $name name of the radio button list.
+ * @param mixed $select selection of the radio buttons.
+ * @param array $data $data value-label pairs used to generate the radio button list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function inlineRadioButtonList($name, $select, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return self::radioButtonList($name, $select, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a check box list.
+ * @param string $name name of the check box list.
+ * @param mixed $select selection of the check boxes.
+ * @param array $data $data value-label pairs used to generate the check box list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function checkBoxList($name, $select, $data, $htmlOptions = array())
+ {
+ $inline = TbArray::popValue('inline', $htmlOptions, false);
+ $separator = TbArray::popValue('separator', $htmlOptions, ' ');
+ $container = TbArray::popValue('container', $htmlOptions, 'span');
+ $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array());
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+
+ if (substr($name, -2) !== '[]') {
+ $name .= '[]';
+ }
+
+ $checkAll = TbArray::popValue('checkAll', $htmlOptions);
+ $checkAllLast = TbArray::popValue('checkAllLast', $htmlOptions);
+ if ($checkAll !== null) {
+ $checkAllLabel = $checkAll;
+ $checkAllLast = $checkAllLast !== null;
+ }
+
+ $items = array();
+ $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name));
+ $id = 0;
+ $checkAll = true;
+
+ foreach ($data as $value => $label) {
+ $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select);
+ $checkAll = $checkAll && $checked;
+ $htmlOptions['value'] = $value;
+ $htmlOptions['id'] = $baseID . '_' . $id++;
+ if ($inline) {
+ $htmlOptions['label'] = $label;
+ self::addCssClass('inline', $labelOptions);
+ $htmlOptions['labelOptions'] = $labelOptions;
+ $items[] = self::checkBox($name, $checked, $htmlOptions);
+ } else {
+ self::addCssClass('checkbox', $labelOptions);
+ $option = self::checkBox($name, $checked, $htmlOptions);
+ $items[] = self::label($option . ' ' . $label, false, $labelOptions);
+ }
+ }
+
+ if (isset($checkAllLabel)) {
+ $htmlOptions['value'] = 1;
+ $htmlOptions['id'] = $id = $baseID . '_all';
+ $option = self::checkBox($id, $checkAll, $htmlOptions);
+ $item = self::label($option . ' ' . $checkAllLabel, false, $labelOptions);
+ if ($checkAllLast) {
+ $items[] = $item;
+ } else {
+ array_unshift($items, $item);
+ }
+ $name = strtr($name, array('[' => '\\[', ']' => '\\]'));
+ $js = <<getClientScript();
+ $cs->registerCoreScript('jquery');
+ $cs->registerScript($id, $js);
+ }
+
+ $inputs = implode($separator, $items);
+ return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
+ }
+
+ /**
+ * Generates an inline check box list.
+ * @param string $name name of the check box list.
+ * @param mixed $select selection of the check boxes.
+ * @param array $data $data value-label pairs used to generate the check box list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function inlineCheckBoxList($name, $select, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return self::checkBoxList($name, $select, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates an uneditable input.
+ * @param string $value the value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input.
+ */
+ public static function uneditableField($value, $htmlOptions = array())
+ {
+ self::addCssClass('uneditable-input', $htmlOptions);
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+ return self::tag('span', $htmlOptions, $value);
+ }
+
+ /**
+ * Generates a search input.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input.
+ */
+ public static function searchQueryField($name, $value = '', $htmlOptions = array())
+ {
+ self::addCssClass('search-query', $htmlOptions);
+ return self::textField($name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a text field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function textFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_TEXT, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a password field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::textInputField
+ */
+ public static function passwordFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_PASSWORD, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with an url field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function urlFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_URL, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with an email field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function emailFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_EMAIL, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a number field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::textInputField
+ */
+ public static function numberFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_NUMBER, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a range field.
+ * @param string $name the input name
+ * @param string $value the input value
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function rangeFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_RANGE, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a file field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function dateFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_DATE, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a text area.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function textAreaControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_TEXTAREA, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a file field.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function fileFieldControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_FILE, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a radio button.
+ * @param string $name the input name.
+ * @param string $checked whether the radio button is checked.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function radioButtonControlGroup($name, $checked = false, $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_RADIOBUTTON, $name, $checked, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a check box.
+ * @param string $name the input name.
+ * @param string $checked whether the check box is checked.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function checkBoxControlGroup($name, $checked = false, $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_CHECKBOX, $name, $checked, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a drop down list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function dropDownListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_DROPDOWNLIST, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a list box.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function listBoxControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_LISTBOX, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a radio button list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function radioButtonListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline radio button list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function inlineRadioButtonListControlGroup(
+ $name,
+ $select = '',
+ $data = array(),
+ $htmlOptions = array()
+ ) {
+ return self::controlGroup(self::INPUT_TYPE_INLINERADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a check box list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function checkBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_CHECKBOXLIST, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline check box list.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function inlineCheckBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $name, $select, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an uneditable field.
+ * @param string $select the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function uneditableFieldControlGroup($value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_UNEDITABLE, '', $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a search field.
+ * @param string $name the input name.
+ * @param string $select the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::controlGroup
+ */
+ public static function searchQueryControlGroup($name, $value = '', $htmlOptions = array())
+ {
+ return self::controlGroup(self::INPUT_TYPE_SEARCH, $name, $value, $htmlOptions);
+ }
+
+ /**
+ * Generates a form control group.
+ * @param string $type the input type.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for multiple select inputs.
+ * @return string the generated control group.
+ */
+ public static function controlGroup($type, $name, $value = '', $htmlOptions = array(), $data = array())
+ {
+ $color = TbArray::popValue('color', $htmlOptions);
+ $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
+ $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array());
+ $label = TbArray::popValue('label', $htmlOptions);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+
+ if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON))) {
+ $htmlOptions['label'] = $label;
+ $htmlOptions['labelOptions'] = $labelOptions;
+ $label = false;
+ }
+
+ $help = TbArray::popValue('help', $htmlOptions, '');
+ $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array());
+ if (!empty($help)) {
+ $help = self::inputHelp($help, $helpOptions);
+ }
+
+ $input = isset($htmlOptions['input'])
+ ? $htmlOptions['input']
+ : self::createInput($type, $name, $value, $htmlOptions, $data);
+
+ self::addCssClass('control-group', $groupOptions);
+ if (!empty($color)) {
+ self::addCssClass($color, $groupOptions);
+ }
+ self::addCssClass('control-label', $labelOptions);
+ $output = self::openTag('div', $groupOptions);
+ if ($label !== false) {
+ $output .= parent::label($label, $name, $labelOptions);
+ }
+ $output .= self::controls($input . $help, $controlOptions);
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a custom (pre-rendered) form control group.
+ * @param string $input the rendered input.
+ * @param string $name the input name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ */
+ public static function customControlGroup($input, $name, $htmlOptions = array())
+ {
+ $htmlOptions['input'] = $input;
+ return self::controlGroup(self::INPUT_TYPE_CUSTOM, $name, '', $htmlOptions);
+ }
+
+ /**
+ * Creates a form input of the given type.
+ * @param string $type the input type.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for multiple select inputs.
+ * @return string the input.
+ * @throws CException if the input type is invalid.
+ */
+ public static function createInput($type, $name, $value, $htmlOptions = array(), $data = array())
+ {
+ switch ($type) {
+ case self::INPUT_TYPE_TEXT:
+ return self::textField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_PASSWORD:
+ return self::passwordField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_URL:
+ return self::urlField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_EMAIL:
+ return self::emailField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_NUMBER:
+ return self::numberField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_RANGE:
+ return self::rangeField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_DATE:
+ return self::dateField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_TEXTAREA:
+ return self::textArea($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_FILE:
+ return self::fileField($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_RADIOBUTTON:
+ return self::radioButton($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_CHECKBOX:
+ return self::checkBox($name, $value, $htmlOptions);
+ case self::INPUT_TYPE_DROPDOWNLIST:
+ return self::dropDownList($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_LISTBOX:
+ return self::listBox($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_CHECKBOXLIST:
+ return self::checkBoxList($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_INLINECHECKBOXLIST:
+ return self::inlineCheckBoxList($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_RADIOBUTTONLIST:
+ return self::radioButtonList($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
+ return self::inlineRadioButtonList($name, $value, $data, $htmlOptions);
+ case self::INPUT_TYPE_UNEDITABLE:
+ return self::uneditableField($value, $htmlOptions);
+ case self::INPUT_TYPE_SEARCH:
+ return self::searchQueryField($name, $value, $htmlOptions);
+ default:
+ throw new CException('Invalid input type "' . $type . '".');
+ }
+ }
+
+ /**
+ * Generates an input HTML tag.
+ * This method generates an input HTML tag based on the given input name and value.
+ * @param string $type the input type.
+ * @param string $name the input name.
+ * @param string $value the input value.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input tag.
+ */
+ protected static function textInputField($type, $name, $value, $htmlOptions)
+ {
+ parent::clientChange('change', $htmlOptions);
+
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+
+ $addOnClasses = self::getAddOnClasses($htmlOptions);
+ $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
+ self::addCssClass($addOnClasses, $addOnOptions);
+
+ $prepend = TbArray::popValue('prepend', $htmlOptions, '');
+ $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array());
+ if (!empty($prepend)) {
+ $prepend = self::inputAddOn($prepend, $prependOptions);
+ }
+
+ $append = TbArray::popValue('append', $htmlOptions, '');
+ $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array());
+ if (!empty($append)) {
+ $append = self::inputAddOn($append, $appendOptions);
+ }
+
+ $output = '';
+ if (!empty($addOnClasses)) {
+ $output .= self::openTag('div', $addOnOptions);
+ }
+ $output .= $prepend . parent::inputField($type, $name, $value, $htmlOptions) . $append;
+ if (!empty($addOnClasses)) {
+ $output .= '';
+ }
+ return $output;
+ }
+
+ /**
+ * Generates a text field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeTextField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('text', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a password field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activePasswordField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('password', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an url field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeUrlField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('url', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an email field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeEmailField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('email', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a number field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeNumberField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('number', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a range field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeRangeField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('range', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a date field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see self::activeTextInputField
+ */
+ public static function activeDateField($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeTextInputField('date', $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a file field input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see CHtml::activeFileField
+ */
+ public static function activeFileField($model, $attribute, $htmlOptions = array())
+ {
+ return parent::activeFileField($model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a text area input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text area.
+ */
+ public static function activeTextArea($model, $attribute, $htmlOptions = array())
+ {
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+ return parent::activeTextArea($model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a radio button for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated radio button.
+ */
+ public static function activeRadioButton($model, $attribute, $htmlOptions = array())
+ {
+ $label = TbArray::popValue('label', $htmlOptions, false);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+ self::addCssClass('radio', $labelOptions);
+ $input = parent::activeRadioButton($model, $attribute, $htmlOptions);
+ return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
+ }
+
+ /**
+ * Generates a check box for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated check box.
+ */
+ public static function activeCheckBox($model, $attribute, $htmlOptions = array())
+ {
+ $label = TbArray::popValue('label', $htmlOptions, false);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+ self::addCssClass('checkbox', $labelOptions);
+ $input = parent::activeCheckBox($model, $attribute, $htmlOptions);
+ return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
+ }
+
+ /**
+ * Generates a label for a checkbox or radio input by wrapping the input.
+ * @param string $label the label text.
+ * @param string $input the input.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated label.
+ */
+ protected static function createCheckBoxAndRadioButtonLabel($label, $input, $htmlOptions)
+ {
+ list ($hidden, $input) = self::normalizeCheckBoxAndRadio($input);
+ return $hidden . ($label !== false
+ ? self::tag('label', $htmlOptions, $input . ' ' . $label)
+ : $input);
+ }
+
+ /**
+ * Normalizes the inputs in the given string by splitting them up into an array.
+ * @param string $input the inputs.
+ * @return array an array with the following structure: array($hidden, $input)
+ */
+ protected static function normalizeCheckBoxAndRadio($input)
+ {
+ $parts = preg_split("/(<.*?>)/", $input, 2, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+ if (isset($parts[1])) {
+ return $parts;
+ } else {
+ return array('', $parts[0]);
+ }
+ }
+
+ /**
+ * Generates a drop down list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @return string the generated drop down list.
+ */
+ public static function activeDropDownList($model, $attribute, $data, $htmlOptions = array())
+ {
+ $displaySize = TbArray::popValue('displaySize', $htmlOptions);
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+ if (!empty($displaySize)) {
+ $htmlOptions['size'] = $displaySize;
+ }
+ return parent::activeDropDownList($model, $attribute, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a list box for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list box
+ */
+ public static function activeListBox($model, $attribute, $data, $htmlOptions = array())
+ {
+ TbArray::defaultValue('displaySize', 4, $htmlOptions);
+ return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a radio button list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data $data value-label pairs used to generate the radio button list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function activeRadioButtonList($model, $attribute, $data, $htmlOptions = array())
+ {
+ parent::resolveNameID($model, $attribute, $htmlOptions);
+ $selection = parent::resolveValue($model, $attribute);
+ $name = TbArray::popValue('name', $htmlOptions);
+ $uncheckValue = isset($htmlOptions['uncheckValue']) ? TbArray::popValue('uncheckValue', $htmlOptions) : '';
+ $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
+ $hidden = isset($uncheckValue) ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : '';
+ return $hidden . self::radioButtonList($name, $selection, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates an inline radio button list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data $data value-label pairs used to generate the radio button list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates a check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data $data value-label pairs used to generate the check box list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function activeCheckBoxList($model, $attribute, $data, $htmlOptions = array())
+ {
+ parent::resolveNameID($model, $attribute, $htmlOptions);
+ $selection = parent::resolveValue($model, $attribute);
+ if ($model->hasErrors($attribute)) {
+ parent::addErrorCss($htmlOptions);
+ }
+ $name = TbArray::popValue('name', $htmlOptions);
+ $uncheckValue = isset($htmlOptions['uncheckValue']) ? TbArray::popValue('uncheckValue', $htmlOptions) : '';
+ $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
+ $hidden = isset($uncheckValue) ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : '';
+ return $hidden . self::checkBoxList($name, $selection, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates an inline check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data $data value-label pairs used to generate the check box list.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list.
+ */
+ public static function activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
+ }
+
+ /**
+ * Generates an uneditable input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input.
+ */
+ public static function activeUneditableField($model, $attribute, $htmlOptions = array())
+ {
+ parent::resolveNameID($model, $attribute, $htmlOptions);
+ $value = parent::resolveValue($model, $attribute);
+ TbArray::removeValues(array('name', 'id'), $htmlOptions);
+ return self::uneditableField($value, $htmlOptions);
+ }
+
+ /**
+ * Generates a search query input for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input.
+ */
+ public static function activeSearchQueryField($model, $attribute, $htmlOptions = array())
+ {
+ self::addCssClass('search-query', $htmlOptions);
+ return self::activeTextField($model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a text field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeTextFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a password field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activePasswordFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a url field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeUrlFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_URL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a email field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeEmailFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_EMAIL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a number field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeNumberFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a range field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeRangeFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_RANGE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a date field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeDateFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_DATE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a text area for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeTextAreaControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a file field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeFileFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a radio button for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeRadioButtonControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a check box for a model attribute.
+ * @param string $name the input name.
+ * @param string $checked whether the check box is checked.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeCheckBoxControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a drop down list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeDropDownListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a list box for a model attribute.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeListBoxControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a radio button list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeRadioButtonListControlGroup(
+ $model,
+ $attribute,
+ $data = array(),
+ $htmlOptions = array()
+ ) {
+ return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline radio button list for a model attribute.
+ * @param string $name the input name.
+ * @param string $select the selected value.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeInlineRadioButtonListControlGroup(
+ $model,
+ $attribute,
+ $data = array(),
+ $htmlOptions = array()
+ ) {
+ return self::activeControlGroup(
+ self::INPUT_TYPE_INLINERADIOBUTTONLIST,
+ $model,
+ $attribute,
+ $htmlOptions,
+ $data
+ );
+ }
+
+ /**
+ * Generates a control group with a check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeCheckBoxListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeInlineCheckBoxListControlGroup(
+ $model,
+ $attribute,
+ $data = array(),
+ $htmlOptions = array()
+ ) {
+ return self::activeControlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a uneditable field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeUneditableFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a search field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see self::activeControlGroup
+ */
+ public static function activeSearchQueryControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return self::activeControlGroup(self::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an active form row.
+ * @param string $type the input type.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for multiple select inputs.
+ * @return string the generated control group.
+ */
+ public static function activeControlGroup($type, $model, $attribute, $htmlOptions = array(), $data = array())
+ {
+ $color = TbArray::popValue('color', $htmlOptions);
+ $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
+ $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array());
+ $label = TbArray::popValue('label', $htmlOptions);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+
+ if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON))) {
+ $htmlOptions['label'] = isset($label) ? $label : $model->getAttributeLabel($attribute);
+ $htmlOptions['labelOptions'] = $labelOptions;
+ $label = false;
+ }
+ if (isset($label) && $label !== false) {
+ $labelOptions['label'] = $label;
+ }
+
+ $help = TbArray::popValue('help', $htmlOptions, '');
+ $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array());
+ if (!empty($help)) {
+ $help = self::inputHelp($help, $helpOptions);
+ }
+ $error = TbArray::popValue('error', $htmlOptions, '');
+
+ $input = isset($htmlOptions['input'])
+ ? $htmlOptions['input']
+ : self::createActiveInput($type, $model, $attribute, $htmlOptions, $data);
+
+ self::addCssClass('control-group', $groupOptions);
+ if (!empty($color)) {
+ self::addCssClass($color, $groupOptions);
+ }
+ self::addCssClass('control-label', $labelOptions);
+ $output = self::openTag('div', $groupOptions);
+ if ($label !== false) {
+ $output .= parent::activeLabelEx($model, $attribute, $labelOptions);
+ }
+ $output .= self::controls($input . $error . $help, $controlOptions);
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a custom (pre-rendered) active form control group.
+ * @param string $input the rendered input.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ */
+ public static function customActiveControlGroup($input, $model, $attribute, $htmlOptions = array())
+ {
+ $htmlOptions['input'] = $input;
+ return self::activeControlGroup(self::INPUT_TYPE_CUSTOM, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Creates an active form input of the given type.
+ * @param string $type the input type.
+ * @param CModel $model the model instance.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for multiple select inputs.
+ * @return string the input.
+ * @throws CException if the input type is invalid.
+ */
+ public static function createActiveInput($type, $model, $attribute, $htmlOptions = array(), $data = array())
+ {
+ switch ($type) {
+ case self::INPUT_TYPE_TEXT:
+ return self::activeTextField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_PASSWORD:
+ return self::activePasswordField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_URL:
+ return self::activeUrlField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_EMAIL:
+ return self::activeEmailField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_NUMBER:
+ return self::activeNumberField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_RANGE:
+ return self::activeRangeField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_DATE:
+ return self::activeDateField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_TEXTAREA:
+ return self::activeTextArea($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_FILE:
+ return self::activeFileField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_RADIOBUTTON:
+ return self::activeRadioButton($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_CHECKBOX:
+ return self::activeCheckBox($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_DROPDOWNLIST:
+ return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_LISTBOX:
+ return self::activeListBox($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_CHECKBOXLIST:
+ return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_INLINECHECKBOXLIST:
+ return self::activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_RADIOBUTTONLIST:
+ return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
+ return self::activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions);
+ case self::INPUT_TYPE_UNEDITABLE:
+ return self::activeUneditableField($model, $attribute, $htmlOptions);
+ case self::INPUT_TYPE_SEARCH:
+ return self::activeSearchQueryField($model, $attribute, $htmlOptions);
+ default:
+ throw new CException('Invalid input type "' . $type . '".');
+ }
+ }
+
+ /**
+ * Displays a summary of validation errors for one or several models.
+ * @param mixed $model the models whose input errors are to be displayed.
+ * @param string $header a piece of HTML code that appears in front of the errors.
+ * @param string $footer a piece of HTML code that appears at the end of the errors.
+ * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
+ * @return string the error summary. Empty if no errors are found.
+ */
+ public static function errorSummary($model, $header = null, $footer = null, $htmlOptions = array())
+ {
+ // kind of a quick fix but it will do for now.
+ self::addCssClass(self::$errorSummaryCss, $htmlOptions);
+ return parent::errorSummary($model, $header, $footer, $htmlOptions);
+ }
+
+ /**
+ * Displays the first validation error for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the rendered error. Empty if no errors are found.
+ */
+ public static function error($model, $attribute, $htmlOptions = array())
+ {
+ parent::resolveName($model, $attribute); // turn [a][b]attr into attr
+ $error = $model->getError($attribute);
+ return !empty($error) ? self::help($error, $htmlOptions) : '';
+ }
+
+ /**
+ * Generates an input HTML tag for a model attribute.
+ * This method generates an input HTML tag based on the given input name and value.
+ * @param string $type the input type.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input tag.
+ */
+ protected static function activeTextInputField($type, $model, $attribute, $htmlOptions)
+ {
+ parent::resolveNameID($model, $attribute, $htmlOptions);
+ parent::clientChange('change', $htmlOptions);
+
+ $htmlOptions = self::normalizeInputOptions($htmlOptions);
+
+ $addOnClasses = self::getAddOnClasses($htmlOptions);
+ $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
+ self::addCssClass($addOnClasses, $addOnOptions);
+
+ $prepend = TbArray::popValue('prepend', $htmlOptions, '');
+ $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array());
+ if (!empty($prepend)) {
+ $prepend = self::inputAddOn($prepend, $prependOptions);
+ }
+
+ $append = TbArray::popValue('append', $htmlOptions, '');
+ $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array());
+ if (!empty($append)) {
+ $append = self::inputAddOn($append, $appendOptions);
+ }
+
+ $output = '';
+ if (!empty($addOnClasses)) {
+ $output .= self::openTag('div', $addOnOptions);
+ }
+ $output .= $prepend . parent::activeInputField($type, $model, $attribute, $htmlOptions) . $append;
+ if (!empty($addOnClasses)) {
+ $output .= '';
+ }
+ return $output;
+ }
+
+ /**
+ * Returns the add-on classes based on the given options.
+ * @param array $htmlOptions the options.
+ * @return string the classes.
+ */
+ protected static function getAddOnClasses($htmlOptions)
+ {
+ $classes = array();
+ if (TbArray::getValue('append', $htmlOptions)) {
+ $classes[] = 'input-append';
+ }
+ if (TbArray::getValue('prepend', $htmlOptions)) {
+ $classes[] = 'input-prepend';
+ }
+ return !empty($classes) ? implode(' ', $classes) : $classes;
+ }
+
+ /**
+ * Generates an add-on for an input field.
+ * @param string $addOn the add-on.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated add-on.
+ */
+ protected static function inputAddOn($addOn, $htmlOptions)
+ {
+ $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
+ self::addCssClass('add-on', $addOnOptions);
+ return strpos($addOn, 'btn') === false // buttons should not be wrapped in a span
+ ? self::tag('span', $addOnOptions, $addOn)
+ : $addOn;
+ }
+
+ /**
+ * Generates a help text for an input field.
+ * @param string $help the help text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated help text.
+ */
+ protected static function inputHelp($help, $htmlOptions)
+ {
+ $type = TbArray::popValue('type', $htmlOptions, self::HELP_TYPE_INLINE);
+ return $type === self::HELP_TYPE_INLINE
+ ? self::help($help, $htmlOptions)
+ : self::helpBlock($help, $htmlOptions);
+ }
+
+ /**
+ * Normalizes input options.
+ * @param array $options the options.
+ * @return array the normalized options.
+ */
+ protected static function normalizeInputOptions($options)
+ {
+ self::addSpanClass($options);
+ self::addTextAlignClass($options);
+ $size = TbArray::popValue('size', $options);
+ if (TbArray::popValue('block', $options, false)) {
+ self::addCssClass('input-block-level', $options);
+ } else {
+ if (!empty($size)) {
+ self::addCssClass('input-' . $size, $options);
+ }
+ }
+ return $options;
+ }
+
+ /**
+ * Generates form controls.
+ * @param mixed $controls the controls.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated controls.
+ */
+ public static function controls($controls, $htmlOptions = array())
+ {
+ self::addCssClass('controls', $htmlOptions);
+ if (TbArray::popValue('row', $htmlOptions, false)) {
+ self::addCssClass('controls-row', $htmlOptions);
+ }
+ $before = TbArray::popValue('before', $htmlOptions, '');
+ $after = TbArray::popValue('after', $htmlOptions, '');
+ if (is_array($controls)) {
+ $controls = implode('', $controls);
+ }
+ $content = $before . $controls . $after;
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates form controls row.
+ * @param mixed $controls the controls.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated controls.
+ */
+ public static function controlsRow($controls, $htmlOptions = array())
+ {
+ $htmlOptions['row'] = true;
+ return self::controls($controls, $htmlOptions);
+ }
+
+ /**
+ * Generates form actions.
+ * @param mixed $actions the actions.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated actions.
+ */
+ public static function formActions($actions, $htmlOptions = array())
+ {
+ self::addCssClass('form-actions', $htmlOptions);
+ if (is_array($actions)) {
+ $actions = implode(' ', $actions);
+ }
+ return self::tag('div', $htmlOptions, $actions);
+ }
+
+ /**
+ * Generates a search form.
+ * @param mixed $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated form.
+ */
+ public static function searchForm($action, $method = 'post', $htmlOptions = array())
+ {
+ self::addCssClass('form-search', $htmlOptions);
+ $inputOptions = TbArray::popValue('inputOptions', $htmlOptions, array());
+ $inputOptions = TbArray::merge(array('type' => 'text', 'placeholder' => 'Search'), $inputOptions);
+ $name = TbArray::popValue('name', $inputOptions, 'search');
+ $value = TbArray::popValue('value', $inputOptions, '');
+ $output = self::beginFormTb(self::FORM_LAYOUT_SEARCH, $action, $method, $htmlOptions);
+ $output .= self::searchQueryField($name, $value, $inputOptions);
+ $output .= parent::endForm();
+ return $output;
+ }
+
+ // Buttons
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#buttons
+ // --------------------------------------------------
+
+ /**
+ * Generates a hyperlink tag.
+ * @param string $text link body. It will NOT be HTML-encoded.
+ * @param mixed $url a URL or an action route that can be used to create a URL.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated hyperlink
+ */
+ public static function link($text, $url = '#', $htmlOptions = array())
+ {
+ $htmlOptions['href'] = parent::normalizeUrl($url);
+ self::clientChange('click', $htmlOptions);
+ return self::tag('a', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates an button.
+ * @param string $label the button label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function button($label = 'Button', $htmlOptions = array())
+ {
+ return self::htmlButton($label, $htmlOptions);
+ }
+
+ /**
+ * Generates an image submit button.
+ * @param string $src the image URL
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function htmlButton($label = 'Button', $htmlOptions = array())
+ {
+ return self::btn(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a submit button.
+ * @param string $label the button label
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function submitButton($label = 'Submit', $htmlOptions = array())
+ {
+ return self::btn(self::BUTTON_TYPE_SUBMIT, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a reset button.
+ * @param string $label the button label
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function resetButton($label = 'Reset', $htmlOptions = array())
+ {
+ return self::btn(self::BUTTON_TYPE_RESET, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates an image submit button.
+ * @param string $src the image URL
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function imageButton($src, $htmlOptions = array())
+ {
+ return self::btn(self::BUTTON_TYPE_IMAGE, $src, $htmlOptions);
+ }
+
+ /**
+ * Generates a link submit button.
+ * @param string $label the button label.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button tag.
+ */
+ public static function linkButton($label = 'Submit', $htmlOptions = array())
+ {
+ return self::btn(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a link that can initiate AJAX requests.
+ * @param string $text the link body (it will NOT be HTML-encoded.)
+ * @param mixed $url the URL for the AJAX request.
+ * @param array $ajaxOptions AJAX options.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function ajaxLink($text, $url, $ajaxOptions = array(), $htmlOptions = array())
+ {
+ if (!isset($htmlOptions['href'])) {
+ $htmlOptions['href'] = '#';
+ }
+ $ajaxOptions['url'] = $url;
+ $htmlOptions['ajax'] = $ajaxOptions;
+ parent::clientChange('click', $htmlOptions);
+ return self::tag('a', $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a push button that can initiate AJAX requests.
+ * @param string $label the button label.
+ * @param mixed $url the URL for the AJAX request.
+ * @param array $ajaxOptions AJAX options.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function ajaxButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
+ {
+ $ajaxOptions['url'] = $url;
+ $htmlOptions['ajaxOptions'] = $ajaxOptions;
+ return self::btn(self::BUTTON_TYPE_AJAXBUTTON, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a push button that can submit the current form in POST method.
+ * @param string $label the button label
+ * @param mixed $url the URL for the AJAX request.
+ * @param array $ajaxOptions AJAX options.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function ajaxSubmitButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
+ {
+ $ajaxOptions['type'] = 'POST';
+ $htmlOptions['type'] = 'submit';
+ return self::ajaxButton($label, $url, $ajaxOptions, $htmlOptions);
+ }
+
+ // todo: add methods for input button and input submit.
+
+ /**
+ * Generates a button.
+ * @param string $type the button type.
+ * @param string $label the button label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function btn($type, $label, $htmlOptions = array())
+ {
+ self::addCssClass('btn', $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('btn-' . $color, $htmlOptions);
+ }
+ $size = TbArray::popValue('size', $htmlOptions);
+ if (!empty($size)) {
+ self::addCssClass('btn-' . $size, $htmlOptions);
+ }
+ if (TbArray::popValue('block', $htmlOptions, false)) {
+ self::addCssClass('btn-block', $htmlOptions);
+ }
+ if (TbArray::popValue('disabled', $htmlOptions, false)) {
+ self::addCssClass('disabled', $htmlOptions);
+ $htmlOptions['disabled'] = 'disabled';
+ }
+ $loading = TbArray::popValue('loading', $htmlOptions);
+ if (!empty($loading)) {
+ $htmlOptions['data-loading-text'] = $loading;
+ }
+ if (TbArray::popValue('toggle', $htmlOptions, false)) {
+ $htmlOptions['data-toggle'] = 'button';
+ }
+ $icon = TbArray::popValue('icon', $htmlOptions);
+ $iconOptions = TbArray::popValue('iconOptions', $htmlOptions, array());
+ if (strpos($type, 'input') === false) {
+ if (!empty($icon)) {
+ $label = self::icon($icon, $iconOptions) . ' ' . $label;
+ }
+ $items = TbArray::popValue('items', $htmlOptions);
+ }
+ $dropdownOptions = $htmlOptions;
+ TbArray::removeValues(array('groupOptions', 'menuOptions', 'dropup'), $htmlOptions);
+ self::addSpanClass($htmlOptions); // must be called here as parent renders buttons
+ self::addPullClass($htmlOptions); // must be called here as parent renders buttons
+ return isset($items)
+ ? self::btnDropdown($type, $label, $items, $dropdownOptions)
+ : self::createButton($type, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a button dropdown.
+ * @param string $type the button type.
+ * @param string $label the button label text.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ protected static function btnDropdown($type, $label, $items, $htmlOptions)
+ {
+ $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
+ $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
+ self::addCssClass('btn-group', $groupOptions);
+ if (TbArray::popValue('dropup', $htmlOptions, false)) {
+ self::addCssClass('dropup', $groupOptions);
+ }
+ $output = self::openTag('div', $groupOptions);
+ if (TbArray::popValue('split', $htmlOptions, false)) {
+ $output .= self::createButton($type, $label, $htmlOptions);
+ $output .= self::dropdownToggleButton('', $htmlOptions);
+ } else {
+ $output .= self::dropdownToggleLink($label, $htmlOptions);
+ }
+ $output .= self::dropdown($items, $menuOptions);
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Creates a button the of given type.
+ * @param string $type the button type.
+ * @param string $label the button label.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the button.
+ * @throws CException if the button type is valid.
+ */
+ protected static function createButton($type, $label, $htmlOptions)
+ {
+ $url = TbArray::popValue('url', $htmlOptions, '#');
+ $ajaxOptions = TbArray::popValue('ajaxOptions', $htmlOptions, array());
+ switch ($type) {
+ case self::BUTTON_TYPE_HTML:
+ return parent::htmlButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_SUBMIT:
+ $htmlOptions['type'] = 'submit';
+ return parent::htmlButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_RESET:
+ $htmlOptions['type'] = 'reset';
+ return parent::htmlButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_IMAGE:
+ return parent::imageButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_LINKBUTTON:
+ return parent::linkButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_AJAXLINK:
+ return parent::ajaxLink($label, $url, $ajaxOptions, $htmlOptions);
+
+ case self::BUTTON_TYPE_AJAXBUTTON:
+ $htmlOptions['ajax'] = $ajaxOptions;
+ return parent::htmlButton($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_INPUTBUTTON:
+ return parent::button($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_INPUTSUBMIT:
+ $htmlOptions['type'] = 'submit';
+ return parent::button($label, $htmlOptions);
+
+ case self::BUTTON_TYPE_LINK:
+ return self::link($label, $url, $htmlOptions);
+
+ default:
+ throw new CException('Invalid button type "' . $type . '".');
+ }
+ }
+
+ // Images
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#images
+ // --------------------------------------------------
+
+ /**
+ * Generates an image tag with rounded corners.
+ * @param string $src the image URL.
+ * @param string $alt the alternative text display.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated image tag.
+ */
+ public static function imageRounded($src, $alt = '', $htmlOptions = array())
+ {
+ $htmlOptions['type'] = self::IMAGE_TYPE_ROUNDED;
+ return self::image($src, $alt, $htmlOptions);
+ }
+
+ /**
+ * Generates an image tag with circle.
+ * @param string $src the image URL.
+ * @param string $alt the alternative text display.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated image tag.
+ */
+ public static function imageCircle($src, $alt = '', $htmlOptions = array())
+ {
+ $htmlOptions['type'] = self::IMAGE_TYPE_CIRCLE;
+ return self::image($src, $alt, $htmlOptions);
+ }
+
+ /**
+ * Generates an image tag within polaroid frame.
+ * @param string $src the image URL.
+ * @param string $alt the alternative text display.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated image tag.
+ */
+ public static function imagePolaroid($src, $alt = '', $htmlOptions = array())
+ {
+ $htmlOptions['type'] = self::IMAGE_TYPE_POLAROID;
+ return self::image($src, $alt, $htmlOptions);
+ }
+
+ /**
+ * Generates an image tag.
+ * @param string $src the image URL.
+ * @param string $alt the alternative text display.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated image tag.
+ */
+ public static function image($src, $alt = '', $htmlOptions = array())
+ {
+ $type = TbArray::popValue('type', $htmlOptions);
+ if (!empty($type)) {
+ self::addCssClass('img-' . $type, $htmlOptions);
+ }
+ return parent::image($src, $alt, $htmlOptions);
+ }
+
+ // Icons by Glyphicons
+ // http://twitter.github.io/bootstrap/2.3.2/base-css.html#icons
+ // --------------------------------------------------
+
+ /**
+ * Generates an icon.
+ * @param string $icon the icon type.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param string $tagName the icon HTML tag.
+ * @return string the generated icon.
+ */
+ public static function icon($icon, $htmlOptions = array(), $tagName = 'i')
+ {
+ if (is_string($icon)) {
+ if (strpos($icon, 'icon') === false) {
+ $icon = 'icon-' . implode(' icon-', explode(' ', $icon));
+ }
+ self::addCssClass($icon, $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color) && $color === self::ICON_COLOR_WHITE) {
+ self::addCssClass('icon-white', $htmlOptions);
+ }
+ return self::openTag($tagName, $htmlOptions) . parent::closeTag($tagName); // tag won't work in this case
+ }
+ return '';
+ }
+
+ //
+ // COMPONENTS
+ // --------------------------------------------------
+
+ // Dropdowns
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#dropdowns
+ // --------------------------------------------------
+
+ /**
+ * Generates a dropdown menu.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ protected static function dropdown($items, $htmlOptions = array())
+ {
+ TbArray::defaultValue('role', 'menu', $htmlOptions);
+ self::addCssClass('dropdown-menu', $htmlOptions);
+ return self::menu($items, $htmlOptions);
+ }
+
+ /**
+ * Generates a dropdown toggle link.
+ * @param string $label the link label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function dropdownToggleLink($label, $htmlOptions = array())
+ {
+ return self::dropdownToggle(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a dropdown toggle button.
+ * @param string $label the button label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function dropdownToggleButton($label = '', $htmlOptions = array())
+ {
+ return self::dropdownToggle(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a dropdown toggle element.
+ * @param string $tag the HTML tag.
+ * @param string $label the element text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated element.
+ */
+ protected static function dropdownToggle($type, $label, $htmlOptions)
+ {
+ self::addCssClass('dropdown-toggle', $htmlOptions);
+ $label .= ' ';
+ $htmlOptions['data-toggle'] = 'dropdown';
+ return self::btn($type, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a dropdown toggle menu item.
+ * @param string $label the menu item text.
+ * @param string $url the menu item URL.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param int $depth the menu depth at which this link is located
+ * @return string the generated menu item.
+ */
+ public static function dropdownToggleMenuLink($label, $url = '#', $htmlOptions = array(), $depth = 0)
+ {
+ self::addCssClass('dropdown-toggle', $htmlOptions);
+ if ($depth === 0) {
+ $label .= ' ';
+ }
+ $htmlOptions['data-toggle'] = 'dropdown';
+ return self::link($label, $url, $htmlOptions);
+ }
+
+ // Button groups
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#buttonGroups
+ // --------------------------------------------------
+
+ /**
+ * Generates a button group.
+ * @param array $buttons the button configurations.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated button group.
+ */
+ public static function buttonGroup(array $buttons, $htmlOptions = array())
+ {
+ if (!empty($buttons)) {
+ self::addCssClass('btn-group', $htmlOptions);
+ if (TbArray::popValue('vertical', $htmlOptions, false)) {
+ self::addCssClass('btn-group-vertical', $htmlOptions);
+ }
+ $toggle = TbArray::popValue('toggle', $htmlOptions);
+ if (!empty($toggle)) {
+ $htmlOptions['data-toggle'] = 'buttons-' . $toggle;
+ }
+ $parentOptions = array(
+ 'color' => TbArray::popValue('color', $htmlOptions),
+ 'size' => TbArray::popValue('size', $htmlOptions),
+ 'disabled' => TbArray::popValue('disabled', $htmlOptions)
+ );
+ $output = self::openTag('div', $htmlOptions);
+ foreach ($buttons as $buttonOptions) {
+ if (isset($buttonOptions['visible']) && $buttonOptions['visible'] === false) {
+ continue;
+ }
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $buttonOptions, array());
+ if (!empty($options)) {
+ $buttonOptions = TbArray::merge($options, $buttonOptions);
+ }
+ $buttonLabel = TbArray::popValue('label', $buttonOptions, '');
+ $buttonOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $buttonOptions);
+ $items = TbArray::popValue('items', $buttonOptions, array());
+ if (!empty($items)) {
+ $output .= self::buttonDropdown($buttonLabel, $items, $buttonOptions);
+ } else {
+ $ajaxOptions = TbArray::popValue('ajaxOptions', $buttonOptions, array());
+ if(!empty($ajaxOptions)) {
+ $output .= self::ajaxButton($buttonLabel, TbArray::popValue('url', $ajaxOptions, '#'), $ajaxOptions, $buttonOptions);
+ } else {
+ $output .= self::linkButton($buttonLabel, $buttonOptions);
+ }
+ }
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a vertical button group.
+ * @param array $buttons the button configurations.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated button group.
+ */
+ public static function verticalButtonGroup(array $buttons, $htmlOptions = array())
+ {
+ $htmlOptions['vertical'] = true;
+ return self::buttonGroup($buttons, $htmlOptions);
+ }
+
+ /**
+ * Generates a button toolbar.
+ * @param array $groups the button group configurations.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated button toolbar.
+ */
+ public static function buttonToolbar(array $groups, $htmlOptions = array())
+ {
+ if (!empty($groups)) {
+ self::addCssClass('btn-toolbar', $htmlOptions);
+ $parentOptions = array(
+ 'color' => TbArray::popValue('color', $htmlOptions),
+ 'size' => TbArray::popValue('size', $htmlOptions),
+ 'disabled' => TbArray::popValue('disabled', $htmlOptions)
+ );
+ $output = self::openTag('div', $htmlOptions);
+ foreach ($groups as $groupOptions) {
+ if (isset($groupOptions['visible']) && $groupOptions['visible'] === false) {
+ continue;
+ }
+ $items = TbArray::popValue('items', $groupOptions, array());
+ if (empty($items)) {
+ continue;
+ }
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $groupOptions, array());
+ if (!empty($options)) {
+ $groupOptions = TbArray::merge($options, $groupOptions);
+ }
+ $groupOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $groupOptions);
+ $output .= self::buttonGroup($items, $groupOptions);
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ // Button dropdowns
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#buttonDropdowns
+ // --------------------------------------------------
+
+ /**
+ * Generates a button with a dropdown menu.
+ * @param string $label the button label text.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function buttonDropdown($label, $items, $htmlOptions = array())
+ {
+ $htmlOptions['items'] = $items;
+ $type = TbArray::popValue('type', $htmlOptions, self::BUTTON_TYPE_LINKBUTTON);
+ return self::btn($type, $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a button with a split dropdown menu.
+ * @param string $label the button label text.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated button.
+ */
+ public static function splitButtonDropdown($label, $items, $htmlOptions = array())
+ {
+ $htmlOptions['split'] = true;
+ return self::buttonDropdown($label, $items, $htmlOptions);
+ }
+
+ // Navs
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#navs
+ // --------------------------------------------------
+
+ /**
+ * Generates a tab navigation.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function tabs($items, $htmlOptions = array())
+ {
+ return self::nav(self::NAV_TYPE_TABS, $items, $htmlOptions);
+ }
+
+ /**
+ * Generates a stacked tab navigation.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function stackedTabs($items, $htmlOptions = array())
+ {
+ $htmlOptions['stacked'] = true;
+ return self::tabs($items, $htmlOptions);
+ }
+
+ /**
+ * Generates a pills navigation.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function pills($items, $htmlOptions = array())
+ {
+ return self::nav(self::NAV_TYPE_PILLS, $items, $htmlOptions);
+ }
+
+ /**
+ * Generates a stacked pills navigation.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function stackedPills($items, $htmlOptions = array())
+ {
+ $htmlOptions['stacked'] = true;
+ return self::pills($items, $htmlOptions);
+ }
+
+ /**
+ * Generates a list navigation.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function navList($items, $htmlOptions = array())
+ {
+ foreach ($items as $i => $itemOptions) {
+ if (is_string($itemOptions)) {
+ continue;
+ }
+ if (!isset($itemOptions['url']) && !isset($itemOptions['items'])) {
+ $label = TbArray::popValue('label', $itemOptions, '');
+ $items[$i] = self::menuHeader($label, $itemOptions);
+ }
+ }
+ return self::nav(self::NAV_TYPE_LIST, $items, $htmlOptions);
+ }
+
+ /**
+ * Generates a navigation menu.
+ * @param string $type the menu type.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function nav($type, $items, $htmlOptions = array())
+ {
+ self::addCssClass('nav', $htmlOptions);
+ if (!empty($type)) {
+ self::addCssClass('nav-' . $type, $htmlOptions);
+ }
+ $stacked = TbArray::popValue('stacked', $htmlOptions, false);
+ if ($type !== self::NAV_TYPE_LIST && $stacked) {
+ self::addCssClass('nav-stacked', $htmlOptions);
+ }
+ return self::menu($items, $htmlOptions);
+ }
+
+ /**
+ * Generates a menu.
+ * @param array $items the menu items.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param integer $depth the current depth.
+ * @return string the generated menu.
+ */
+ public static function menu(array $items, $htmlOptions = array(), $depth = 0)
+ {
+ // todo: consider making this method protected.
+ if (!empty($items)) {
+ $htmlOptions['role'] = 'menu';
+ $output = self::openTag('ul', $htmlOptions);
+ foreach ($items as $itemOptions) {
+ if (is_string($itemOptions)) {
+ $output .= $itemOptions;
+ } else {
+ if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
+ continue;
+ }
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $itemOptions, array());
+ if (!empty($options)) {
+ $itemOptions = TbArray::merge($options, $itemOptions);
+ }
+ $label = TbArray::popValue('label', $itemOptions, '');
+ if (TbArray::popValue('active', $itemOptions, false)) {
+ self::addCssClass('active', $itemOptions);
+ }
+ if (TbArray::popValue('disabled', $itemOptions, false)) {
+ self::addCssClass('disabled', $itemOptions);
+ }
+ if (!isset($itemOptions['linkOptions'])) {
+ $itemOptions['linkOptions'] = array();
+ }
+ $icon = TbArray::popValue('icon', $itemOptions);
+ if (!empty($icon)) {
+ $label = self::icon($icon) . ' ' . $label;
+ }
+ $items = TbArray::popValue('items', $itemOptions, array());
+ $url = TbArray::popValue('url', $itemOptions, false);
+ if (empty($items)) {
+ if (!$url) {
+ $output .= self::menuHeader($label);
+ } else {
+ $itemOptions['linkOptions']['tabindex'] = -1;
+ $output .= self::menuLink($label, $url, $itemOptions);
+ }
+ } else {
+ $output .= self::menuDropdown($label, $url, $items, $itemOptions, $depth);
+ }
+ }
+ }
+ $output .= '';
+ return $output;
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Generates a menu link.
+ * @param string $label the link label.
+ * @param array $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu item.
+ */
+ public static function menuLink($label, $url, $htmlOptions = array())
+ {
+ TbArray::defaultValue('role', 'menuitem', $htmlOptions);
+ $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
+ $content = self::link($label, $url, $linkOptions);
+ return self::tag('li', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates a menu dropdown.
+ * @param string $label the link label.
+ * @param string $url the link URL.
+ * @param array $items the menu configuration.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param integer $depth the current depth.
+ * @return string the generated dropdown.
+ */
+ protected static function menuDropdown($label, $url, $items, $htmlOptions, $depth = 0)
+ {
+ self::addCssClass($depth === 0 ? 'dropdown' : 'dropdown-submenu', $htmlOptions);
+ TbArray::defaultValue('role', 'menuitem', $htmlOptions);
+ $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
+ $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
+ self::addCssClass('dropdown-menu', $menuOptions);
+ if ($depth === 0) {
+ $defaultId = parent::ID_PREFIX . parent::$count++;
+ TbArray::defaultValue('id', $defaultId, $menuOptions);
+ $menuOptions['aria-labelledby'] = $menuOptions['id'];
+ $menuOptions['role'] = 'menu';
+ }
+ $output = self::openTag('li', $htmlOptions);
+ $output .= self::dropdownToggleMenuLink($label, $url, $linkOptions, $depth);
+ $output .= self::menu($items, $menuOptions, $depth + 1);
+ $output .= ' ';
+ return $output;
+ }
+
+ /**
+ * Generates a menu header.
+ * @param string $label the header text.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated header.
+ */
+ public static function menuHeader($label, $htmlOptions = array())
+ {
+ self::addCssClass('nav-header', $htmlOptions);
+ return self::tag('li', $htmlOptions, $label);
+ }
+
+ /**
+ * Generates a menu divider.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu item.
+ */
+ public static function menuDivider($htmlOptions = array())
+ {
+ self::addCssClass('divider', $htmlOptions);
+ return self::tag('li', $htmlOptions);
+ }
+
+ /**
+ * Generates a tabbable tabs menu.
+ * @param array $tabs the tab configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function tabbableTabs($tabs, $htmlOptions = array())
+ {
+ return self::tabbable(self::NAV_TYPE_TABS, $tabs, $htmlOptions);
+ }
+
+ /**
+ * Generates a tabbable pills menu.
+ * @param array $tabs the tab configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function tabbablePills($pills, $htmlOptions = array())
+ {
+ return self::tabbable(self::NAV_TYPE_PILLS, $pills, $htmlOptions);
+ }
+
+ /**
+ * Generates a tabbable menu.
+ * @param string $type the menu type.
+ * @param array $tabs the tab configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated menu.
+ */
+ public static function tabbable($type, $tabs, $htmlOptions = array())
+ {
+ self::addCssClass('tabbable', $htmlOptions);
+ $placement = TbArray::popValue('placement', $htmlOptions);
+ if (!empty($placement)) {
+ self::addCssClass('tabs-' . $placement, $htmlOptions);
+ }
+ $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
+ $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array());
+ self::addCssClass('tab-content', $contentOptions);
+ $panes = array();
+ $items = self::normalizeTabs($tabs, $panes);
+ $menu = self::nav($type, $items, $menuOptions);
+ $content = self::tag('div', $contentOptions, implode('', $panes));
+ $output = self::openTag('div', $htmlOptions);
+ $output .= $placement === self::TABS_PLACEMENT_BELOW ? $content . $menu : $menu . $content;
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Normalizes the tab configuration.
+ * @param array $tabs the tab configuration.
+ * @param array $panes a reference to the panes array.
+ * @param integer $i the running index.
+ * @return array the items.
+ */
+ protected static function normalizeTabs($tabs, &$panes, $i = 0)
+ {
+ $menuItems = array();
+ foreach ($tabs as $tabOptions) {
+ if (isset($tabOptions['visible']) && $tabOptions['visible'] === false) {
+ continue;
+ }
+ $menuItem = array();
+ $menuItem['icon'] = TbArray::popValue('icon', $tabOptions);
+ $menuItem['label'] = TbArray::popValue('label', $tabOptions, '');
+ $menuItem['active'] = TbArray::getValue('active', $tabOptions, false);
+ $menuItem['disabled'] = TbArray::popValue('disabled', $tabOptions, false);
+ $menuItem['linkOptions'] = TbArray::popValue('linkOptions', $tabOptions, array());
+ $menuItem['htmlOptions'] = TbArray::popValue('htmlOptions', $tabOptions, array());
+ $items = TbArray::popValue('items', $tabOptions, array());
+ if (!empty($items)) {
+ $menuItem['linkOptions']['data-toggle'] = 'dropdown';
+ $menuItem['items'] = self::normalizeTabs($items, $panes, $i);
+ } else {
+ $paneOptions = TbArray::popValue('paneOptions', $tabOptions, array());
+ $id = $paneOptions['id'] = TbArray::popValue('id', $tabOptions, 'tab_' . ++$i);
+ $menuItem['linkOptions']['data-toggle'] = 'tab';
+ $menuItem['url'] = '#' . $id;
+ self::addCssClass('tab-pane', $paneOptions);
+ if (TbArray::popValue('fade', $tabOptions, true)) {
+ self::addCssClass('fade', $paneOptions);
+ }
+ if (TbArray::popValue('active', $tabOptions, false)) {
+ self::addCssClass('active in', $paneOptions);
+ }
+ $paneContent = TbArray::popValue('content', $tabOptions, '');
+ $panes[] = self::tag('div', $paneOptions, $paneContent);
+ }
+ $menuItems[] = $menuItem;
+ }
+ return $menuItems;
+ }
+
+ // Navbar
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#navbar
+ // --------------------------------------------------
+
+ /**
+ * Generates a navbar.
+ * @param string $content the navbar content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated navbar.
+ */
+ public static function navbar($content, $htmlOptions = array())
+ {
+ self::addCssClass('navbar', $htmlOptions);
+ $display = TbArray::popValue('display', $htmlOptions);
+ if (!empty($display)) {
+ self::addCssClass('navbar-' . $display, $htmlOptions);
+ }
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('navbar-' . $color, $htmlOptions);
+ }
+ $innerOptions = TbArray::popValue('innerOptions', $htmlOptions, array());
+ self::addCssClass('navbar-inner', $innerOptions);
+ $output = self::openTag('div', $htmlOptions);
+ $output .= self::tag('div', $innerOptions, $content);
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a brand link for the navbar.
+ * @param string $label the link label text.
+ * @param string $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function navbarBrandLink($label, $url, $htmlOptions = array())
+ {
+ self::addCssClass('brand', $htmlOptions);
+ return self::link($label, $url, $htmlOptions);
+ }
+
+ /**
+ * Generates a text for the navbar.
+ * @param string $text the text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param string $tag the HTML tag.
+ * @return string the generated text block.
+ */
+ public static function navbarText($text, $htmlOptions = array(), $tag = 'p')
+ {
+ self::addCssClass('navbar-text', $htmlOptions);
+ return self::tag($tag, $htmlOptions, $text);
+ }
+
+ /**
+ * Generates a menu divider for the navbar.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated divider.
+ */
+ public static function navbarMenuDivider($htmlOptions = array())
+ {
+ self::addCssClass('divider-vertical', $htmlOptions);
+ return self::tag('li', $htmlOptions);
+ }
+
+ /**
+ * Generates a navbar form.
+ * @param mixed $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML attributes
+ * @return string the generated form.
+ */
+ public static function navbarForm($action, $method = 'post', $htmlOptions = array())
+ {
+ self::addCssClass('navbar-form', $htmlOptions);
+ return self::form($action, $method, $htmlOptions);
+ }
+
+ /**
+ * Generates a navbar search form.
+ * @param mixed $action the form action URL.
+ * @param string $method form method (e.g. post, get).
+ * @param array $htmlOptions additional HTML attributes
+ * @return string the generated form.
+ */
+ public static function navbarSearchForm($action, $method = 'post', $htmlOptions = array())
+ {
+ self::addCssClass('navbar-search', $htmlOptions);
+ return self::searchForm($action, $method, $htmlOptions);
+ }
+
+ /**
+ * Generates a collapse element.
+ * @param string $target the CSS selector for the target element.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated icon.
+ */
+ public static function navbarCollapseLink($target, $htmlOptions = array())
+ {
+ self::addCssClass('btn btn-navbar', $htmlOptions);
+ $htmlOptions['data-toggle'] = 'collapse';
+ $htmlOptions['data-target'] = $target;
+ $content = ' ';
+ return self::tag('a', $htmlOptions, $content);
+ }
+
+ // Breadcrumbs
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#breadcrumbs
+ // --------------------------------------------------
+
+ /**
+ * Generates a breadcrumb menu.
+ * @param array $links the breadcrumb links.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated breadcrumb.
+ */
+ public static function breadcrumbs($links, $htmlOptions = array())
+ {
+ $divider = TbArray::popValue('divider', $htmlOptions, '/');
+ self::addCssClass('breadcrumb', $htmlOptions);
+ $output = self::openTag('ul', $htmlOptions);
+ foreach ($links as $label => $url) {
+ if (is_string($label)) {
+ $output .= self::openTag('li');
+ $output .= self::link($label, $url);
+ $output .= self::tag('span', array('class' => 'divider'), $divider);
+ $output .= '';
+ } else {
+ $output .= self::tag('li', array('class' => 'active'), $url);
+ }
+ }
+ $output .= '';
+ return $output;
+ }
+
+ // Pagination
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#pagination
+ // --------------------------------------------------
+
+ /**
+ * Generates a pagination.
+ * @param array $items the pagination buttons.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated pagination.
+ */
+ public static function pagination(array $items, $htmlOptions = array())
+ {
+ if (!empty($items)) {
+ self::addCssClass('pagination', $htmlOptions);
+ $size = TbArray::popValue('size', $htmlOptions);
+ if (!empty($size)) {
+ self::addCssClass('pagination-' . $size, $htmlOptions);
+ }
+ $align = TbArray::popValue('align', $htmlOptions);
+ if (!empty($align)) {
+ self::addCssClass('pagination-' . $align, $htmlOptions);
+ }
+ $listOptions = TbArray::popValue('listOptions', $htmlOptions, array());
+ $output = self::openTag('div', $htmlOptions);
+ $output .= self::openTag('ul', $listOptions);
+ foreach ($items as $itemOptions) {
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $itemOptions, array());
+ if (!empty($options)) {
+ $itemOptions = TbArray::merge($options, $itemOptions);
+ }
+ $label = TbArray::popValue('label', $itemOptions, '');
+ $url = TbArray::popValue('url', $itemOptions, false);
+ $output .= self::paginationLink($label, $url, $itemOptions);
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a pagination link.
+ * @param string $label the link label text.
+ * @param mixed $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function paginationLink($label, $url, $htmlOptions = array())
+ {
+ $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
+ if (TbArray::popValue('active', $htmlOptions, false)) {
+ self::addCssClass('active', $htmlOptions);
+ }
+ if (TbArray::popValue('disabled', $htmlOptions, false)) {
+ self::addCssClass('disabled', $htmlOptions);
+ }
+ $content = self::link($label, $url, $linkOptions);
+ return self::tag('li', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates a pager.
+ * @param array $links the pager buttons.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated pager.
+ */
+ public static function pager(array $links, $htmlOptions = array())
+ {
+ if (!empty($links)) {
+ self::addCssClass('pager', $htmlOptions);
+ $output = self::openTag('ul', $htmlOptions);
+ foreach ($links as $itemOptions) {
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $itemOptions, array());
+ if (!empty($options)) {
+ $itemOptions = TbArray::merge($options, $itemOptions);
+ }
+ $label = TbArray::popValue('label', $itemOptions, '');
+ $url = TbArray::popValue('url', $itemOptions, false);
+ $output .= self::pagerLink($label, $url, $itemOptions);
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a pager link.
+ * @param string $label the link label text.
+ * @param mixed $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function pagerLink($label, $url, $htmlOptions = array())
+ {
+ $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
+ if (TbArray::popValue('previous', $htmlOptions, false)) {
+ self::addCssClass('previous', $htmlOptions);
+ }
+ if (TbArray::popValue('next', $htmlOptions, false)) {
+ self::addCssClass('next', $htmlOptions);
+ }
+ if (TbArray::popValue('disabled', $htmlOptions, false)) {
+ self::addCssClass('disabled', $htmlOptions);
+ }
+ $content = self::link($label, $url, $linkOptions);
+ return self::tag('li', $htmlOptions, $content);
+ }
+
+ // Labels and badges
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#labels-badges
+ // --------------------------------------------------
+
+ /**
+ * Generates a label span.
+ * @param string $label the label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated span.
+ */
+ public static function labelTb($label, $htmlOptions = array())
+ {
+ self::addCssClass('label', $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('label-' . $color, $htmlOptions);
+ }
+ return self::tag('span', $htmlOptions, $label);
+ }
+
+ /**
+ * Generates a badge span.
+ * @param string $label the badge text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated span.
+ */
+ public static function badge($label, $htmlOptions = array())
+ {
+ self::addCssClass('badge', $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('badge-' . $color, $htmlOptions);
+ }
+ return self::tag('span', $htmlOptions, $label);
+ }
+
+ // Typography
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#typography
+ // --------------------------------------------------
+
+ /**
+ * Generates a hero unit.
+ * @param string $heading the heading text.
+ * @param string $content the content text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated hero unit.
+ */
+ public static function heroUnit($heading, $content, $htmlOptions = array())
+ {
+ self::addCssClass('hero-unit', $htmlOptions);
+ $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
+ $output = self::openTag('div', $htmlOptions);
+ $output .= self::tag('h1', $headingOptions, $heading);
+ $output .= $content;
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a pager header.
+ * @param string $heading the heading text.
+ * @param string $subtext the subtext.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated pager header.
+ */
+ public static function pageHeader($heading, $subtext, $htmlOptions = array())
+ {
+ self::addCssClass('page-header', $htmlOptions);
+ $headerOptions = TbArray::popValue('headerOptions', $htmlOptions, array());
+ $subtextOptions = TbArray::popValue('subtextOptions', $htmlOptions, array());
+ $output = self::openTag('div', $htmlOptions);
+ $output .= self::openTag('h1', $headerOptions);
+ $output .= parent::encode($heading) . ' ' . self::tag('small', $subtextOptions, $subtext);
+ $output .= '';
+ $output .= '';
+ return $output;
+ }
+
+ // Thumbnails
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#thumbnails
+ // --------------------------------------------------
+
+ /**
+ * Generates a list of thumbnails.
+ * @param array $thumbnails the list configuration.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated thumbnails.
+ */
+ public static function thumbnails(array $thumbnails, $htmlOptions = array())
+ {
+ if (!empty($thumbnails)) {
+ self::addCssClass('thumbnails', $htmlOptions);
+ $defaultSpan = TbArray::popValue('span', $htmlOptions, 3);
+ $output = self::openTag('ul', $htmlOptions);
+ foreach ($thumbnails as $thumbnailOptions) {
+ if (isset($thumbnailOptions['visible']) && $thumbnailOptions['visible'] === false) {
+ continue;
+ }
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $thumbnailOptions, array());
+ if (!empty($options)) {
+ $thumbnailOptions = TbArray::merge($options, $thumbnailOptions);
+ }
+ $thumbnailOptions['itemOptions']['span'] = TbArray::popValue('span', $thumbnailOptions, $defaultSpan);
+ $caption = TbArray::popValue('caption', $thumbnailOptions, '');
+ $captionOptions = TbArray::popValue('captionOptions', $thumbnailOptions, array());
+ self::addCssClass('caption', $captionOptions);
+ $label = TbArray::popValue('label', $thumbnailOptions);
+ $labelOptions = TbArray::popValue('labelOptions', $thumbnailOptions, array());
+ if (!empty($label)) {
+ $caption = self::tag('h3', $labelOptions, $label) . $caption;
+ }
+ $content = !empty($caption) ? self::tag('div', $captionOptions, $caption) : '';
+ $image = TbArray::popValue('image', $thumbnailOptions);
+ $imageOptions = TbArray::popValue('imageOptions', $thumbnailOptions, array());
+ $imageAlt = TbArray::popValue('alt', $imageOptions, '');
+ if (!empty($image)) {
+ $content = parent::image($image, $imageAlt, $imageOptions) . $content;
+ }
+ $url = TbArray::popValue('url', $thumbnailOptions, false);
+ $output .= $url !== false
+ ? self::thumbnailLink($content, $url, $thumbnailOptions)
+ : self::thumbnail($content, $thumbnailOptions);
+ }
+ $output .= '';
+ return $output;
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Generates a thumbnail.
+ * @param string $content the thumbnail content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated thumbnail.
+ */
+ public static function thumbnail($content, $htmlOptions = array())
+ {
+ $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array());
+ self::addCssClass('thumbnail', $htmlOptions);
+ $output = self::openTag('li', $itemOptions);
+ $output .= self::tag('div', $htmlOptions, $content);
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a link thumbnail.
+ * @param string $content the thumbnail content.
+ * @param mixed $url the url that the thumbnail links to.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated thumbnail.
+ */
+ public static function thumbnailLink($content, $url = '#', $htmlOptions = array())
+ {
+ $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array());
+ self::addCssClass('thumbnail', $htmlOptions);
+ $content = self::link($content, $url, $htmlOptions);
+ return self::tag('li', $itemOptions, $content);
+ }
+
+ // Alerts
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#alerts
+ // --------------------------------------------------
+
+ /**
+ * Generates an alert.
+ * @param string $color the color of the alert.
+ * @param string $message the message to display.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated alert.
+ */
+ public static function alert($color, $message, $htmlOptions = array())
+ {
+ self::addCssClass('alert', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('alert-' . $color, $htmlOptions);
+ }
+ if (TbArray::popValue('in', $htmlOptions, true)) {
+ self::addCssClass('in', $htmlOptions);
+ }
+ if (TbArray::popValue('block', $htmlOptions, false)) {
+ self::addCssClass('alert-block', $htmlOptions);
+ }
+ if (TbArray::popValue('fade', $htmlOptions, true)) {
+ self::addCssClass('fade', $htmlOptions);
+ }
+ $closeText = TbArray::popValue('closeText', $htmlOptions, self::CLOSE_TEXT);
+ $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array());
+ $closeOptions['dismiss'] = self::CLOSE_DISMISS_ALERT;
+ $output = self::openTag('div', $htmlOptions);
+ $output .= $closeText !== false ? self::closeLink($closeText, '#', $closeOptions) : '';
+ $output .= $message;
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates an alert block.
+ * @param string $color the color of the alert.
+ * @param string $message the message to display.
+ * @param array $htmlOptions additional HTML options.
+ * @return string the generated alert.
+ */
+ public static function blockAlert($color, $message, $htmlOptions = array())
+ {
+ $htmlOptions['block'] = true;
+ return self::alert($color, $message, $htmlOptions);
+ }
+
+ // Progress bars
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#progress
+ // --------------------------------------------------
+
+ /**
+ * Generates a progress bar.
+ * @param integer $width the progress in percent.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated progress bar.
+ */
+ public static function progressBar($width = 0, $htmlOptions = array())
+ {
+ self::addCssClass('progress', $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('progress-' . $color, $htmlOptions);
+ }
+ if (TbArray::popValue('striped', $htmlOptions, false)) {
+ self::addCssClass('progress-striped', $htmlOptions);
+ }
+ if (TbArray::popValue('animated', $htmlOptions, false)) {
+ self::addCssClass('active', $htmlOptions);
+ }
+ $barOptions = TbArray::popValue('barOptions', $htmlOptions, array());
+ $content = TbArray::popValue('content', $htmlOptions);
+ if (!empty($content)) {
+ $barOptions['content'] = $content;
+ }
+ $content = self::bar($width, $barOptions);
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates a striped progress bar.
+ * @param integer $width the progress in percent.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated progress bar.
+ */
+ public static function stripedProgressBar($width = 0, $htmlOptions = array())
+ {
+ $htmlOptions['striped'] = true;
+ return self::progressBar($width, $htmlOptions);
+ }
+
+ /**
+ * Generates an animated progress bar.
+ * @param integer $width the progress in percent.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated progress bar.
+ */
+ public static function animatedProgressBar($width = 0, $htmlOptions = array())
+ {
+ $htmlOptions['animated'] = true;
+ return self::stripedProgressBar($width, $htmlOptions);
+ }
+
+ /**
+ * Generates a stacked progress bar.
+ * @param array $bars the bar configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated progress bar.
+ */
+ public static function stackedProgressBar(array $bars, $htmlOptions = array())
+ {
+ if (!empty($bars)) {
+ self::addCssClass('progress', $htmlOptions);
+ $output = self::openTag('div', $htmlOptions);
+ $totalWidth = 0;
+ foreach ($bars as $barOptions) {
+ if (isset($barOptions['visible']) && !$barOptions['visible']) {
+ continue;
+ }
+ $width = TbArray::popValue('width', $barOptions, 0);
+ $tmp = $totalWidth;
+ $totalWidth += $width;
+ if ($totalWidth > 100) {
+ $width = 100 - $tmp;
+ }
+ $output .= self::bar($width, $barOptions);
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a progress bar.
+ * @param integer $width the progress in percent.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated bar.
+ */
+ protected static function bar($width = 0, $htmlOptions = array())
+ {
+ self::addCssClass('bar', $htmlOptions);
+ $color = TbArray::popValue('color', $htmlOptions);
+ if (!empty($color)) {
+ self::addCssClass('bar-' . $color, $htmlOptions);
+ }
+ if ($width < 0) {
+ $width = 0;
+ }
+ if ($width > 100) {
+ $width = 100;
+ }
+ if ($width > 0) {
+ $width .= '%';
+ }
+ self::addCssStyle("width: {$width};", $htmlOptions);
+ $content = TbArray::popValue('content', $htmlOptions, '');
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ // Media objects
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#media
+ // --------------------------------------------------
+
+ /**
+ * Generates a list of media objects.
+ * @param array $items item configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string generated list.
+ */
+ public static function mediaList(array $items, $htmlOptions = array())
+ {
+ if (!empty($items)) {
+ self::addCssClass('media-list', $htmlOptions);
+ $output = '';
+ $output .= self::openTag('ul', $htmlOptions);
+ $output .= self::medias($items, 'li');
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates multiple media objects.
+ * @param array $items item configurations.
+ * @param string $tag the item tag name.
+ * @return string generated objects.
+ */
+ public static function medias(array $items, $tag = 'div')
+ {
+ if (!empty($items)) {
+ $output = '';
+ foreach ($items as $itemOptions) {
+ if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
+ continue;
+ }
+ // todo: consider removing the support for htmlOptions.
+ $options = TbArray::popValue('htmlOptions', $itemOptions, array());
+ if (!empty($options)) {
+ $itemOptions = TbArray::merge($options, $itemOptions);
+ }
+ $image = TbArray::popValue('image', $itemOptions);
+ $heading = TbArray::popValue('heading', $itemOptions, '');
+ $content = TbArray::popValue('content', $itemOptions, '');
+ TbArray::defaultValue('tag', $tag, $itemOptions);
+ $output .= self::media($image, $heading, $content, $itemOptions);
+ }
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a single media object.
+ * @param string $image the image url.
+ * @param string $heading the heading text.
+ * @param string $content the content text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the media object.
+ */
+ public static function media($image, $heading, $content, $htmlOptions = array())
+ {
+ $tag = TbArray::popValue('tag', $htmlOptions, 'div');
+ self::addCssClass('media', $htmlOptions);
+ $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
+ TbArray::defaultValue('pull', self::PULL_LEFT, $linkOptions);
+ $imageOptions = TbArray::popValue('imageOptions', $htmlOptions, array());
+ self::addCssClass('media-object', $imageOptions);
+ $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array());
+ self::addCssClass('media-body', $contentOptions);
+ $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
+ self::addCssClass('media-heading', $headingOptions);
+ $items = TbArray::popValue('items', $htmlOptions);
+
+ $output = self::openTag($tag, $htmlOptions);
+ $alt = TbArray::popValue('alt', $imageOptions, '');
+ $href = TbArray::popValue('href', $linkOptions, '#');
+ if (!empty($image)) {
+ $output .= self::link(parent::image($image, $alt, $imageOptions), $href, $linkOptions);
+ }
+ $output .= self::openTag('div', $contentOptions);
+ $output .= self::tag('h4', $headingOptions, $heading);
+ $output .= $content;
+ if (!empty($items)) {
+ $output .= self::medias($items);
+ }
+ $output .= '';
+ $output .= self::closeTag($tag);
+ return $output;
+ }
+
+ // Misc
+ // http://twitter.github.io/bootstrap/2.3.2/components.html#misc
+ // --------------------------------------------------
+
+ /**
+ * Generates a well element.
+ * @param string $content the well content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated well.
+ */
+ public static function well($content, $htmlOptions = array())
+ {
+ self::addCssClass('well', $htmlOptions);
+ $size = TbArray::popValue('size', $htmlOptions);
+ if (!empty($size)) {
+ self::addCssClass('well-' . $size, $htmlOptions);
+ }
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates a close link.
+ * @param string $label the link label text.
+ * @param mixed $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function closeLink($label = self::CLOSE_TEXT, $url = '#', $htmlOptions = array())
+ {
+ $htmlOptions['href'] = $url;
+ return self::close('a', $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a close button.
+ * @param string $label the button label text.
+ * @param array $htmlOptions the HTML options for the button.
+ * @return string the generated button.
+ */
+ public static function closeButton($label = self::CLOSE_TEXT, $htmlOptions = array())
+ {
+ return self::close('button', $label, $htmlOptions);
+ }
+
+ /**
+ * Generates a close element.
+ * @param string $tag the tag name.
+ * @param string $label the element label text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated element.
+ */
+ protected static function close($tag, $label, $htmlOptions = array())
+ {
+ self::addCssClass('close', $htmlOptions);
+ $dismiss = TbArray::popValue('dismiss', $htmlOptions);
+ if (!empty($dismiss)) {
+ $htmlOptions['data-dismiss'] = $dismiss;
+ }
+ $htmlOptions['type'] = 'button';
+ return self::tag($tag, $htmlOptions, $label);
+ }
+
+ /**
+ * Generates a collapse link.
+ * @param string $label the link label.
+ * @param string $target the CSS selector.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function collapseLink($label, $target, $htmlOptions = array())
+ {
+ $htmlOptions['data-toggle'] = 'collapse';
+ return self::link($label, $target, $htmlOptions);
+ }
+
+ //
+ // JAVASCRIPT
+ // --------------------------------------------------
+
+ // Modals
+ // http://twitter.github.io/bootstrap/2.3.2/javascript.html#modals
+ // --------------------------------------------------
+
+ /**
+ * Generates a modal header.
+ * @param string $content the header content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated header.
+ */
+ public static function modalHeader($content, $htmlOptions = array())
+ {
+ self::addCssClass('modal-header', $htmlOptions);
+ $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array());
+ $closeOptions['dismiss'] = 'modal';
+ $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
+ $closeLabel = TbArray::popValue('closeLabel', $htmlOptions, self::CLOSE_TEXT);
+ $closeButton = self::closeButton($closeLabel, $closeOptions);
+ $header = self::tag('h3', $headingOptions, $content);
+ return self::tag('div', $htmlOptions, $closeButton . $header);
+ }
+
+ /**
+ * Generates a modal body.
+ * @param string $content the body content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated body.
+ */
+ public static function modalBody($content, $htmlOptions = array())
+ {
+ self::addCssClass('modal-body', $htmlOptions);
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ /**
+ * Generates a modal footer.
+ * @param string $content the footer content.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated footer.
+ */
+ public static function modalFooter($content, $htmlOptions = array())
+ {
+ self::addCssClass('modal-footer', $htmlOptions);
+ return self::tag('div', $htmlOptions, $content);
+ }
+
+ // Tooltips and Popovers
+ // http://twitter.github.io/bootstrap/2.3.2/javascript.html#tooltips
+ // http://twitter.github.io/bootstrap/2.3.2/javascript.html#popovers
+ // --------------------------------------------------
+
+ /**
+ * Generates a tooltip.
+ * @param string $label the tooltip link label text.
+ * @param mixed $url the link url.
+ * @param string $content the tooltip content text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated tooltip.
+ */
+ public static function tooltip($label, $url, $content, $htmlOptions = array())
+ {
+ $htmlOptions['rel'] = 'tooltip';
+ return self::tooltipPopover($label, $url, $content, $htmlOptions);
+ }
+
+ /**
+ * Generates a popover.
+ * @param string $label the popover link label text.
+ * @param string $title the popover title text.
+ * @param string $content the popover content text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated popover.
+ */
+ public static function popover($label, $title, $content, $htmlOptions = array())
+ {
+ $htmlOptions['rel'] = 'popover';
+ $htmlOptions['data-content'] = $content;
+ $htmlOptions['data-toggle'] = 'popover';
+ return self::tooltipPopover($label, '#', $title, $htmlOptions);
+ }
+
+ /**
+ * Generates a base tooltip.
+ * @param string $label the tooltip link label text.
+ * @param mixed $url the link url.
+ * @param string $title the tooltip title text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated tooltip.
+ */
+ protected static function tooltipPopover($label, $url, $title, $htmlOptions)
+ {
+ $htmlOptions['title'] = $title;
+ if (TbArray::popValue('animation', $htmlOptions)) {
+ $htmlOptions['data-animation'] = 'true';
+ }
+ if (TbArray::popValue('html', $htmlOptions)) {
+ $htmlOptions['data-html'] = 'true';
+ }
+ $selector = TbArray::popValue('selector', $htmlOptions);
+ if (!empty($selector)) {
+ $htmlOptions['data-selector'] = $selector;
+ }
+ $placement = TbArray::popValue('placement', $htmlOptions);
+ if (!empty($placement)) {
+ $htmlOptions['data-placement'] = $placement;
+ }
+ $trigger = TbArray::popValue('trigger', $htmlOptions);
+ if (!empty($trigger)) {
+ $htmlOptions['data-trigger'] = $trigger;
+ }
+ if (($delay = TbArray::popValue('delay', $htmlOptions)) !== null) {
+ $htmlOptions['data-delay'] = $delay;
+ }
+ return self::link($label, $url, $htmlOptions);
+ }
+
+ // Carousel
+ // http://twitter.github.io/bootstrap/2.3.2/javascript.html#carousel
+ // --------------------------------------------------
+
+ /**
+ * Generates an image carousel.
+ * @param array $items the item configurations.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated carousel.
+ */
+ public static function carousel(array $items, $htmlOptions = array())
+ {
+ if (!empty($items)) {
+ $id = TbArray::getValue('id', $htmlOptions, parent::ID_PREFIX . parent::$count++);
+ TbArray::defaultValue('id', $id, $htmlOptions);
+ $selector = '#' . $id;
+ self::addCssClass('carousel', $htmlOptions);
+ if (TbArray::popValue('slide', $htmlOptions, true)) {
+ self::addCssClass('slide', $htmlOptions);
+ }
+ $interval = TbArray::popValue('data-interval', $htmlOptions);
+ if ($interval) {
+ $htmlOptions['data-interval'] = $interval;
+ }
+ $pause = TbArray::popValue('data-pause', $htmlOptions);
+ if ($pause) {
+ $htmlOptions['data-pause'] = $pause;
+ }
+ $indicatorOptions = TbArray::popValue('indicatorOptions', $htmlOptions, array());
+ $innerOptions = TbArray::popValue('innerOptions', $htmlOptions, array());
+ self::addCssClass('carousel-inner', $innerOptions);
+ $prevOptions = TbArray::popValue('prevOptions', $htmlOptions, array());
+ $prevLabel = TbArray::popValue('label', $prevOptions, '‹');
+ $nextOptions = TbArray::popValue('nextOptions', $htmlOptions, array());
+ $nextLabel = TbArray::popValue('label', $nextOptions, '›');
+ $hidePrevAndNext = TbArray::popValue('hidePrevAndNext', $htmlOptions, false);
+ $output = self::openTag('div', $htmlOptions);
+ $output .= self::carouselIndicators($selector, count($items), $indicatorOptions);
+ $output .= self::openTag('div', $innerOptions);
+ foreach ($items as $i => $itemOptions) {
+ if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
+ continue;
+ }
+ if ($i === 0) { // first item should be active
+ self::addCssClass('active', $itemOptions);
+ }
+ $content = TbArray::popValue('content', $itemOptions, '');
+ $image = TbArray::popValue('image', $itemOptions, '');
+ $imageOptions = TbArray::popValue('imageOptions', $itemOptions, array());
+ $imageAlt = TbArray::popValue('alt', $imageOptions, '');
+ if (!empty($image)) {
+ $content = parent::image($image, $imageAlt, $imageOptions);
+ }
+ $label = TbArray::popValue('label', $itemOptions);
+ $caption = TbArray::popValue('caption', $itemOptions);
+ $output .= self::carouselItem($content, $label, $caption, $itemOptions);
+ }
+ $output .= '';
+ if (!$hidePrevAndNext) {
+ $output .= self::carouselPrevLink($prevLabel, $selector, $prevOptions);
+ $output .= self::carouselNextLink($nextLabel, $selector, $nextOptions);
+ }
+ $output .= '';
+ return $output;
+ }
+ return '';
+ }
+
+ /**
+ * Generates a carousel item.
+ * @param string $content the content.
+ * @param string $label the item label text.
+ * @param string $caption the item caption text.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated item.
+ */
+ public static function carouselItem($content, $label, $caption, $htmlOptions = array())
+ {
+ self::addCssClass('item', $htmlOptions);
+ $overlayOptions = TbArray::popValue('overlayOptions', $htmlOptions, array());
+ self::addCssClass('carousel-caption', $overlayOptions);
+ $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
+ $captionOptions = TbArray::popValue('captionOptions', $htmlOptions, array());
+ $url = TbArray::popValue('url', $htmlOptions, false);
+ if ($url !== false) {
+ $content = self::link($content, $url);
+ }
+ $output = self::openTag('div', $htmlOptions);
+ $output .= $content;
+ if (isset($label) || isset($caption)) {
+ $output .= self::openTag('div', $overlayOptions);
+ if ($label) {
+ $output .= self::tag('h4', $labelOptions, $label);
+ }
+ if ($caption) {
+ $output .= self::tag('p', $captionOptions, $caption);
+ }
+ $output .= '';
+ }
+ $output .= '';
+ return $output;
+ }
+
+ /**
+ * Generates a previous link for the carousel.
+ * @param string $label the link label text.
+ * @param mixed $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function carouselPrevLink($label, $url = '#', $htmlOptions = array())
+ {
+ self::addCssClass('carousel-control left', $htmlOptions);
+ $htmlOptions['data-slide'] = 'prev';
+ return self::link($label, $url, $htmlOptions);
+ }
+
+ /**
+ * Generates a next link for the carousel.
+ * @param string $label the link label text.
+ * @param mixed $url the link url.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated link.
+ */
+ public static function carouselNextLink($label, $url = '#', $htmlOptions = array())
+ {
+ self::addCssClass('carousel-control right', $htmlOptions);
+ $htmlOptions['data-slide'] = 'next';
+ return self::link($label, $url, $htmlOptions);
+ }
+
+ /**
+ * Generates an indicator for the carousel.
+ * @param string $target the CSS selector for the target element.
+ * @param integer $numSlides the number of slides.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated indicators.
+ */
+ public static function carouselIndicators($target, $numSlides, $htmlOptions = array())
+ {
+ self::addCssClass('carousel-indicators', $htmlOptions);
+ $output = self::openTag('ol', $htmlOptions);
+ for ($i = 0; $i < $numSlides; $i++) {
+ $itemOptions = array('data-target' => $target, 'data-slide-to' => $i);
+ if ($i === 0) {
+ $itemOptions['class'] = 'active';
+ }
+ $output .= self::tag('li', $itemOptions, '', true);
+ }
+ $output .= '';
+ return $output;
+ }
+
+ // UTILITIES
+ // --------------------------------------------------
+
+ /**
+ * Appends new class names to the given options..
+ * @param mixed $className the class(es) to append.
+ * @param array $htmlOptions the options.
+ * @return array the options.
+ */
+ public static function addCssClass($className, &$htmlOptions)
+ {
+ // Always operate on arrays
+ if (is_string($className)) {
+ $className = explode(' ', $className);
+ }
+ if (isset($htmlOptions['class'])) {
+ $classes = array_filter(explode(' ', $htmlOptions['class']));
+ foreach ($className as $class) {
+ $class = trim($class);
+ // Don't add the class if it already exists
+ if (array_search($class, $classes) === false) {
+ $classes[] = $class;
+ }
+ }
+ $className = $classes;
+ }
+ $htmlOptions['class'] = implode(' ', $className);
+ }
+
+ /**
+ * Appends a CSS style string to the given options.
+ * @param string $style the CSS style string.
+ * @param array $htmlOptions the options.
+ * @return array the options.
+ */
+ public static function addCssStyle($style, &$htmlOptions)
+ {
+ if (is_array($style)) {
+ $style = implode('; ', $style);
+ }
+ $style = rtrim($style, ';');
+ $htmlOptions['style'] = isset($htmlOptions['style'])
+ ? rtrim($htmlOptions['style'], ';') . '; ' . $style
+ : $style;
+ }
+
+ /**
+ * Adds the grid span class to the given options is applicable.
+ * @param array $htmlOptions the HTML attributes.
+ */
+ protected static function addSpanClass(&$htmlOptions)
+ {
+ $span = TbArray::popValue('span', $htmlOptions);
+ if (!empty($span)) {
+ self::addCssClass('span' . $span, $htmlOptions);
+ }
+ }
+
+ /**
+ * Adds the pull class to the given options is applicable.
+ * @param array $htmlOptions the HTML attributes.
+ */
+ protected static function addPullClass(&$htmlOptions)
+ {
+ $pull = TbArray::popValue('pull', $htmlOptions);
+ if (!empty($pull)) {
+ self::addCssClass('pull-' . $pull, $htmlOptions);
+ }
+ }
+
+ /**
+ * Adds the text align class to the given options if applicable.
+ * @param array $htmlOptions the HTML attributes.
+ */
+ protected static function addTextAlignClass(&$htmlOptions)
+ {
+ $align = TbArray::popValue('textAlign', $htmlOptions);
+ if (!empty($align)) {
+ self::addCssClass('text-' . $align, $htmlOptions);
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/package.json b/www/protected/extensions/bootstrap/package.json
new file mode 100644
index 0000000..1e644cf
--- /dev/null
+++ b/www/protected/extensions/bootstrap/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "yiistrap",
+ "version": "1.0.0",
+ "author": "Christoffer Niska ",
+ "description": "Yiistrap, Twitter Bootstrap for Yii.",
+ "contributors": [
+ {
+ "name": "Christoffer Niska",
+ "email": "christoffer.niska@gmail.com",
+ "homepage": "http://www.cniska.net/"
+ },
+ {
+ "name": "Antonio Ramirez",
+ "email": "ramirez.cobos@gmail.com",
+ "homepage": "http://www.ramirezcobos.com/"
+ }
+ ],
+ "keywords": [
+ "yii",
+ "yiistrap",
+ "bootstrap"
+ ],
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-contrib-less": "~0.6.1",
+ "grunt-contrib-watch": "~0.4.4"
+ }
+}
diff --git a/www/protected/extensions/bootstrap/tests/_bootstrap.php b/www/protected/extensions/bootstrap/tests/_bootstrap.php
new file mode 100644
index 0000000..a2a1e9b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/_bootstrap.php
@@ -0,0 +1,14 @@
+assertTrue(strpos($node->text(), $text) !== false);
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param $pattern $text
+ */
+ public function seeNodePattern($node, $pattern)
+ {
+ $this->assertEquals(1, preg_match($pattern, $node->html()));
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ */
+ public function seeNodeEmpty($node)
+ {
+ $this->assertEquals('', $node->text());
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ */
+ public function seeNodeCssClass($node, $cssClass)
+ {
+ if (is_string($cssClass)) {
+ $cssClass = explode(' ', $cssClass);
+ }
+ foreach ($cssClass as $className) {
+ $this->assertTrue(in_array($className, explode(' ', $node->attr('class'))));
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ */
+ public function dontSeeNodeCssClass($node, $cssClass)
+ {
+ if (is_string($cssClass)) {
+ $cssClass = explode(' ', $cssClass);
+ }
+ foreach ($cssClass as $className) {
+ $this->assertFalse(in_array($className, explode(' ', $node->attr('class'))));
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ */
+ public function seeNodeCssStyle($node, $cssStyle)
+ {
+ if (is_string($cssStyle)) {
+ $cssStyle = explode(';', rtrim($cssStyle, ';'));
+ }
+ $cssStyle = $this->normalizeCssStyle($cssStyle);
+ foreach ($cssStyle as $style) {
+ $this->assertTrue(strpos($node->attr('style'), $style) !== false);
+ }
+ }
+
+ /**
+ * @param array $cssStyle
+ * @return array
+ */
+ protected function normalizeCssStyle(array $cssStyle)
+ {
+ array_walk(
+ $cssStyle,
+ function (&$value) {
+ $value = trim($value);
+ }
+ );
+ return $cssStyle;
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ */
+ public function dontSeeNodeCssStyle($node, $cssStyle)
+ {
+ if (is_string($cssStyle)) {
+ $cssStyle = explode(';', rtrim($cssStyle, ';'));
+ }
+ $cssStyle = $this->normalizeCssStyle($cssStyle);
+ foreach ($cssStyle as $style) {
+ $this->assertFalse(strpos($node->attr('style'), $style));
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $name
+ * @param string $value
+ */
+ public function seeNodeAttribute($node, $name, $value = null)
+ {
+ $attr = $node->attr($name);
+ $this->assertTrue($attr !== null);
+ if ($value !== null) {
+ $this->assertEquals($value, $attr);
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $name
+ */
+ public function dontSeeNodeAttribute($node, $name)
+ {
+ $this->assertEquals('', $node->attr($name));
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ */
+ public function seeNodeAttributes($node, array $attributes)
+ {
+ foreach ($attributes as $name => $value) {
+ $this->seeNodeAttribute($node, $name, $value);
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ */
+ public function dontSeeNodeAttributes($node, array $attributes)
+ {
+ foreach ($attributes as $name) {
+ $this->dontSeeNodeAttribute($node, $name);
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ */
+ public function seeNodeChildren($node, array $elements)
+ {
+ /** @var \DomElement $child */
+ foreach ($node->children() as $i => $child) {
+ if (isset($elements[$i])) {
+ $this->assertTrue($this->nodeMatchesCssSelector($child, $elements[$i]));
+ }
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ */
+ public function dontSeeNodeChildren($node, array $elements)
+ {
+ /** @var \DomElement $child */
+ foreach ($node->children() as $i => $child) {
+ if (isset($elements[$i])) {
+ $this->assertFalse($this->nodeMatchesCssSelector($child, $elements[$i]));
+ }
+ }
+ }
+
+ /**
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param integer $amount
+ */
+ public function seeNodeNumChildren($node, $amount, $filter = null)
+ {
+ $count = $filter !== null ? $node->filter($filter)->count() : $node->children()->count();
+ $this->assertEquals($amount, $count);
+ }
+
+ /**
+ * @param \DomElement $node
+ * @param string $selector
+ * @return boolean
+ */
+ protected function nodeMatchesCssSelector($node, $selector)
+ {
+ if ($node->parentNode === null) {
+ return false;
+ }
+ $crawler = $this->createNode($node->parentNode);
+ return count($crawler->filter($selector)) > 0;
+ }
+
+ /**
+ * @param mixed $content
+ * @param string $filter
+ * @return \Symfony\Component\DomCrawler\Crawler
+ */
+ public function createNode($content, $filter = null)
+ {
+ $crawler = new \Symfony\Component\DomCrawler\Crawler($content);
+ if ($filter !== null) {
+ $node = $crawler->filter($filter);
+ $this->assertNotEquals(null, $node);
+ return $node;
+ }
+ return $crawler;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/tests/_helpers/TestHelper.php b/www/protected/extensions/bootstrap/tests/_helpers/TestHelper.php
new file mode 100644
index 0000000..37737cd
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/_helpers/TestHelper.php
@@ -0,0 +1,8 @@
+scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeText', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $text
+ * @see Codeception\Module\CodeHelper::seeNodeText()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeText($node, $text) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeText', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param $pattern $text
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodePattern()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodePattern($node, $pattern) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodePattern', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param $pattern $text
+ * @see Codeception\Module\CodeHelper::seeNodePattern()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodePattern($node, $pattern) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodePattern', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeEmpty()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeEmpty($node) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeEmpty', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @see Codeception\Module\CodeHelper::seeNodeEmpty()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeEmpty($node) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeEmpty', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeCssClass()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeCssClass($node, $cssClass) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeCssClass', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ * @see Codeception\Module\CodeHelper::seeNodeCssClass()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeCssClass($node, $cssClass) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeCssClass', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::dontSeeNodeCssClass()
+ * @return \Codeception\Maybe
+ */
+ public function cantSeeNodeCssClass($node, $cssClass) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeNodeCssClass', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param mixed $cssClass
+ * @see Codeception\Module\CodeHelper::dontSeeNodeCssClass()
+ * @return \Codeception\Maybe
+ */
+ public function dontSeeNodeCssClass($node, $cssClass) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeNodeCssClass', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeCssStyle()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeCssStyle($node, $cssStyle) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeCssStyle', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ * @see Codeception\Module\CodeHelper::seeNodeCssStyle()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeCssStyle($node, $cssStyle) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeCssStyle', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::dontSeeNodeCssStyle()
+ * @return \Codeception\Maybe
+ */
+ public function cantSeeNodeCssStyle($node, $cssStyle) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeNodeCssStyle', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $cssStyle
+ * @see Codeception\Module\CodeHelper::dontSeeNodeCssStyle()
+ * @return \Codeception\Maybe
+ */
+ public function dontSeeNodeCssStyle($node, $cssStyle) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeNodeCssStyle', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $name
+ * @param string $value
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeAttribute()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeAttribute($node, $name, $value = null) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeAttribute', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param string $name
+ * @param string $value
+ * @see Codeception\Module\CodeHelper::seeNodeAttribute()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeAttribute($node, $name, $value = null) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeAttribute', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $name
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::dontSeeNodeAttribute()
+ * @return \Codeception\Maybe
+ */
+ public function cantSeeNodeAttribute($node, $name) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeNodeAttribute', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $name
+ * @see Codeception\Module\CodeHelper::dontSeeNodeAttribute()
+ * @return \Codeception\Maybe
+ */
+ public function dontSeeNodeAttribute($node, $name) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeNodeAttribute', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeAttributes()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeAttributes($node, $attributes) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeAttributes', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ * @see Codeception\Module\CodeHelper::seeNodeAttributes()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeAttributes($node, $attributes) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeAttributes', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::dontSeeNodeAttributes()
+ * @return \Codeception\Maybe
+ */
+ public function cantSeeNodeAttributes($node, $attributes) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeNodeAttributes', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $attributes
+ * @see Codeception\Module\CodeHelper::dontSeeNodeAttributes()
+ * @return \Codeception\Maybe
+ */
+ public function dontSeeNodeAttributes($node, $attributes) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeNodeAttributes', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeChildren()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeChildren($node, $elements) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ * @see Codeception\Module\CodeHelper::seeNodeChildren()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeChildren($node, $elements) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::dontSeeNodeChildren()
+ * @return \Codeception\Maybe
+ */
+ public function cantSeeNodeChildren($node, $elements) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('dontSeeNodeChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param array $elements
+ * @see Codeception\Module\CodeHelper::dontSeeNodeChildren()
+ * @return \Codeception\Maybe
+ */
+ public function dontSeeNodeChildren($node, $elements) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('dontSeeNodeChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param integer $amount
+ * Conditional Assertion: Test won't be stopped on fail
+ * @see Codeception\Module\CodeHelper::seeNodeNumChildren()
+ * @return \Codeception\Maybe
+ */
+ public function canSeeNodeNumChildren($node, $amount) {
+ $this->scenario->addStep(new \Codeception\Step\ConditionalAssertion('seeNodeNumChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param \Symfony\Component\DomCrawler\Crawler $node
+ * @param integer $amount
+ * @see Codeception\Module\CodeHelper::seeNodeNumChildren()
+ * @return \Codeception\Maybe
+ */
+ public function seeNodeNumChildren($node, $amount) {
+ $this->scenario->addStep(new \Codeception\Step\Assertion('seeNodeNumChildren', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+
+
+ /**
+ * This method is generated.
+ * Documentation taken from corresponding module.
+ * ----------------------------------------------
+ *
+ * @param mixed $content
+ * @param string $filter
+ * @return \Symfony\Component\DomCrawler\Crawler
+ * @see Codeception\Module\CodeHelper::createNode()
+ * @return \Codeception\Maybe
+ */
+ public function createNode($content, $filter = null) {
+ $this->scenario->addStep(new \Codeception\Step\Action('createNode', func_get_args()));
+ if ($this->scenario->running()) {
+ $result = $this->scenario->runStep();
+ return new Maybe($result);
+ }
+ return new Maybe();
+ }
+}
+
diff --git a/www/protected/extensions/bootstrap/tests/unit/TbArrayTest.php b/www/protected/extensions/bootstrap/tests/unit/TbArrayTest.php
new file mode 100644
index 0000000..0e08d46
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/unit/TbArrayTest.php
@@ -0,0 +1,93 @@
+ 'value');
+ $this->assertEquals('value', TbArray::getValue('key', $array));
+ }
+
+ public function testPopValue()
+ {
+ $array = array('key' => 'value');
+ $this->assertEquals('value', TbArray::popValue('key', $array));
+ $this->assertArrayNotHasKey('key', $array);
+ }
+
+ public function testDefaultValue()
+ {
+ $array = array();
+ TbArray::defaultValue('key', 'default', $array);
+ $this->assertEquals('default', TbArray::getValue('key', $array));
+ TbArray::defaultValue('key', 'value', $array);
+ $this->assertEquals('default', TbArray::getValue('key', $array));
+ }
+
+ public function testDefaultValues()
+ {
+ $array = array('my' => 'value');
+ TbArray::defaultValues(array('these' => 'are', 'my' => 'defaults'), $array);
+ $this->assertEquals('are', TbArray::getValue('these', $array));
+ $this->assertEquals('value', TbArray::getValue('my', $array));
+ }
+
+ public function testRemoveValue()
+ {
+ $array = array('key' => 'value');
+ TbArray::removeValue('key', $array);
+ $this->assertArrayNotHasKey('key', $array);
+ }
+
+ public function testRemoveValues()
+ {
+ $array = array('these' => 'are', 'my' => 'values');
+ TbArray::removeValues(array('these', 'my'), $array);
+ $this->assertArrayNotHasKey('these', $array);
+ $this->assertArrayNotHasKey('my', $array);
+ }
+
+ public function testCopyValues()
+ {
+ $a = array('key' => 'value');
+ $b = array();
+ $array = TbArray::copyValues(array('key'), $a, $b);
+ $this->assertEquals($a, $array);
+ $a = array('key' => 'value');
+ $b = array('key' => 'other');
+ $array = TbArray::copyValues(array('key'), $a, $b, true);
+ $this->assertEquals($a, $array);
+ }
+
+ public function testMoveValues()
+ {
+ $a = array('key' => 'value');
+ $b = array();
+ $array = TbArray::moveValues(array('key'), $a, $b);
+ $this->assertArrayNotHasKey('key', $a);
+ $this->assertEquals('value', TbArray::getValue('key', $array));
+ $a = array('key' => 'value');
+ $b = array('key' => 'other');
+ $array = TbArray::moveValues(array('key'), $a, $b, true);
+ $this->assertEquals('value', TbArray::getValue('key', $array));
+ }
+
+ public function testMerge()
+ {
+ $a = array('this' => 'is', 'array' => 'a');
+ $b = array('is' => 'this', 'b' => 'array');
+ $array = TbArray::merge($a, $b);
+ $this->assertEquals('is', TbArray::getValue('this', $array));
+ $this->assertEquals('a', TbArray::getValue('array', $array));
+ $this->assertEquals('this', TbArray::getValue('is', $array));
+ $this->assertEquals('array', TbArray::getValue('b', $array));
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/tests/unit/TbHtmlTest.php b/www/protected/extensions/bootstrap/tests/unit/TbHtmlTest.php
new file mode 100644
index 0000000..fd1527a
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/unit/TbHtmlTest.php
@@ -0,0 +1,3934 @@
+mockApplication();
+ }
+
+ public function testLead()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::lead('Lead text');
+ $p = $I->createNode($html, 'p.lead');
+ $I->seeNodeText($p, 'Lead text');
+ }
+
+ public function testSmall()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::small('Small text');
+ $small = $I->createNode($html, 'small');
+ $I->seeNodeText($small, 'Small text');
+ }
+
+ public function testBold()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::b('Bold text');
+ $strong = $I->createNode($html, 'strong');
+ $I->seeNodeText($strong, 'Bold text');
+ }
+
+ public function testItalic()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::i('Italic text');
+ $em = $I->createNode($html, 'em');
+ $I->seeNodeText($em, 'Italic text');
+ }
+
+ public function testEmphasize()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::em(
+ 'Warning text',
+ array(
+ 'color' => TbHtml::TEXT_COLOR_WARNING,
+ )
+ );
+ $span = $I->createNode($html, 'p.text-warning');
+ $I->seeNodeText($span, 'Warning text');
+
+ $html = TbHtml::em(
+ 'Success text',
+ array(
+ 'color' => TbHtml::TEXT_COLOR_SUCCESS,
+ ),
+ 'span'
+ );
+ $span = $I->createNode($html, 'span.text-success');
+ $I->seeNodeText($span, 'Success text');
+ }
+
+ public function testMuted()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::muted('Muted text');
+ $p = $I->createNode($html, 'p.muted');
+ $I->seeNodeText($p, 'Muted text');
+ }
+
+ public function testMutedSpan()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::mutedSpan('Muted text');
+ $span = $I->createNode($html, 'span.muted');
+ $I->seeNodeText($span, 'Muted text');
+ }
+
+ public function testAbbreviation()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::abbr('Abbreviation', 'Word');
+ $abbr = $I->createNode($html, 'abbr');
+ $I->seeNodeAttribute($abbr, 'title', 'Word');
+ $I->seeNodeText($abbr, 'Abbreviation');
+ }
+
+ public function testSmallAbbreviation()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::smallAbbr('Abbreviation', 'Word');
+ $abbr = $I->createNode($html, 'abbr');
+ $I->seeNodeAttribute($abbr, 'title', 'Word');
+ $I->seeNodeCssClass($abbr, 'initialism');
+ $I->seeNodeText($abbr, 'Abbreviation');
+ }
+
+ public function testAddress()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::address('Address text');
+ $addr = $I->createNode($html, 'address');
+ $I->seeNodeText($addr, 'Address text');
+ }
+
+ public function testQuote()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::quote(
+ 'Quote text',
+ array(
+ 'paragraphOptions' => array('class' => 'paragraph'),
+ 'source' => 'Source text',
+ 'sourceOptions' => array('class' => 'source'),
+ 'cite' => 'Cited text',
+ 'citeOptions' => array('class' => 'cite'),
+ )
+ );
+ $blockquote = $I->createNode($html, 'blockquote');
+ $I->seeNodeChildren($blockquote, array('p', 'small'));
+ $p = $blockquote->filter('p');
+ $I->seeNodeCssClass($p, 'paragraph');
+ $I->seeNodeText($p, 'Quote text');
+ $small = $blockquote->filter('blockquote > small');
+ $I->seeNodeCssClass($small, 'source');
+ $I->seeNodeText($small, 'Source text');
+ $cite = $small->filter('small > cite');
+ $I->seeNodeCssClass($cite, 'cite');
+ $I->seeNodeText($cite, 'Cited text');
+ // todo: consider writing a test including the pull-right quote as well.
+ }
+
+ public function testHelp()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::help('Help text');
+ $span = $I->createNode($html, 'span.help-inline');
+ $I->seeNodeText($span, 'Help text');
+ }
+
+ public function testHelpBlock()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::helpBlock('Help text');
+ $p = $I->createNode($html, 'p.help-block');
+ $I->seeNodeText($p, 'Help text');
+ }
+
+ public function testCode()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::code('Source code');
+ $code = $I->createNode($html, 'code');
+ $I->seeNodeText($code, 'Source code');
+ }
+
+ public function testCodeBlock()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::codeBlock('Source code');
+ $pre = $I->createNode($html, 'pre');
+ $I->seeNodeText($pre, 'Source code');
+ }
+
+ public function testTag()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::tag(
+ 'div',
+ array(
+ 'textAlign' => TbHtml::TEXT_ALIGN_RIGHT,
+ 'pull' => TbHtml::PULL_RIGHT,
+ 'span' => 3,
+ ),
+ 'Content'
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'pull-right span3 text-right');
+ }
+
+ public function testOpenTag()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::openTag(
+ 'p',
+ array(
+ 'class' => 'tag',
+ )
+ );
+ $p = $I->createNode($html, 'p');
+ $I->seeNodeCssClass($p, 'tag');
+ }
+
+ public function testForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::formTb(
+ TbHtml::FORM_LAYOUT_VERTICAL,
+ '#',
+ 'post',
+ array(
+ 'class' => 'form',
+ )
+ );
+ $form = $I->createNode($html, 'form.form-vertical');
+ $I->seeNodeCssClass($form, 'form');
+ $I->seeNodeAttributes(
+ $form,
+ array(
+ 'action' => '#',
+ 'method' => 'post'
+ )
+ );
+ }
+
+ public function testBeginForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::beginFormTb(TbHtml::FORM_LAYOUT_VERTICAL, '#');
+ $form = $I->createNode($html, 'form');
+ $I->seeNodeCssClass($form, 'form-vertical');
+ }
+
+ public function testStatefulForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::statefulFormTb(TbHtml::FORM_LAYOUT_VERTICAL, '#');
+ $body = $I->createNode($html);
+ $form = $body->filter('form');
+ $I->seeNodeCssClass($form, 'form-vertical');
+ $div = $body->filter('div');
+ $I->seeNodeCssStyle($div, 'display: none');
+ $input = $div->filter('input[type=hidden]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'name' => 'YII_PAGE_STATE',
+ 'value' => '',
+ )
+ );
+ }
+
+ public function testTextField()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::textField(
+ 'text',
+ 'text',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=text]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'text',
+ 'name' => 'text',
+ 'value' => 'text',
+ )
+ );
+
+ $html = TbHtml::textField(
+ 'text',
+ 'text',
+ array(
+ 'prepend' => 'Prepend text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-prepend');
+ $I->seeNodeChildren($div, array('span', 'input'));
+ $span = $div->filter('span.add-on');
+ $I->seeNodeText($span, 'Prepend text');
+
+ $html = TbHtml::textField(
+ 'text',
+ 'text',
+ array(
+ 'append' => 'Append text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-append');
+ $I->seeNodeChildren($div, array('input', 'span'));
+ $span = $div->filter('span.add-on');
+ $I->seeNodeText($span, 'Append text');
+
+ $html = TbHtml::textField(
+ 'text',
+ 'text',
+ array(
+ 'prepend' => 'Prepend text',
+ 'append' => 'Append text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-prepend input-append');
+ $I->seeNodeChildren($div, array('span', 'input', 'span'));
+
+ $html = TbHtml::textField(
+ 'text',
+ 'text',
+ array(
+ 'block' => true,
+ )
+ );
+ $input = $I->createNode($html, 'input');
+ $I->seeNodeCssClass($input, 'input-block-level');
+ }
+
+ public function testPasswordField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::passwordField(
+ 'password',
+ 'secret',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=password]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'password',
+ 'name' => 'password',
+ 'value' => 'secret',
+ )
+ );
+ }
+
+ public function testUrlField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::urlField(
+ 'url',
+ 'http://www.getyiistrap.com',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=url]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'url',
+ 'name' => 'url',
+ 'value' => 'http://www.getyiistrap.com',
+ )
+ );
+ }
+
+ public function testEmailField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::emailField(
+ 'email',
+ 'christoffer.niska@gmail.com',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=email]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'email',
+ 'name' => 'email',
+ 'value' => 'christoffer.niska@gmail.com',
+ )
+ );
+ }
+
+ public function testNumberField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::numberField(
+ 'number',
+ 42,
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=number]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'number',
+ 'name' => 'number',
+ 'value' => '42',
+ )
+ );
+ }
+
+ public function testRangeField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::rangeField(
+ 'range',
+ 3.33,
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=range]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'range',
+ 'name' => 'range',
+ 'value' => '3.33',
+ )
+ );
+ }
+
+ public function testDateField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dateField(
+ 'date',
+ '2013-08-28',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=date]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'date',
+ 'name' => 'date',
+ 'value' => '2013-08-28',
+ )
+ );
+ }
+
+ public function testFileField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::fileField(
+ 'file',
+ '',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=file]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'file',
+ 'name' => 'file',
+ 'value' => '',
+ )
+ );
+ }
+
+ public function testTextArea()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::textArea(
+ 'textarea',
+ 'Textarea text',
+ array(
+ 'class' => 'textarea',
+ )
+ );
+ $textarea = $I->createNode($html, 'textarea');
+ $I->seeNodeAttributes(
+ $textarea,
+ array(
+ 'class' => 'textarea',
+ 'id' => 'textarea',
+ 'name' => 'textarea',
+ )
+ );
+ $I->seeNodeText($textarea, 'Textarea text');
+ }
+
+ public function testRadioButton()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::radioButton(
+ 'radio',
+ false,
+ array(
+ 'class' => 'input',
+ 'label' => 'Label text',
+ )
+ );
+ $label = $I->createNode($html, 'label');
+ $I->seeNodeCssClass($label, 'radio');
+ $I->seeNodePattern($label, '/> Label text$/');
+ $input = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'radio',
+ 'name' => 'radio',
+ 'value' => '1',
+ )
+ );
+ $I->dontSeeNodeAttribute($input, 'checked');
+
+ $html = TbHtml::radioButton('radio', true);
+ $input = $I->createNode($html, 'input[type=radio]');
+ $I->seeNodeAttribute($input, 'checked', 'checked');
+ }
+
+ public function testCheckBox()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::checkBox(
+ 'checkbox',
+ false,
+ array(
+ 'class' => 'input',
+ 'label' => 'Label text',
+ )
+ );
+ $label = $I->createNode($html, 'label');
+ $I->seeNodeCssClass($label, 'checkbox');
+ $I->seeNodePattern($label, '/> Label text$/');
+ $input = $label->filter('input[type=checkbox]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'checkbox',
+ 'name' => 'checkbox',
+ 'value' => '1',
+ )
+ );
+ $I->dontSeeNodeAttribute($input, 'checked');
+
+ $html = TbHtml::checkBox('checkbox', true);
+ $input = $I->createNode($html, 'input[type=checkbox]');
+ $I->seeNodeAttribute($input, 'checked', 'checked');
+ }
+
+ public function testDropDownList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dropDownList(
+ 'dropdown',
+ null,
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'class' => 'list',
+ 'empty' => 'Empty text',
+ 'size' => TbHtml::INPUT_SIZE_LARGE,
+ 'textAlign' => TbHtml::TEXT_ALIGN_CENTER,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeCssClass($select, 'input-large text-center list');
+ $I->dontSeeNodeAttribute($select, 'size');
+ }
+
+ public function testListBox()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::listBox(
+ 'listbox',
+ null,
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'class' => 'list',
+ 'empty' => 'Empty text',
+ 'size' => TbHtml::INPUT_SIZE_LARGE,
+ 'textAlign' => TbHtml::TEXT_ALIGN_CENTER,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeCssClass($select, 'input-large text-center list');
+ $I->seeNodeAttributes(
+ $select,
+ array(
+ 'name' => 'listbox',
+ 'id' => 'listbox',
+ 'size' => 4,
+ )
+ );
+
+ $html = TbHtml::listBox(
+ 'listbox',
+ null,
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'multiple' => true,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeAttribute($select, 'name', 'listbox[]');
+ }
+
+ public function testRadioButtonList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::radioButtonList(
+ 'radioList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3'),
+ array(
+ 'separator' => ' ',
+ 'container' => 'div',
+ 'containerOptions' => array('class' => 'container'),
+ )
+ );
+ $container = $I->createNode($html, 'div.container');
+ $I->seeNodeChildren($container, array('label.radio', 'br', 'label.radio', 'br', 'label.radio'));
+ $label = $container->filter('label')->first();
+ $I->seeNodePattern($label, '/> Option 1$/');
+ $input = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'radioList_0',
+ 'name' => 'radioList',
+ 'value' => '0',
+ )
+ );
+ }
+
+ public function testInlineRadioButtonList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::inlineRadioButtonList(
+ 'radioList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $span = $I->createNode($html, 'span');
+ $I->seeNodeNumChildren($span, 3);
+ $I->seeNodeChildren($span, array('label.radio.inline', 'label.radio.inline', 'label.radio.inline'));
+ }
+
+ public function testCheckboxList()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::checkBoxList(
+ 'checkboxList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3'),
+ array(
+ 'separator' => ' ',
+ 'container' => 'div',
+ 'containerOptions' => array('class' => 'container'),
+ )
+ );
+ $container = $I->createNode($html, 'div.container');
+ $I->seeNodeChildren($container, array('label.checkbox', 'br', 'label.checkbox', 'br', 'label.checkbox'));
+ $label = $container->filter('label')->first();
+ $I->seeNodePattern($label, '/> Option 1$/');
+ $input = $label->filter('input[type=checkbox]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'checkboxList_0',
+ 'name' => 'checkboxList[]',
+ 'value' => '0',
+ )
+ );
+
+ $html = TbHtml::checkBoxList(
+ 'checkboxList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3'),
+ array(
+ 'checkAll' => true,
+ )
+ );
+ $span = $I->createNode($html, 'span');
+ $I->seeNodeChildren(
+ $span,
+ array('input[type=checkbox]', 'label.checkbox', 'label.checkbox', 'label.checkbox', 'label.checkbox')
+ );
+ $label = $span->filter('label')->first();
+ $input = $label->filter('input');
+ $I->seeNodeAttribute($input, 'name', 'checkboxList_all');
+
+ $html = TbHtml::checkBoxList(
+ 'checkboxList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3'),
+ array(
+ 'checkAll' => true,
+ 'checkAllLast' => true,
+ )
+ );
+ $span = $I->createNode($html, 'span');
+ $I->seeNodeChildren(
+ $span,
+ array('label.checkbox', 'label.checkbox', 'label.checkbox', 'label.checkbox', 'input[type=checkbox]')
+ );
+ $label = $span->filter('label')->last();
+ $input = $label->filter('input');
+ $I->seeNodeAttribute($input, 'name', 'checkboxList_all');
+ }
+
+ public function testInlineCheckBoxList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::inlineCheckBoxList(
+ 'checkboxList',
+ null,
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $span = $I->createNode($html, 'span');
+ $I->seeNodeNumChildren($span, 3);
+ $I->seeNodeChildren(
+ $span,
+ array('label.checkbox.inline', 'label.checkbox.inline', 'label.checkbox.inline')
+ );
+ }
+
+ public function testUneditableField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::uneditableField(
+ 'Uneditable text',
+ array(
+ 'class' => 'span',
+ )
+ );
+ $span = $I->createNode($html, 'span.uneditable-input');
+ $I->seeNodeCssClass($span, 'span');
+ $I->seeNodeText($span, 'Uneditable text');
+ }
+
+ public function testSearchQueryField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::searchQueryField(
+ 'search',
+ 'Search query',
+ array(
+ 'class' => 'input',
+ )
+ );
+ $input = $I->createNode($html, 'input[type=text].search-query');
+ $I->seeNodeCssClass($input, 'input');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'search',
+ 'name' => 'search',
+ 'value' => 'Search query',
+ )
+ );
+ }
+
+ public function testTextFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::textFieldControlGroup('text', 'text');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=text]'));
+ }
+
+ public function testPasswordFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::passwordFieldControlGroup('password', 'secret');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=password]'));
+ }
+
+ public function testUrlFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::urlFieldControlGroup('url', 'url');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=url]'));
+ }
+
+ public function testEmailFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::emailFieldControlGroup('email', 'email');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=email]'));
+ }
+
+ public function testNumberFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::numberFieldControlGroup('number', 'number');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=number]'));
+ }
+
+ public function testRangeFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::rangeFieldControlGroup('range', 'range');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=range]'));
+ }
+
+ public function testDateFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dateFieldControlGroup('date', 'date');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=date]'));
+ }
+
+ public function testFileFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::fileFieldControlGroup('file', 'file');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=file]'));
+ }
+
+ public function testTextAreaControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::textAreaControlGroup('textarea', 'Textarea text');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('textarea'));
+ }
+
+ public function testRadioButtonControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::radioButtonControlGroup(
+ 'radio',
+ false,
+ array(
+ 'label' => 'Label text',
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.radio');
+ $I->seeNodeChildren($label, array('input[type=radio]'));
+ }
+
+ public function testCheckBoxControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::checkBoxControlGroup(
+ 'checkbox',
+ false,
+ array(
+ 'label' => 'Label text',
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.checkbox');
+ $I->seeNodeChildren($label, array('input[type=checkbox]'));
+ }
+
+ public function testDropDownListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dropDownListControlGroup(
+ 'dropdown',
+ '',
+ array('1', '2', '3', '4', '5')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('select'));
+ }
+
+ public function testListBoxControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::listBoxControlGroup(
+ 'listbox',
+ '',
+ array('1', '2', '3', '4', '5')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('select'));
+ }
+
+ public function testRadioButtonListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::radioButtonListControlGroup(
+ 'radioList',
+ '1',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('label.radio', 'label.radio', 'label.radio'));
+ }
+
+ public function testInlineRadioButtonListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::inlineRadioButtonListControlGroup(
+ 'radioList',
+ '1',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('label.radio.inline', 'label.radio.inline', 'label.radio.inline'));
+ }
+
+ public function testCheckBoxListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::checkBoxListControlGroup(
+ 'checkboxList',
+ array('0', '2'),
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('label.checkbox', 'label.checkbox', 'label.checkbox'));
+ }
+
+ public function testInlineCheckBoxListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::inlineCheckBoxListControlGroup(
+ 'checkboxList',
+ array('0', '2'),
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren(
+ $controls,
+ array('label.checkbox.inline', 'label.checkbox.inline', 'label.checkbox.inline')
+ );
+ }
+
+ public function testUneditableFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::uneditableFieldControlGroup('Uneditable text');
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('span.uneditable-input'));
+ }
+
+ public function testSearchQueryControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::searchQueryControlGroup('Search query');
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input[type=text].search-query'));
+ }
+
+ public function testControlGroup()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::controlGroup(
+ TbHtml::INPUT_TYPE_TEXT,
+ 'text',
+ '',
+ array(
+ 'color' => TbHtml::INPUT_COLOR_SUCCESS,
+ 'groupOptions' => array('class' => 'group'),
+ 'label' => 'Label text',
+ 'labelOptions' => array('class' => 'label'),
+ 'help' => 'Help text',
+ 'helpOptions' => array('class' => 'help'),
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeCssClass($group, 'success group');
+ $I->seeNodeChildren($group, array('label.control-label', 'div.controls'));
+ $label = $group->filter('label.control-label');
+ $I->seeNodeCssClass($label, 'label');
+ $I->seeNodeAttribute($label, 'for', 'text');
+ $I->seeNodeText($label, 'Label text');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input', 'span'));
+ $input = $controls->filter('input[type=text]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'text',
+ 'name' => 'text',
+ 'value' => '',
+ )
+ );
+ $help = $controls->filter('span.help-inline');
+ $I->seeNodeCssClass($help, 'help');
+ $I->seeNodeText($help, 'Help text');
+
+ $html = TbHtml::controlGroup(
+ TbHtml::INPUT_TYPE_RADIOBUTTON,
+ 'radio',
+ true,
+ array(
+ 'label' => 'Label text',
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeChildren($group, array('div.controls'));
+ $controls = $group->filter('div.controls');
+ $label = $controls->filter('label.radio');
+ $I->seeNodePattern($label, '/> Label text$/');
+ $radio = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $radio,
+ array(
+ 'checked' => 'checked',
+ 'id' => 'radio',
+ 'name' => 'radio',
+ 'value' => '1',
+ )
+ );
+ }
+
+ public function testCustomControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::customControlGroup(
+ '
',
+ 'custom',
+ array(
+ 'label' => false,
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('div.widget'));
+ }
+
+ public function testActiveTextField()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::activeTextField(
+ new Dummy,
+ 'text',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=text]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_text',
+ 'name' => 'Dummy[text]',
+ 'value' => 'text',
+ )
+ );
+
+ $html = TbHtml::activeTextField(
+ new Dummy,
+ 'text',
+ array(
+ 'prepend' => 'Prepend text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-prepend');
+ $I->seeNodeChildren($div, array('span.add-on', 'input'));
+ $span = $div->filter('span.add-on');
+ $I->seeNodeText($span, 'Prepend text');
+
+ $html = TbHtml::activeTextField(
+ new Dummy,
+ 'text',
+ array(
+ 'append' => 'Append text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-append');
+ $I->seeNodeChildren($div, array('input', 'span'));
+ $span = $div->filter('span.add-on');
+ $I->seeNodeText($span, 'Append text');
+
+ $html = TbHtml::activeTextField(
+ new Dummy,
+ 'text',
+ array(
+ 'prepend' => 'Prepend text',
+ 'append' => 'Append text',
+ )
+ );
+ $div = $I->createNode($html, 'div');
+ $I->seeNodeCssClass($div, 'input-prepend input-append');
+ $I->seeNodeChildren($div, array('span.add-on', 'input', 'span.add-on'));
+ }
+
+ public function testActivePasswordField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activePasswordField(
+ new Dummy,
+ 'password',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=password]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_password',
+ 'name' => 'Dummy[password]',
+ 'value' => 'secret',
+ )
+ );
+ }
+
+ public function testActiveUrlField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeUrlField(
+ new Dummy,
+ 'url',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=url]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_url',
+ 'name' => 'Dummy[url]',
+ 'value' => 'http://www.getyiistrap.com',
+ )
+ );
+ }
+
+ public function testActiveEmailField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeEmailField(
+ new Dummy,
+ 'email',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=email]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_email',
+ 'name' => 'Dummy[email]',
+ 'value' => 'christoffer.niska@gmail.com',
+ )
+ );
+ }
+
+ public function testActiveNumberField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeNumberField(
+ new Dummy,
+ 'number',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=number]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_number',
+ 'name' => 'Dummy[number]',
+ 'value' => '42',
+ )
+ );
+ }
+
+ public function testActiveRangeField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRangeField(
+ new Dummy,
+ 'range',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=range]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_range',
+ 'name' => 'Dummy[range]',
+ 'value' => '3.33',
+ )
+ );
+ }
+
+ public function testActiveDateField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeDateField(
+ new Dummy,
+ 'date',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=date]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_date',
+ 'name' => 'Dummy[date]',
+ 'value' => '2013-08-28',
+ )
+ );
+ }
+
+ public function testActiveTextArea()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeTextArea(
+ new Dummy,
+ 'textarea',
+ array(
+ 'class' => 'textarea',
+ )
+ );
+ $textarea = $I->createNode($html, 'textarea');
+ $I->seeNodeAttributes(
+ $textarea,
+ array(
+ 'class' => 'textarea',
+ 'id' => 'Dummy_textarea',
+ 'name' => 'Dummy[textarea]',
+ )
+ );
+ $I->seeNodeText($textarea, 'Textarea text');
+ }
+
+ public function testActiveRadioButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRadioButton(
+ new Dummy,
+ 'radio',
+ array(
+ 'class' => 'input',
+ 'label' => 'Label text',
+ )
+ );
+ $body = $I->createNode($html, 'body');
+ $hidden = $body->filter('input[type=hidden]');
+ $I->seeNodeAttributes(
+ $hidden,
+ array(
+ 'id' => 'ytDummy_radio',
+ 'name' => 'Dummy[radio]',
+ 'value' => '0',
+ )
+ );
+ $label = $body->filter('label');
+ $I->seeNodeCssClass($label, 'radio');
+ $radio = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $radio,
+ array(
+ 'class' => 'input',
+ 'checked' => 'checked',
+ 'id' => 'Dummy_radio',
+ 'name' => 'Dummy[radio]',
+ 'value' => '1',
+ )
+ );
+ $I->seeNodePattern($label, '/> Label text$/');
+ }
+
+ public function testActiveCheckBox()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeCheckBox(
+ new Dummy,
+ 'checkbox',
+ array(
+ 'class' => 'input',
+ 'label' => 'Label text',
+ )
+ );
+ $body = $I->createNode($html, 'body');
+ $hidden = $body->filter('input[type=hidden]');
+ $I->seeNodeAttributes(
+ $hidden,
+ array(
+ 'id' => 'ytDummy_checkbox',
+ 'name' => 'Dummy[checkbox]',
+ 'value' => '0',
+ )
+ );
+ $label = $body->filter('label');
+ $I->seeNodeCssClass($label, 'checkbox');
+ $checkbox = $label->filter('input[type=checkbox]');
+ $I->seeNodeAttributes(
+ $checkbox,
+ array(
+ 'class' => 'input',
+ 'id' => 'Dummy_checkbox',
+ 'name' => 'Dummy[checkbox]',
+ 'value' => '1',
+ )
+ );
+ $I->seeNodePattern($label, '/> Label text$/');
+ }
+
+ public function testActiveDropDownList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeDropDownList(
+ new Dummy,
+ 'dropdown',
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'class' => 'list',
+ 'empty' => 'Empty text',
+ 'size' => TbHtml::INPUT_SIZE_LARGE,
+ 'textAlign' => TbHtml::TEXT_ALIGN_CENTER,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeCssClass($select, 'input-large text-center list');
+ $I->dontSeeNodeAttribute($select, 'size');
+ }
+
+ public function testActiveListBox()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::activeListBox(
+ new Dummy,
+ 'listbox',
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'class' => 'list',
+ 'empty' => 'Empty text',
+ 'size' => TbHtml::INPUT_SIZE_LARGE,
+ 'textAlign' => TbHtml::TEXT_ALIGN_CENTER,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeCssClass($select, 'input-large text-center list');
+ $I->seeNodeAttributes(
+ $select,
+ array(
+ 'name' => 'Dummy[listbox]',
+ 'id' => 'Dummy_listbox',
+ 'size' => 4,
+ )
+ );
+
+ $html = TbHtml::activeListBox(
+ new Dummy,
+ 'listbox',
+ array('1', '2', '3', '4', '5'),
+ array(
+ 'multiple' => true,
+ )
+ );
+ $select = $I->createNode($html, 'select');
+ $I->seeNodeAttribute($select, 'name', 'Dummy[listbox][]');
+ }
+
+ public function testActiveRadioButtonList()
+ {
+ // todo: ensure that this test is actually correct.
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRadioButtonList(
+ new Dummy,
+ 'radioList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $body = $I->createNode($html);
+ $I->seeNodeChildren(
+ $body,
+ array('input[type=hidden]', 'label.radio', 'label.radio', 'label.radio')
+ );
+ $label = $body->filter('label')->first();
+ $I->seeNodePattern($label, '/> Option 1$/');
+ $input = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'Dummy_radioList_0',
+ 'name' => 'Dummy[radioList]',
+ 'value' => '0',
+ )
+ );
+ }
+
+ public function testActiveInlineRadioButtonList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeInlineRadioButtonList(
+ new Dummy,
+ 'radioList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $container = $I->createNode($html);
+ $I->seeNodeChildren($container, array('label.radio.inline', 'label.radio.inline', 'label.radio.inline'));
+ }
+
+ public function testActiveCheckBoxList()
+ {
+ // todo: ensure that this test is actually correct.
+ $I = $this->codeGuy;
+ $html = TbHtml::activeCheckBoxList(
+ new Dummy,
+ 'checkboxList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $container = $I->createNode($html);
+ $I->seeNodeChildren(
+ $container,
+ array('input[type=hidden]', 'label.checkbox', 'label.checkbox', 'label.checkbox')
+ );
+ $label = $container->filter('label')->first();
+ $I->seeNodePattern($label, '/> Option 1$/');
+ $input = $label->filter('input[type=checkbox]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'Dummy_checkboxList_0',
+ 'name' => 'Dummy[checkboxList][]',
+ 'value' => '0',
+ )
+ );
+ }
+
+ public function testActiveInlineCheckBoxList()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeInlineCheckBoxList(
+ new Dummy,
+ 'checkboxList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $container = $I->createNode($html);
+ $I->seeNodeChildren(
+ $container,
+ array('label.checkbox.inline', 'label.checkbox.inline', 'label.checkbox.inline')
+ );
+ }
+
+ public function testActiveUneditableField()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeUneditableField(
+ new Dummy,
+ 'uneditable',
+ array(
+ 'class' => 'span'
+ )
+ );
+ $span = $I->createNode($html, 'span.uneditable-input');
+ $I->seeNodeCssClass($span, 'span');
+ $I->seeNodeText($span, 'Uneditable text');
+ }
+
+ public function testActiveSearchQueryField()
+ {
+ $I = $this->codeGuy;
+ $model = new Dummy;
+ $html = TbHtml::activeSearchQueryField(
+ $model,
+ 'search',
+ array(
+ 'class' => 'input'
+ )
+ );
+ $input = $I->createNode($html, 'input[type=text].search-query');
+ $I->seeNodeCssClass($input, 'input');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'Dummy_search',
+ 'name' => 'Dummy[search]',
+ 'value' => 'Search query',
+ )
+ );
+ }
+
+ public function testActiveTextFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeTextFieldControlGroup(new Dummy, 'text');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=text]'));
+ }
+
+ public function testActivePasswordFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activePasswordFieldControlGroup(new Dummy, 'password');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=password]'));
+ }
+
+ public function testActiveUrlFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeUrlFieldControlGroup(new Dummy, 'url');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=url]'));
+ }
+
+ public function testActiveEmailFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeEmailFieldControlGroup(new Dummy, 'email');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=email]'));
+ }
+
+ public function testActiveNumberFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeNumberFieldControlGroup(new Dummy, 'number');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=number]'));
+ }
+
+ public function testActiveRangeFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRangeFieldControlGroup(new Dummy, 'range');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=range]'));
+ }
+
+ public function testActiveDateFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeDateFieldControlGroup(new Dummy, 'date');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=date]'));
+ }
+
+ public function testActiveFileFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeFileFieldControlGroup(new Dummy, 'file');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('input[type=file]'));
+ }
+
+ public function testActiveTextAreaControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeTextAreaControlGroup(new Dummy, 'textarea');
+ $group = $I->createNode($html, 'div.control-group');
+ $label = $group->filter('label.control-label');
+ $I->seeNodeChildren($label, array('textarea'));
+ }
+
+ public function testActiveRadioButtonControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRadioButtonControlGroup(new Dummy, 'radio');
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeChildren($group, array('input[type=hidden]', 'label.radio'));
+ $label = $group->filter('label.radio');
+ $I->seeNodeChildren($label, array('input[type=radio]'));
+ }
+
+ public function testActiveCheckBoxControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeCheckBoxControlGroup(new Dummy, 'checkbox');
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeChildren($group, array('input[type=hidden]', 'label.checkbox'));
+ $label = $group->filter('label.checkbox');
+ $I->seeNodeChildren($label, array('input[type=checkbox]'));
+ }
+
+ public function testActiveDropDownListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeDropDownListControlGroup(
+ new Dummy,
+ 'dropdown',
+ array('1', '2', '3', '4', '5')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('select'));
+ }
+
+ public function testActiveListBoxControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeListBoxControlGroup(
+ new Dummy,
+ 'listbox',
+ array('1', '2', '3', '4', '5')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('select'));
+ }
+
+ public function testActiveRadioButtonListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeRadioButtonListControlGroup(
+ new Dummy,
+ 'radioList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input[type=hidden]', 'label.radio', 'label.radio', 'label.radio'));
+ }
+
+ public function testActiveInlineRadioButtonListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeInlineRadioButtonListControlGroup(
+ new Dummy,
+ 'radioList',
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren(
+ $controls,
+ array('input[type=hidden]', 'label.radio.inline', 'label.radio.inline', 'label.radio.inline')
+ );
+ }
+
+ public function testActiveCheckBoxListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeCheckBoxListControlGroup(
+ new Dummy,
+ 'checkboxList',
+ array('0', '2'),
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren(
+ $controls,
+ array('input[type=hidden]', 'label.checkbox', 'label.checkbox', 'label.checkbox')
+ );
+ }
+
+ public function testActiveInlineCheckBoxListControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeInlineCheckBoxListControlGroup(
+ new Dummy,
+ 'checkboxList',
+ array('0', '2'),
+ array('Option 1', 'Option 2', 'Option 3')
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren(
+ $controls,
+ array('input[type=hidden]', 'label.checkbox.inline', 'label.checkbox.inline', 'label.checkbox.inline')
+ );
+ }
+
+ public function testActiveUneditableFieldControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeUneditableFieldControlGroup(new Dummy, 'uneditable');
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('span.uneditable-input'));
+ }
+
+ public function testActiveSearchQueryControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::activeSearchQueryControlGroup(new Dummy, 'search');
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input[type=text].search-query'));
+ }
+
+ public function testActiveControlGroup()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::activeControlGroup(
+ TbHtml::INPUT_TYPE_TEXT,
+ new Dummy,
+ 'text',
+ array(
+ 'color' => TbHtml::INPUT_COLOR_ERROR,
+ 'groupOptions' => array('class' => 'group'),
+ 'labelOptions' => array('class' => 'label'),
+ 'help' => 'Help text',
+ 'helpOptions' => array('class' => 'help'),
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeCssClass($group, 'error group');
+ $I->seeNodeChildren($group, array('label.control-label', 'div.controls'));
+ $label = $group->filter('label.control-label');
+ $I->seeNodeCssClass($label, 'label');
+ $I->seeNodeAttribute($label, 'for', 'Dummy_text');
+ $I->seeNodeText($label, 'Text');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input', 'span'));
+ $input = $controls->filter('input[type=text]');
+ $I->seeNodeAttributes(
+ $input,
+ array(
+ 'id' => 'Dummy_text',
+ 'name' => 'Dummy[text]',
+ 'value' => 'text',
+ )
+ );
+ $help = $controls->filter('span.help-inline');
+ $I->seeNodeCssClass($help, 'help');
+ $I->seeNodeText($help, 'Help text');
+
+ $html = TbHtml::activeControlGroup(
+ TbHtml::INPUT_TYPE_RADIOBUTTON,
+ new Dummy,
+ 'radio',
+ array(
+ 'labelOptions' => array('class' => 'label'),
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $I->seeNodeChildren($group, array('div.controls'));
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('input[type=hidden]', 'label.radio'));
+ $hidden = $controls->filter('input[type=hidden]');
+ $I->seeNodeAttributes(
+ $hidden,
+ array(
+ 'id' => 'ytDummy_radio',
+ 'name' => 'Dummy[radio]',
+ 'value' => '0',
+ )
+ );
+ $label = $controls->filter('label.radio');
+ $I->seeNodePattern($label, '/> Radio$/');
+ $radio = $label->filter('input[type=radio]');
+ $I->seeNodeAttributes(
+ $radio,
+ array(
+ 'checked' => 'checked',
+ 'id' => 'Dummy_radio',
+ 'name' => 'Dummy[radio]',
+ 'value' => '1',
+ )
+ );
+ }
+
+ public function testActiveCustomControlGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::customActiveControlGroup(
+ '
',
+ new Dummy,
+ 'text',
+ array(
+ 'label' => false,
+ )
+ );
+ $group = $I->createNode($html, 'div.control-group');
+ $controls = $group->filter('div.controls');
+ $I->seeNodeChildren($controls, array('div.widget'));
+ }
+
+ public function testErrorSummary()
+ {
+ $I = $this->codeGuy;
+ $model = new Dummy;
+ $model->addError('text', 'Error text');
+ $html = TbHtml::errorSummary(
+ $model,
+ 'Header text',
+ 'Footer text',
+ array(
+ 'class' => 'summary'
+ )
+ );
+ $div = $I->createNode($html, 'div.alert');
+ $I->seeNodeCssClass($div, 'alert-block alert-error summary');
+ $I->seeNodePattern($div, '/^Header text/');
+ $I->seeNodePattern($div, '/Footer text$/');
+ $li = $div->filter('ul > li')->first();
+ $I->seeNodeText($li, 'Error text');
+ }
+
+ public function testError()
+ {
+ $I = $this->codeGuy;
+ $model = new Dummy;
+ $model->addError('text', 'Error text');
+ $html = TbHtml::error(
+ $model,
+ 'text',
+ array(
+ 'class' => 'error',
+ )
+ );
+ $span = $I->createNode($html, 'span.help-inline');
+ $I->seeNodeCssClass($span, 'error');
+ $I->seeNodeText($span, 'Error text');
+ }
+
+ public function testControls()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::controls(
+ '
',
+ array(
+ 'before' => 'Before text',
+ 'after' => 'After text',
+ )
+ );
+ $controls = $I->createNode($html, 'div.controls');
+ $I->seeNodeChildren($controls, array('div.control', 'div.control'));
+ $I->seeNodePattern($controls, '/^Before text');
+ $I->seeNodePattern($controls, '/>After text$/');
+ }
+
+ public function testControlsRow()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::controlsRow(
+ array(
+ '
',
+ '
',
+ )
+ );
+ $controls = $I->createNode($html, 'div.controls');
+ $I->seeNodeCssClass($controls, 'controls-row');
+ $I->seeNodeChildren($controls, array('div.control', 'div.control'));
+ }
+
+ public function testFormActions()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::formActions('
');
+ $this->assertEquals(
+ '',
+ $html
+ );
+ $actions = $I->createNode($html, 'div.form-actions');
+ $I->seeNodeChildren($actions, array('div.action', 'div.action'));
+
+ $html = TbHtml::formActions(
+ array(
+ '
',
+ '
',
+ )
+ );
+ $actions = $I->createNode($html, 'div.form-actions');
+ $I->seeNodeChildren($actions, array('div.action', 'div.action'));
+ }
+
+ public function testSearchForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::searchForm(
+ '#',
+ 'post',
+ array(
+ 'class' => 'form',
+ )
+ );
+ $form = $I->createNode($html, 'form.form-search');
+ $I->seeNodeCssClass($form, 'form');
+ $I->seeNodeAttributes(
+ $form,
+ array(
+ 'action' => '#',
+ 'method' => 'post'
+ )
+ );
+ $input = $form->filter('input[type=text]');
+ $I->seeNodeCssClass($input, 'search-query');
+ }
+
+ public function testLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::link(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'link'
+ )
+ );
+ $a = $I->createNode($html, 'a.link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::button(
+ 'Button',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ 'color' => TbHtml::BUTTON_COLOR_PRIMARY,
+ 'size' => TbHtml::BUTTON_SIZE_LARGE,
+ 'block' => true,
+ 'disabled' => true,
+ 'loading' => 'Loading text',
+ 'toggle' => true,
+ 'icon' => TbHtml::ICON_CHECK
+ )
+ );
+ $button = $I->createNode($html, 'button[type=button].btn');
+ $I->seeNodeCssClass($button, 'btn-primary btn-large btn-block disabled button');
+ $I->seeNodeAttributes(
+ $button,
+ array(
+ 'name' => 'button',
+ 'data-loading-text' => 'Loading text',
+ 'data-toggle' => 'button',
+ 'disabled' => 'disabled',
+ )
+ );
+ $I->seeNodeChildren($button, array('i.icon-check'));
+ $I->seeNodePattern($button, '/> Button$/');
+ }
+
+ public function testHtmlButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::htmlButton(
+ 'Button',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=button].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttribute($button, 'name', 'button');
+ $I->seeNodeText($button, 'Button');
+ }
+
+ public function testSubmitButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::submitButton(
+ 'Submit',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=submit].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttribute($button, 'name', 'button');
+ $I->seeNodeText($button, 'Submit');
+ }
+
+ public function testResetButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::resetButton(
+ 'Reset',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=reset].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttribute($button, 'name', 'button');
+ $I->seeNodeText($button, 'Reset');
+ }
+
+ public function testImageButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::imageButton(
+ 'image.png',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'input[type=image].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttributes(
+ $button,
+ array(
+ 'name' => 'button',
+ 'src' => 'image.png',
+ )
+ );
+ }
+
+ public function testLinkButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::linkButton(
+ 'Link',
+ array(
+ 'class' => 'button',
+ )
+ );
+ $a = $I->createNode($html, 'a.btn');
+ $I->seeNodeCssClass($a, 'button');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testAjaxLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::ajaxLink(
+ 'Link',
+ '#',
+ array(), // todo: figure out a way to test the ajax options as well.
+ array(
+ 'id' => 'button',
+ 'class' => 'button',
+ )
+ );
+ $a = $I->createNode($html, 'a');
+ $I->seeNodeCssClass($a, 'button');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'id' => 'button',
+ 'href' => '#',
+ )
+ );
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testAjaxButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::ajaxButton(
+ 'Button',
+ '#',
+ array(),
+ array(
+ 'id' => 'button',
+ 'class' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=button].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttribute($button, 'id', 'button');
+ $I->seeNodeText($button, 'Button');
+ }
+
+ public function testAjaxSubmitButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::ajaxSubmitButton(
+ 'Submit',
+ '#',
+ array(),
+ array(
+ 'class' => 'button',
+ 'id' => 'button',
+ 'name' => 'button'
+ )
+ );
+ $button = $I->createNode($html, 'button[type=submit].btn');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttributes(
+ $button,
+ array(
+ 'id' => 'button',
+ 'name' => 'button'
+ )
+ );
+ $I->seeNodeText($button, 'Submit');
+ }
+
+ public function testImageRounded()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::imageRounded(
+ 'image.png',
+ 'Alternative text',
+ array(
+ 'class' => 'image',
+ )
+ );
+ $img = $I->createNode($html, 'img.img-rounded');
+ $I->seeNodeCssClass($img, 'image');
+ $I->seeNodeAttributes(
+ $img,
+ array(
+ 'src' => 'image.png',
+ 'alt' => 'Alternative text',
+ )
+ );
+ }
+
+ public function testImageCircle()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::imageCircle(
+ 'image.png',
+ 'Alternative text',
+ array(
+ 'class' => 'image',
+ )
+ );
+ $img = $I->createNode($html, 'img.img-circle');
+ $I->seeNodeCssClass($img, 'image');
+ $I->seeNodeAttributes(
+ $img,
+ array(
+ 'src' => 'image.png',
+ 'alt' => 'Alternative text',
+ )
+ );
+ }
+
+ public function testImagePolaroid()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::imagePolaroid(
+ 'image.png',
+ 'Alternative text',
+ array(
+ 'class' => 'image',
+ )
+ );
+ $img = $I->createNode($html, 'img.img-polaroid');
+ $I->seeNodeCssClass($img, 'image');
+ $I->seeNodeAttributes(
+ $img,
+ array(
+ 'src' => 'image.png',
+ 'alt' => 'Alternative text',
+ )
+ );
+ }
+
+ public function testIcon()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::icon(
+ TbHtml::ICON_CHECK,
+ array(
+ 'class' => 'icon',
+ )
+ );
+ $i = $I->createNode($html, 'i.icon-check');
+ $I->seeNodeEmpty($i);
+
+ $html = TbHtml::icon(
+ TbHtml::ICON_REMOVE,
+ array(
+ 'color' => TbHtml::ICON_COLOR_WHITE,
+ )
+ );
+ $i = $I->createNode($html, 'i.icon-remove');
+ $I->seeNodeCssClass($i, 'icon-white');
+ $I->seeNodeEmpty($i);
+
+ $html = TbHtml::icon('pencil white');
+ $i = $I->createNode($html, 'i.icon-pencil');
+ $I->seeNodeCssClass($i, 'icon-white');
+ $I->seeNodeEmpty($i);
+
+ $html = TbHtml::icon(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testDropdownToggleLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dropdownToggleLink(
+ 'Link',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.btn.dropdown-toggle');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'data-toggle' => 'dropdown',
+ )
+ );
+ $I->seeNodePattern($a, '/^Link ');
+ $I->seeNodeChildren($a, array('b.caret'));
+ }
+
+ public function testDropdownToggleButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dropdownToggleButton(
+ 'Button',
+ array(
+ 'class' => 'button',
+ 'name' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=button].btn.dropdown-toggle');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttributes(
+ $button,
+ array(
+ 'name' => 'button',
+ 'data-toggle' => 'dropdown',
+ )
+ );
+ $I->seeNodePattern($button, '/^Button ');
+ $I->seeNodeChildren($button, array('b.caret'));
+ }
+
+ public function testDropdownToggleMenuLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::dropdownToggleMenuLink(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.dropdown-toggle');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'data-toggle' => 'dropdown',
+ )
+ );
+ $I->seeNodePattern($a, '/^Link ');
+ $I->seeNodeChildren($a, array('b.caret'));
+ }
+
+ public function testButtonGroup()
+ {
+ $I = $this->codeGuy;
+
+ $buttons = array(
+ array('label' => 'Left'),
+ array(
+ 'label' => 'Middle',
+ 'items' => array(
+ array('label' => 'Action', 'url' => '#'),
+ ),
+ 'htmlOptions' => array('color' => TbHtml::BUTTON_COLOR_INVERSE),
+ ),
+ array('label' => 'Right', 'visible' => false),
+ );
+
+ $html = TbHtml::buttonGroup(
+ $buttons,
+ array(
+ 'class' => 'div',
+ 'color' => TbHtml::BUTTON_COLOR_PRIMARY,
+ 'toggle' => TbHtml::BUTTON_TOGGLE_CHECKBOX,
+ )
+ );
+ $group = $I->createNode($html, 'div.btn-group');
+ $I->seeNodeCssClass($group, 'div');
+ $I->seeNodeAttribute($group, 'data-toggle', 'buttons-checkbox');
+ $I->seeNodeNumChildren($group, 2);
+ foreach ($group->children() as $i => $btnElement) {
+ $btn = $I->createNode($btnElement);
+ if ($i === 1) {
+ $I->seeNodeChildren($btn, array('a.dropdown-toggle', 'ul.dropdown-menu'));
+ $a = $btn->filter('a.dropdown-toggle');
+ $I->seeNodeCssClass($a, 'btn-inverse');
+ $I->seeNodeText($a, 'Middle');
+ } else {
+ $I->seeNodeCssClass($btn, 'btn');
+ $I->seeNodeAttribute($btn, 'href', '#');
+ $I->seeNodeCssClass($btn, 'btn-primary');
+ $I->seeNodeText($btn, $buttons[$i]['label']);
+ }
+ }
+
+ $html = TbHtml::buttonGroup(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testVerticalButtonGroup()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::verticalButtonGroup(
+ array(
+ array('icon' => TbHtml::ICON_ALIGN_LEFT),
+ array('icon' => TbHtml::ICON_ALIGN_CENTER),
+ array('icon' => TbHtml::ICON_ALIGN_RIGHT),
+ array('icon' => TbHtml::ICON_ALIGN_JUSTIFY),
+ )
+ );
+ $group = $I->createNode($html, 'div.btn-group');
+ $I->seeNodeCssClass($group, 'btn-group-vertical');
+ }
+
+ public function testButtonToolbar()
+ {
+ $I = $this->codeGuy;
+
+ $groups = array(
+ array(
+ 'items' => array(
+ array('label' => '1', 'color' => TbHtml::BUTTON_COLOR_DANGER),
+ array('label' => '2'),
+ array('label' => '3'),
+ array('label' => '4'),
+ ),
+ 'htmlOptions' => array(
+ 'color' => TbHtml::BUTTON_COLOR_INVERSE,
+ ),
+ ),
+ array(
+ 'items' => array(
+ array('label' => '5'),
+ array('label' => '6'),
+ array('label' => '7'),
+ )
+ ),
+ array(
+ 'visible' => false,
+ 'items' => array(
+ array('label' => '8'),
+ )
+ ),
+ array(
+ 'items' => array()
+ ),
+ );
+
+ $html = TbHtml::buttonToolbar(
+ $groups,
+ array(
+ 'class' => 'div',
+ 'color' => TbHtml::BUTTON_COLOR_PRIMARY,
+ )
+ );
+ $toolbar = $I->createNode($html, 'div.btn-toolbar');
+ $I->seeNodeCssClass($toolbar, 'div');
+ foreach ($toolbar->children() as $i => $groupElement) {
+ $group = $I->createNode($groupElement);
+ $I->seeNodeCssClass($group, 'btn-group');
+ foreach ($group->children() as $j => $btnElement) {
+ $btn = $I->createNode($btnElement);
+ $I->seeNodeCssClass($btn, 'btn');
+ if ($i === 0) {
+ $I->seeNodeCssClass($btn, $j === 0 ? 'btn-danger' : 'btn-inverse');
+ } else {
+ $I->seeNodeCssClass($btn, 'btn-primary');
+ }
+ $I->seeNodeText($btn, $groups[$i]['items'][$j]['label']);
+ }
+ }
+
+ $html = TbHtml::buttonToolbar(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testButtonDropdown()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array(
+ 'label' => 'Action',
+ 'url' => '#',
+ 'class' => 'item',
+ 'linkOptions' => array('class' => 'link'),
+ ),
+ array('label' => 'Another action', 'url' => '#'),
+ array('label' => 'Something else here', 'url' => '#'),
+ TbHtml::menuDivider(),
+ array('label' => 'Separate link', 'url' => '#'),
+ );
+
+ $html = TbHtml::buttonDropdown(
+ 'Action',
+ $items,
+ array(
+ 'class' => 'link',
+ 'dropup' => true,
+ 'groupOptions' => array('class' => 'group'),
+ 'menuOptions' => array('class' => 'menu'),
+ )
+ );
+ $group = $I->createNode($html, 'div.btn-group');
+ $I->seeNodeCssClass($group, 'dropup group');
+ $I->seeNodeChildren($group, array('a.dropdown-toggle', 'ul.dropdown-menu'));
+ $a = $group->filter('a.dropdown-toggle');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'data-toggle' => 'dropdown',
+ 'href' => '#',
+ )
+ );
+ $I->seeNodePattern($a, '/Action ');
+ $b = $a->filter('b.caret');
+ $I->seeNodeEmpty($b);
+ $ul = $group->filter('ul.dropdown-menu');
+ foreach ($ul->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ if ($i === 3) {
+ $I->seeNodeCssClass($li, 'divider');
+ } else {
+ $a = $li->filter('a');
+ if ($i === 0) {
+ $I->seeNodeCssClass($li, 'item');
+ $I->seeNodeCssClass($a, 'link');
+ }
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'tabindex' => '-1',
+ )
+ );
+ $I->seeNodeText($a, $items[$i]['label']);
+ }
+ }
+ }
+
+ public function testSplitButtonDropdown()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array('label' => 'Action', 'url' => '#'),
+ array('label' => 'Another action', 'url' => '#'),
+ array('label' => 'Something else here', 'url' => '#'),
+ TbHtml::menuDivider(),
+ array('label' => 'Separate link', 'url' => '#'),
+ );
+
+ $html = TbHtml::splitButtonDropdown('Action', $items);
+ $group = $I->createNode($html, 'div.btn-group');
+ $I->seeNodeChildren($group, array('a.btn', 'button.dropdown-toggle', 'ul.dropdown-menu'));
+ CHtml::$count = 0;
+ }
+
+ public function testTabs()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::tabs(
+ array(
+ array('label' => 'Link', 'url' => '#'),
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-tabs');
+ }
+
+ public function testStackedTabs()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::stackedTabs(
+ array(
+ array('label' => 'Link', 'url' => '#'),
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-tabs nav-stacked');
+ }
+
+ public function testPills()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::pills(
+ array(
+ array('label' => 'Link', 'url' => '#'),
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-pills');
+ }
+
+ public function testStackedPills()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::stackedPills(
+ array(
+ array('label' => 'Link', 'url' => '#'),
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-pills nav-stacked');
+ }
+
+ public function testNavList()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array('label' => 'Header text'),
+ array('label' => 'Link', 'url' => '#'),
+ TbHtml::menuDivider(),
+ );
+
+ $html = TbHtml::navList(
+ $items,
+ array(
+ 'stacked' => true,
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-list');
+ $I->dontSeeNodeCssClass($nav, 'nav-stacked');
+ foreach ($nav->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ if ($i === 0) {
+ $I->seeNodeCssClass($li, 'nav-header');
+ $I->seeNodeText($li, 'Header text');
+ } else if ($i === 1) {
+ $a = $li->filter('a');
+ $I->seeNodeText($a, $items[$i]['label']);
+ } else if ($i === 2) {
+ $I->seeNodeCssClass($li, 'divider');
+ }
+ }
+ }
+
+ public function testNav()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::nav(
+ TbHtml::NAV_TYPE_NONE,
+ array(
+ array('label' => 'Link', 'url' => '#'),
+ ),
+ array(
+ 'stacked' => true,
+ )
+ );
+ $nav = $I->createNode($html, 'ul.nav');
+ $I->seeNodeCssClass($nav, 'nav-stacked');
+ }
+
+ public function testMenu()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array('icon' => TbHtml::ICON_HOME, 'label' => 'Home', 'url' => '#'),
+ array('label' => 'Profile', 'url' => '#', 'htmlOptions' => array('disabled' => true)),
+ array('label' => 'Dropdown', 'active' => true, 'items' => array(
+ array('label' => 'Action', 'url' => '#'),
+ array('label' => 'Another action', 'url' => '#'),
+ array('label' => 'Dropdown', 'items' => array(
+ array('label' => 'Action', 'url' => '#'),
+ )),
+ TbHtml::menuDivider(),
+ array('label' => 'Separate link', 'url' => '#'),
+ )),
+ array('label' => 'Hidden', 'url' => '#', 'visible' => false),
+ );
+
+ $html = TbHtml::menu(
+ $items,
+ array(
+ 'class' => 'ul',
+ )
+ );
+ $nav = $I->createNode($html, 'ul');
+ $I->seeNodeAttribute($nav, 'role', 'menu');
+ $I->seeNodeNumChildren($nav, 3);
+ foreach ($nav->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ if ($i === 2) {
+ $I->seeNodeCssClass($li, 'dropdown active');
+ $I->seeNodeChildren($li, array('a.dropdown-toggle', 'ul.dropdown-menu'));
+ $ul = $li->filter('ul.dropdown-menu');
+ $I->seeNodeNumChildren($ul, 5);
+ foreach ($ul->children() as $j => $subLiElement) {
+ $subLi = $I->createNode($subLiElement);
+ if ($j === 2) {
+ $I->seeNodeCssClass($subLi, 'dropdown-submenu');
+ $I->seeNodeChildren($subLi, array('a.dropdown-toggle', 'ul.dropdown-menu'));
+ $subUl = $subLi->filter('ul.dropdown-menu');
+ $I->seeNodeNumChildren($subUl, 1);
+ } else {
+ if ($j === 3) {
+ $I->seeNodeCssClass($subLi, 'divider');
+ } else {
+ $subA = $subLi->filter('a');
+ $I->seeNodeText($subA, $items[$i]['items'][$j]['label']);
+ }
+ }
+ }
+ } else {
+ if ($i === 0) {
+ $I->seeNodeChildren($li, array('i.icon-home', 'a'));
+ }
+ if ($i === 2) {
+ $I->seeNodeCssClass($li, 'disabled');
+ }
+ $a = $li->filter('a');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'tabindex' => '-1',
+ )
+ );
+ $I->seeNodeText($a, $items[$i]['label']);
+ }
+ }
+
+ $html = TbHtml::menu(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testMenuLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::menuLink(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'item',
+ 'linkOptions' => array('class' => 'link'),
+ )
+ );
+ $li = $I->createNode($html, 'li');
+ $I->seeNodeCssClass($li, 'item');
+ $a = $li->filter('a');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testMenuHeader()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::menuHeader(
+ 'Header text',
+ array(
+ 'class' => 'item',
+ )
+ );
+ $li = $I->createNode($html, 'li.nav-header');
+ $I->seeNodeCssClass($li, 'item');
+ $I->seeNodeText($li, 'Header text');
+ }
+
+ public function testMenuDivider()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::menuDivider(
+ array(
+ 'class' => 'item',
+ )
+ );
+ $li = $I->createNode($html, 'li.divider');
+ $I->seeNodeCssClass($li, 'item');
+ $I->seeNodeEmpty($li);
+ }
+
+ public function testTabbableTabs()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::tabbableTabs(
+ array(
+ array('label' => 'Link', 'content' => 'Tab content'),
+ )
+ );
+ $tabbable = $I->createNode($html, 'div.tabbable');
+ $ul = $tabbable->filter('ul.nav');
+ $I->seeNodeCssClass($ul, 'nav-tabs');
+ }
+
+ public function testTabbablePills()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::tabbablePills(
+ array(
+ array('label' => 'Link', 'content' => 'Tab content'),
+ )
+ );
+ $tabbable = $I->createNode($html, 'div.tabbable');
+ $ul = $tabbable->filter('ul.nav');
+ $I->seeNodeCssClass($ul, 'nav-pills');
+ }
+
+ public function testTabbable()
+ {
+ $I = $this->codeGuy;
+
+ $tabs = array(
+ array('label' => 'Home', 'content' => 'Tab content', 'active' => true),
+ array('label' => 'Profile', 'content' => 'Tab content', 'id' => 'profile'),
+ array(
+ 'label' => 'Messages',
+ 'items' => array(
+ array('label' => '@fat', 'content' => 'Tab content'),
+ array('label' => '@mdo', 'content' => 'Tab content'),
+ )
+ ),
+ );
+
+ $html = TbHtml::tabbable(
+ TbHtml::NAV_TYPE_NONE,
+ $tabs,
+ array(
+ 'class' => 'div',
+ )
+ );
+ $tabbable = $I->createNode($html, 'div.tabbable');
+ $I->seeNodeCssClass($tabbable, 'div');
+ $ul = $tabbable->filter('ul.nav');
+ $I->seeNodeNumChildren($ul, 3);
+ foreach ($ul->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ if ($i === 0) {
+ $I->seeNodeCssClass($li, 'active');
+ }
+ if ($i === 2) {
+ $I->seeNodeCssClass($li, 'dropdown');
+ $a = $li->filter('a.dropdown-toggle');
+ $I->seeNodeText($a, 'Messages');
+ $subUl = $li->filter('ul.dropdown-menu');
+ foreach ($subUl->children() as $j => $subLiElement) {
+ $subLi = $I->createNode($subLiElement);
+ $subA = $subLi->filter('a');
+ $I->seeNodeAttributes(
+ $subA,
+ array(
+ 'data-toggle' => 'tab',
+ 'tabindex' => '-1',
+ 'href' => '#tab_' . ($i + $j + 1),
+ )
+ );
+ $I->seeNodeText($subA, $tabs[$i]['items'][$j]['label']);
+ }
+ } else {
+ $a = $li->filter('a');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'data-toggle' => 'tab',
+ 'tabindex' => '-1',
+ 'href' => '#' . (isset($tabs[$i]['id']) ? $tabs[$i]['id'] : 'tab_' . ($i + 1)),
+ )
+ );
+ $I->seeNodeText($a, $tabs[$i]['label']);
+ }
+ }
+ $content = $tabbable->filter('div.tab-content');
+ $I->seeNodeNumChildren($content, 4);
+ foreach ($content->children() as $i => $paneElement) {
+ $pane = $I->createNode($paneElement);
+ $I->seeNodeCssClass($pane, 'tab-pane fade');
+ if ($i === 0) {
+ $I->seeNodeCssClass($pane, 'active in');
+ }
+ if ($i > 1) {
+ $I->seeNodeText($pane, $tabs[2]['items'][$i - 2]['content']);
+ } else {
+ $I->seeNodeText($pane, $tabs[$i]['content']);
+ }
+ }
+ }
+
+ public function testNavbar()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::navbar(
+ 'Navbar content',
+ array(
+ 'class' => 'nav',
+ 'innerOptions' => array('class' => 'inner'),
+ )
+ );
+ $navbar = $I->createNode($html, 'div.navbar');
+ $I->seeNodeCssClass($navbar, 'nav');
+ $inner = $navbar->filter('div.navbar-inner');
+ $I->seeNodeText($inner, 'Navbar content');
+
+ $html = TbHtml::navbar(
+ '',
+ array(
+ 'display' => TbHtml::NAVBAR_DISPLAY_STATICTOP,
+ )
+ );
+ $navbar = $I->createNode($html, 'div.navbar');
+ $I->seeNodeCssClass($navbar, 'navbar-static-top');
+
+ $html = TbHtml::navbar(
+ '',
+ array(
+ 'display' => TbHtml::NAVBAR_DISPLAY_FIXEDTOP,
+ )
+ );
+ $navbar = $I->createNode($html, 'div.navbar');
+ $I->seeNodeCssClass($navbar, 'navbar-fixed-top');
+
+ $html = TbHtml::navbar(
+ '',
+ array(
+ 'display' => TbHtml::NAVBAR_DISPLAY_FIXEDBOTTOM,
+ )
+ );
+ $navbar = $I->createNode($html, 'div.navbar');
+ $I->seeNodeCssClass($navbar, 'navbar-fixed-bottom');
+
+ $html = TbHtml::navbar(
+ '',
+ array(
+ 'color' => TbHtml::NAVBAR_COLOR_INVERSE,
+ )
+ );
+ $navbar = $I->createNode($html, 'div.navbar');
+ $I->seeNodeCssClass($navbar, 'navbar-inverse');
+ }
+
+ public function testNavbarBrandLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarBrandLink(
+ 'Brand text',
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.brand');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Brand text');
+ }
+
+ public function testNavbarText()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarText(
+ 'Navbar text',
+ array(
+ 'class' => 'text',
+ )
+ );
+ $p = $I->createNode($html, 'p.navbar-text');
+ $I->seeNodeCssClass($p, 'text');
+ $I->seeNodeText($p, 'Navbar text');
+ }
+
+ public function testNavbarMenuDivider()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarMenuDivider(
+ array(
+ 'class' => 'item',
+ )
+ );
+ $li = $I->createNode($html, 'li.divider-vertical');
+ $I->seeNodeCssClass($li, 'item');
+ $I->seeNodeEmpty($li);
+ }
+
+ public function testNavbarForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarForm('#');
+ $I->createNode($html, 'form.navbar-form');
+ }
+
+ public function testNavbarSearchForm()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarSearchForm('#');
+ $I->createNode($html, 'form.navbar-search');
+ }
+
+ public function testNavbarCollapseLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::navbarCollapseLink(
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.btn.btn-navbar');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'data-toggle' => 'collapse',
+ 'data-target' => '#',
+ )
+ );
+ $I->seeNodeChildren($a, array('span.icon-bar', 'span.icon-bar', 'span.icon-bar'));
+ }
+
+ public function testBreadcrumbs()
+ {
+ $I = $this->codeGuy;
+
+ $links = array(
+ 'Home' => '#',
+ 'Library' => '#',
+ 'Data',
+ );
+
+ $html = TbHtml::breadcrumbs(
+ $links,
+ array(
+ 'class' => 'ul',
+ )
+ );
+ $ul = $I->createNode($html, 'ul.breadcrumb');
+ $I->seeNodeCssClass($ul, 'ul');
+ $I->seeNodeNumChildren($ul, 3);
+ foreach ($ul->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ switch ($i) {
+ case 0:
+ $a = $li->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Home');
+ break;
+ case 1:
+ $a = $li->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Library');
+ break;
+ case 2:
+ $I->seeNodeText($li, 'Data');
+ break;
+ }
+ }
+ }
+
+ public function testPagination()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array('label' => 'Prev', 'url' => '#', 'disabled' => true),
+ array(
+ 'label' => '1',
+ 'url' => '#',
+ 'active' => true,
+ 'htmlOptions' => array('class' => 'item'),
+ 'linkOptions' => array('class' => 'link'),
+ ),
+ array('label' => '2', 'url' => '#'),
+ array('label' => '3', 'url' => '#'),
+ array('label' => '4', 'url' => '#'),
+ array('label' => '5', 'url' => '#'),
+ array('label' => 'Next', 'url' => '#'),
+ );
+
+ $html = TbHtml::pagination(
+ $items,
+ array(
+ 'class' => 'div',
+ 'listOptions' => array('class' => 'list'),
+ )
+ );
+ $div = $I->createNode($html, 'div.pagination');
+ $I->seeNodeCssClass($div, 'div');
+ $ul = $div->filter('ul');
+ $I->seeNodeCssClass($ul, 'list');
+ $I->seeNodeNumChildren($ul, 7);
+ foreach ($ul->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ $a = $li->filter('a');
+ if ($i === 0) {
+ $I->seeNodeCssClass($li, 'disabled');
+ }
+ if ($i === 1) {
+ $I->seeNodeCssClass($li, 'item active');
+ $I->seeNodeCssClass($a, 'link');
+ }
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, $items[$i]['label']);
+ }
+
+ $html = TbHtml::pagination(
+ $items,
+ array(
+ 'size' => TbHtml::PAGINATION_SIZE_LARGE,
+ )
+ );
+ $div = $I->createNode($html, 'div.pagination');
+ $I->seeNodeCssClass($div, 'pagination-large');
+
+ $html = TbHtml::pagination(
+ $items,
+ array(
+ 'align' => TbHtml::PAGINATION_ALIGN_CENTER,
+ )
+ );
+ $div = $I->createNode($html, 'div.pagination');
+ $I->seeNodeCssClass($div, 'pagination-centered');
+
+ $html = TbHtml::pagination(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testPaginationLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::paginationLink(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'item',
+ 'linkOptions' => array('class' => 'link'),
+ )
+ );
+ $li = $I->createNode($html, 'li');
+ $I->seeNodeCssClass($li, 'item');
+ $a = $li->filter('a');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ }
+
+ public function testPager()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array(
+ 'label' => 'Prev',
+ 'url' => '#',
+ 'previous' => true,
+ 'htmlOptions' => array('disabled' => true),
+ ),
+ array('label' => 'Next', 'url' => '#', 'next' => true),
+ );
+
+ $html = TbHtml::pager(
+ $items,
+ array(
+ 'class' => 'list',
+ )
+ );
+ $ul = $I->createNode($html, 'ul.pager');
+ $I->seeNodeCssClass($ul, 'list');
+ $I->seeNodeNumChildren($ul, 2);
+ $prev = $ul->filter('li')->first();
+ $I->seeNodeCssClass($prev, 'previous disabled');
+ $a = $prev->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Prev');
+ $next = $ul->filter('li')->last();
+ $I->seeNodeCssClass($next, 'next');
+ $a = $next->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Next');
+
+ $html = TbHtml::pager(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testPagerLink()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::pagerLink(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'item',
+ 'linkOptions' => array('class' => 'link'),
+ 'disabled' => true,
+ )
+ );
+ $li = $I->createNode($html, 'li');
+ $I->seeNodeCssClass($li, 'item disabled');
+ $a = $li->filter('a');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Link');
+
+ $html = TbHtml::pagerLink(
+ 'Previous',
+ '#',
+ array(
+ 'previous' => true,
+ )
+ );
+ $li = $I->createNode($html, 'li.previous');
+ $a = $li->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Previous');
+
+ $html = TbHtml::pagerLink(
+ 'Next',
+ '#',
+ array(
+ 'next' => true,
+ )
+ );
+ $li = $I->createNode($html, 'li.next');
+ $a = $li->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Next');
+ }
+
+ public function testLabel()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::labelTb(
+ 'Label text',
+ array(
+ 'color' => TbHtml::LABEL_COLOR_INFO,
+ 'class' => 'span',
+ )
+ );
+ $span = $I->createNode($html, 'span.label');
+ $I->seeNodeCssClass($span, 'label-info span');
+ $I->seeNodeText($span, 'Label text');
+ }
+
+ public function testBadge()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::badge(
+ 'Badge text',
+ array(
+ 'color' => TbHtml::BADGE_COLOR_WARNING,
+ 'class' => 'span',
+ )
+ );
+ $span = $I->createNode($html, 'span.badge');
+ $I->seeNodeCssClass($span, 'badge-warning span');
+ $I->seeNodeText($span, 'Badge text');
+ }
+
+ public function testHeroUnit()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::heroUnit(
+ 'Heading text',
+ 'Content text',
+ array(
+ 'class' => 'div',
+ 'headingOptions' => array('class' => 'heading'),
+ )
+ );
+ $hero = $I->createNode($html, 'div.hero-unit');
+ $I->seeNodeCssClass($hero, 'div');
+ $I->seeNodeText($hero, 'Content text');
+ $h1 = $hero->filter('h1');
+ $I->seeNodeCssClass($h1, 'heading');
+ $I->seeNodeText($h1, 'Heading text');
+ }
+
+ public function testPageHeader()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::pageHeader(
+ 'Heading text',
+ 'Subtext',
+ array(
+ 'class' => 'header',
+ 'headerOptions' => array('class' => 'heading'),
+ 'subtextOptions' => array('class' => 'subtext')
+ )
+ );
+ $header = $I->createNode($html, 'div.page-header');
+ $I->seeNodeCssClass($header, 'header');
+ $h1 = $header->filter('h1');
+ $I->seeNodeCssClass($h1, 'heading');
+ $I->seeNodeText($h1, 'Heading text');
+ $small = $h1->filter('small');
+ $I->seeNodeCssClass($small, 'subtext');
+ $I->seeNodeText($small, 'Subtext');
+ }
+
+ public function testThumbnails()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array(
+ 'image' => 'image.png',
+ 'label' => 'Thumbnail label',
+ 'caption' => 'Caption text',
+ 'span' => 6,
+ 'imageOptions' => array('class' => 'image', 'alt' => 'Alternative text'),
+ 'captionOptions' => array('class' => 'div'),
+ 'labelOptions' => array('class' => 'heading'),
+ ),
+ array('image' => 'image.png', 'label' => 'Thumbnail label', 'caption' => 'Caption text'),
+ array('image' => 'image.png', 'label' => 'Thumbnail label', 'caption' => 'Caption text'),
+ );
+
+ $html = TbHtml::thumbnails(
+ $items,
+ array(
+ 'span' => 3,
+ 'class' => 'list',
+ )
+ );
+ $thumbnails = $I->createNode($html, 'ul.thumbnails');
+ $I->seeNodeCssClass($thumbnails, 'list');
+ $I->seeNodeNumChildren($thumbnails, 3);
+ $I->seeNodeChildren($thumbnails, array('li.span6', 'li.span3', 'li.span3'));
+ foreach ($thumbnails->children() as $i => $liElement) {
+ $li = $I->createNode($liElement);
+ $thumbnail = $li->filter('div.thumbnail');
+ $I->seeNodeChildren($thumbnail, array('img', 'div.caption'));
+ $img = $thumbnail->filter('img');
+ $I->seeNodeAttribute($img, 'src', 'image.png');
+ $caption = $thumbnail->filter('div.caption');
+ $h3 = $caption->filter('h3');
+ $I->seeNodeText($caption, $items[$i]['caption']);
+ $I->seeNodeText($h3, $items[$i]['label']);
+ if ($i === 0) {
+ $I->seeNodeCssClass($img, 'image');
+ $I->seeNodeAttribute($img, 'alt', 'Alternative text');
+ $I->seeNodeCssClass($caption, 'div');
+ $I->seeNodeCssClass($h3, 'heading');
+ }
+ }
+
+ $html = TbHtml::thumbnails(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testThumbnail()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::thumbnail(
+ 'Thumbnail text',
+ array(
+ 'class' => 'div',
+ 'itemOptions' => array('class' => 'item'),
+ )
+ );
+ $li = $I->createNode($html, 'li');
+ $I->seeNodeCssClass($li, 'item');
+ $thumbnail = $li->filter('div.thumbnail');
+ $I->seeNodeCssClass($thumbnail, 'div');
+ $I->seeNodeText($thumbnail, 'Thumbnail text');
+ }
+
+ public function testThumbnailLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::thumbnailLink(
+ 'Thumbnail text',
+ '#',
+ array(
+ 'class' => 'link',
+ 'itemOptions' => array('class' => 'item'),
+ )
+ );
+ $li = $I->createNode($html, 'li');
+ $I->seeNodeCssClass($li, 'item');
+ $thumbnail = $li->filter('a.thumbnail');
+ $I->seeNodeCssClass($thumbnail, 'link');
+ $I->seeNodeAttribute($thumbnail, 'href', '#');
+ $I->seeNodeText($thumbnail, 'Thumbnail text');
+ }
+
+ public function testAlert()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::alert(
+ TbHtml::ALERT_COLOR_SUCCESS,
+ 'Alert message',
+ array(
+ 'class' => 'div',
+ 'closeText' => 'Close',
+ 'closeOptions' => array('class' => 'text'),
+ )
+ );
+ $alert = $I->createNode($html, 'div.alert');
+ $I->seeNodeCssClass($alert, 'alert-success in fade div');
+ $I->seeNodeText($alert, 'Alert message');
+ $close = $alert->filter('a[type=button].close');
+ $I->seeNodeCssClass($close, 'text');
+ $I->seeNodeAttributes(
+ $close,
+ array(
+ 'href' => '#',
+ 'data-dismiss' => 'alert',
+ )
+ );
+ $I->seeNodeText($close, 'Close');
+
+ $html = TbHtml::alert(
+ TbHtml::ALERT_COLOR_INFO,
+ 'Alert message',
+ array(
+ 'closeText' => false,
+ 'in' => false,
+ 'fade' => false,
+ )
+ );
+ $alert = $I->createNode($html, 'div.alert');
+ $I->seeNodeCssClass($alert, 'alert-info');
+ $I->dontSeeNodeCssClass($alert, 'fade in');
+ $I->dontSeeNodeChildren($alert, array('.close'));
+ $I->seeNodeText($alert, 'Alert message');
+ }
+
+ public function testBlockAlert()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::blockAlert(TbHtml::ALERT_COLOR_WARNING, 'Alert message');
+ $alert = $I->createNode($html, 'div.alert');
+ $I->seeNodeCssClass($alert, 'alert-warning alert-block fade in');
+ $I->seeNodeText($alert, 'Alert message');
+ $I->seeNodeChildren($alert, array('div.alert > a[type=button].close'));
+ }
+
+ public function testProgressBar()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::progressBar(
+ 60,
+ array(
+ 'class' => 'div',
+ 'color' => TbHtml::PROGRESS_COLOR_INFO,
+ 'content' => 'Bar text',
+ 'barOptions' => array('class' => 'div'),
+ )
+ );
+ $progress = $I->createNode($html, 'div.progress');
+ $I->seeNodeCssClass($progress, 'progress-info div');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssClass($bar, 'div');
+ $I->seeNodeCssStyle($bar, 'width: 60%');
+ $I->seeNodeText($bar, 'Bar text');
+
+ $html = TbHtml::progressBar(
+ 35,
+ array(
+ 'barOptions' => array('color' => TbHtml::PROGRESS_COLOR_SUCCESS),
+ )
+ );
+ $progress = $I->createNode($html, 'div.progress');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssClass($bar, 'bar-success');
+ $I->seeNodeCssStyle($bar, 'width: 35%');
+
+ $html = TbHtml::progressBar(-1);
+ $progress = $I->createNode($html, 'div.progress');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssStyle($bar, 'width: 0');
+
+ $html = TbHtml::progressBar(100.1);
+ $progress = $I->createNode($html, 'div.progress');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssStyle($bar, 'width: 100%');
+ }
+
+ public function testStripedProgressBar()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::stripedProgressBar(20);
+ $progress = $I->createNode($html, 'div.progress');
+ $I->seeNodeCssClass($progress, 'progress-striped');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssStyle($bar, 'width: 20%');
+ }
+
+ public function testAnimatedProgressBar()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::animatedProgressBar(40);
+ $progress = $I->createNode($html, 'div.progress');
+ $I->seeNodeCssClass($progress, 'progress-striped active');
+ $bar = $progress->filter('div.bar');
+ $I->seeNodeCssStyle($bar, 'width: 40%');
+ }
+
+ public function testStackedProgressBar()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::stackedProgressBar(
+ array(
+ array('color' => TbHtml::PROGRESS_COLOR_SUCCESS, 'width' => 35),
+ array('color' => TbHtml::PROGRESS_COLOR_WARNING, 'width' => 20),
+ array('color' => TbHtml::PROGRESS_COLOR_DANGER, 'width' => 10),
+ )
+ );
+ $progress = $I->createNode($html, 'div.progress');
+ $I->seeNodeChildren($progress, array('div.bar-success', 'div.bar-warning', 'div.bar-danger'));
+ $success = $progress->filter('div.bar-success');
+ $I->seeNodeCssClass($success, 'bar');
+ $I->seeNodeCssStyle($success, 'width: 35%');
+ $warning = $progress->filter('div.bar-warning');
+ $I->seeNodeCssClass($warning, 'bar');
+ $I->seeNodeCssStyle($warning, 'width: 20%');
+ $danger = $progress->filter('div.bar-danger');
+ $I->seeNodeCssClass($danger, 'bar');
+ $I->seeNodeCssStyle($danger, 'width: 10%');
+
+ $html = TbHtml::stackedProgressBar(
+ array(
+ array('width' => 35),
+ array('width' => 20),
+ array('width' => 100),
+ )
+ );
+ $progress = $I->createNode($html, 'div.progress');
+ $last = $progress->filter('div.bar')->last();
+ $I->seeNodeCssStyle($last, 'width: 45%');
+
+ $html = TbHtml::stackedProgressBar(
+ array(
+ array('width' => 35),
+ array('width' => 20),
+ array('width' => 10, 'visible' => false),
+ )
+ );
+ $progress = $I->createNode($html, 'div.progress');
+ $last = $progress->filter('div.bar')->last();
+ $I->seeNodeCssStyle($last, 'width: 20%');
+
+ $html = TbHtml::stackedProgressBar(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testMediaList()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array('image' => 'image.png', 'heading' => 'Media heading', 'content' => 'Content text'),
+ array('heading' => 'Media heading', 'content' => 'Content text'),
+ );
+
+ $html = TbHtml::mediaList(
+ $items,
+ array(
+ 'class' => 'list',
+ )
+ );
+ $ul = $I->createNode($html, 'ul.media-list');
+ $I->seeNodeNumChildren($ul, 2);
+ $I->seeNodeChildren($ul, array('li.media', 'li.media'));
+
+ $html = TbHtml::mediaList(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testMedias()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array(
+ 'image' => 'image.png',
+ 'heading' => 'Media heading',
+ 'content' => 'Content text',
+ 'items' => array(
+ array(
+ 'image' => '#',
+ 'heading' => 'Media heading',
+ 'content' => 'Content text',
+ ),
+ array(
+ 'image' => '#',
+ 'heading' => 'Media heading',
+ 'content' => 'Content text',
+ 'visible' => false,
+ ),
+ )
+ ),
+ array('heading' => 'Media heading', 'content' => 'Content text'),
+ );
+
+ $html = TbHtml::medias($items);
+ $body = $I->createNode($html, 'body');
+ $medias = $body->filter('div.media');
+ $first = $medias->first();
+ $I->seeNodeChildren($first, array('a.pull-left', 'div.media-body'));
+ $img = $first->filter('img.media-object');
+ $I->seeNodeAttribute($img, 'src', 'image.png');
+ $mediaBody = $first->filter('div.media-body');
+ $I->seeNodeChildren($mediaBody, array('h4.media-heading', 'div.media'));
+ $I->seeNodeText($mediaBody, 'Content text');
+ $h4 = $body->filter('h4.media-heading');
+ $I->seeNodeText($h4, 'Media heading');
+ $I->seeNodeNumChildren($mediaBody, 1, 'div.media');
+ $last = $medias->last();
+ $I->seeNodeChildren($last, array('div.media-body'));
+
+ $html = TbHtml::medias(array());
+ $this->assertEquals('', $html);
+ }
+
+ public function testMedia()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::media(
+ 'image.png',
+ 'Heading text',
+ 'Content text',
+ array(
+ 'class' => 'div',
+ 'linkOptions' => array('class' => 'link'),
+ 'imageOptions' => array('class' => 'image', 'alt' => 'Alternative text'),
+ 'contentOptions' => array('class' => 'content'),
+ 'headingOptions' => array('class' => 'heading'),
+ )
+ );
+ $div = $I->createNode($html, 'div.media');
+ $I->seeNodeCssClass($div, 'div');
+ $I->seeNodeChildren($div, array('a.pull-left', 'div.media-body'));
+ $a = $div->filter('a.pull-left');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $img = $a->filter('img.media-object');
+ $I->seeNodeCssClass($img, 'image');
+ $I->seeNodeAttributes(
+ $img,
+ array(
+ 'src' => 'image.png',
+ 'alt' => 'Alternative text',
+ )
+ );
+ $content = $div->filter('div.media-body');
+ $I->seeNodeCssClass($content, 'content');
+ $I->seeNodeText($content, 'Content text');
+ $h4 = $content->filter('h4.media-heading');
+ $I->seeNodeCssClass($h4, 'heading');
+ $I->seeNodeText($h4, 'Heading text');
+ }
+
+ public function testWell()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::well(
+ 'Well text',
+ array(
+ 'class' => 'div',
+ 'size' => TbHtml::WELL_SIZE_LARGE,
+ )
+ );
+ $well = $I->createNode($html, 'div.well');
+ $I->seeNodeCssClass($well, 'well-large');
+ $I->seeNodeText($well, 'Well text');
+ }
+
+ public function testCloseLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::closeLink(
+ 'Close',
+ '#',
+ array(
+ 'class' => 'link',
+ 'dismiss' => TbHtml::CLOSE_DISMISS_ALERT,
+ )
+ );
+ $a = $I->createNode($html, 'a[type=button].close');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'data-dismiss' => 'alert',
+ )
+ );
+ $I->seeNodeText($a, 'Close');
+ }
+
+ public function testCloseButton()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::closeButton(
+ 'Close',
+ array(
+ 'dismiss' => TbHtml::CLOSE_DISMISS_MODAL,
+ 'class' => 'button',
+ )
+ );
+ $button = $I->createNode($html, 'button[type=button].close');
+ $I->seeNodeCssClass($button, 'button');
+ $I->seeNodeAttribute($button, 'data-dismiss', 'modal');
+ $I->seeNodeText($button, 'Close');
+ }
+
+
+ public function testCollapseLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::collapseLink(
+ 'Link',
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a[data-toggle=collapse]');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttribute($a, 'href', '#');
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testTooltip()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::tooltip(
+ 'Link',
+ '#',
+ 'Tooltip text',
+ array(
+ 'class' => 'link',
+ 'animation' => true,
+ 'html' => true,
+ 'selector' => '.selector',
+ 'placement' => TbHtml::TOOLTIP_PLACEMENT_RIGHT,
+ 'trigger' => TbHtml::TOOLTIP_TRIGGER_CLICK,
+ 'delay' => 350,
+ )
+ );
+ $a = $I->createNode($html, 'a[rel=tooltip]');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'title' => 'Tooltip text',
+ 'data-animation' => 'true',
+ 'data-html' => 'true',
+ 'data-selector' => '.selector',
+ 'data-placement' => 'right',
+ 'data-trigger' => 'click',
+ 'data-delay' => '350',
+ 'href' => '#'
+ )
+ );
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testPopover()
+ {
+ $I = $this->codeGuy;
+
+ $html = TbHtml::popover(
+ 'Link',
+ 'Heading text',
+ 'Content text',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a[rel=popover]');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'title' => 'Heading text',
+ 'data-content' => 'Content text',
+ 'data-toggle' => 'popover',
+ 'href' => '#'
+ )
+ );
+ $I->seeNodeText($a, 'Link');
+ }
+
+ public function testCarousel()
+ {
+ $I = $this->codeGuy;
+
+ $items = array(
+ array(
+ 'image' => 'image.png',
+ 'label' => 'First Thumbnail label',
+ 'url' => '#',
+ 'caption' => 'Caption text',
+ ),
+ array('image' => 'image.png', 'label' => 'Second Thumbnail label'),
+ array('image' => 'image.png', 'imageOptions' => array('class' => 'image', 'alt' => 'Alternative text')),
+ );
+
+ $html = TbHtml::carousel(
+ $items,
+ array(
+ 'id' => 'carousel',
+ 'class' => 'div',
+ )
+ );
+ $carousel = $I->createNode($html, 'div.carousel');
+ $I->seeNodeCssClass($carousel, 'div slide');
+ $I->seeNodeAttribute($carousel, 'carousel');
+ $I->seeNodeChildren($carousel, array('ol.carousel-indicators', 'div.carousel-inner', 'a.carousel-control', 'a.carousel-control'));
+ $inner = $carousel->filter('div.carousel-inner');
+ foreach ($inner->children() as $i => $divElement) {
+ $div = $I->createNode($divElement);
+ $I->seeNodeCssClass($div, 'item');
+ switch ($i) {
+ case 0:
+ $I->seeNodeCssClass($div, 'active');
+ $I->seeNodeChildren($div, array('a', 'div.carousel-caption'));
+ $a = $div->filter('a');
+ $I->seeNodeAttribute($a, 'href', '#');
+ break;
+ case 1:
+ $I->seeNodeChildren($div, array('img', 'div.carousel-caption'));
+ break;
+ case 2:
+ $img = $div->filter('img.image');
+ $I->seeNodeAttributes(
+ $img,
+ array(
+ 'src' => 'image.png',
+ 'alt' => 'Alternative text',
+ )
+ );
+ break;
+ }
+ }
+ }
+
+ public function testCarouselItem()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::carouselItem(
+ 'Content text',
+ 'Label text',
+ 'Caption text',
+ array(
+ 'class' => 'div',
+ 'overlayOptions' => array('class' => 'overlay'),
+ 'labelOptions' => array('class' => 'label'),
+ 'captionOptions' => array('class' => 'caption'),
+ )
+ );
+ $div = $I->createNode($html, 'div.item');
+ $I->seeNodeCssClass($div, 'div');
+ $I->seeNodeText($div, 'Content text');
+ $overlay = $div->filter('div.carousel-caption');
+ $I->seeNodeCssClass($overlay, 'overlay');
+ $I->seeNodeChildren($overlay, array('h4', 'p'));
+ $h4 = $overlay->filter('h4');
+ $I->seeNodeCssClass($h4, 'label');
+ $caption = $overlay->filter('p');
+ $I->seeNodeCssClass($caption, 'caption');
+ $I->seeNodeText($caption, 'Caption text');
+ }
+
+ public function testCarouselPrevLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::carouselPrevLink(
+ 'Previous',
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.carousel-control.left');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'data-slide' => 'prev',
+ )
+ );
+ $I->seeNodeText($a, 'Previous');
+ }
+
+ public function testCarouselNextLink()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::carouselNextLink(
+ 'Next',
+ '#',
+ array(
+ 'class' => 'link',
+ )
+ );
+ $a = $I->createNode($html, 'a.carousel-control.right');
+ $I->seeNodeCssClass($a, 'link');
+ $I->seeNodeAttributes(
+ $a,
+ array(
+ 'href' => '#',
+ 'data-slide' => 'next',
+ )
+ );
+ $I->seeNodeText($a, 'Next');
+ }
+
+ public function testCarouselIndicators()
+ {
+ $I = $this->codeGuy;
+ $html = TbHtml::carouselIndicators(
+ '#',
+ 3,
+ array(
+ 'class' => 'list',
+ )
+ );
+ $ol = $I->createNode($html, 'ol.carousel-indicators');
+ $I->seeNodeCssClass($ol, 'list');
+ $I->seeNodeChildren($ol, array('li.active', 'li', 'li'));
+ foreach ($ol->filter('li') as $i => $element) {
+ $node = $I->createNode($element);
+ $I->seeNodeAttributes(
+ $node,
+ array(
+ 'data-target' => '#',
+ 'data-slide-to' => $i,
+ )
+ );
+ $I->seeNodeEmpty($node);
+ }
+ }
+
+ public function testAddCssClass()
+ {
+ $htmlOptions = array('class' => 'my');
+ TbHtml::addCssClass(array('class'), $htmlOptions);
+ $this->assertEquals('my class', $htmlOptions['class']);
+ TbHtml::addCssClass('more classes', $htmlOptions);
+ $this->assertEquals('my class more classes', $htmlOptions['class']);
+ TbHtml::addCssClass(array('my'), $htmlOptions);
+ $this->assertEquals('my class more classes', $htmlOptions['class']);
+ TbHtml::addCssClass('class more classes', $htmlOptions);
+ $this->assertEquals('my class more classes', $htmlOptions['class']);
+ }
+
+ public function testAddCssStyle()
+ {
+ $htmlOptions = array('style' => 'display: none');
+ TbHtml::addCssStyle('color: purple', $htmlOptions);
+ TbHtml::addCssStyle('background: #fff;', $htmlOptions);
+ TbHtml::addCssStyle(array('font-family: "Open sans"', 'font-weight: bold;'), $htmlOptions);
+ $this->assertEquals(
+ 'display: none; color: purple; background: #fff; font-family: "Open sans"; font-weight: bold',
+ $htmlOptions['style']
+ );
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/tests/unit/TbTestCase.php b/www/protected/extensions/bootstrap/tests/unit/TbTestCase.php
new file mode 100644
index 0000000..54475fb
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/unit/TbTestCase.php
@@ -0,0 +1,69 @@
+destroyApplication();
+ }
+
+ /**
+ * @param array $config
+ * @param string $appClass
+ */
+ protected function mockApplication($config = array(), $appClass = 'TestApplication')
+ {
+ $defaultConfig = array(
+ 'basePath' => __DIR__,
+ 'aliases' => array(
+ 'bootstrap' => __DIR__ . '/../..',
+ ),
+ );
+ Yii::createApplication(
+ $appClass,
+ CMap::mergeArray($defaultConfig, $config)
+ );
+ }
+
+ /**
+ *
+ */
+ protected function destroyApplication()
+ {
+ Yii::setApplication(null);
+ }
+
+ /**
+ * @param $widgetClass
+ * @param array $properties
+ * @return string
+ */
+ protected function runWidget($widgetClass, $properties = array())
+ {
+ return $this->mockController()->widget($widgetClass, $properties, true);
+ }
+
+ /**
+ * @param $widgetClass
+ * @param array $properties
+ * @return CWidget
+ */
+ protected function beginWidget($widgetClass, $properties = array())
+ {
+ return $this->mockController()->beginWidget($widgetClass, $properties);
+ }
+
+ /**
+ * @return CController
+ */
+ private function mockController()
+ {
+ return new CController('dummy');
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/tests/unit/_bootstrap.php b/www/protected/extensions/bootstrap/tests/unit/_bootstrap.php
new file mode 100644
index 0000000..7dfa7c3
--- /dev/null
+++ b/www/protected/extensions/bootstrap/tests/unit/_bootstrap.php
@@ -0,0 +1,2 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap active form widget.
+ */
+class TbActiveForm extends CActiveForm
+{
+ /**
+ * @var string the form layout.
+ */
+ public $layout;
+ /**
+ * @var string the help type. Valid values are TbHtml::HELP_INLINE and TbHtml::HELP_BLOCK.
+ */
+ public $helpType = TbHtml::HELP_TYPE_BLOCK;
+ /**
+ * @var string the CSS class name for error messages.
+ */
+ public $errorMessageCssClass = 'error';
+ /**
+ * @var string the CSS class name for success messages.
+ */
+ public $successMessageCssClass = 'success';
+
+ /**
+ * @var boolean whether to hide inline errors. Defaults to false.
+ */
+ public $hideInlineErrors = false;
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ if ($this->stateful) {
+ echo TbHtml::statefulFormTb($this->layout, $this->action, $this->method, $this->htmlOptions);
+ } else {
+ echo TbHtml::beginFormTb($this->layout, $this->action, $this->method, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Displays the first validation error for a model attribute.
+ * @param CModel $model the data model
+ * @param string $attribute the attribute name
+ * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
+ * @param boolean $enableAjaxValidation whether to enable AJAX validation for the specified attribute.
+ * @param boolean $enableClientValidation whether to enable client-side validation for the specified attribute.
+ * @return string the validation result (error display or success message).
+ */
+ public function error(
+ $model,
+ $attribute,
+ $htmlOptions = array(),
+ $enableAjaxValidation = true,
+ $enableClientValidation = true
+ ) {
+ if (!$this->enableAjaxValidation) {
+ $enableAjaxValidation = false;
+ }
+ if (!$this->enableClientValidation) {
+ $enableClientValidation = false;
+ }
+ if (!$enableAjaxValidation && !$enableClientValidation) {
+ return TbHtml::error($model, $attribute, $htmlOptions);
+ }
+ $id = CHtml::activeId($model, $attribute);
+ $inputID = TbArray::getValue('inputID', $htmlOptions, $id);
+ unset($htmlOptions['inputID']);
+ TbArray::defaultValue('id', $inputID . '_em_', $htmlOptions);
+ $option = array(
+ 'id' => $id,
+ 'inputID' => $inputID,
+ 'errorID' => $htmlOptions['id'],
+ 'model' => get_class($model),
+ 'name' => $attribute,
+ 'enableAjaxValidation' => $enableAjaxValidation,
+ 'inputContainer' => 'div.control-group', // Bootstrap requires this
+ );
+ $optionNames = array(
+ 'validationDelay',
+ 'validateOnChange',
+ 'validateOnType',
+ 'hideErrorMessage',
+ 'inputContainer',
+ 'errorCssClass',
+ 'successCssClass',
+ 'validatingCssClass',
+ 'beforeValidateAttribute',
+ 'afterValidateAttribute',
+ );
+ foreach ($optionNames as $name) {
+ if (isset($htmlOptions[$name])) {
+ $option[$name] = TbArray::popValue($name, $htmlOptions);
+ }
+ }
+ if ($model instanceof CActiveRecord && !$model->isNewRecord) {
+ $option['status'] = 1;
+ }
+ if ($enableClientValidation) {
+ $validators = TbArray::getValue('clientValidation', $htmlOptions, array());
+ $attributeName = $attribute;
+ if (($pos = strrpos($attribute, ']')) !== false && $pos !== strlen($attribute) - 1) // e.g. [a]name
+ {
+ $attributeName = substr($attribute, $pos + 1);
+ }
+ foreach ($model->getValidators($attributeName) as $validator) {
+ if ($validator->enableClientValidation) {
+ if (($js = $validator->clientValidateAttribute($model, $attributeName)) != '') {
+ $validators[] = $js;
+ }
+ }
+ }
+ if ($validators !== array()) {
+ $option['clientValidation'] = "js:function(value, messages, attribute) {\n" . implode(
+ "\n",
+ $validators
+ ) . "\n}";
+ }
+ }
+ $html = TbHtml::error($model, $attribute, $htmlOptions);
+ if ($html === '') {
+ $htmlOptions['type'] = $this->helpType;
+ TbHtml::addCssStyle('display:none', $htmlOptions);
+ $html = TbHtml::help('', $htmlOptions);
+ }
+ $this->attributes[$inputID] = $option;
+ return $html;
+ }
+
+ /**
+ * Displays a summary of validation errors for one or several models.
+ * @param mixed $models the models whose input errors are to be displayed.
+ * @param string $header a piece of HTML code that appears in front of the errors
+ * @param string $footer a piece of HTML code that appears at the end of the errors
+ * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
+ * @return string the error summary. Empty if no errors are found.
+ */
+ public function errorSummary($models, $header = null, $footer = null, $htmlOptions = array())
+ {
+ if (!$this->enableAjaxValidation && !$this->enableClientValidation) {
+ return TbHtml::errorSummary($models, $header, $footer, $htmlOptions);
+ }
+ TbArray::defaultValue('id', $this->id . '_es_', $htmlOptions);
+ $html = TbHtml::errorSummary($models, $header, $footer, $htmlOptions);
+ if ($html === '') {
+ if ($header === null) {
+ $header = '' . Yii::t('yii', 'Please fix the following input errors:') . '
';
+ }
+ TbHtml::addCssClass(TbHtml::$errorSummaryCss, $htmlOptions);
+ TbHtml::addCssStyle('display:none', $htmlOptions);
+ $html = CHtml::tag('div', $htmlOptions, $header . '' . $footer);
+ }
+ $this->summaryID = $htmlOptions['id'];
+ return $html;
+ }
+
+ /**
+ * Generates a text field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see TbHtml::activeTextField
+ */
+ public function textField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a password field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see TbHtml::activePasswordField
+ */
+ public function passwordField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an url field for a model attribute.
+ * @param CModel $model the data model
+ * @param string $attribute the attribute
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field
+ * @see TbHtml::activeUrlField
+ */
+ public function urlField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_URL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an email field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see TbHtml::activeEmailField
+ */
+ public function emailField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_EMAIL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a number field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see TbHtml::activeNumberField
+ */
+ public function numberField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a range field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ * @see TbHtml::activeRangeField
+ */
+ public function rangeField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_RANGE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a date field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input field.
+ */
+ public function dateField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_DATE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a text area for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated text area.
+ * @see TbHtml::activeTextArea
+ */
+ public function textArea($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a file field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes
+ * @return string the generated input field.
+ * @see TbHtml::activeFileField
+ */
+ public function fileField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a radio button for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated radio button.
+ * @see TbHtml::activeRadioButton
+ */
+ public function radioButton($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a checkbox for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated check box.
+ * @see TbHtml::activeCheckBox
+ */
+ public function checkBox($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a dropdown list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated drop down list.
+ * @see TbHtml::activeDropDownList
+ */
+ public function dropDownList($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a list box for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated list box.
+ * @see TbHtml::activeListBox
+ */
+ public function listBox($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a radio button list for a model attribute
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display)
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated radio button list.
+ * @see TbHtml::activeRadioButtonList
+ */
+ public function radioButtonList($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates an inline radio button list for a model attribute
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display)
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated radio button list.
+ * @see TbHtml::activeInlineRadioButtonList
+ */
+ public function inlineRadioButtonList($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return $this->createInput(TbHtml::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a checkbox list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display)
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated checkbox list.
+ * @see TbHtml::activeCheckBoxList
+ */
+ public function checkBoxList($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates an inline checkbox list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $data data for generating the list options (value=>display)
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated checkbox list.
+ * @see TbHtml::activeInlineCheckBoxList
+ */
+ public function inlineCheckBoxList($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return $this->createInput(TbHtml::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates an uneditable field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated field.
+ * @see TbHtml::activeUneditableField
+ */
+ public function uneditableField($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a search query field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated input.
+ * @see TbHtml::activeSearchField
+ */
+ public function searchQuery($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createInput(TbHtml::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates an input for a model attribute.
+ * @param string $type the input type.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for generating the list options (value=>display).
+ * @return string the generated input.
+ * @see TbHtml::createActiveInput
+ */
+ public function createInput($type, $model, $attribute, $htmlOptions = array(), $data = array())
+ {
+ return TbHtml::createActiveInput($type, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a text field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeTextFieldControlGroup
+ */
+ public function textFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a password field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activePasswordFieldControlGroup
+ */
+ public function passwordFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with an url field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeUrlFieldControlGroup
+ */
+ public function urlFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_URL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with an email field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeEmailFieldControlGroup
+ */
+ public function emailFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_EMAIL, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a number field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeNumberFieldControlGroup
+ */
+ public function numberFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a range field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeRangeFieldControlGroup
+ */
+ public function rangeFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_RANGE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a date field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeDateFieldControlGroup
+ */
+ public function dateFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_DATE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a text area for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeTextAreaControlGroup
+ */
+ public function textAreaControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a check box for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeCheckBoxControlGroup
+ */
+ public function checkBoxControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a radio button for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeRadioButtonControlGroup
+ */
+ public function radioButtonControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a drop down list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeDropDownListControlGroup
+ */
+ public function dropDownListControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a list box for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeListBoxControlGroup
+ */
+ public function listBoxControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a file field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeFileFieldControlGroup
+ */
+ public function fileFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a radio button list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeRadioButtonListControlGroup
+ */
+ public function radioButtonListControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline radio button list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeInlineCheckBoxListControlGroup
+ */
+ public function inlineRadioButtonListControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with a check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeCheckBoxListControlGroup
+ */
+ public function checkBoxListControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an inline check box list for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $data data for generating the list options (value=>display).
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeInlineCheckBoxListControlGroup
+ */
+ public function inlineCheckBoxListControlGroup($model, $attribute, $data, $htmlOptions = array())
+ {
+ $htmlOptions['inline'] = true;
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Generates a control group with an uneditable field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeUneditableFieldControlGroup
+ */
+ public function uneditableFieldControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group with a search field for a model attribute.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @return string the generated control group.
+ * @see TbHtml::activeSearchFieldControlGroup
+ */
+ public function searchQueryControlGroup($model, $attribute, $htmlOptions = array())
+ {
+ return $this->createControlGroup(TbHtml::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions);
+ }
+
+ /**
+ * Generates a control group for a model attribute.
+ * @param string $type the input type.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $htmlOptions additional HTML attributes.
+ * @param array $data data for generating the list options (value=>display).
+ * @return string the generated control group.
+ * @see TbHtml::activeControlGroup
+ */
+ public function createControlGroup($type, $model, $attribute, $htmlOptions = array(), $data = array())
+ {
+ $htmlOptions = $this->processControlGroupOptions($model, $attribute, $htmlOptions);
+ return TbHtml::activeControlGroup($type, $model, $attribute, $htmlOptions, $data);
+ }
+
+ /**
+ * Processes the options for a input row.
+ * @param CModel $model the data model.
+ * @param string $attribute the attribute name.
+ * @param array $options the options.
+ * @return array the processed options.
+ */
+ protected function processControlGroupOptions($model, $attribute, $options)
+ {
+ $errorOptions = TbArray::popValue('errorOptions', $options, array());
+ $enableAjaxValidation = TbArray::popValue('enableAjaxValidation', $errorOptions, true);
+ $enableClientValidation = TbArray::popValue('enableClientValidation', $errorOptions, true);
+ $errorOptions['type'] = $this->helpType;
+ $error = $this->error($model, $attribute, $errorOptions, $enableAjaxValidation, $enableClientValidation);
+ // kind of a hack for ajax forms but this works for now.
+ if (!empty($error) && strpos($error, 'display:none') === false) {
+ $options['color'] = TbHtml::INPUT_COLOR_ERROR;
+ }
+ if (!$this->hideInlineErrors) {
+ $options['error'] = $error;
+ }
+ $helpOptions = TbArray::popValue('helpOptions', $options, array());
+ $helpOptions['type'] = $this->helpType;
+ $options['helpOptions'] = $helpOptions;
+ return $options;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbAffix.php b/www/protected/extensions/bootstrap/widgets/TbAffix.php
new file mode 100644
index 0000000..837bccf
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbAffix.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap affix widget.
+ * @see http://twitter.github.com/bootstrap/javascript.html#affix
+ */
+class TbAffix extends CWidget
+{
+ /**
+ * @var string the HTML tag for the container.
+ */
+ public $tagName = 'div';
+ /**
+ * @var mixed pixels to offset from screen when calculating position of scroll.
+ */
+ public $offset;
+ /**
+ * @var array the HTML attributes for the container.
+ */
+ public $htmlOptions = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ $this->htmlOptions['data-spy'] = 'affix';
+ if (isset($this->offset)) {
+ if (is_string($this->offset)) {
+ $this->offset = array('top', $this->offset);
+ }
+
+ if (is_array($this->offset) && count($this->offset) === 2) {
+ list($position, $offset) = $this->offset;
+ $this->htmlOptions['data-offset-' . $position] = $offset;
+ }
+ }
+ echo TbHtml::openTag($this->tagName, $this->htmlOptions);
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ echo CHtml::closeTag($this->tagName);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbAlert.php b/www/protected/extensions/bootstrap/widgets/TbAlert.php
new file mode 100644
index 0000000..0dcac64
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbAlert.php
@@ -0,0 +1,95 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap alert widget.
+ * @see http://twitter.github.com/bootstrap/javascript.html#alerts
+ */
+class TbAlert extends CWidget
+{
+ /**
+ * @var array the alerts configurations (style=>config).
+ */
+ public $alerts;
+ /**
+ * @var string|boolean the close link text. If this is set false, no close link will be displayed.
+ */
+ public $closeText = TbHtml::CLOSE_TEXT;
+ /**
+ * @var boolean indicates whether the alert should be an alert block. Defaults to 'true'.
+ */
+ public $block = true;
+ /**
+ * @var boolean indicates whether alerts should use transitions. Defaults to 'true'.
+ */
+ public $fade = true;
+ /**
+ * @var string[] the JavaScript event configuration (name=>handler).
+ */
+ public $events = array();
+ /**
+ * @var array the HTML attributes for the alert container.
+ */
+ public $htmlOptions = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ if (is_string($this->alerts)) {
+ $colors = explode(' ', $this->alerts);
+ } else {
+ if (!isset($this->alerts)) {
+ $colors = array(
+ TbHtml::ALERT_COLOR_SUCCESS,
+ TbHtml::ALERT_COLOR_WARNING,
+ TbHtml::ALERT_COLOR_INFO,
+ TbHtml::ALERT_COLOR_ERROR
+ ); // render all styles by default
+ }
+ }
+ if (isset($colors)) {
+ $this->alerts = array();
+ foreach ($colors as $color) {
+ $this->alerts[$color] = array();
+ }
+ }
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ /* @var $user CWebUser */
+ $user = Yii::app()->getUser();
+ if (count($user->getFlashes(false)) == 0) {
+ return;
+ }
+ echo TbHtml::openTag('div', $this->htmlOptions);
+ foreach ($this->alerts as $color => $alert) {
+ if (isset($alert['visible']) && !$alert['visible']) {
+ continue;
+ }
+
+ if ($user->hasFlash($color)) {
+ $htmlOptions = TbArray::popValue('htmlOptions', $alert, array());
+ TbArray::defaultValue('closeText', $this->closeText, $htmlOptions);
+ TbArray::defaultValue('block', $this->block, $htmlOptions);
+ TbArray::defaultValue('fade', $this->fade, $htmlOptions);
+ echo TbHtml::alert($color, $user->getFlash($color), $htmlOptions);
+ }
+ }
+ echo '';
+ $this->registerEvents("#{$this->htmlOptions['id']} > .alert", $this->events);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbBreadcrumb.php b/www/protected/extensions/bootstrap/widgets/TbBreadcrumb.php
new file mode 100644
index 0000000..7a52619
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbBreadcrumb.php
@@ -0,0 +1,74 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Bootstrap breadcrumb widget.
+ * @see http://twitter.github.com/bootstrap/components.html#breadcrumbs
+ * @package bootstrap.widgets
+ */
+class TbBreadcrumb extends CWidget
+{
+ /**
+ * @var string the divider between links in the breadcrumbs.
+ */
+ public $divider = '/';
+ /**
+ * @var boolean whether to HTML encode the link labels.
+ */
+ public $encodeLabel = true;
+ /**
+ * @var string the label for the first link in the breadcrumb.
+ */
+ public $homeLabel;
+ /**
+ * @var array the url for the first link in the breadcrumb
+ */
+ public $homeUrl;
+ /**
+ * @var array the HTML attributes for the breadcrumbs.
+ */
+ public $htmlOptions = array();
+ /**
+ * @var array list of links to appear in the breadcrumbs.
+ */
+ public $links = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->htmlOptions['divider'] = $this->divider;
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ // todo: consider adding control property for displaying breadcrumbs even when empty.
+ if (!empty($this->links)) {
+ $links = array();
+ if ($this->homeLabel !== false) {
+ $label = $this->homeLabel !== null ? $this->homeLabel : TbHtml::icon('home');
+ $links[$label] = $this->homeUrl !== null ? $this->homeUrl : Yii::app()->homeUrl;
+ }
+ foreach ($this->links as $label => $url) {
+ if (is_string($label)) {
+ if ($this->encodeLabel) {
+ $label = CHtml::encode($label);
+ }
+ $links[$label] = $url;
+ } else {
+ $links[] = $this->encodeLabel ? CHtml::encode($url) : $url;
+ }
+ }
+ echo TbHtml::breadcrumbs($links, $this->htmlOptions);
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbButtonColumn.php b/www/protected/extensions/bootstrap/widgets/TbButtonColumn.php
new file mode 100644
index 0000000..c427dff
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbButtonColumn.php
@@ -0,0 +1,88 @@
+
+ * @author Christoffer Niska
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+Yii::import('zii.widgets.grid.CButtonColumn');
+
+/**
+ * Bootstrap button column widget.
+ */
+class TbButtonColumn extends CButtonColumn
+{
+ /**
+ * @var string the view button icon (defaults to TbHtml::ICON_EYE_OPEN).
+ */
+ public $viewButtonIcon = TbHtml::ICON_EYE_OPEN;
+ /**
+ * @var string the update button icon (defaults to TbHtml::ICON_PENCIL).
+ */
+ public $updateButtonIcon = TbHtml::ICON_PENCIL;
+ /**
+ * @var string the delete button icon (defaults to TbHtml::ICON_TRASH).
+ */
+ public $deleteButtonIcon = TbHtml::ICON_TRASH;
+
+ /**
+ * Initializes the default buttons (view, update and delete).
+ */
+ protected function initDefaultButtons()
+ {
+ parent::initDefaultButtons();
+
+ if ($this->viewButtonIcon !== false && !isset($this->buttons['view']['icon'])) {
+ $this->buttons['view']['icon'] = $this->viewButtonIcon;
+ }
+ if ($this->updateButtonIcon !== false && !isset($this->buttons['update']['icon'])) {
+ $this->buttons['update']['icon'] = $this->updateButtonIcon;
+ }
+ if ($this->deleteButtonIcon !== false && !isset($this->buttons['delete']['icon'])) {
+ $this->buttons['delete']['icon'] = $this->deleteButtonIcon;
+ }
+ }
+
+ /**
+ * Renders a link button.
+ * @param string $id the ID of the button
+ * @param array $button the button configuration which may contain 'label', 'url', 'imageUrl' and 'options' elements.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data object associated with the row
+ */
+ protected function renderButton($id, $button, $row, $data)
+ {
+ if (isset($button['visible']) && !$this->evaluateExpression(
+ $button['visible'],
+ array('row' => $row, 'data' => $data)
+ )
+ ) {
+ return;
+ }
+
+ $url = TbArray::popValue('url', $button);
+ if ($url !== '#') {
+ $url = $this->evaluateExpression($url, array('data' => $data, 'row' => $row));
+ }
+
+ $imageUrl = TbArray::popValue('imageUrl', $button, false);
+ $label = TbArray::popValue('label', $button, $id);
+ $options = TbArray::popValue('options', $button, array());
+
+ TbArray::defaultValue('title', $label, $options);
+ TbArray::defaultValue('rel', 'tooltip', $options);
+
+ if ($icon = TbArray::popValue('icon', $button, false)) {
+ echo CHtml::link(TbHtml::icon($icon), $url, $options);
+ } else {
+ if ($imageUrl && is_string($imageUrl)) {
+ echo CHtml::link(CHtml::image($imageUrl, $label), $url, $options);
+ } else {
+ echo CHtml::link($label, $url, $options);
+ }
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbCollapse.php b/www/protected/extensions/bootstrap/widgets/TbCollapse.php
new file mode 100644
index 0000000..afc6b0b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbCollapse.php
@@ -0,0 +1,82 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap collapse widget.
+ * @see http://twitter.github.com/bootstrap/javascript.html#collapse
+ */
+class TbCollapse extends CWidget
+{
+ /**
+ * @var string the HTML tag for the container.
+ */
+ public $tagName = 'div';
+ /**
+ * @var string the content text.
+ */
+ public $content;
+ /**
+ * @var string the path to a partial view.
+ */
+ public $view;
+ /**
+ * @var string the CSS selector for the parent element.
+ */
+ public $parent;
+ /**
+ * @var boolean whether to be collapsed on invocation.
+ */
+ public $toggle;
+ /**
+ * @var string[] $events the JavaScript event configuration (name=>handler).
+ */
+ public $events = array();
+ /**
+ * @var array the HTML attributes for the container.
+ */
+ public $htmlOptions = array();
+ /**
+ * @var array additional data to be passed to the view.
+ */
+ public $viewData = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ TbHtml::addCssClass('collapse', $this->htmlOptions);
+ if (isset($this->parent)) {
+ TbArray::defaultValue('data-parent', $this->parent, $this->htmlOptions);
+ }
+ if (isset($this->toggle) && $this->toggle) {
+ TbHtml::addCssClass('in', $this->htmlOptions);
+ }
+ if (isset($this->view)) {
+ $controller = $this->getController();
+ if (isset($controller) && $controller->getViewFile($this->view) !== false) {
+ $this->content = $this->controller->renderPartial($this->view, $this->viewData, true);
+ }
+ }
+ echo TbHtml::openTag($this->tagName, $this->htmlOptions);
+ echo $this->content;
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ echo CHtml::closeTag($this->tagName);
+ $selector = '#' . $this->htmlOptions['id'];
+ $this->registerEvents($selector, $this->events);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbDataColumn.php b/www/protected/extensions/bootstrap/widgets/TbDataColumn.php
new file mode 100644
index 0000000..08a398c
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbDataColumn.php
@@ -0,0 +1,103 @@
+
+ * @author Christoffer Niska
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+Yii::import('zii.widgets.grid.CDataColumn');
+
+/**
+ * Bootstrap grid data column.
+ */
+class TbDataColumn extends CDataColumn
+{
+ /**
+ * @var array HTML options for filter input
+ * @link {TbDataColumn::renderFilterCellContent()}
+ */
+ public $filterInputOptions;
+
+ /**
+ * Renders the header cell content.
+ * This method will render a link that can trigger the sorting if the column is sortable.
+ */
+ protected function renderHeaderCellContent()
+ {
+ if ($this->grid->enableSorting && $this->sortable && $this->name !== null) {
+ $sort = $this->grid->dataProvider->getSort();
+ $label = isset($this->header) ? $this->header : $sort->resolveLabel($this->name);
+
+ if ($sort->resolveAttribute($this->name) !== false) {
+ $label .= ' ';
+ }
+
+ echo $sort->link($this->name, $label, array('class' => 'sort-link'));
+ } else {
+ if ($this->name !== null && $this->header === null) {
+ if ($this->grid->dataProvider instanceof CActiveDataProvider) {
+ echo CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name));
+ } else {
+ echo CHtml::encode($this->name);
+ }
+ } else {
+ parent::renderHeaderCellContent();
+ }
+ }
+ }
+
+ /**
+ * Renders the filter cell.
+ */
+ public function renderFilterCell()
+ {
+ echo CHtml::openTag('td', $this->filterHtmlOptions);
+ echo '';
+ $this->renderFilterCellContent();
+ echo '
';
+ echo CHtml::closeTag('td');
+ }
+
+ /**
+ * Renders the filter cell content. Here we can provide HTML options for actual filter input
+ */
+ protected function renderFilterCellContent()
+ {
+ if (is_string($this->filter)) {
+ echo $this->filter;
+ } else {
+ if ($this->filter !== false && $this->grid->filter !== null && $this->name !== null && strpos(
+ $this->name,
+ '.'
+ ) === false
+ ) {
+ if ($this->filterInputOptions) {
+ $filterInputOptions = $this->filterInputOptions;
+ if (empty($filterInputOptions['id'])) {
+ $filterInputOptions['id'] = false;
+ }
+ } else {
+ $filterInputOptions = array();
+ }
+ if (is_array($this->filter)) {
+ $filterInputOptions['prompt'] = '';
+ echo CHtml::activeDropDownList(
+ $this->grid->filter,
+ $this->name,
+ $this->filter,
+ $filterInputOptions
+ );
+ } else {
+ if ($this->filter === null) {
+ echo CHtml::activeTextField($this->grid->filter, $this->name, $filterInputOptions);
+ }
+ }
+ } else {
+ parent::renderFilterCellContent();
+ }
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbDetailView.php b/www/protected/extensions/bootstrap/widgets/TbDetailView.php
new file mode 100644
index 0000000..698a8ad
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbDetailView.php
@@ -0,0 +1,47 @@
+
+ * @author Christoffer Niska
+ * @copyright Copyright © Sam Stenvall 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+Yii::import('zii.widgets.CDetailView');
+
+/**
+ * Bootstrap Zii detail widget.
+ */
+class TbDetailView extends CDetailView
+{
+ /**
+ * @var string|array the detail view style.
+ * Valid values are TbHtml::DETAIL_STRIPED, TbHtml::DETAIL_BORDERED, TbHtml::DETAIL_CONDENSED and/or TbHtml::DETAIL_HOVER.
+ */
+ public $type = array(TbHtml::DETAIL_TYPE_STRIPED, TbHtml::DETAIL_TYPE_CONDENSED);
+ /**
+ * @var string the URL of the CSS file used by this grid view.
+ * Defaults to false, meaning that no CSS will be included.
+ */
+ public $cssFile = false;
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ parent::init();
+ $classes = array('table');
+ if (!empty($this->type)) {
+ if (is_string($this->type)) {
+ $this->type = explode(' ', $this->type);
+ }
+
+ foreach ($this->type as $type) {
+ $classes[] = 'table-' . $type;
+ }
+ }
+ TbHtml::addCssClass($classes, $this->htmlOptions);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbGridView.php b/www/protected/extensions/bootstrap/widgets/TbGridView.php
new file mode 100644
index 0000000..74f7055
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbGridView.php
@@ -0,0 +1,106 @@
+
+ * @author Christoffer Niska
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+Yii::import('zii.widgets.grid.CGridView');
+
+/**
+ * Bootstrap Zii grid view.
+ */
+class TbGridView extends CGridView
+{
+ /**
+ * @var string|array the table style.
+ * Valid values are TbHtml::GRID_TYPE_STRIPED, TbHtml::GRID_TYPE_BORDERED, TbHtml::GRID_TYPE_CONDENSED and/or
+ * TbHtml::GRID_TYPE_HOVER.
+ */
+ public $type;
+ /**
+ * @var string the CSS class name for the pager container. Defaults to 'pagination'.
+ */
+ public $pagerCssClass = 'pagination';
+ /**
+ * @var array the configuration for the pager.
+ * Defaults to array('class'=>'ext.bootstrap.widgets.TbPager')
.
+ */
+ public $pager = array('class' => 'bootstrap.widgets.TbPager');
+ /**
+ * @var string the URL of the CSS file used by this grid view.
+ * Defaults to false, meaning that no CSS will be included.
+ */
+ public $cssFile = false;
+ /**
+ * @var string the template to be used to control the layout of various sections in the view.
+ */
+ public $template = "{items}\n";
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ parent::init();
+ $classes = array('table');
+ if (isset($this->type) && !empty($this->type)) {
+ if (is_string($this->type)) {
+ $this->type = explode(' ', $this->type);
+ }
+
+ foreach ($this->type as $type) {
+ $classes[] = 'table-' . $type;
+ }
+ }
+ if (!empty($classes)) {
+ $classes = implode(' ', $classes);
+ if (isset($this->itemsCssClass)) {
+ $this->itemsCssClass .= ' ' . $classes;
+ } else {
+ $this->itemsCssClass = $classes;
+ }
+ }
+ }
+
+ /**
+ * Creates column objects and initializes them.
+ */
+ protected function initColumns()
+ {
+ foreach ($this->columns as $i => $column) {
+ if (is_array($column) && !isset($column['class'])) {
+ $this->columns[$i]['class'] = 'bootstrap.widgets.TbDataColumn';
+ }
+ }
+ parent::initColumns();
+ }
+
+ /**
+ * Creates a column based on a shortcut column specification string.
+ * @param mixed $text the column specification string
+ * @return \TbDataColumn|\CDataColumn the column instance
+ * @throws CException if the column format is incorrect
+ */
+ protected function createDataColumn($text)
+ {
+ if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $text, $matches)) {
+ throw new CException(Yii::t(
+ 'zii',
+ 'The column must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'
+ ));
+ }
+ $column = new TbDataColumn($this);
+ $column->name = $matches[1];
+ if (isset($matches[3]) && $matches[3] !== '') {
+ $column->type = $matches[3];
+ }
+ if (isset($matches[5])) {
+ $column->header = $matches[5];
+ }
+ return $column;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbHeroUnit.php b/www/protected/extensions/bootstrap/widgets/TbHeroUnit.php
new file mode 100644
index 0000000..3660be5
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbHeroUnit.php
@@ -0,0 +1,62 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap hero unit widget.
+ * @see http://twitter.github.com/bootstrap/javascript.html#affix
+ */
+class TbHeroUnit extends CWidget
+{
+ /**
+ * @var string the heading text.
+ */
+ public $heading;
+ /**
+ * @var array the HTML attributes for the heading.
+ */
+ public $headingOptions = array();
+ /**
+ * @var string the content text.
+ */
+ public $content;
+ /**
+ * @var string the path to a partial view.
+ */
+ public $view;
+ /**
+ * @var array the HTML attributes for the container tag.
+ */
+ public $htmlOptions = array();
+ /**
+ * @var array additional data to be passed to the view.
+ */
+ public $viewData = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ if (isset($this->view)) {
+ $controller = $this->getController();
+ if (isset($controller) && $controller->getViewFile($this->view) !== false) {
+ $this->content = $this->controller->renderPartial($this->view, $this->viewData, true);
+ }
+ }
+ $this->htmlOptions['headingOptions'] = $this->headingOptions;
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ echo TbHtml::heroUnit($this->heading, $this->content, $this->htmlOptions);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbListView.php b/www/protected/extensions/bootstrap/widgets/TbListView.php
new file mode 100644
index 0000000..a7f98dd
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbListView.php
@@ -0,0 +1,44 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+Yii::import('zii.widgets.CListView');
+
+/**
+ * Bootstrap Zii list view.
+ */
+class TbListView extends CListView
+{
+ /**
+ * @var string the CSS class name for the pager container. Defaults to 'pagination'.
+ */
+ public $pagerCssClass = 'pagination';
+ /**
+ * @var array the configuration for the pager.
+ * Defaults to array('class'=>'ext.bootstrap.widgets.TbPager')
.
+ */
+ public $pager = array('class' => 'bootstrap.widgets.TbPager');
+ /**
+ * @var string the URL of the CSS file used by this detail view.
+ * Defaults to false, meaning that no CSS will be included.
+ */
+ public $cssFile = false;
+ /**
+ * @var string the template to be used to control the layout of various sections in the view.
+ */
+ public $template = "{items}\n";
+
+ /**
+ * Renders the empty message when there is no data.
+ */
+ public function renderEmptyText()
+ {
+ $emptyText = $this->emptyText === null ? Yii::t('zii', 'No results found.') : $this->emptyText;
+ echo TbHtml::tag('div', array('class' => 'empty', 'span' => 12), $emptyText);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbModal.php b/www/protected/extensions/bootstrap/widgets/TbModal.php
new file mode 100644
index 0000000..0dad704
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbModal.php
@@ -0,0 +1,261 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap modal widget.
+ */
+class TbModal extends CWidget
+{
+ /**
+ * @var array the HTML options for the view container tag.
+ */
+ public $htmlOptions = array();
+
+ /**
+ * @var array The additional HTML attributes of the button that will show the modal. If empty array, only
+ * the markup of the modal will be rendered on the page, so users can easily call the modal manually with their own
+ * scripts. The following special attributes are available:
+ *
+ * label: string, the label of the button
+ *
+ *
+ * For available options of the button trigger, see http://twitter.github.com/bootstrap/javascript.html#modals.
+ */
+ public $buttonOptions = array();
+
+ /**
+ * @var boolean indicates whether the modal should use transitions. Defaults to 'true'.
+ */
+ public $fade = true;
+
+ /**
+ * @var bool $keyboard, closes the modal when escape key is pressed.
+ */
+ public $keyboard = true;
+
+ /**
+ * @var bool $show, shows the modal when initialized.
+ */
+ public $show = false;
+
+ /**
+ * @var mixed includes a modal-backdrop element. Alternatively, specify `static` for a backdrop which doesn't close
+ * the modal on click.
+ */
+ public $backdrop = true;
+
+ /**
+ * @var mixed the remote url. If a remote url is provided, content will be loaded via jQuery's load method and
+ * injected into the .modal-body of the modal.
+ */
+ public $remote;
+
+ /**
+ * @var string a javascript function that will be invoked immediately when the `show` instance method is called.
+ */
+ public $onShow;
+
+ /**
+ * @var string a javascript function that will be invoked when the modal has been made visible to the user
+ * (will wait for css transitions to complete).
+ */
+ public $onShown;
+
+ /**
+ * @var string a javascript function that will be invoked immediately when the hide instance method has been called.
+ */
+ public $onHide;
+
+ /**
+ * @var string a javascript function that will be invoked when the modal has finished being hidden from the user
+ * (will wait for css transitions to complete).
+ */
+ public $onHidden;
+
+ /**
+ * @var string[] the Javascript event handlers.
+ */
+ protected $events = array();
+
+ /**
+ * @var array $options the plugin options.
+ */
+ protected $options = array();
+
+ /**
+ * @var string
+ */
+ public $closeText = TbHtml::CLOSE_TEXT;
+
+ /**
+ * @var string header content
+ */
+ public $header;
+
+ /**
+ * @var string body of modal
+ */
+ public $content;
+
+ /**
+ * @var string footer content
+ */
+ public $footer;
+
+ /**
+ * Widget's initialization method
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+
+ TbArray::defaultValue('id', $this->getId(), $this->htmlOptions);
+ TbArray::defaultValue('role', 'dialog', $this->htmlOptions);
+ TbArray::defaultValue('tabindex', '-1', $this->htmlOptions);
+
+ TbHtml::addCssClass('modal hide', $this->htmlOptions);
+ if ($this->fade) {
+ TbHtml::addCssClass('fade', $this->htmlOptions);
+ }
+
+ if (is_array($this->footer)) {
+ $this->footer = implode(' ', $this->footer);
+ }
+
+ $this->initOptions();
+ $this->initEvents();
+ }
+
+ /**
+ * Initialize events if any
+ */
+ public function initEvents()
+ {
+ foreach (array('onShow', 'onShown', 'onHide', 'onHidden') as $event) {
+ if ($this->$event !== null) {
+ $modalEvent = strtolower(substr($event, 2));
+ if ($this->$event instanceof CJavaScriptExpression) {
+ $this->events[$modalEvent] = $this->$event;
+ } else {
+ $this->events[$modalEvent] = new CJavaScriptExpression($this->$event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initialize plugin options.
+ * ***Important***: The display of the button overrides the initialization of the modal bootstrap widget.
+ */
+ public function initOptions()
+ {
+ if ($remote = TbArray::popValue('remote', $this->options)) {
+ $this->options['remote'] = CHtml::normalizeUrl($remote);
+ }
+
+ TbArray::defaultValue('backdrop', $this->backdrop, $this->options);
+ TbArray::defaultValue('keyboard', $this->keyboard, $this->options);
+ TbArray::defaultValue('show', $this->show, $this->options);
+ }
+
+ /**
+ * Widget's run method
+ */
+ public function run()
+ {
+ $this->renderModal();
+ $this->renderButton();
+ $this->registerClientScript();
+ }
+
+ /**
+ * Renders the button
+ */
+ public function renderButton()
+ {
+ if (!empty($this->buttonOptions) && is_array($this->buttonOptions)) {
+ TbArray::defaultValue('data-toggle', 'modal', $this->buttonOptions);
+
+ if ($this->remote !== null) {
+ $this->buttonOptions['data-remote'] = CHtml::normalizeUrl($this->remote);
+ }
+
+ $selector = '#' . $this->htmlOptions['id'];
+ $label = TbArray::popValue('label', $this->buttonOptions, 'button');
+ $attr = isset($this->buttonOptions['data-remote']) ? 'data-target' : 'href';
+ TbArray::defaultValue($attr, $selector, $this->buttonOptions);
+ echo TbHtml::button($label, $this->buttonOptions);
+ }
+ }
+
+ /**
+ * Renders the modal markup
+ */
+ public function renderModal()
+ {
+ echo TbHtml::openTag('div', $this->htmlOptions) . PHP_EOL;
+
+ $this->renderModalHeader();
+ $this->renderModalBody();
+ $this->renderModalFooter();
+
+ echo '' . PHP_EOL;
+ }
+
+ /**
+ * Renders the header HTML markup of the modal
+ */
+ public function renderModalHeader()
+ {
+ echo '' . PHP_EOL;
+ }
+
+ /**
+ * Renders the HTML markup for the body of the modal
+ */
+ public function renderModalBody()
+ {
+ echo '' . PHP_EOL;
+ echo $this->content;
+ echo '
' . PHP_EOL;
+ }
+
+ /**
+ * Renders the HTML markup for the footer of the modal
+ */
+ public function renderModalFooter()
+ {
+
+ echo '' . PHP_EOL;
+ }
+
+ /**
+ * Registers necessary client scripts.
+ */
+ public function registerClientScript()
+ {
+ $selector = '#' . $this->htmlOptions['id'];
+
+ // do we render a button? If so, bootstrap will handle its behavior through its
+ // mark-up, otherwise, register the plugin.
+ if (empty($this->buttonOptions)) {
+ $this->registerPlugin(TbApi::PLUGIN_MODAL, $selector, $this->options);
+ }
+
+ $this->registerEvents($selector, $this->events);
+ }
+
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbNav.php b/www/protected/extensions/bootstrap/widgets/TbNav.php
new file mode 100644
index 0000000..a262d5b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbNav.php
@@ -0,0 +1,171 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap navigation menu widget.
+ * @see http://twitter.github.com/bootstrap/components.html#navbar
+ */
+class TbNav extends CWidget
+{
+ /**
+ * @var string the menu type.
+ */
+ public $type;
+ /**
+ * @var boolean whether the menu items should be stacked on top of each other.
+ */
+ public $stacked = false;
+ /**
+ * @var string|array the scrollspy target or configuration.
+ */
+ public $scrollspy;
+ /**
+ * @var array list of menu items. Each menu item is specified as an array of name-value pairs.
+ */
+ public $items = array();
+ /**
+ * @var boolean whether the labels for menu items should be HTML-encoded. Defaults to true.
+ */
+ public $encodeLabel = true;
+ /**
+ * @var boolean whether to automatically activate items according to whether their route setting
+ * matches the currently requested route. Defaults to true.
+ */
+ public $activateItems = true;
+ /**
+ * @var boolean whether to activate parent menu items when one of the corresponding child menu items is active.
+ */
+ public $activateParents = false;
+ /**
+ * @var boolean whether to hide empty menu items.
+ */
+ public $hideEmptyItems = true;
+ /**
+ * @var array HTML attributes for the menu's root container tag.
+ */
+ public $htmlOptions = array();
+
+ // todo: consider supporting these.
+ //public $submenuHtmlOptions = array();
+ //public $linkLabelWrapper;
+ //public $linkLabelWrapperHtmlOptions=array();
+ //public $itemCssClass;
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ $route = $this->controller->getRoute();
+ if ($this->stacked) {
+ TbHtml::addCssClass('nav-stacked', $this->htmlOptions);
+ }
+ if (isset($this->scrollspy)) {
+ if (is_string($this->scrollspy)) {
+ $this->scrollspy = array('target' => $this->scrollspy);
+ }
+ $this->widget('bootstrap.widgets.TbScrollspy', $this->scrollspy);
+ }
+ $this->items = $this->normalizeItems($this->items, $route, $hasActiveChild);
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ if (!empty($this->items)) {
+ echo TbHtml::nav($this->type, $this->items, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Normalizes the menu items.
+ * @param array $items the items to be normalized.
+ * @param string $route the route of the current request.
+ * @param boolean $active whether there is an active child menu item.
+ * @return array the normalized menu items.
+ */
+ protected function normalizeItems($items, $route, &$active)
+ {
+ foreach ($items as $i => $item) {
+ // skip dividers
+ if (is_string($item)) {
+ continue;
+ }
+
+ if (isset($item['visible']) && !$item['visible']) {
+ unset($items[$i]);
+ continue;
+ }
+
+ TbArray::defaultValue('label', '', $item);
+
+ if ($this->encodeLabel) {
+ $items[$i]['label'] = CHtml::encode($item['label']);
+ }
+
+ $hasActiveChild = false;
+
+ if (isset($item['items']) && !empty($item['items'])) {
+ $items[$i]['items'] = $this->normalizeItems($item['items'], $route, $hasActiveChild);
+
+ if (empty($items[$i]['items']) && $this->hideEmptyItems) {
+ unset($items[$i]['items']);
+ if (!isset($item['url'])) {
+ unset($items[$i]);
+ continue;
+ }
+ }
+ }
+
+ if (!isset($item['active'])) {
+ if ($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive(
+ $item,
+ $route
+ )
+ ) {
+ $active = $items[$i]['active'] = true;
+ } else {
+ $items[$i]['active'] = false;
+ }
+ } else {
+ if ($item['active']) {
+ $active = true;
+ }
+ }
+ }
+
+ return array_values($items);
+ }
+
+ /**
+ * Checks whether a menu item is active.
+ * @param array $item the menu item to be checked.
+ * @param string $route the route of the current request.
+ * @return boolean whether the menu item is active.
+ */
+ protected function isItemActive($item, $route)
+ {
+ if (isset($item['url']) && is_array($item['url']) && !strcasecmp(trim($item['url'][0], '/'), $route)) {
+ unset($item['url']['#']);
+ if (count($item['url']) > 1) {
+ foreach (array_splice($item['url'], 1) as $name => $value) {
+ if (!isset($_GET[$name]) || $_GET[$name] != $value) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbNavbar.php b/www/protected/extensions/bootstrap/widgets/TbNavbar.php
new file mode 100644
index 0000000..ea5f9d6
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbNavbar.php
@@ -0,0 +1,129 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap navbar widget.
+ * @see http://twitter.github.com/bootstrap/components.html#navbar
+ */
+class TbNavbar extends CWidget
+{
+ /**
+ * @var string the navbar color.
+ */
+ public $color;
+ /**
+ * @var string the brand label text.
+ */
+ public $brandLabel;
+ /**
+ * @var mixed the brand url.
+ */
+ public $brandUrl;
+ /**
+ * @var array the HTML attributes for the brand link.
+ */
+ public $brandOptions = array();
+ /**
+ * @var string nanvbar display type.
+ */
+ public $display = TbHtml::NAVBAR_DISPLAY_FIXEDTOP;
+ /**
+ * @var boolean whether the navbar spans over the whole page.
+ */
+ public $fluid = false;
+ /**
+ * @var boolean whether to enable collapsing of the navbar on narrow screens.
+ */
+ public $collapse = false;
+ /**
+ * @var array additional HTML attributes for the collapse widget.
+ */
+ public $collapseOptions = array();
+ /**
+ * @var array list of navbar item.
+ */
+ public $items = array();
+ /**
+ * @var array the HTML attributes for the navbar.
+ */
+ public $htmlOptions = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ if ($this->brandLabel !== false) {
+ if (!isset($this->brandLabel)) {
+ $this->brandLabel = CHtml::encode(Yii::app()->name);
+ }
+
+ if (!isset($this->brandUrl)) {
+ $this->brandUrl = Yii::app()->homeUrl;
+ }
+ }
+ if (isset($this->color)) {
+ TbArray::defaultValue('color', $this->color, $this->htmlOptions);
+ }
+ if (isset($this->display) && $this->display !== TbHtml::NAVBAR_DISPLAY_NONE) {
+ TbArray::defaultValue('display', $this->display, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ $brand = $this->brandLabel !== false
+ ? TbHtml::navbarBrandLink($this->brandLabel, $this->brandUrl, $this->brandOptions)
+ : '';
+ ob_start();
+ foreach ($this->items as $item) {
+ if (is_string($item)) {
+ echo $item;
+ } else {
+ $widgetClassName = TbArray::popValue('class', $item);
+ if ($widgetClassName !== null) {
+ $this->controller->widget($widgetClassName, $item);
+ }
+ }
+ }
+ $items = ob_get_clean();
+ ob_start();
+ if ($this->collapse !== false) {
+ TbHtml::addCssClass('nav-collapse', $this->collapseOptions);
+ ob_start();
+ /* @var TbCollapse $collapseWidget */
+ $collapseWidget = $this->controller->widget(
+ 'bootstrap.widgets.TbCollapse',
+ array(
+ 'toggle' => false, // navbars are collapsed by default
+ 'content' => $items,
+ 'htmlOptions' => $this->collapseOptions,
+ )
+ );
+ $collapseContent = ob_get_clean();
+ echo TbHtml::navbarCollapseLink('#' . $collapseWidget->getId());
+ echo $brand . $collapseContent;
+
+ } else {
+ echo $brand . $items;
+ }
+ $containerContent = ob_get_clean();
+ $containerOptions = TbArray::popValue('containerOptions', $this->htmlOptions, array());
+ TbHtml::addCssClass($this->fluid ? 'container-fluid' : 'container', $containerOptions);
+ ob_start();
+ echo TbHtml::openTag('div', $containerOptions);
+ echo $containerContent;
+ echo '';
+ $content = ob_get_clean();
+ echo TbHtml::navbar($content, $this->htmlOptions);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbPager.php b/www/protected/extensions/bootstrap/widgets/TbPager.php
new file mode 100644
index 0000000..2145b68
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbPager.php
@@ -0,0 +1,158 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap pager widget.
+ * http://twitter.github.com/bootstrap/components.html#pagination
+ */
+class TbPager extends CBasePager
+{
+ /**
+ * @var string the pager size.
+ */
+ public $size;
+ /**
+ * @var integer maximum number of page buttons that can be displayed.
+ */
+ public $maxButtonCount = 5;
+ /**
+ * @var string the text label for the next page button.
+ */
+ public $nextPageLabel = '›';
+ /**
+ * @var string the text label for the previous page button.
+ */
+ public $prevPageLabel = '‹';
+ /**
+ * @var string the text label for the first page button.
+ */
+ public $firstPageLabel = '«';
+ /**
+ * @var string the text label for the last page button.
+ */
+ public $lastPageLabel = '»';
+
+ /**
+ * @var boolean whether the "first" and "last" buttons should be hidden.
+ * Defaults to false.
+ */
+ public $hideFirstAndLast = false;
+ /**
+ * @var array HTML attributes for the pager container tag.
+ */
+ public $htmlOptions = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ if (isset($this->size)) {
+ TbArray::defaultValue('size', $this->size, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ $links = $this->createPageLinks();
+ if (!empty($links)) {
+ echo TbHtml::pagination($links, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Creates the page buttons.
+ * @return array a list of page buttons (in HTML code).
+ */
+ protected function createPageLinks()
+ {
+ if (($pageCount = $this->getPageCount()) <= 1) {
+ return array();
+ }
+
+ list($beginPage, $endPage) = $this->getPageRange();
+
+ $currentPage = $this->getCurrentPage(false); // currentPage is calculated in getPageRange()
+ $links = array();
+
+ // first page
+ if (!$this->hideFirstAndLast) {
+ $links[] = $this->createPageLink($this->firstPageLabel, 0, $currentPage <= 0, false);
+ }
+
+ // prev page
+ if (($page = $currentPage - 1) < 0) {
+ $page = 0;
+ }
+
+ $links[] = $this->createPageLink($this->prevPageLabel, $page, $currentPage <= 0, false);
+
+ // internal pages
+ for ($i = $beginPage; $i <= $endPage; ++$i) {
+ $links[] = $this->createPageLink($i + 1, $i, false, $i == $currentPage);
+ }
+
+ // next page
+ if (($page = $currentPage + 1) >= $pageCount - 1) {
+ $page = $pageCount - 1;
+ }
+
+ $links[] = $this->createPageLink($this->nextPageLabel, $page, $currentPage >= $pageCount - 1, false);
+
+ // last page
+ if (!$this->hideFirstAndLast) {
+ $links[] = $this->createPageLink(
+ $this->lastPageLabel,
+ $pageCount - 1,
+ $currentPage >= $pageCount - 1,
+ false
+ );
+ }
+
+ return $links;
+ }
+
+ /**
+ * Creates a page link.
+ * @param string $label the link label text.
+ * @param integer $page the page number.
+ * @param boolean $visible whether the link is disabled.
+ * @param boolean $active whether the link is active.
+ * @return string the generated link.
+ */
+ protected function createPageLink($label, $page, $disabled, $active)
+ {
+ return array(
+ 'label' => $label,
+ 'url' => $this->createPageUrl($page),
+ 'disabled' => $disabled,
+ 'active' => $active,
+ );
+ }
+
+ /**
+ * @return array the begin and end pages that need to be displayed.
+ */
+ protected function getPageRange()
+ {
+ $currentPage = $this->getCurrentPage();
+ $pageCount = $this->getPageCount();
+ $beginPage = max(0, $currentPage - (int)($this->maxButtonCount / 2));
+ if (($endPage = $beginPage + $this->maxButtonCount - 1) >= $pageCount) {
+ $endPage = $pageCount - 1;
+ $beginPage = max(0, $endPage - $this->maxButtonCount + 1);
+ }
+ return array($beginPage, $endPage);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbScrollspy.php b/www/protected/extensions/bootstrap/widgets/TbScrollspy.php
new file mode 100644
index 0000000..bef810b
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbScrollspy.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap scrollspy widget.
+ * @see http://twitter.github.com/bootstrap/javascript.html#scrollspy
+ */
+class TbScrollspy extends CWidget
+{
+ /**
+ * @var string the CSS selector for the scrollspy element.
+ */
+ public $selector = 'body';
+ /**
+ * @var string the CSS selector for the spying element.
+ */
+ public $target;
+ /**
+ * @var integer the scroll offset (in pixels).
+ */
+ public $offset;
+ /**
+ * @var string[] $events the JavaScript event configuration (name=>handler).
+ */
+ public $events = array();
+
+ /**
+ * Initializes the widget.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ }
+
+ /**
+ * Runs the widget.
+ */
+ public function run()
+ {
+ // todo: think of a better way of doing this.
+ $script = "jQuery('{$this->selector}').attr('data-spy', 'scroll');";
+ if (isset($this->target)) {
+ $script .= "jQuery('{$this->selector}').attr('data-target', '{$this->target}');";
+ }
+ if (isset($this->offset)) {
+ $script .= "jQuery('{$this->selector}').attr('data-offset', '{$this->offset}');";
+ }
+ Yii::app()->clientScript->registerScript($this->getId(), $script, CClientScript::POS_BEGIN);
+ $this->registerEvents($this->selector, $this->events);
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbTabs.php b/www/protected/extensions/bootstrap/widgets/TbTabs.php
new file mode 100644
index 0000000..4722407
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbTabs.php
@@ -0,0 +1,125 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap tabs widget.
+ */
+class TbTabs extends CWidget
+{
+ /**
+ * @var string the type of tabs to display. Valid values are 'tabs' and 'pills' (defaults to 'tabs').
+ * @see TbHtml::$navStyles
+ */
+ public $type = TbHtml::NAV_TYPE_TABS;
+ /**
+ * @var string the placement of the tabs. Valid values are 'right, 'left' and 'below'.
+ * @see TbHtml::tabPlacements
+ */
+ public $placement;
+ /**
+ * @var array the tab configuration.
+ */
+ public $tabs = array();
+ /**
+ * @var array additional data submitted to the views.
+ */
+ public $viewData;
+ /**
+ * @var string a javascript function that This event fires on tab show, but before the new tab has been shown.
+ * Use `event.target` and `event.relatedTarget` to target the active tab and the previous active tab (if available)
+ * respectively.
+ */
+ public $onShow;
+ /**
+ * @var string a javascript function that fires on tab show after a tab has been shown. Use `event.target` and
+ * `event.relatedTarget` to target the active tab and the previous active tab (if available) respectively.
+ */
+ public $onShown;
+ /**
+ * @var array the HTML attributes for the widget container.
+ */
+ public $htmlOptions = array();
+ /**
+ * @var string[] the Javascript event handlers.
+ */
+ protected $events = array();
+
+ /**
+ * Widget's initialization method
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->copyId();
+ TbArray::defaultValue('placement', $this->placement, $this->htmlOptions);
+ $this->initEvents();
+ }
+
+ /**
+ * Initialize events if any
+ */
+ public function initEvents()
+ {
+ foreach (array('onShow', 'onShown') as $event) {
+ if ($this->$event !== null) {
+ $modalEvent = strtolower(substr($event, 2));
+ if ($this->$event instanceof CJavaScriptExpression) {
+ $this->events[$modalEvent] = $this->$event;
+ } else {
+ $this->events[$modalEvent] = new CJavaScriptExpression($this->$event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Widget's run method
+ */
+ public function run()
+ {
+ $this->tabs = $this->normalizeTabs($this->tabs);
+ echo TbHtml::tabbable($this->type, $this->tabs, $this->htmlOptions);
+ $this->registerClientScript();
+ }
+
+ /**
+ * Normalizes the tab configuration.
+ * @param array $tabs a reference to the tabs tab configuration.
+ */
+ protected function normalizeTabs($tabs)
+ {
+ $controller = $this->getController();
+ if (isset($controller)) {
+ foreach ($tabs as &$tabOptions) {
+ $items = TbArray::getValue('items', $tabOptions, array());
+ if (!empty($items)) {
+ $tabOptions['items'] = $this->normalizeTabs($items);
+ } else {
+ if (isset($tabOptions['view'])) {
+ $view = TbArray::popValue('view', $tabOptions);
+ if ($controller->getViewFile($view) !== false) {
+ $tabOptions['content'] = $controller->renderPartial($view, $this->viewData, true);
+ }
+ }
+ }
+ }
+ }
+ return $tabs;
+ }
+
+ /**
+ * Registers necessary client scripts.
+ */
+ public function registerClientScript()
+ {
+ $selector = '#' . $this->htmlOptions['id'];
+ Yii::app()->clientScript->registerScript(__CLASS__ . $selector, "jQuery('{$selector}').tab('show');");
+ $this->registerEvents($selector, $this->events);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/extensions/bootstrap/widgets/TbThumbnails.php b/www/protected/extensions/bootstrap/widgets/TbThumbnails.php
new file mode 100644
index 0000000..0b35fba
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbThumbnails.php
@@ -0,0 +1,70 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap thumbnails widget.
+ * http://twitter.github.com/bootstrap/components.html#thumbnails
+ */
+class TbThumbnails extends TbListView
+{
+ /**
+ * @var mixed a PHP expression that is evaluated for every item and whose result is used
+ * as the URL for the thumbnail.
+ */
+ public $url;
+ /**
+ * @var integer the number of grid columns that the thumbnails spans over.
+ */
+ public $span;
+
+ /**
+ * Initializes the widget
+ */
+ public function init()
+ {
+ parent::init();
+
+ if (isset($this->itemsCssClass)) {
+ TbHtml::addCssClass($this->itemsCssClass, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Renders the data items for the view.
+ * Each item is corresponding to a single data model instance.
+ */
+ public function renderItems()
+ {
+ $thumbnails = array();
+ $data = $this->dataProvider->getData();
+
+ if (!empty($data)) {
+ $owner = $this->getOwner();
+ $render = $owner instanceof CController ? 'renderPartial' : 'render';
+ foreach ($data as $i => $row) {
+ $thumbnail = array();
+ $d = $this->viewData;
+ $d['index'] = $i;
+ $d['data'] = $row;
+ $d['widget'] = $this;
+ $thumbnail['caption'] = $owner->$render($this->itemView, $d, true);
+ if (isset($this->url)) {
+ $thumbnail['url'] = $this->evaluateExpression($this->url, array('data' => $row));
+ }
+ if (isset($this->span)) {
+ $thumbnail['span'] = $this->span;
+ }
+ $thumbnails[] = $thumbnail;
+ }
+ echo TbHtml::thumbnails($thumbnails, $this->htmlOptions);
+ } else {
+ $this->renderEmptyText();
+ }
+ }
+}
diff --git a/www/protected/extensions/bootstrap/widgets/TbTypeAhead.php b/www/protected/extensions/bootstrap/widgets/TbTypeAhead.php
new file mode 100644
index 0000000..2e3751a
--- /dev/null
+++ b/www/protected/extensions/bootstrap/widgets/TbTypeAhead.php
@@ -0,0 +1,134 @@
+
+ * @copyright Copyright © Christoffer Niska 2013-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @package bootstrap.widgets
+ */
+
+/**
+ * Bootstrap typeahead widget.
+ */
+class TbTypeAhead extends CInputWidget
+{
+ /**
+ * @var mixed the data source to query against. May be an array of strings or a function. The function is passed
+ * two arguments, the query value in the input field and the process callback. The function may be used synchronously
+ * by returning the data source directly or asynchronously via the process callback's single argument.
+ */
+ public $source = array();
+
+ /**
+ * @var int the max number of items to display in the dropdown. Defaults to 8.
+ */
+ public $items = 8;
+
+ /**
+ * @var int the minimum character length needed before triggering autocomplete suggestions
+ */
+ public $minLength = 1;
+
+ /**
+ * @var string javascript function the method used to determine if a query matches an item. Accepts a single argument, the item
+ * against which to test the query. Access the current query with this.query. Return a boolean true if query is a
+ * match. Case insensitive.
+ */
+ public $matcher;
+
+ /**
+ * @var string javascript function method used to sort autocomplete results. Accepts a single argument items and has
+ * the scope of the typeahead instance. Reference the current query with this.query. Exact match, case sensitive,
+ * case insensitive
+ */
+ public $sorter;
+
+ /**
+ * @var string javascript the method used to return selected item. Accepts a single argument, the item and has the
+ * scope of the typeahead instance. Returns selected item.
+ */
+ public $updater;
+
+ /**
+ * @var string javascript method used to highlight autocomplete results. Accepts a single argument item and has the
+ * scope of the typeahead instance. Should return html. Highlights all default matches
+ */
+ public $highlighter;
+
+ /**
+ * @var array the plugin options
+ */
+ protected $pluginOptions = array();
+
+ /**
+ * Widget's initialization method.
+ */
+ public function init()
+ {
+ $this->attachBehavior('TbWidget', new TbWidget);
+ $this->initOptions();
+ }
+
+ /**
+ * Initializes the plugin options
+ */
+ public function initOptions()
+ {
+ $options = array();
+ foreach (array('matcher', 'sorter', 'updater', 'highlighter') as $fn) {
+ if ($this->$fn !== null) {
+ if ($this->$fn instanceof CJavaScriptExpression) {
+ $options[$fn] = $this->$fn;
+ } else {
+ $options[$fn] = new CJavaScriptExpression($this->$fn);
+ }
+ }
+ }
+
+ $this->pluginOptions = TbArray::merge(
+ array(
+ 'source' => $this->source,
+ 'items' => $this->items,
+ 'minLength' => $this->minLength
+ ),
+ $options
+ );
+ }
+
+ /**
+ * Widget's run method.
+ */
+ public function run()
+ {
+ $this->renderField();
+ $this->registerClientScript();
+ }
+
+ /**
+ * Renders field
+ */
+ public function renderField()
+ {
+ list($name, $id) = $this->resolveNameID();
+
+ TbArray::defaultValue('id', $id, $this->htmlOptions);
+ TbArray::defaultValue('name', $name, $this->htmlOptions);
+
+ // by using TbHtml we support all bootstrap options
+ if ($this->hasModel()) {
+ echo TbHtml::activeTextField($this->model, $this->attribute, $this->htmlOptions);
+ } else {
+ echo TbHtml::textField($name, $this->value, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * Register required scripts.
+ */
+ public function registerClientScript()
+ {
+ /** @var TbApi $api */
+ $selector = '#' . TbArray::getValue('id', $this->htmlOptions, $this->getId());
+ $this->registerPlugin(TbApi::PLUGIN_TYPEAHEAD, $selector, $this->pluginOptions);
+ }
+}
\ No newline at end of file
diff --git a/www/protected/views/layouts/column1.php b/www/protected/views/layouts/column1_.php
similarity index 100%
rename from www/protected/views/layouts/column1.php
rename to www/protected/views/layouts/column1_.php
diff --git a/www/protected/views/layouts/column2.php b/www/protected/views/layouts/column2_.php
similarity index 100%
rename from www/protected/views/layouts/column2.php
rename to www/protected/views/layouts/column2_.php
diff --git a/www/protected/views/layouts/main.php b/www/protected/views/layouts/main.php
index daf905e..56edd85 100644
--- a/www/protected/views/layouts/main.php
+++ b/www/protected/views/layouts/main.php
@@ -1,59 +1,101 @@
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ bootstrap->register(); ?>
+
+
+
pageTitle); ?>
-
+
-
+
-
+
+
+
+
+
+
+
+
+
name); ?>
-
- widget('zii.widgets.CMenu',array(
- 'items'=>array(
- array('label'=>'Home', 'url'=>array('/site/index')),
- array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
- array('label'=>'Contact', 'url'=>array('/site/contact')),
- array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
- array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
- ),
- )); ?>
-
- breadcrumbs)):?>
- widget('zii.widgets.CBreadcrumbs', array(
+
+
+
+
+
+
+breadcrumbs))
+ {
+ $this->widget('bootstrap.widgets.TbBreadcrumb', array(
'links'=>$this->breadcrumbs,
- )); ?>
-
+ ));
+ }
+?>
-
+
-
-
-
-
-
+
+
+
+
+
+
-
+
\ No newline at end of file