1
0

Added Yiistrap

This commit is contained in:
Mike Schwörer 2014-05-13 14:06:18 +02:00
parent 5e21ecb401
commit 826c4bdfb3
118 changed files with 31164 additions and 54 deletions

View File

@ -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}.
*/

View File

@ -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}.
*/

View File

@ -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'),
),

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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']);
};

View File

@ -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.

View File

@ -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)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -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;
}

View File

@ -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}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -0,0 +1,248 @@
//
// Dropdown menus
// --------------------------------------------------
// Use the .menu class on any <li> 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);
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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%));
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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%));
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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; }
}

View File

@ -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";

View File

@ -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
}

View File

@ -0,0 +1,197 @@
//
// Sprites
// --------------------------------------------------
// ICONS
// -----
// All icons receive the styles of the <i> 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
// <i class="icon-inbox"></i>.
// For the white version of the icons, just add the .icon-white class:
// <i class="icon-inbox icon-white"></i>
[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; }

View File

@ -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%);
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -0,0 +1,169 @@
<?php
/**
* TbWidget class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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');
}
}
}

View File

@ -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/*

View File

@ -0,0 +1,221 @@
<?php
/**
* TbApi class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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;
}
}
}

View File

@ -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/"
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
<?php
/**
* TbForm class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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)) : '';
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* TbFormButtonElement class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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);
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* TbFormInputElement class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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));
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* BootstrapCode class file.
* @author Christoffer Niska <ChristofferNiska@gmail.com>
* @copyright Copyright &copy; 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))";
}
}
}
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* BootstrapGenerator class file.
* @author Christoffer Niska <ChristofferNiska@gmail.com>
* @copyright Copyright &copy; 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';
}

View File

@ -0,0 +1,48 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
/* @var $form TbActiveForm */
<?php echo "?>\n"; ?>
<div class="form">
<?php echo "<?php \$form=\$this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id'=>'" . $this->class2id($this->modelClass) . "-form',
// Please note: When you enable ajax validation, make sure the corresponding
// controller action is handling ajax validation correctly.
// There is a call to performAjaxValidation() commented in generated controller code.
// See class documentation of CActiveForm for details on this.
'enableAjaxValidation'=>false,
)); ?>\n"; ?>
<p class="help-block">Fields with <span class="required">*</span> are required.</p>
<?php echo "<?php echo \$form->errorSummary(\$model); ?>\n"; ?>
<?php
foreach ($this->tableSchema->columns as $column) {
if ($column->autoIncrement) {
continue;
}
?>
<?php echo "<?php echo " . $this->generateActiveControlGroup($this->modelClass, $column) . "; ?>\n"; ?>
<?php
}
?>
<div class="form-actions">
<?php echo "<?php echo TbHtml::submitButton(\$model->isNewRecord ? 'Create' : 'Save',array(
'color'=>TbHtml::BUTTON_COLOR_PRIMARY,
'size'=>TbHtml::BUTTON_SIZE_LARGE,
)); ?>\n"; ?>
</div>
<?php echo "<?php \$this->endWidget(); ?>\n"; ?>
</div><!-- form -->

View File

@ -0,0 +1,36 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
/* @var $form CActiveForm */
<?php echo "?>\n"; ?>
<div class="wide form">
<?php echo "<?php \$form=\$this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'action'=>Yii::app()->createUrl(\$this->route),
'method'=>'get',
)); ?>\n"; ?>
<?php foreach ($this->tableSchema->columns as $column): ?>
<?php
$field = $this->generateInputField($this->modelClass, $column);
if (strpos($field, 'password') !== false) {
continue;
}
?>
<?php echo "<?php echo " . $this->generateActiveControlGroup($this->modelClass, $column) . "; ?>\n"; ?>
<?php endforeach; ?>
<div class="form-actions">
<?php echo "<?php echo TbHtml::submitButton('Search', array('color' => TbHtml::BUTTON_COLOR_PRIMARY,));?>\n" ?>
</div>
<?php echo "<?php \$this->endWidget(); ?>\n"; ?>
</div><!-- search-form -->

View File

@ -0,0 +1,33 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $data <?php echo $this->getModelClass(); ?> */
<?php echo "?>\n"; ?>
<div class="view">
<?php
echo "\t<b><?php echo CHtml::encode(\$data->getAttributeLabel('{$this->tableSchema->primaryKey}')); ?>:</b>\n";
echo "\t<?php echo CHtml::link(CHtml::encode(\$data->{$this->tableSchema->primaryKey}),array('view','id'=>\$data->{$this->tableSchema->primaryKey})); ?>\n\t<br />\n\n";
$count = 0;
foreach ($this->tableSchema->columns as $column) {
if ($column->isPrimaryKey) {
continue;
}
if (++$count == 7) {
echo "\t<?php /*\n";
}
echo "\t<b><?php echo CHtml::encode(\$data->getAttributeLabel('{$column->name}')); ?>:</b>\n";
echo "\t<?php echo CHtml::encode(\$data->{$column->name}); ?>\n\t<br />\n\n";
}
if ($count >= 7) {
echo "\t*/ ?>\n";
}
?>
</div>

View File

@ -0,0 +1,76 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
<?php
echo "\n";
$label = $this->pluralize($this->class2name($this->modelClass));
echo "\$this->breadcrumbs=array(
'$label'=>array('index'),
'Manage',
);\n";
?>
$this->menu=array(
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
);
Yii::app()->clientScript->registerScript('search', "
$('.search-button').click(function(){
$('.search-form').toggle();
return false;
});
$('.search-form form').submit(function(){
$('#<?php echo $this->class2id($this->modelClass); ?>-grid').yiiGridView('update', {
data: $(this).serialize()
});
return false;
});
");
?>
<h1>Manage <?php echo $this->pluralize($this->class2name($this->modelClass)); ?></h1>
<p>
You may optionally enter a comparison operator (<b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>, <b>
&lt;&gt;</b>
or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.
</p>
<?php echo "<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button btn')); ?>"; ?>
<div class="search-form" style="display:none">
<?php echo "<?php \$this->renderPartial('_search',array(
'model'=>\$model,
)); ?>\n"; ?>
</div><!-- search-form -->
<?php echo "<?php"; ?> $this->widget('bootstrap.widgets.TbGridView',array(
'id'=>'<?php echo $this->class2id($this->modelClass); ?>-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
<?php
$count = 0;
foreach ($this->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',
),
),
)); ?>

View File

@ -0,0 +1,187 @@
<?php
/**
* This is the template for generating a controller class file for CRUD feature.
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
class <?php echo $this->controllerClass; ?> extends <?php echo $this->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 <?php echo $this->modelClass; ?>;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if (isset($_POST['<?php echo $this->modelClass; ?>'])) {
$model->attributes=$_POST['<?php echo $this->modelClass; ?>'];
if ($model->save()) {
$this->redirect(array('view','id'=>$model-><?php echo $this->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['<?php echo $this->modelClass; ?>'])) {
$model->attributes=$_POST['<?php echo $this->modelClass; ?>'];
if ($model->save()) {
$this->redirect(array('view','id'=>$model-><?php echo $this->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('<?php echo $this->modelClass; ?>');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new <?php echo $this->modelClass; ?>('search');
$model->unsetAttributes(); // clear any default values
if (isset($_GET['<?php echo $this->modelClass; ?>'])) {
$model->attributes=$_GET['<?php echo $this->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 <?php echo $this->modelClass; ?> the loaded model
* @throws CHttpException
*/
public function loadModel($id)
{
$model=<?php echo $this->modelClass; ?>::model()->findByPk($id);
if ($model===null) {
throw new CHttpException(404,'The requested page does not exist.');
}
return $model;
}
/**
* Performs the AJAX validation.
* @param <?php echo $this->modelClass; ?> $model the model to be validated
*/
protected function performAjaxValidation($model)
{
if (isset($_POST['ajax']) && $_POST['ajax']==='<?php echo $this->class2id($this->modelClass); ?>-form') {
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
<?php echo "?>\n"; ?>
<?php
echo "<?php\n";
$label = $this->pluralize($this->class2name($this->modelClass));
echo "\$this->breadcrumbs=array(
'$label'=>array('index'),
'Create',
);\n";
?>
$this->menu=array(
array('label'=>'List <?php echo $this->modelClass; ?>', 'url'=>array('index')),
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
);
?>
<h1>Create <?php echo $this->modelClass; ?></h1>
<?php echo "<?php \$this->renderPartial('_form', array('model'=>\$model)); ?>"; ?>

View File

@ -0,0 +1,31 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $dataProvider CActiveDataProvider */
<?php echo "?>\n"; ?>
<?php
echo "<?php\n";
$label = $this->pluralize($this->class2name($this->modelClass));
echo "\$this->breadcrumbs=array(
'$label',
);\n";
?>
$this->menu=array(
array('label'=>'Create <?php echo $this->modelClass; ?>','url'=>array('create')),
array('label'=>'Manage <?php echo $this->modelClass; ?>','url'=>array('admin')),
);
?>
<h1><?php echo $label; ?></h1>
<?php echo "<?php"; ?> $this->widget('bootstrap.widgets.TbListView',array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
)); ?>

View File

@ -0,0 +1,33 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
<?php echo "?>\n"; ?>
<?php
echo "<?php\n";
$nameColumn = $this->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 <?php echo $this->modelClass; ?>', 'url'=>array('index')),
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
array('label'=>'View <?php echo $this->modelClass; ?>', 'url'=>array('view', 'id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>)),
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
);
?>
<h1>Update <?php echo $this->modelClass . " <?php echo \$model->{$this->tableSchema->primaryKey}; ?>"; ?></h1>
<?php echo "<?php \$this->renderPartial('_form', array('model'=>\$model)); ?>"; ?>

View File

@ -0,0 +1,45 @@
<?php
/**
* The following variables are available in this template:
* - $this: the BootstrapCode object
*/
?>
<?php echo "<?php\n"; ?>
/* @var $this <?php echo $this->getControllerClass(); ?> */
/* @var $model <?php echo $this->getModelClass(); ?> */
<?php echo "?>\n"; ?>
<?php
echo "<?php\n";
$nameColumn = $this->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 <?php echo $this->modelClass; ?>', 'url'=>array('index')),
array('label'=>'Create <?php echo $this->modelClass; ?>', 'url'=>array('create')),
array('label'=>'Update <?php echo $this->modelClass; ?>', 'url'=>array('update', 'id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>)),
array('label'=>'Delete <?php echo $this->modelClass; ?>', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model-><?php echo $this->tableSchema->primaryKey; ?>),'confirm'=>'Are you sure you want to delete this item?')),
array('label'=>'Manage <?php echo $this->modelClass; ?>', 'url'=>array('admin')),
);
?>
<h1>View <?php echo $this->modelClass . " #<?php echo \$model->{$this->tableSchema->primaryKey}; ?>"; ?></h1>
<?php echo "<?php"; ?> $this->widget('zii.widgets.CDetailView',array(
'htmlOptions' => array(
'class' => 'table table-striped table-condensed table-hover',
),
'data'=>$model,
'attributes'=>array(
<?php
foreach ($this->tableSchema->columns as $column) {
echo "\t\t'" . $column->name . "',\n";
}
?>
),
)); ?>

View File

@ -0,0 +1,67 @@
<?php
$class = get_class($model);
Yii::app()->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);
}
});
"
);
?>
<h1>Bootstrap Generator</h1>
<p>This generator generates a controller and views that implement CRUD operations for the specified data model.</p>
<?php $form = $this->beginWidget('CCodeForm', array('model' => $model)); ?>
<div class="row">
<?php echo $form->labelEx($model, 'model'); ?>
<?php echo $form->textField($model, 'model', array('size' => 65)); ?>
<div class="tooltip">
Model class is case-sensitive. It can be either a class name (e.g. <code>Post</code>)
or the path alias of the class file (e.g. <code>application.models.Post</code>).
Note that if the former, the class must be auto-loadable.
</div>
<?php echo $form->error($model, 'model'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model, 'controller'); ?>
<?php echo $form->textField($model, 'controller', array('size' => 65)); ?>
<div class="tooltip">
Controller ID is case-sensitive. CRUD controllers are often named after
the model class name that they are dealing with. Below are some examples:
<ul>
<li><code>post</code> generates <code>PostController.php</code></li>
<li><code>postTag</code> generates <code>PostTagController.php</code></li>
<li><code>admin/user</code> generates <code>admin/UserController.php</code>.
If the application has an <code>admin</code> module enabled,
it will generate <code>UserController</code> (and other CRUD code)
within the module instead.
</li>
</ul>
</div>
<?php echo $form->error($model, 'controller'); ?>
</div>
<div class="row sticky">
<?php echo $form->labelEx($model, 'baseControllerClass'); ?>
<?php echo $form->textField($model, 'baseControllerClass', array('size' => 65)); ?>
<div class="tooltip">
This is the class that the new CRUD controller class will extend from.
Please make sure the class exists and can be autoloaded.
</div>
<?php echo $form->error($model, 'baseControllerClass'); ?>
</div>
<?php $this->endWidget(); ?>

View File

@ -0,0 +1,151 @@
<?php
/**
* TbArray class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
{
"name": "yiistrap",
"version": "1.0.0",
"author": "Christoffer Niska <christoffer.niska@gmail.com>",
"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"
}
}

View File

@ -0,0 +1,14 @@
<?php
// This is global bootstrap for autoloading
// disable Yii error handling logic
defined('YII_ENABLE_EXCEPTION_HANDLER') or define('YII_ENABLE_EXCEPTION_HANDLER', false);
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', false);
defined('YII_DEBUG') or define('YII_DEBUG', true);
$_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;
require(__DIR__ . '/../vendor/yiisoft/yii/framework/yii.php');
require(__DIR__ . '/unit/TbTestCase.php');
Yii::$enableIncludePath = false;

View File

@ -0,0 +1 @@
/* Replace this file with actual dump of your database */

View File

@ -0,0 +1,217 @@
<?php
namespace Codeception\Module;
class CodeHelper extends \Codeception\Module
{
/**
* @param \Symfony\Component\DomCrawler\Crawler $node
* @param string $text
*/
public function seeNodeText($node, $text)
{
$this->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;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module
{
}

View File

@ -0,0 +1,8 @@
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
}

View File

@ -0,0 +1,8 @@
# Codeception Test Suite Configuration
# suite for unit (internal) tests.
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy
modules:
enabled: [CodeHelper]

View File

@ -0,0 +1,595 @@
<?php
// This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build
// @codingStandardsIgnoreFile
use \Codeception\Maybe;
use Codeception\Module\CodeHelper;
/**
* Inherited methods
* @method void execute($callable)
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void offsetGet($offset)
* @method void offsetSet($offset, $value)
* @method void offsetExists($offset)
* @method void offsetUnset($offset)
*/
class CodeGuy extends \Codeception\AbstractGuy
{
/**
* This method is generated.
* Documentation taken from corresponding module.
* ----------------------------------------------
*
* @param \Symfony\Component\DomCrawler\Crawler $node
* @param string $text
* Conditional Assertion: Test won't be stopped on fail
* @see Codeception\Module\CodeHelper::seeNodeText()
* @return \Codeception\Maybe
*/
public function canSeeNodeText($node, $text) {
$this->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();
}
}

View File

@ -0,0 +1,93 @@
<?php
use Codeception\Util\Stub;
require(__DIR__ . '/../../helpers/TbArray.php');
class TbArrayTest extends TbTestCase
{
/**
* @var \CodeGuy
*/
protected $codeGuy;
public function testGetValue()
{
$array = array('key' => '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));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
<?php
require(__DIR__ . '/../../vendor/yiisoft/yii/tests/TestApplication.php');
require(__DIR__ . '/../../vendor/yiisoft/yii/framework/collections/CMap.php');
class TbTestCase extends \Codeception\TestCase\Test
{
/**
*
*/
protected function _after()
{
$this->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');
}
}

View File

@ -0,0 +1,2 @@
<?php
// Here you can initialize variables that will for your tests

View File

@ -0,0 +1,733 @@
<?php
/**
* TbActiveForm class file.
* @author Antonio Ramirez <ramirez.cobos@gmail.com>
* @copyright Copyright &copy; 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 = '<p>' . Yii::t('yii', 'Please fix the following input errors:') . '</p>';
}
TbHtml::addCssClass(TbHtml::$errorSummaryCss, $htmlOptions);
TbHtml::addCssStyle('display:none', $htmlOptions);
$html = CHtml::tag('div', $htmlOptions, $header . '<ul><li>dummy</li></ul>' . $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;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* TbAffix class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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);
}
}

View File

@ -0,0 +1,95 @@
<?php
/**
* TbAlert class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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 '</div>';
$this->registerEvents("#{$this->htmlOptions['id']} > .alert", $this->events);
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* TbBreadcrumbs class file.
* @author Christoffer Niska <christoffer.niska@gmail.com>
* @copyright Copyright &copy; 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);
}
}
}

Some files were not shown because too many files have changed in this diff Show More