├── .gitignore ├── start.php ├── public ├── img │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png └── css │ └── bootstrap-responsive.min.css ├── .travis.yml ├── config └── bootstrapper.php ├── tests ├── start.php ├── ButtonToolbar.test.php ├── Typeahead.test.php ├── Config.test.php ├── Image.test.php ├── Breadcrumb.test.php ├── Badge.test.php ├── Label.test.php ├── ButtonGroup.test.php ├── Icon.test.php ├── Typography.test.php ├── Alert.test.php ├── Thumbnail.test.php ├── Carousel.test.php ├── Progress.test.php ├── MediaObject.test.php ├── DropdownButton.test.php ├── Navbar.test.php ├── Tabbable.test.php ├── Button.test.php ├── Table.test.php └── Navigation.test.php ├── composer.json ├── src ├── Bootstrapper │ ├── ButtonToolbar.php │ ├── Typeahead.php │ ├── Config.php │ ├── Image.php │ ├── Thumbnail.php │ ├── Breadcrumb.php │ ├── ButtonGroup.php │ ├── Helpers.php │ ├── Icon.php │ ├── Badge.php │ ├── Label.php │ ├── Typography.php │ ├── Paginator.php │ ├── Navbar.php │ ├── Progress.php │ ├── DropdownButton.php │ ├── MediaObject.php │ ├── Alert.php │ ├── Carousel.php │ ├── Button.php │ ├── Tabbable.php │ ├── Navigation.php │ └── Table.php └── start.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vendor 3 | composer.lock -------------------------------------------------------------------------------- /start.php: -------------------------------------------------------------------------------- 1 | array('auto' => true));" > ./laravel/application/bundles.php 12 | - cd ./laravel 13 | 14 | script: "php artisan test bootstrapper" -------------------------------------------------------------------------------- /config/bootstrapper.php: -------------------------------------------------------------------------------- 1 | 'icon-', 5 | 6 | // Options relatives to the Table class 7 | 'table' => array( 8 | 9 | // An array of columns to never display 10 | 'ignore' => array(), 11 | 12 | // An array of classes to use for all tables 13 | // Example : ['bordered', 'striped', 'hover'] 14 | 'classes' => array(), 15 | ), 16 | 17 | ); -------------------------------------------------------------------------------- /tests/start.php: -------------------------------------------------------------------------------- 1 | 'foo', 8 | 'data-foo' => 'bar', 9 | ); 10 | 11 | /** 12 | * Uniformize test environment 13 | */ 14 | public static function setUpBeforeClass() 15 | { 16 | URL::$base = 'http://test/'; 17 | Config::set('application.languages', array()); 18 | Config::set('application.index', ''); 19 | Config::set('application.asset_url', ''); 20 | Config::set('application.ssl', true); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patricktalmadge/bootstrapper", 3 | "description": "Twitter Bootstrap markup generator", 4 | "license": "MIT", 5 | "keywords": [ 6 | "bootstrap", 7 | "laravel" 8 | ], 9 | "authors": [ 10 | { 11 | "name": "Patrick Talmadge", 12 | "email": "ptalmadge@gmail.com" 13 | }, 14 | { 15 | "name": "Maxime Fabre", 16 | "email": "ehtnam6@gmail.com" 17 | } 18 | ], 19 | "require": { 20 | "illuminate/container": "dev-master", 21 | "meido/html": "1.1.x" 22 | }, 23 | "autoload": { 24 | "psr-0": { 25 | "Bootstrapper": "src" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/ButtonToolbar.test.php: -------------------------------------------------------------------------------- 1 | testAttributes); 9 | $matcher = array( 10 | 'tag' => 'div', 11 | 'attributes' => array( 12 | 'class' => 'foo btn-toolbar', 13 | 'data-foo' => 'bar', 14 | ), 15 | ); 16 | 17 | $this->assertTag($matcher, $open); 18 | } 19 | 20 | public function testClose() 21 | { 22 | $close = ButtonToolbar::close(); 23 | 24 | $this->assertEquals('', $close); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Typeahead.test.php: -------------------------------------------------------------------------------- 1 | items, 8, $this->testAttributes); 15 | $matcher = array( 16 | 'tag' => 'input', 17 | 'attributes' => array( 18 | 'class' => 'foo', 19 | 'data-foo' => 'bar', 20 | 'data-items' => 8, 21 | 'data-provide' => 'typeahead', 22 | 'data-source' => '["Lorem","Ipsum","Dolor"]', 23 | 'type' => 'text', 24 | ), 25 | ); 26 | 27 | $this->assertTag($matcher, $typeahead); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Config.test.php: -------------------------------------------------------------------------------- 1 | assertEquals('bar', $config); 20 | } 21 | 22 | public function testCanGetValuesFromUserConfig() 23 | { 24 | LaravelConfig::set('bootstrapper.foo', 'bar'); 25 | $config = Config::get('foo'); 26 | 27 | $this->assertEquals('bar', $config); 28 | } 29 | 30 | public function testCanProvideAFallback() 31 | { 32 | LaravelConfig::set('bootstrapper.foo', 'bar'); 33 | $config = Config::get('ter', 'fallback'); 34 | 35 | $this->assertEquals('fallback', $config); 36 | } 37 | 38 | public function testUserCanSetEmptyConfigKeys() 39 | { 40 | LaravelConfig::set('bootstrapper.foo', ''); 41 | $config = Config::get('foo'); 42 | 43 | $this->assertEquals('', $config); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Image.test.php: -------------------------------------------------------------------------------- 1 | 'img', 18 | 'attributes' => array( 19 | 'alt' => 'foo', 20 | 'class' => 'foo img-'.$class, 21 | 'data-foo' => 'bar', 22 | 'src' => $this->url, 23 | ), 24 | ); 25 | } 26 | 27 | // Data providers ------------------------------------------------ / 28 | 29 | public function classes() 30 | { 31 | return array( 32 | array('circle'), 33 | array('polaroid'), 34 | array('rounded'), 35 | ); 36 | } 37 | 38 | // Tests --------------------------------------------------------- / 39 | 40 | /** 41 | * @dataProvider classes 42 | */ 43 | public function testImage($class) 44 | { 45 | $image = Image::$class($this->url, 'foo', $this->testAttributes); 46 | 47 | $this->assertTag($this->createMatcher($class), $image); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Bootstrapper/ButtonToolbar.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class ButtonToolbar 20 | { 21 | /** 22 | * Opens a new ButtonToolbar section. 23 | * 24 | * @param array $attributes Attributes for the button toolbar 25 | * 26 | * @return string A button toolbar 27 | */ 28 | public static function open($attributes = array()) 29 | { 30 | $attributes = Helpers::add_class($attributes, 'btn-toolbar'); 31 | 32 | return ''; 33 | } 34 | 35 | /** 36 | * Closes the ButtonToolbar section. 37 | * 38 | * @return string 39 | */ 40 | public static function close() 41 | { 42 | return ''; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/Breadcrumb.test.php: -------------------------------------------------------------------------------- 1 | 'bar', 8 | 'kal' => 'tom', 9 | 'sat' => 'ven', 10 | ); 11 | 12 | private $matcher = array( 13 | 'tag' => 'ul', 14 | 'children' => array( 15 | 'count' => 3, 16 | 'only' => array( 17 | 'tag' => 'li', 18 | 'descendant' => array( 19 | 'tag' => 'span', 20 | 'attributes' => array('class' => 'divider'), 21 | 'content' => '/', 22 | ), 23 | ), 24 | ), 25 | 'attributes' => array( 26 | 'class' => 'foo breadcrumb', 27 | 'data-foo' => 'bar', 28 | ), 29 | ); 30 | 31 | public function testCreate() 32 | { 33 | $breadcrumb = Breadcrumb::create($this->crumbs, $this->testAttributes); 34 | 35 | $this->assertTag($this->matcher, $breadcrumb); 36 | } 37 | 38 | public function testChangeSeparator() 39 | { 40 | Breadcrumb::$separator = '__'; 41 | $breadcrumb = Breadcrumb::create($this->crumbs, $this->testAttributes); 42 | 43 | $matcher = $this->matcher; 44 | $matcher['children']['only']['descendant']['content'] = '__'; 45 | 46 | $this->assertTag($matcher, $breadcrumb); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Bootstrapper/Typeahead.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Typeahead 20 | { 21 | /** 22 | * Creates a new Typeahead instance. 23 | * 24 | * @param array $source Array of items for list 25 | * @param int $items Number of items to display 26 | * @param array $attributes An array of attributes to use 27 | * 28 | * @return Typeahead 29 | */ 30 | public static function create($source, $items = 8, $attributes = array()) 31 | { 32 | $attributes['type'] = 'text'; 33 | $attributes['data-items'] = $items; 34 | $attributes['data-provide'] = 'typeahead'; 35 | $attributes['data-source'] = json_encode($source); 36 | 37 | return ''; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/start.php: -------------------------------------------------------------------------------- 1 | 10 | * @license MIT License 11 | * @link http://laravelbootstrapper.phpfogapp.com/ 12 | * 13 | * @see http://twitter.github.com/bootstrap/ 14 | */ 15 | 16 | // Autoload Boostrapper 17 | Autoloader::namespaces( 18 | array('Bootstrapper' => Bundle::path('bootstrapper') . 'src' .DS. 'Bootstrapper') 19 | ); 20 | 21 | // Define main assets 22 | Asset::container('bootstrapper') 23 | ->bundle('bootstrapper') 24 | ->add('bootstrap', 'css/bootstrap.min.css') 25 | ->add('bootstrap-responsive', 'css/bootstrap-responsive.min.css') 26 | ->add('jquery', 'js/jquery-1.9.1.min.js') 27 | ->add('bootstrap-js', 'js/bootstrap.min.js', 'jquery'); 28 | 29 | // Define unminified version of the assets 30 | Asset::container('bootstrapper-unminified') 31 | ->bundle('bootstrapper') 32 | ->add('bootstrap', 'css/bootstrap.css') 33 | ->add('bootstrap-responsive', 'css/bootstrap-responsive.css') 34 | ->add('jquery', 'js/jquery-1.9.1.js') 35 | ->add('bootstrap-js', 'js/bootstrap.js', 'jquery'); -------------------------------------------------------------------------------- /tests/Badge.test.php: -------------------------------------------------------------------------------- 1 | 'span', 14 | 'attributes' => array('class' => 'bar badge'.$class), 15 | 'content' => 'foo', 16 | ); 17 | } 18 | 19 | // Data providers ----------------------------------------------- / 20 | 21 | public function classes() 22 | { 23 | return array( 24 | array('normal'), 25 | array('important'), 26 | array('info'), 27 | array('inverse'), 28 | array('success'), 29 | array('warning'), 30 | ); 31 | } 32 | 33 | // Tests --------------------------------------------------------- / 34 | 35 | public function testCustom() 36 | { 37 | $badge = Badge::custom('success', 'foo', array('class' => 'bar')); 38 | $match = $this->createMatcher('success'); 39 | 40 | $this->assertTag($match, $badge); 41 | } 42 | 43 | /** 44 | * @dataProvider classes 45 | */ 46 | public function testStatic($class) 47 | { 48 | $badge = Badge::$class('foo', array('class' => 'bar')); 49 | $match = $this->createMatcher($class); 50 | 51 | $this->assertTag($match, $badge); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/Label.test.php: -------------------------------------------------------------------------------- 1 | 'span', 14 | 'attributes' => array('class' => 'foo label'.$class), 15 | 'content' => 'foo', 16 | ); 17 | } 18 | 19 | // Data providers ------------------------------------------------ / 20 | 21 | public function classes() 22 | { 23 | return array( 24 | array('normal'), 25 | array('important'), 26 | array('info'), 27 | array('inverse'), 28 | array('success'), 29 | array('warning'), 30 | ); 31 | } 32 | 33 | // Tests --------------------------------------------------------- / 34 | 35 | public function testCustom() 36 | { 37 | $label = Label::custom('success', 'foo', $this->testAttributes); 38 | $match = $this->createMatcher('success'); 39 | 40 | $this->assertTag($match, $label); 41 | } 42 | 43 | /** 44 | * @dataProvider classes 45 | */ 46 | public function testStatic($class) 47 | { 48 | $label = Label::$class('foo', $this->testAttributes); 49 | $match = $this->createMatcher($class); 50 | 51 | $this->assertTag($match, $label); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Bootstrapper/Config.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Config 20 | { 21 | /** 22 | * Get the value of an option 23 | * 24 | * @param string $key The option to get 25 | * @param string $fallback A fallback if undefined 26 | * @return string The option value 27 | */ 28 | public static function get($key, $fallback = null) 29 | { 30 | $user = LaravelConfig::get('bootstrapper.'.$key, null); 31 | $vendor = LaravelConfig::get('bootstrapper::bootstrapper.'.$key, $fallback); 32 | 33 | return is_null($user) ? $vendor : $user; 34 | } 35 | 36 | /** 37 | * Set an option 38 | * 39 | * @param string $key The option to set 40 | * @param string $value Its new value 41 | */ 42 | public static function set($key, $value) 43 | { 44 | LaravelConfig::set('bootstrapper::bootstrapper.'.$key, $value); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/ButtonGroup.test.php: -------------------------------------------------------------------------------- 1 | 'div', 8 | 'attributes' => array( 9 | 'data-foo' => 'bar', 10 | 'class' => 'foo btn-group', 11 | ), 12 | ); 13 | 14 | public function testOpen() 15 | { 16 | $open = ButtonGroup::open(false, $this->testAttributes); 17 | 18 | $this->assertTag($this->buttonGroup, $open); 19 | } 20 | 21 | public function testClose() 22 | { 23 | $this->assertEquals('', ButtonGroup::close()); 24 | } 25 | 26 | public function OpenToggle() 27 | { 28 | $open = ButtonGroup::open(true, $this->testAttributes); 29 | $matcher = $this->buttonGroup; 30 | $matcher['attributes']['data-toggle'] = 'buttons-1'; 31 | 32 | $this->assertTag($matcher, $open); 33 | } 34 | 35 | public function testHorizontalOpenCheckbox() 36 | { 37 | $open = ButtonGroup::horizontal_open('checkbox', $this->testAttributes); 38 | 39 | $equals = ButtonGroup::open('checkbox', $this->testAttributes); 40 | $matcher = $this->buttonGroup; 41 | $matcher['attributes']['data-toggle'] = 'buttons-checkbox'; 42 | 43 | $this->assertTag($matcher, $open); 44 | $this->assertEquals($equals, $open); 45 | } 46 | 47 | public function testVerticalOpenRadio() 48 | { 49 | $open = ButtonGroup::vertical_open('radio', $this->testAttributes); 50 | 51 | $matcher = $this->buttonGroup; 52 | $matcher['attributes']['class'] = 'btn-group-vertical '.$matcher['attributes']['class']; 53 | $matcher['attributes']['data-toggle'] = 'buttons-radio'; 54 | 55 | $this->assertTag($matcher, $open); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Icon.test.php: -------------------------------------------------------------------------------- 1 | 'i', 18 | 'attributes' => array( 19 | 'class' => 'icon-folder-open', 20 | )); 21 | 22 | /** 23 | * Matcher for the icon with attributes 24 | * @var array 25 | */ 26 | private $baseIconWithAttributes = array( 27 | 'tag' => 'i', 28 | 'attributes' => array( 29 | 'class' => 'foo icon-folder-open', 30 | 'data-foo' => 'bar', 31 | )); 32 | 33 | // Tests --------------------------------------------------------- / 34 | 35 | public function testMake() 36 | { 37 | $icon = Icon::make($this->testIcon); 38 | 39 | $this->assertTag($this->baseIcon, $icon); 40 | } 41 | 42 | public function testMakeWithAttributes() 43 | { 44 | $icon = Icon::make($this->testIcon, $this->testAttributes); 45 | 46 | $this->assertTag($this->baseIconWithAttributes, $icon); 47 | } 48 | 49 | public function testStatic() 50 | { 51 | $icon = Icon::folder_open(); 52 | 53 | $this->assertTag($this->baseIcon, $icon); 54 | } 55 | 56 | public function testStaticWithAttributes() 57 | { 58 | $icon = Icon::folder_open($this->testAttributes); 59 | 60 | $this->assertTag($this->baseIconWithAttributes, $icon); 61 | } 62 | 63 | public function testStaticWhiteWithAttributes() 64 | { 65 | $icon = Icon::white_folder_open($this->testAttributes); 66 | 67 | $matcher = $this->baseIcon; 68 | $matcher['attributes']['class'] .= ' icon-white'; 69 | $matcher['attributes']['data-foo'] = 'bar'; 70 | 71 | $this->assertTag($matcher, $icon); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Bootstrapper/Image.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Image 20 | { 21 | /** 22 | * Creates an image with rounded corners 23 | * 24 | * @param string $url An url 25 | * @param string $alt An alt text 26 | * @param array $attributes An array of attributes 27 | * 28 | * @return string An img tag 29 | */ 30 | public static function rounded($url, $alt = '', $attributes = array()) 31 | { 32 | $attributes = Helpers::add_class($attributes, 'img-'.__FUNCTION__); 33 | 34 | return HTML::image($url, $alt, $attributes); 35 | } 36 | 37 | /** 38 | * Creates an image masked with a circle 39 | * 40 | * @param string $url An url 41 | * @param string $alt An alt text 42 | * @param array $attributes An array of attributes 43 | * 44 | * @return string An img tag 45 | */ 46 | public static function circle($url, $alt = '', $attributes = array()) 47 | { 48 | $attributes = Helpers::add_class($attributes, 'img-'.__FUNCTION__); 49 | 50 | return HTML::image($url, $alt, $attributes); 51 | } 52 | 53 | /** 54 | * Creates an image with polaroid borders 55 | * 56 | * @param string $url An url 57 | * @param string $alt An alt text 58 | * @param array $attributes An array of attributes 59 | * 60 | * @return string An img tag 61 | */ 62 | public static function polaroid($url, $alt = '', $attributes = array()) 63 | { 64 | $attributes = Helpers::add_class($attributes, 'img-'.__FUNCTION__); 65 | 66 | return HTML::image($url, $alt, $attributes); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Bootstrapper/Thumbnail.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Thumbnail 20 | { 21 | public static function create($images = null, $closure = null) 22 | { 23 | $thumbnails = '
    '; 24 | 25 | // Generate the thumbnails 26 | foreach ($images as $image) { 27 | 28 | // If we provide a closure 29 | if (is_callable($closure)) { 30 | $thumbnails .= $closure($image); 31 | continue; 32 | } 33 | 34 | // If we provided a rich thumbnail 35 | if (is_array($image)) { 36 | $link = array_get($image, 'link'); 37 | $label = array_get($image, 'label'); 38 | $caption = array_get($image, 'caption'); 39 | $image = array_get($image, 'image'); 40 | 41 | $thumbnails .= '
  • '; 42 | 43 | // Linked thumbnail 44 | if (!$caption and !$label and $link) { 45 | $image = HTML::image($image); 46 | $thumbnails .= HTML::decode( HTML::link($link, $image, array('class' => 'thumbnail')) ); 47 | 48 | // Plain thumbnail 49 | } else { 50 | $thumbnails .= '
    '; 51 | $thumbnails .= HTML::image($image); 52 | if($label) $thumbnails .= '

    ' .$label. '

    '; 53 | if($caption) $thumbnails .= '

    ' .$caption. '

    '; 54 | $thumbnails .= '
    '; 55 | } 56 | $thumbnails .= '
  • '; 57 | continue; 58 | } 59 | 60 | // Else just assume we were given an image path 61 | if(!str_contains($image, ''; 63 | } 64 | 65 | $thumbnails .= '
'; 66 | 67 | return $thumbnails; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/Typography.test.php: -------------------------------------------------------------------------------- 1 | 'p', 12 | 'attributes' => array('class' => $class), 13 | 'content' => 'foo', 14 | ); 15 | } 16 | 17 | private function createMatcher2($class) 18 | { 19 | return array( 20 | 'tag' => 'div', 21 | 'attributes' => array('class' => 'foo '.$class), 22 | 'content' => 'foo', 23 | ); 24 | } 25 | 26 | // Data providers ------------------------------------------------ / 27 | 28 | public function classes() 29 | { 30 | return array( 31 | array('muted', 'muted'), 32 | array('lead', 'lead'), 33 | array('warning', 'text-warning'), 34 | array('error', 'text-error'), 35 | array('info', 'text-info'), 36 | array('success', 'text-success'), 37 | ); 38 | } 39 | 40 | // Tests --------------------------------------------------------- / 41 | 42 | /** 43 | * @dataProvider classes 44 | */ 45 | public function testEmphasis($method, $class) 46 | { 47 | $typography = Typography::$method('foo'); 48 | $match = $this->createMatcher($class); 49 | 50 | $this->assertTag($match, $typography); 51 | } 52 | 53 | /** 54 | * @dataProvider classes 55 | */ 56 | public function testEmphasisTag($method, $class) 57 | { 58 | $typography = Typography::$method('foo', 'div', $this->testAttributes); 59 | $match = $this->createMatcher2($class); 60 | 61 | $this->assertTag($match, $typography); 62 | } 63 | 64 | private $list = array( 65 | 'foo' => 'bar', 66 | 'far' => 'bur' 67 | ); 68 | 69 | private $listMatcher = array( 70 | 'tag' => 'dl', 71 | 'children' => array('count' => 4), 72 | 'attributes' => array( 73 | 'class' => 'foo', 74 | 'data-foo' => 'bar', 75 | ), 76 | ); 77 | 78 | public function testDl() 79 | { 80 | $dl = Typography::dl($this->list, $this->testAttributes); 81 | $matcher = $this->listMatcher; 82 | 83 | $this->assertTag($matcher, $dl); 84 | } 85 | 86 | public function testHorizontalDl() 87 | { 88 | $dl = Typography::horizontal_dl($this->list, $this->testAttributes); 89 | $matcher = $this->listMatcher; 90 | $matcher['attributes']['class'] = 'foo dl-horizontal'; 91 | 92 | $this->assertTag($matcher, $dl); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrapper V4 2 | 3 | Travis status : [![Build Status](https://secure.travis-ci.org/patricktalmadge/bootstrapper.png?branch=master)](https://travis-ci.org/patricktalmadge/bootstrapper) 4 | 5 | Bootstrapper is a set of classes that allow you to quickly create Twitter Bootstrap style markup. 6 | 7 | ## Installation 8 | 9 | Install using Artisan CLI: 10 | 11 | ```shell 12 | php artisan bundle:install bootstrapper 13 | ``` 14 | 15 | Add the following line to application/bundles.php 16 | 17 | ```php 18 | 'bootstrapper' => array('auto' => true), 19 | ``` 20 | 21 | Add the following to the application.php config file: 22 | 23 | ```php 24 | 'Alert' => 'Bootstrapper\\Alert', 25 | 'Badge' => 'Bootstrapper\\Badge', 26 | 'Breadcrumb' => 'Bootstrapper\\Breadcrumb', 27 | 'Button' => 'Bootstrapper\\Button', 28 | 'ButtonGroup' => 'Bootstrapper\\ButtonGroup', 29 | 'ButtonToolbar' => 'Bootstrapper\\ButtonToolbar', 30 | 'Carousel' => 'Bootstrapper\\Carousel', 31 | 'DropdownButton' => 'Bootstrapper\\DropdownButton', 32 | 'Form' => 'Bootstrapper\\Form', 33 | 'Helpers' => 'Bootstrapper\\Helpers', 34 | 'Icon' => 'Bootstrapper\\Icon', 35 | 'Image' => 'Bootstrapper\\Image', 36 | 'Label' => 'Bootstrapper\\Label', 37 | 'MediaObject' => 'Bootstrapper\\MediaObject', 38 | 'Navbar' => 'Bootstrapper\\Navbar', 39 | 'Navigation' => 'Bootstrapper\\Navigation', 40 | 'Paginator' => 'Bootstrapper\\Paginator', 41 | 'Progress' => 'Bootstrapper\\Progress', 42 | 'Tabbable' => 'Bootstrapper\\Tabbable', 43 | 'Table' => 'Bootstrapper\\Table', 44 | 'Thumbnail' => 'Bootstrapper\\Thumbnail', 45 | 'Typeahead' => 'Bootstrapper\\Typeahead', 46 | 'Typography' => 'Bootstrapper\\Typography', 47 | ``` 48 | 49 | Update `laravel\database\query.php` to use the Bootstrapper Paginator and not the core class by changing the use statement. 50 | 51 | ```php 52 | // Change 53 | use Laravel\Paginator; 54 | 55 | // To 56 | use Paginator; 57 | ``` 58 | 59 | Publish the bundle assets to your public folder. 60 | 61 | ```shell 62 | php artisan bundle:publish 63 | ``` 64 | 65 | Add the following to your template view file to include the Twitter Bootstrap CSS and Javascript. 66 | 67 | ```php 68 | Asset::container('bootstrapper')->styles(); 69 | Asset::container('bootstrapper')->scripts(); 70 | ``` 71 | 72 | ## View bundle site for full install instructions. 73 | 74 | http://bootstrapper.aws.af.cm/ 75 | 76 | ## Current Twitter Bootstrap version is 2.2.2 77 | 78 | - Homepage: http://twitter.github.com/bootstrap/ 79 | - GitHub: https://github.com/twitter/bootstrap/ 80 | -------------------------------------------------------------------------------- /src/Bootstrapper/Breadcrumb.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Breadcrumb 20 | { 21 | /** 22 | * The values that represnts the Breadcrumb separator. 23 | * 24 | * @var array 25 | */ 26 | public static $separator = '/'; 27 | 28 | /** 29 | * Creates the a new Breadcrumb. 30 | * 31 | * @param array $links An array of breadcrumbs links 32 | * @param array $attributes Attributes to apply the breadcrumbs wrapper 33 | * 34 | * @return string A breadcrumbs-styled unordered list 35 | */ 36 | public static function create($links, $attributes = array()) 37 | { 38 | // If no links given, cancel 39 | if (empty($links)) return false; 40 | 41 | // Render each link 42 | $l = array(); 43 | foreach ($links as $label => $url) { 44 | $l[] = (is_string($label) or is_array($url)) 45 | ? static::renderItem(HTML::link($url, $label)) 46 | : static::renderItem($url, true); 47 | } 48 | 49 | // Add global .breadcrumb class 50 | $attributes = Helpers::add_class($attributes, 'breadcrumb'); 51 | 52 | // Wrap in an
    tag 53 | $html = ''; 54 | $html .= implode('', $l); 55 | $html .= '
'; 56 | 57 | return $html; 58 | } 59 | 60 | /** 61 | * Renders a breadcrumb item 62 | * 63 | * @param string $content The item content 64 | * @param boolean $active Whether the item is active or not 65 | * 66 | * @return string 67 | */ 68 | protected static function renderItem($content, $active = false) 69 | { 70 | // If the link is not active it's the last one, don't append separator 71 | $separator = !$active ? ''.static::$separator.'' : ''; 72 | 73 | // If it's active, add correspondig class to it 74 | $class = $active ? ' class="active"' : ''; 75 | 76 | // Wrap item in a list item 77 | $html = ''; 78 | $html .= $content.$separator; 79 | $html .= ''; 80 | 81 | return $html; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Bootstrapper/ButtonGroup.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class ButtonGroup 20 | { 21 | /** 22 | * Puts the ButtonGroup in a checkbox mode. 23 | * 24 | * @var string 25 | */ 26 | const TOGGLE_CHECKBOX = 'checkbox'; 27 | 28 | /** 29 | * Puts the ButtonGroup in a radio button mode. Allowing only 30 | * one button to be selected at a time. 31 | * 32 | * @var string 33 | */ 34 | const TOGGLE_RADIO = 'radio'; 35 | 36 | /** 37 | * Opens a vertical button group 38 | * 39 | * @param boolean $toggle Whether the button group should be togglable 40 | * @param array $attributes An array of attributes 41 | * 42 | * @return string An opening
tag 43 | */ 44 | public static function vertical_open($toggle = null, $attributes = array()) 45 | { 46 | $attributes = Helpers::add_class($attributes, 'btn-group-vertical'); 47 | 48 | return static::open($toggle, $attributes); 49 | } 50 | 51 | /** 52 | * Alias for open so both horizontal_open and open can be used. 53 | * 54 | * @param boolean $toggle Whether the button group should be togglable 55 | * @param array $attributes An array of attributes 56 | * 57 | * @return string An opening
tag 58 | */ 59 | public static function horizontal_open($toggle = null, $attributes = array()) 60 | { 61 | return static::open($toggle, $attributes); 62 | } 63 | 64 | /** 65 | * Opens a new ButtonGroup section. 66 | * 67 | * @param string $toggle Whether the button group should be togglable 68 | * @param array $attributes An array of attributes 69 | * 70 | * @return string An opening
tag 71 | */ 72 | public static function open($toggle = null, $attributes = array()) 73 | { 74 | $validToggles = array(ButtonGroup::TOGGLE_CHECKBOX, ButtonGroup::TOGGLE_RADIO); 75 | if (isset($toggle) && in_array($toggle, $validToggles)) { 76 | $attributes['data-toggle'] = 'buttons-'.$toggle; 77 | } 78 | 79 | $attributes = Helpers::add_class($attributes, 'btn-group'); 80 | 81 | return ''; 82 | } 83 | 84 | /** 85 | * Closes the ButtonGroup section. 86 | * 87 | * @return string 88 | */ 89 | public static function close() 90 | { 91 | return '
'; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Bootstrapper/Helpers.php: -------------------------------------------------------------------------------- 1 | 11 | * @author Maxime Fabre - 12 | * @license MIT License 13 | * @link http://laravelbootstrapper.phpfogapp.com/ 14 | * 15 | * @see http://twitter.github.com/bootstrap/ 16 | */ 17 | class Helpers 18 | { 19 | /** 20 | * Function adds the given value to an array. If the key already 21 | * exists the value is concatenated to the end of the string. 22 | * Mainly used for adding classes. 23 | * 24 | * @param array $array Array object to be added to 25 | * @param string $value String value 26 | * @param string $key Array key to use 27 | * 28 | * @return array 29 | */ 30 | public static function add_class($array, $value, $key = 'class') 31 | { 32 | $array[$key] = isset($array[$key]) ? $array[$key].' '.$value : $value; 33 | 34 | return $array; 35 | } 36 | 37 | /** 38 | * Function to create a random string of a differing length used for creating IDs 39 | * 40 | * @param int $length Length of the random string 41 | * 42 | * @return string 43 | */ 44 | public static function rand_string($length) 45 | { 46 | $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 47 | 48 | $size = strlen($chars); 49 | $str = ''; 50 | for ($i = 0; $i < $length; $i++) { 51 | $str .= $chars[ rand(0, $size - 1) ]; 52 | } 53 | 54 | return $str; 55 | } 56 | 57 | /** 58 | * Function used to prime the attributes array for dynamic calls. 59 | * 60 | * @param string $exclude String to exclude from array 61 | * @param array $class_array Class array 62 | * @param array $params Parameters array 63 | * @param int $index Index of the parameters array to use 64 | * @param string $extra Prefix to the class 65 | * @param string $extra_unless Value to exclude the prefix from 66 | * 67 | * @return array 68 | */ 69 | public static function set_multi_class_attributes($exclude, $class_array, $params, $index, $extra = '', $extra_unless = null) 70 | { 71 | // Make sure the class attribute exists 72 | if (!isset($params[$index])) $params[$index] = array(); 73 | if (!isset($params[$index]['class'])) $params[$index]['class'] = ''; 74 | 75 | foreach ($class_array as $s) { 76 | if ($s != $exclude) { 77 | $class = ' '.$extra.$s; 78 | if (isset($extra_unless) && strpos($s, $extra_unless) !== false) { 79 | $class = ' '.$s; 80 | } 81 | 82 | $params[$index]['class'] .= $class; 83 | } 84 | } 85 | 86 | $params[$index]['class'] = trim($params[$index]['class']); 87 | 88 | return $params; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/Alert.test.php: -------------------------------------------------------------------------------- 1 | 'div', 14 | 'attributes' => array( 15 | 'data-foo' => 'bar', 16 | 'class' => 'foo alert alert-'.$class), 17 | 'content' => 'foo', 18 | 'child' => array( 19 | 'tag' => 'a', 20 | 'attributes' => array( 21 | 'class' => 'close', 22 | 'data-dismiss' => 'alert', 23 | 'href' => '#', 24 | ), 25 | ), 26 | ); 27 | } else { 28 | return array( 29 | 'tag' => 'div', 30 | 'attributes' => array( 31 | 'data-foo' => 'bar', 32 | 'class' => 'foo alert alert-'.$class), 33 | 'content' => 'foo', 34 | ); 35 | } 36 | } 37 | 38 | // Data providers ----------------------------------------------- / 39 | 40 | public function classes() 41 | { 42 | return array( 43 | array('danger'), 44 | array('error'), 45 | array('info'), 46 | array('success'), 47 | array('warning'), 48 | ); 49 | } 50 | 51 | // Tests --------------------------------------------------------- / 52 | 53 | public function testCustom() 54 | { 55 | $alert = Alert::custom('success', 'foo', $this->testAttributes); 56 | $match = $this->createMatcher('success'); 57 | 58 | $this->assertTag($match, $alert); 59 | } 60 | 61 | public function testCustomWithoutClose() 62 | { 63 | $alert = Alert::custom('success', 'foo', $this->testAttributes)->open(); 64 | $match = array( 65 | 'attributes' => array('data-foo' => 'bar', 'class' => 'foo alert alert-success'), 66 | 'content' => 'foo', 67 | 'tag' => 'div', 68 | ); 69 | 70 | $this->assertTag($match, $alert); 71 | } 72 | 73 | public function testStaticOpened() 74 | { 75 | $alert = Alert::open_success('foo', $this->testAttributes); 76 | $match = $this->createMatcher('success', false); 77 | 78 | $this->assertTag($match, $alert); 79 | } 80 | 81 | public function testStaticOpenBlock() 82 | { 83 | $alert = Alert::open_block_success('foo', $this->testAttributes); 84 | $match = $this->createMatcher('success', false); 85 | $match['attributes']['class'] .= ' alert-block'; 86 | 87 | $this->assertTag($match, $alert); 88 | } 89 | 90 | public function testStaticWhatever() 91 | { 92 | $alert = Alert::foo_bar('foo', $this->testAttributes); 93 | $match = $this->createMatcher('foo-bar'); 94 | 95 | $this->assertTag($match, $alert); 96 | } 97 | 98 | /** 99 | * @dataProvider classes 100 | */ 101 | public function testStatic($class) 102 | { 103 | $alert = Alert::$class('foo', $this->testAttributes); 104 | $match = $this->createMatcher($class); 105 | 106 | $this->assertTag($match, $alert); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Bootstrapper/Icon.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Icon 20 | { 21 | /** 22 | * Allows magic methods such as Icon::home([attributes]) or Icon::close_white() 23 | * 24 | * Sample Usage: 25 | * 26 | * 29 | * Icon::folder_open(array('class'=>'widget','data-foo'=>'bar')); 30 | * // 31 | * Icon::circle_arrow_right_white(); 32 | * // 33 | * ?> 34 | * 35 | * 36 | * @param string $method Name of missing method 37 | * @param array $parameters array of parameters passed to missing method 38 | * 39 | * @return string 40 | */ 41 | public static function __callStatic($method, $parameters) 42 | { 43 | // Explode method name 44 | $method_bits = explode('_', strtolower($method)); 45 | 46 | // White icon variant? (when using glyphicons sprite version) 47 | $white = in_array('white', $method_bits); 48 | 49 | // Remove white from array 50 | $method_bits = array_filter( 51 | $method_bits, 52 | function ($val) { 53 | return ($val != 'white'); 54 | } 55 | ); 56 | 57 | // Get icon name 58 | $icon_classes = array(implode('-', $method_bits)); 59 | if ($white) $icon_classes[] = 'white'; 60 | 61 | // If the parameters weren't put into an array, do it 62 | if (!isset($parameters[0])) { 63 | $parameters = array(0 => $parameters); 64 | } 65 | 66 | // Prepend icon- to classes 67 | $parameters = Helpers::set_multi_class_attributes(null, $icon_classes, $parameters, 0, Config::get('icons_prefix')); 68 | 69 | return ''; 70 | } 71 | 72 | /** 73 | * Return icon HTML using alternate syntax. 74 | * Overload via __callStatic() allows calls like Icon::check() or Icon::paper_clip_white() 75 | * but code-inspecting IDEs will show the method as undefined, and there are just way too many 76 | * icon classes to use @ method docblock instead 77 | * 78 | * Sample Usage: 79 | * 80 | * 'widget')); 82 | * // 83 | * ?> 84 | * 85 | * 86 | * @param string $icon_class name of the bootstrap icon class 87 | * @param array $attributes attributes to apply the icon itself 88 | * 89 | * @return string 90 | */ 91 | public static function make($icon_class, $attributes = array()) 92 | { 93 | return static::__callStatic($icon_class, $attributes); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tests/Thumbnail.test.php: -------------------------------------------------------------------------------- 1 | 'foo', 'link' => 'foo'), 10 | array('image' => 'bar', 'link' => 'foo'), 11 | ); 12 | 13 | private $richImages = array( 14 | array('image' => 'foo', 'caption' => 'kel'), 15 | array('image' => 'bar', 'label' => 'bar'), 16 | array('image' => 'den', 'label' => 'den', 'caption' => 'kel'), 17 | ); 18 | 19 | public static function setUpBeforeClass() 20 | { 21 | URL::$base = 'http://test/'; 22 | Config::set('application.index', ''); 23 | Config::set('application.asset_url', 'test'); 24 | } 25 | 26 | // Matchers ------------------------------------------------------ / 27 | 28 | public function matcher($thumbnails) 29 | { 30 | return '
    ' .$thumbnails. '
'; 31 | } 32 | 33 | public function image($image) 34 | { 35 | return ''; 36 | } 37 | 38 | public function link($content) 39 | { 40 | return '' .$content. ''; 41 | } 42 | 43 | // Tests --------------------------------------------------------- / 44 | 45 | public function testSimpleThumbnails() 46 | { 47 | $thumbnails = Thumbnail::create($this->images); 48 | $matcher = $this->matcher( 49 | '
  • '.$this->image('foo').'
  • '. 50 | '
  • '.$this->image('bar').'
  • ' 51 | ); 52 | 53 | $this->assertEquals($matcher, $thumbnails); 54 | } 55 | 56 | public function testAlreadyWrappedThumbnails() 57 | { 58 | $images = array($this->image('foo'), $this->image('bar')); 59 | $thumbnails = Thumbnail::create($images); 60 | $matcher = $this->matcher( 61 | '
  • '.$this->image('foo').'
  • '. 62 | '
  • '.$this->image('bar').'
  • ' 63 | ); 64 | 65 | $this->assertEquals($matcher, $thumbnails); 66 | } 67 | 68 | public function testLinkedThumbnails() 69 | { 70 | $thumbnails = Thumbnail::create($this->linkedImages); 71 | $matcher = $this->matcher( 72 | '
  • '.$this->link($this->image('foo')).'
  • '. 73 | '
  • '.$this->link($this->image('bar')).'
  • ' 74 | ); 75 | 76 | $this->assertEquals($matcher, $thumbnails); 77 | } 78 | 79 | public function testRichThumbnails() 80 | { 81 | $thumbnails = Thumbnail::create($this->richImages); 82 | $matcher = $this->matcher( 83 | '
  • '.$this->image('foo').'

    kel

  • '. 84 | '
  • '.$this->image('bar').'

    bar

  • '. 85 | '
  • '.$this->image('den').'

    den

    kel

  • ' 86 | ); 87 | 88 | $this->assertEquals($matcher, $thumbnails); 89 | } 90 | 91 | public function testWithClosure() 92 | { 93 | $thumbnails = Thumbnail::create($this->richImages, function($image) { 94 | $image = (object) $image; 95 | 96 | $return = '
  • ' .HTML::image($image->image). '
    '; 97 | if(isset($image->label)) $return .= '

    '.$image->label.'

    '; 98 | $return .= '
  • '; 99 | 100 | return $return; 101 | }); 102 | $matcher = $this->matcher( 103 | '
  • '.$this->image('foo').'
  • '. 104 | '
  • '.$this->image('bar').'

    bar

  • '. 105 | '
  • '.$this->image('den').'

    den

  • ' 106 | ); 107 | 108 | $this->assertEquals($matcher, $thumbnails); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/Carousel.test.php: -------------------------------------------------------------------------------- 1 | 'div', 14 | 'child' => array( 15 | 'tag' => 'div', 16 | 'attributes' => array('class' => 'carousel-inner'), 17 | 'children' => array( 18 | 'count' => 4, 19 | 'only' => array( 20 | 'tag' => 'div', 21 | 'attributes' => array('class' => 'item'), 22 | 'child' => array('tag' => 'img'), 23 | ) 24 | ) 25 | ) 26 | ); 27 | 28 | /** 29 | * Match the basic structure of a Carousel 30 | * 31 | * @param string $html A carousel markup 32 | */ 33 | private function carouselMarkup($html) 34 | { 35 | // Matcher for the left navigation element 36 | $matcherLeft = array( 37 | 'tag' => 'div', 38 | 'attributes' => array( 39 | 'class' => 'foo carousel slide', 40 | 'data-foo' => 'bar' 41 | ), 42 | 'child' => array( 43 | 'tag' => 'a', 44 | 'content' => '‹', 45 | 'attributes' => array( 46 | 'class' => 'carousel-control left', 47 | 'data-slide' => 'prev', 48 | ), 49 | ) 50 | ); 51 | 52 | // Matcher for the right navigation element 53 | $matcherRight = array( 54 | 'tag' => 'div', 55 | 'child' => array( 56 | 'tag' => 'a', 57 | 'content' => '›', 58 | 'attributes' => array( 59 | 'class' => 'carousel-control right', 60 | 'data-slide' => 'next', 61 | ), 62 | ) 63 | ); 64 | 65 | $this->assertTag($matcherLeft, $html); 66 | $this->assertTag($matcherRight, $html); 67 | } 68 | 69 | // Tests --------------------------------------------------------- / 70 | 71 | public function testCreateSimple() 72 | { 73 | $carousel = Carousel::create(array('foo', 'bar', 'kal', 'tem'), $this->testAttributes); 74 | 75 | // Matcher for the slides 76 | $matcherSlide = $this->innerItem; 77 | 78 | $this->carouselMarkup($carousel); 79 | $this->assertTag($matcherSlide, $carousel); 80 | } 81 | 82 | public function testCarouselComplex() 83 | { 84 | $carousel = Carousel::create(array( 85 | array('image' => 'foo', 'alt_text' => 'bar', 'caption' => 'caption', 'label' => 'label', 'attributes' => $this->testAttributes), 86 | array('image' => 'foo', 'alt_text' => 'bar', 'caption' => 'caption', 'label' => 'label', 'attributes' => $this->testAttributes), 87 | array('image' => 'foo', 'alt_text' => 'bar', 'caption' => 'caption', 'label' => 'label', 'attributes' => $this->testAttributes), 88 | array('image' => 'foo', 'alt_text' => 'bar', 'caption' => 'caption', 'label' => 'label', 'attributes' => $this->testAttributes), 89 | ), $this->testAttributes); 90 | 91 | // Matcher for the slides 92 | $matcherSlide = $this->innerItem; 93 | $matcherSlide['child']['children']['only']['child']['attributes'] = array( 94 | 'alt' => 'bar', 95 | 'class' => 'foo', 96 | 'data-foo' => 'bar', 97 | ); 98 | 99 | // Matcher for the captions 100 | $matcherCaption = $this->innerItem; 101 | $matcherCaption['child']['children'] = array( 102 | 'count' => 4, 103 | 'only' => array( 104 | 'tag' => 'div', 105 | 'attributes' => array('class' => 'item'), 106 | 'child' => array( 107 | 'tag' => 'div', 108 | 'attributes' => array('class' => 'carousel-caption'), 109 | 'child' => array('tag' => 'h4', 'content' => 'label'), 110 | 'descendant' => array('tag' => 'p', 'content' => 'caption'), 111 | ) 112 | ) 113 | ); 114 | 115 | $this->carouselMarkup($carousel); 116 | $this->assertTag($matcherSlide, $carousel); 117 | $this->assertTag($matcherCaption, $carousel); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/Progress.test.php: -------------------------------------------------------------------------------- 1 | 'div', 19 | 'attributes' => array( 20 | 'class' => $class, 21 | 'data-foo' => 'bar', 22 | ), 23 | 'child' => array( 24 | 'tag' => 'div', 25 | 'attributes' => array( 26 | 'class' => 'bar', 27 | 'style' => 'width: ' .$width. '%;' 28 | ), 29 | ), 30 | ); 31 | } 32 | 33 | // Data providers ------------------------------------------------ / 34 | 35 | public function provideBars() 36 | { 37 | return array( 38 | array('normal'), 39 | array('success'), 40 | array('info'), 41 | array('warning'), 42 | array('danger'), 43 | ); 44 | } 45 | 46 | // Tests --------------------------------------------------------- / 47 | 48 | /** 49 | * @dataProvider provideBars 50 | */ 51 | public function testSimple($class) 52 | { 53 | $progress = Progress::$class(50, $this->testAttributes); 54 | $matcher = $this->matchProgress($class); 55 | 56 | $this->assertTag($matcher, $progress); 57 | } 58 | 59 | public function testStacked() 60 | { 61 | $progress = Progress::danger( 62 | array(25 => 'success', 50 => 'error', 10 => 'warning'), 63 | $this->testAttributes 64 | ); 65 | 66 | // Build more complex matcher 67 | $matcher = $this->matchProgress(); 68 | $matcher['attributes']['class'] = 'foo progress'; 69 | $matcher['child']['attributes']['class'] = 'bar bar-error'; 70 | $matcher['descendant'] = array( 71 | 'tag' => 'div', 72 | 'attributes' => array( 73 | 'class' => 'bar bar-success', 74 | 'style' => 'width: 25%;' 75 | ), 76 | ); 77 | $matcher['children'] = array( 78 | 'count' => 3, 79 | 'only' => array( 80 | 'tag' => 'div', 81 | 'attributes' => array('class' => 'bar'), 82 | ), 83 | ); 84 | 85 | $this->assertTag($matcher, $progress); 86 | } 87 | 88 | public function testFloat() 89 | { 90 | $progress = Progress::success(5.40, $this->testAttributes); 91 | $matcher = $this->matchProgress('success', 5); 92 | 93 | $this->assertTag($matcher, $progress); 94 | } 95 | 96 | public function testAutomatic() 97 | { 98 | $classes = array( 99 | 0 => 'danger', 100 | 20 => 'danger', 101 | 40 => 'warning', 102 | 60 => 'info', 103 | 80 => 'success', 104 | 100 => 'success'); 105 | 106 | for ($i = 0; $i <= 100; $i = $i + 20) { 107 | $progress = Progress::automatic($i, $this->testAttributes); 108 | $matcher = $this->matchProgress($classes[$i], $i); 109 | 110 | $this->assertTag($matcher, $progress); 111 | } 112 | } 113 | 114 | public function testStriped() 115 | { 116 | $progress = Progress::striped_info(50, $this->testAttributes); 117 | $matcher = $this->matchProgress('info', 50, true); 118 | 119 | $this->assertTag($matcher, $progress); 120 | } 121 | 122 | public function testActive() 123 | { 124 | $progress = Progress::active_info(50, $this->testAttributes); 125 | $matcher = $this->matchProgress('info', 50, false, true); 126 | 127 | $this->assertTag($matcher, $progress); 128 | } 129 | 130 | public function testActiveStriped() 131 | { 132 | $progress = Progress::striped_active_info(50, $this->testAttributes); 133 | $matcher = $this->matchProgress('info', 50, true, true); 134 | 135 | $this->assertTag($matcher, $progress); 136 | } 137 | 138 | public function testExceptionAttributes() 139 | { 140 | $this->setExpectedException('InvalidArgumentException'); 141 | 142 | $progress = Progress::striped_normal(50, 'foo'); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Bootstrapper/Badge.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Badge 20 | { 21 | /** 22 | * Badge colors 23 | * 24 | * @var constant 25 | */ 26 | const NORMAL = ''; 27 | const IMPORTANT = 'badge-important'; 28 | const INFO = 'badge-info'; 29 | const INVERSE = 'badge-inverse'; 30 | const SUCCESS = 'badge-success'; 31 | const WARNING = 'badge-warning'; 32 | 33 | /** 34 | * Create a new Badge. 35 | * 36 | * @param string $type Type of badge 37 | * @param string $message Message in badge 38 | * @param array $attributes Parent div attributes 39 | * 40 | * @return string Badge HTML 41 | */ 42 | protected static function show($type, $message, $attributes = array()) 43 | { 44 | $attributes = Helpers::add_class($attributes, 'badge '.$type); 45 | 46 | return ''.$message.''; 47 | } 48 | 49 | /** 50 | * Create a new Normal Badge. 51 | * 52 | * @param string $message Message in badge 53 | * @param array $attributes Parent div attributes 54 | * 55 | * @return string Badge HTML 56 | */ 57 | public static function normal($message, $attributes = array()) 58 | { 59 | return static::show(Badge::NORMAL, $message, $attributes); 60 | } 61 | 62 | /** 63 | * Create a new Success Badge. 64 | * 65 | * @param string $message Message in badge 66 | * @param array $attributes Parent div attributes 67 | * 68 | * @return string Badge HTML 69 | */ 70 | public static function success($message, $attributes = array()) 71 | { 72 | return static::show(Badge::SUCCESS, $message, $attributes); 73 | } 74 | 75 | /** 76 | * Create a new Warning Badge. 77 | * 78 | * @param string $message Message in badge 79 | * @param array $attributes Parent div attributes 80 | * 81 | * @return string Badge HTML 82 | */ 83 | public static function warning($message, $attributes = array()) 84 | { 85 | return static::show(Badge::WARNING, $message, $attributes); 86 | } 87 | 88 | /** 89 | * Create a new Important Badge. 90 | * 91 | * @param string $message Message in badge 92 | * @param array $attributes Parent div attributes 93 | * 94 | * @return string Badge HTML 95 | */ 96 | public static function important($message, $attributes = array()) 97 | { 98 | return static::show(Badge::IMPORTANT, $message, $attributes); 99 | } 100 | 101 | /** 102 | * Create a new Info Badge. 103 | * 104 | * @param string $message Message in badge 105 | * @param array $attributes Parent div attributes 106 | * 107 | * @return string Badge HTML 108 | */ 109 | public static function info($message, $attributes = array()) 110 | { 111 | return static::show(Badge::INFO, $message, $attributes); 112 | } 113 | 114 | /** 115 | * Create a new Inverse Badge. 116 | * 117 | * @param string $message Message in badge 118 | * @param array $attributes Parent div attributes 119 | * 120 | * @return string Badge HTML 121 | */ 122 | public static function inverse($message, $attributes = array()) 123 | { 124 | return static::show(Badge::INVERSE, $message, $attributes); 125 | } 126 | 127 | /** 128 | * Create a new custom Badge. 129 | * This assumes you have created the appropriate css class for the label type. 130 | * 131 | * @param string $type Type of badge 132 | * @param string $message Message in badge 133 | * @param array $attributes Parent div attributes 134 | * 135 | * @return string Badge HTML 136 | */ 137 | public static function custom($type, $message, $attributes = array()) 138 | { 139 | $type = 'badge-'.(string) $type; 140 | 141 | return static::show($type, $message, $attributes); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Bootstrapper/Label.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Label 20 | { 21 | /** 22 | * Label colors 23 | * @var constant 24 | */ 25 | const NORMAL = ''; 26 | const IMPORTANT = 'label-important'; 27 | const INFO = 'label-info'; 28 | const INVERSE = 'label-inverse'; 29 | const SUCCESS = 'label-success'; 30 | const WARNING = 'label-warning'; 31 | 32 | /** 33 | * Create a new Label 34 | * 35 | * @param string $type Label type 36 | * @param string $message Label text 37 | * @param array $attributes Attributes to apply the label itself 38 | * 39 | * @return string Label HTML 40 | */ 41 | protected static function show($type = Label::NORMAL, $message, $attributes = array()) 42 | { 43 | $attributes = Helpers::add_class($attributes, 'label '.$type); 44 | 45 | return ''.$message.''; 46 | } 47 | 48 | /** 49 | * Create a new Normal Label 50 | * 51 | * @param string $message Label text 52 | * @param array $attributes Attributes to apply the label itself 53 | * 54 | * @return string Label HTML 55 | */ 56 | public static function normal($message, $attributes = array()) 57 | { 58 | return static::show(Label::NORMAL, $message, $attributes); 59 | } 60 | 61 | /** 62 | * Create a new Success Label 63 | * 64 | * @param string $message Label text 65 | * @param array $attributes Attributes to apply the label itself 66 | * 67 | * @return string Label HTML 68 | */ 69 | public static function success($message, $attributes = array()) 70 | { 71 | return static::show(Label::SUCCESS, $message, $attributes); 72 | } 73 | 74 | /** 75 | * Create a new Warning Label 76 | * 77 | * @param string $message Label text 78 | * @param array $attributes Attributes to apply the label itself 79 | * 80 | * @return string Label HTML 81 | */ 82 | public static function warning($message, $attributes = array()) 83 | { 84 | return static::show(Label::WARNING, $message, $attributes); 85 | } 86 | 87 | /** 88 | * Create a new Important Label 89 | * 90 | * @param string $message Label text 91 | * @param array $attributes Attributes to apply the label itself 92 | * 93 | * @return string Label HTML 94 | */ 95 | public static function important($message, $attributes = array()) 96 | { 97 | return static::show(Label::IMPORTANT, $message, $attributes); 98 | } 99 | 100 | /** 101 | * Create a new Info Label instance 102 | * 103 | * @param string $message Label text 104 | * @param array $attributes Attributes to apply the label itself 105 | * 106 | * @return string Label HTML 107 | */ 108 | public static function info($message, $attributes = array()) 109 | { 110 | return static::show(Label::INFO, $message, $attributes); 111 | } 112 | 113 | /** 114 | * Create a new Inverse Label 115 | * 116 | * @param string $message Label text 117 | * @param array $attributes Attributes to apply the label itself 118 | * 119 | * @return string Label HTML 120 | */ 121 | public static function inverse($message, $attributes = array()) 122 | { 123 | return static::show(Label::INVERSE, $message, $attributes); 124 | } 125 | 126 | /** 127 | * Create a new custom Label 128 | * This assumes you have created the appropriate css class for the label type. 129 | * 130 | * @param string $type Label type 131 | * @param string $message Label text 132 | * @param array $attributes Attributes to apply the label itself 133 | * 134 | * @return string Label HTML 135 | */ 136 | public static function custom($type, $message, $attributes = array()) 137 | { 138 | $type = 'label-'.(string) $type; 139 | 140 | return static::show($type, $message, $attributes); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /tests/MediaObject.test.php: -------------------------------------------------------------------------------- 1 | '; 9 | if(!$pull) $pull ='left'; 10 | 11 | return 12 | '
    '. 13 | ''. 14 | $image. 15 | ''. 16 | '
    '. 17 | $title. 18 | 'foo'. 19 | '
    '. 20 | '
    '; 21 | } 22 | 23 | public function titles() 24 | { 25 | $titles = array(); 26 | for ($i = 1; $i <= 6; $i++) { 27 | $titles[] = array( 28 | 'with_h'.$i, 29 | 'foobar', 30 | ); 31 | } 32 | 33 | return $titles; 34 | } 35 | 36 | public function tearDown() 37 | { 38 | MediaObject::close_list(); 39 | MediaObject::$object = null; 40 | } 41 | 42 | public function testOpenList() 43 | { 44 | $open = MediaObject::open_list($this->testAttributes); 45 | $matcher = '
      '; 46 | 47 | $this->assertEquals($matcher, $open); 48 | } 49 | 50 | public function testCloseList() 51 | { 52 | $close = MediaObject::close_list(); 53 | $matcher = '
    '; 54 | 55 | $this->assertEquals($matcher, $close); 56 | } 57 | 58 | public function testBaseMediaObject() 59 | { 60 | $media = MediaObject::create('foo', 'bar', $this->testAttributes)->__toString(); 61 | $matcher = $this->createMatcher(); 62 | 63 | $this->assertEquals($matcher, $media); 64 | } 65 | 66 | public function testWithImage() 67 | { 68 | $media = MediaObject::create('foo', null, $this->testAttributes) 69 | ->with_image('bar', 'alt', $this->testAttributes)->__toString(); 70 | $matcher = $this->createMatcher(''); 71 | 72 | $this->assertEquals($matcher, $media); 73 | } 74 | 75 | public function testPullLeft() 76 | { 77 | $media1 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull_left()->__toString(); 78 | $media2 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull('left')->__toString(); 79 | $matcher = $this->createMatcher(); 80 | 81 | $this->assertEquals($matcher, $media1); 82 | $this->assertEquals($matcher, $media2); 83 | } 84 | 85 | public function testPullRight() 86 | { 87 | $media1 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull_right()->__toString(); 88 | $media2 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull('right')->__toString(); 89 | $matcher = $this->createMatcher(null, 'right'); 90 | 91 | $this->assertEquals($matcher, $media1); 92 | $this->assertEquals($matcher, $media2); 93 | } 94 | 95 | public function testPullWhatever() 96 | { 97 | $media1 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull_whatever()->__toString(); 98 | $media2 = MediaObject::create('foo', 'bar', $this->testAttributes)->pull('whatever')->__toString(); 99 | $matcher = $this->createMatcher(); 100 | 101 | $this->assertEquals($matcher, $media1); 102 | $this->assertEquals($matcher, $media2); 103 | } 104 | 105 | public function testWithTitle() 106 | { 107 | $media = MediaObject::create('foo', 'bar', $this->testAttributes)->with_title('

    foobar

    ')->__toString(); 108 | $matcher = $this->createMatcher(null, null, '

    foobar

    '); 109 | 110 | $this->assertEquals($matcher, $media); 111 | } 112 | 113 | /** 114 | * @dataProvider titles 115 | */ 116 | public function testMagicTitles($title, $expected) 117 | { 118 | $media = MediaObject::create('foo', 'bar', $this->testAttributes)->$title('foobar', $this->testAttributes)->__toString(); 119 | $matcher = $this->createMatcher(null, null, $expected); 120 | 121 | $this->assertEquals($matcher, $media); 122 | } 123 | 124 | public function testNesting() 125 | { 126 | $media = MediaObject::create('foo', 'bar', $this->testAttributes) 127 | ->nest(MediaObject::create('foo2', 'bar2')->with_h1('foobar')) 128 | ->__toString(); 129 | $matcher = 130 | '
    '. 131 | ''. 132 | '
    foo'. 133 | '
    '. 134 | ''. 135 | '

    foobar

    foo2
    '. 136 | '
    '. 137 | '
    '. 138 | '
    '; 139 | 140 | $this->assertEquals($matcher, $media); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /tests/DropdownButton.test.php: -------------------------------------------------------------------------------- 1 | links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 14 | } 15 | 16 | private function matcher($class = 'normal', $right = false, $dropup = false, $split = false) 17 | { 18 | $class = $class == 'normal' ? null : ' btn-'.$class; 19 | $right = $right ? 'pull-right ' : null; 20 | $dropup = $dropup ? ' dropup' : null; 21 | 22 | if ($split) { 23 | $btn = ''. 24 | ''; 25 | } else { 26 | $btn = ''; 29 | } 30 | 31 | return 32 | '
    '. 33 | $btn. 34 | '
      '. 35 | '
    • foo
    • '. 36 | '
    • bar
    • '. 37 | '
    '. 38 | '
    '; 39 | 40 | } 41 | 42 | // Data providers ----------------------------------------------- / 43 | 44 | public function classes() 45 | { 46 | return array( 47 | array('normal'), 48 | array('custom'), 49 | array('primary'), 50 | array('danger'), 51 | array('warning'), 52 | array('success'), 53 | array('info'), 54 | array('inverse'), 55 | ); 56 | } 57 | 58 | // Tests --------------------------------------------------------- / 59 | 60 | public function testDropdown() 61 | { 62 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->__toString(); 63 | $matcher = $this->matcher(); 64 | 65 | $this->assertEquals($matcher, $dropdown); 66 | } 67 | 68 | public function testSplitDropdown() 69 | { 70 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->split()->__toString(); 71 | $matcher = $this->matcher('normal', false, false, true); 72 | 73 | $this->assertEquals($matcher, $dropdown); 74 | } 75 | 76 | public function testRightDropdown() 77 | { 78 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->pull_right()->__toString(); 79 | $matcher = $this->matcher('normal', true); 80 | 81 | $this->assertEquals($matcher, $dropdown); 82 | } 83 | 84 | public function testRightSplitDropdown() 85 | { 86 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->pull_right()->split()->__toString(); 87 | $matcher = $this->matcher('normal', true, false, true); 88 | 89 | $this->assertEquals($matcher, $dropdown); 90 | } 91 | 92 | public function testDropup() 93 | { 94 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->dropup()->__toString(); 95 | $matcher = $this->matcher('normal', false, true); 96 | 97 | $this->assertEquals($matcher, $dropdown); 98 | } 99 | 100 | public function testDropupSplit() 101 | { 102 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->dropup()->split()->__toString(); 103 | $matcher = $this->matcher('normal', false, true, true); 104 | 105 | $this->assertEquals($matcher, $dropdown); 106 | } 107 | 108 | /** 109 | * @dataProvider classes 110 | */ 111 | public function testCallStatic($class) 112 | { 113 | $dropdown = DropdownButton::$class('foo', $this->links, $this->testAttributes)->__toString(); 114 | $matcher = $this->matcher($class); 115 | 116 | $this->assertEquals($matcher, $dropdown); 117 | } 118 | 119 | public function testDynamicAttribute() 120 | { 121 | $dropdown = DropdownButton::normal('foo', $this->links, $this->testAttributes)->data_foo('bar')->class('foo')->__toString(); 122 | $matcher = $this->matcher(); 123 | 124 | $this->assertEquals($matcher, $dropdown); 125 | } 126 | 127 | public function testMultipleDropdowns() 128 | { 129 | $dropdowns = 130 | DropdownButton::normal('foo', $this->links, $this->testAttributes). 131 | DropdownButton::normal('bar', $this->links, $this->testAttributes); 132 | $matcher = $this->matcher().str_replace('foo matcher()); 133 | 134 | $this->assertEquals($matcher, $dropdowns); 135 | } 136 | 137 | public function testWrongLinks() 138 | { 139 | $this->setExpectedException('InvalidArgumentException'); 140 | 141 | $dropdown = DropdownButton::normal('foo', 'bar'); 142 | } 143 | 144 | public function testWrongAttributes() 145 | { 146 | $this->setExpectedException('InvalidArgumentException'); 147 | 148 | $dropdown = DropdownButton::normal('foo', array(), 'bar'); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /tests/Navbar.test.php: -------------------------------------------------------------------------------- 1 | 'div', 11 | 'attributes' => array('class' => 'navbar'), 12 | 'child' => array( 13 | 'tag' => 'div', 14 | 'attributes' => array('class' => 'navbar-inner'), 15 | 'child' => array( 16 | 'tag' => 'div', 17 | 'attributes' => array('class' => 'container'), 18 | ), 19 | ) 20 | ); 21 | 22 | return $matcher; 23 | } 24 | 25 | public function testBasic() 26 | { 27 | $navbar = Navbar::create(); 28 | $matcher = $this->getBasicMatcher(); 29 | $this->assertTag($matcher, $navbar); 30 | } 31 | 32 | public function testAttributes() 33 | { 34 | $navbar = Navbar::create(array('class' => 'foo', 'data-foo' => 'bar')); 35 | $matcher = $this->getBasicMatcher(); 36 | $matcher['attributes']['class'] .= ' foo'; 37 | $matcher['attributes']['data-foo'] = 'bar'; 38 | $this->assertTag($matcher, $navbar); 39 | } 40 | 41 | public function testFixTop() 42 | { 43 | $navbar = Navbar::create(array(), Navbar::FIX_TOP); 44 | $matcher = $this->getBasicMatcher(); 45 | $matcher['attributes']['class'] .= ' navbar-fixed-top'; 46 | $this->assertTag($matcher, $navbar); 47 | } 48 | 49 | public function testFixBottom() 50 | { 51 | $navbar = Navbar::create(array(), Navbar::FIX_BOTTOM); 52 | $matcher = $this->getBasicMatcher(); 53 | $matcher['attributes']['class'] .= ' navbar-fixed-bottom'; 54 | $this->assertTag($matcher, $navbar); 55 | } 56 | 57 | public function testInverse() 58 | { 59 | $navbar = Navbar::inverse(); 60 | $matcher = $this->getBasicMatcher(); 61 | $matcher['attributes']['class'] .= ' navbar-inverse'; 62 | 63 | $this->assertTag($matcher, $navbar); 64 | 65 | } 66 | 67 | public function testBrand() 68 | { 69 | //Bootstrapper 70 | $navbar = Navbar::create()->with_brand('Bootstrapper', '#'); 71 | $matcher = $this->getBasicMatcher(); 72 | $matcher['child']['child']['child'] = array( 73 | 'tag' => 'a', 74 | 'attributes' => array('class' => 'brand', 'href' => '#'), 75 | 'content' => 'Bootstrapper' 76 | ); 77 | 78 | $this->assertTag($matcher, $navbar); 79 | 80 | } 81 | 82 | public function testCollapse() 83 | { 84 | $navbar = Navbar::create()->collapsible(); 85 | $matcher = $this->getBasicMatcher(true); 86 | 87 | //Add collapse tags 88 | $matcher['child']['child']['child'] = array( 89 | 'tag' => 'a', 90 | 'attributes' => array( 91 | 'class' => 'btn btn-navbar', 92 | 'data-toggle' => 'collapse', 93 | 'data-target' => '.nav-collapse' 94 | ), 95 | 'children' => array( 96 | 'count' => 3, 97 | 'only' => array( 98 | 'tag' => 'span', 99 | 'class' => 'icon-bar' 100 | ), 101 | ), 102 | ); 103 | $matcher['child']['child']['descendant'] = array( 104 | 'tag' => 'div', 105 | 'attributes' => array('class' => 'nav-collapse') 106 | ); 107 | 108 | $this->assertTag($matcher, $navbar); 109 | } 110 | 111 | public function testMenu() 112 | { 113 | $navbar = Navbar::create()->with_menus( 114 | Navigation::links(array( 115 | array('foo', '#'), 116 | array('bar', '#') 117 | )) 118 | ); 119 | 120 | $matcher = $this->getBasicMatcher(); 121 | $matcher['child']['child']['child'] = array( 122 | 'tag' => 'ul', 123 | 'attributes' => array('class' => 'nav'), 124 | 'children' => array( 125 | 'count' => 2, 126 | 'only' => array('tag' => 'li') 127 | ) 128 | ); 129 | 130 | $this->assertTag($matcher, $navbar); 131 | } 132 | 133 | public function testMenuAttributes() 134 | { 135 | $navbar = Navbar::create()->with_menus( 136 | Navigation::links(array( 137 | array('foo', '#'), 138 | array('bar', '#') 139 | )), 140 | array('class' => 'foo', 'data-foo' => 'bar') 141 | ); 142 | 143 | $matcher = $this->getBasicMatcher(); 144 | $matcher['child']['child']['child'] = array( 145 | 'tag' => 'ul', 146 | 'attributes' => array('class' => 'nav foo', 'data-foo' => 'bar'), 147 | 'children' => array( 148 | 'count' => 2, 149 | 'only' => array('tag' => 'li') 150 | ) 151 | ); 152 | 153 | $this->assertTag($matcher, $navbar); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Bootstrapper/Typography.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Typography 20 | { 21 | 22 | /** 23 | * Typography types 24 | * @var constant 25 | */ 26 | const LEAD = 'lead'; 27 | const MUTED = 'muted'; 28 | const WARNING = 'text-warning'; 29 | const ERROR = 'text-error'; 30 | const INFO = 'text-info'; 31 | const SUCCESS = 'text-success'; 32 | 33 | /** 34 | * Create a new Typography. 35 | * 36 | * @param string $type Type of Typography 37 | * @param string $message Message in tag 38 | * @param array $attributes Parent div attributes 39 | * 40 | * @return string Typography HTML 41 | */ 42 | protected static function createEmphasis($type, $message, $tag = 'p', $attributes = array()) 43 | { 44 | $attributes = Helpers::add_class($attributes, $type); 45 | 46 | return '<'.$tag.HTML::attributes($attributes).'>'.$message.''; 47 | } 48 | 49 | /* Create a new lead text. 50 | * 51 | * @param string $message Message in tag 52 | * @param array $attributes Parent div attributes 53 | * 54 | * @return string Typography HTML 55 | */ 56 | public static function lead($message, $tag = 'p', $attributes = array()) 57 | { 58 | return static::createEmphasis(Typography::LEAD, $message, $tag, $attributes); 59 | } 60 | 61 | /** 62 | * Create a new muted text. 63 | * 64 | * @param string $message Message in tag 65 | * @param array $attributes Parent div attributes 66 | * 67 | * @return string Typography HTML 68 | */ 69 | public static function muted($message, $tag = 'p', $attributes = array()) 70 | { 71 | return static::createEmphasis(Typography::MUTED, $message, $tag, $attributes); 72 | } 73 | 74 | /** 75 | * Create a new warning text. 76 | * 77 | * @param string $message Message in tag 78 | * @param array $attributes Parent div attributes 79 | * 80 | * @return string Typography HTML 81 | */ 82 | public static function warning($message, $tag = 'p', $attributes = array()) 83 | { 84 | return static::createEmphasis(Typography::WARNING, $message, $tag, $attributes); 85 | } 86 | 87 | /** 88 | * Create a new error text. 89 | * 90 | * @param string $message Message in tag 91 | * @param array $attributes Parent div attributes 92 | * 93 | * @return string Typography HTML 94 | */ 95 | public static function error($message, $tag = 'p', $attributes = array()) 96 | { 97 | return static::createEmphasis(Typography::ERROR, $message, $tag, $attributes); 98 | } 99 | 100 | /** 101 | * Create a new info text. 102 | * 103 | * @param string $message Message in tag 104 | * @param array $attributes Parent div attributes 105 | * 106 | * @return string Typography HTML 107 | */ 108 | public static function info($message, $tag = 'p', $attributes = array()) 109 | { 110 | return static::createEmphasis(Typography::INFO, $message, $tag, $attributes); 111 | } 112 | 113 | /** 114 | * Create a new success text. 115 | * 116 | * @param string $message Message in tag 117 | * @param array $attributes Parent div attributes 118 | * 119 | * @return string Typography HTML 120 | */ 121 | public static function success($message, $tag = 'p', $attributes = array()) 122 | { 123 | return static::createEmphasis(Typography::SUCCESS, $message, $tag, $attributes); 124 | } 125 | 126 | /** 127 | * Creates a definition list 128 | * 129 | * @param array $list An array [term => description] 130 | * @param array $attributes An array of attributes 131 | * 132 | * @return string A formatted
    list 133 | */ 134 | public static function dl($list, $attributes = array()) 135 | { 136 | $dl = null; 137 | 138 | // Check if the list contains anything 139 | if (count($list) == 0) { 140 | return false; 141 | } 142 | 143 | // Write each entry 144 | foreach ($list as $term => $description) { 145 | $dl .= '
    '.HTML::entities($term).'
    '; 146 | $dl .= '
    '.HTML::entities($description).'
    '; 147 | } 148 | 149 | return ''.$dl.'
    '; 150 | } 151 | 152 | /** 153 | * Creates an horizontal definition list 154 | * 155 | * @param array $list An array [term => description] 156 | * @param array $attributes An array of attributes 157 | * 158 | * @return string A formatted
    list 159 | */ 160 | public static function horizontal_dl($list, $attributes = array()) 161 | { 162 | $attributes = Helpers::add_class($attributes, 'dl-horizontal'); 163 | 164 | return static::dl($list, $attributes); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /tests/Tabbable.test.php: -------------------------------------------------------------------------------- 1 | 'div', 16 | 'attributes' => array('class' => 'tabbable '.$position), 17 | 'descendant' => array( 18 | 'tag' => 'ul', 19 | 'attributes' => array('class' => 'nav '.$type), 20 | 'children' => array( 21 | 'count' => 3, 22 | 'only' => array('tag' => 'li'), 23 | ), 24 | ), 25 | 'child' => array( 26 | 'tag' => 'div', 27 | 'attributes' => array('class' => 'tab-content'), 28 | 'children' => array( 29 | 'count' => 3, 30 | 'only' => array( 31 | 'tag' => 'div', 32 | 'class' => 'tab-pane' 33 | ), 34 | ), 35 | ) 36 | ); 37 | 38 | if ($childLinkText !== null) { 39 | $base['descendant']['child'] = array( 40 | 'tag' => 'li', 41 | 'class' => 'active', 42 | 'child' => array( 43 | 'tag' => 'a', 44 | 'attributes' => array('data-toggle' => 'tab'), 45 | 'content' => $childLinkText 46 | ) 47 | ); 48 | } 49 | 50 | if ($childContentText !== null) { 51 | $base['child']['child'] = array( 52 | 'tag' => 'div', 53 | 'attributes' => array('class' => 'tab-pane active'), 54 | 'child' => array( 55 | 'tag' => 'p', 56 | 'content' => $childContentText 57 | ) 58 | ); 59 | } 60 | 61 | return $base; 62 | } 63 | 64 | private function createLinks() 65 | { 66 | return array( 67 | array('Section 1', "

    I'm in Section 1.

    "), 68 | array('Section 2', "

    Howdy, I'm in Section 2.

    "), 69 | array('Section 3', "

    What up girl, this is Section 3.

    ") 70 | ); 71 | } 72 | 73 | public function testBasicTab() 74 | { 75 | $arr = $this->createLinks(); 76 | 77 | $tabs = Tabbable::tabs(Navigation::links($arr)); 78 | $matcher = $this->createMatcher('above','tabs'); 79 | 80 | $this->assertTag($matcher, $tabs); 81 | } 82 | 83 | public function testBasicPills() 84 | { 85 | $arr = $this->createLinks(); 86 | 87 | $tabs = Tabbable::pills(Navigation::links($arr)); 88 | $matcher = $this->createMatcher('above','pills'); 89 | 90 | $this->assertTag($matcher, $tabs); 91 | } 92 | 93 | public function testBasicLists() 94 | { 95 | $arr = $this->createLinks(); 96 | 97 | $tabs = Tabbable::lists(Navigation::links($arr)); 98 | $matcher = $this->createMatcher('above','list'); 99 | 100 | $this->assertTag($matcher, $tabs); 101 | } 102 | 103 | public function testLeftTab() 104 | { 105 | $arr = $this->createLinks(); 106 | 107 | $tabs = Tabbable::tabs_left(Navigation::links($arr)); 108 | $matcher = $this->createMatcher('left','tabs'); 109 | 110 | $this->assertTag($matcher, $tabs); 111 | } 112 | 113 | public function testRightTab() 114 | { 115 | $arr = $this->createLinks(); 116 | 117 | $tabs = Tabbable::tabs_right(Navigation::links($arr)); 118 | $matcher = $this->createMatcher('right','tabs'); 119 | 120 | $this->assertTag($matcher, $tabs); 121 | } 122 | 123 | public function testBelowTab() 124 | { 125 | $arr = $this->createLinks(); 126 | 127 | $tabs = Tabbable::tabs_below(Navigation::links($arr)); 128 | $matcher = $this->createMatcher('below','tabs'); 129 | 130 | $this->assertTag($matcher, $tabs); 131 | } 132 | 133 | public function testStacked() 134 | { 135 | $arr = $this->createLinks(); 136 | 137 | $tabs = Tabbable::tabs(Navigation::links($arr))->stacked(); 138 | $matcher = $this->createMatcher('above','tabs'); 139 | $matcher['descendant']['attributes']['class'] .= ' nav-stacked'; 140 | $this->assertTag($matcher, $tabs); 141 | } 142 | 143 | public function testMenuAttributes() 144 | { 145 | $arr = $this->createLinks(); 146 | 147 | $tabs = Tabbable::tabs(Navigation::links($arr))->menu_attributes(array('class' => 'foo', 'data-bar' => 'bar')); 148 | $matcher = $this->createMatcher('above','tabs'); 149 | $matcher['descendant']['attributes']['class'] = 'foo ' . $matcher['descendant']['attributes']['class']; 150 | $matcher['descendant']['attributes']['data-bar'] = 'bar'; 151 | $this->assertTag($matcher, $tabs); 152 | } 153 | 154 | public function testContentAttributes() 155 | { 156 | $arr = $this->createLinks(); 157 | 158 | $tabs = Tabbable::tabs(Navigation::links($arr))->content_attributes(array('class' => 'foo', 'data-bar' => 'bar')); 159 | $matcher = $this->createMatcher('above','tabs'); 160 | $matcher['child']['attributes']['class'] = 'foo ' . $matcher['child']['attributes']['class']; 161 | $matcher['child']['attributes']['data-bar'] = 'bar'; 162 | $this->assertTag($matcher, $tabs); 163 | } 164 | 165 | public function testActiveTab() 166 | { 167 | $arr = $this->createLinks(); 168 | 169 | //Set second tab as active 170 | $arr[1][2] = true; 171 | 172 | $tabs = Tabbable::tabs(Navigation::links($arr)); 173 | 174 | //Set matcher with 175 | $matcher = $this->createMatcher('above','tabs', 'Section 2', "Howdy, I'm in Section 2."); 176 | $this->assertTag($matcher, $tabs); 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /tests/Button.test.php: -------------------------------------------------------------------------------- 1 | 'button', 15 | 'attributes' => array( 16 | 'type' => 'button', 17 | 'data-foo' => 'bar', 18 | 'class' => 'foo'.$class.' btn'), 19 | 'content' => 'foo', 20 | ); 21 | } 22 | 23 | private function createLink($class) 24 | { 25 | $link = $this->createMatcher($class); 26 | $link['tag'] = 'a'; 27 | $link['attributes']['href'] = '#'; 28 | 29 | unset($link['attributes']['type']); 30 | 31 | return $link; 32 | } 33 | 34 | private function createSubmit($class) 35 | { 36 | $submit = $this->createMatcher($class); 37 | $submit['attributes']['type'] = 'submit'; 38 | 39 | return $submit; 40 | } 41 | 42 | private function createReset($class) 43 | { 44 | $reset = $this->createMatcher($class); 45 | $reset['attributes']['type'] = 'reset'; 46 | 47 | return $reset; 48 | } 49 | 50 | private function createIcon() 51 | { 52 | return array( 53 | 'tag' => 'i', 54 | 'attributes' => array( 55 | 'class' => 'icon-folder-open' 56 | ) 57 | ); 58 | } 59 | 60 | public function testDeemphasizeLink() 61 | { 62 | $button = Button::Link('#', 'foo', $this->testAttributes)->deemphasize(); 63 | $matcher = $this->createMatcher('link'); 64 | $matcher['tag'] = 'a'; 65 | $matcher['attributes']['href'] = '#'; 66 | unset($matcher['attributes']['type']); 67 | 68 | $this->assertTag($matcher, $button); 69 | } 70 | 71 | // Data providers ----------------------------------------------- / 72 | 73 | public function classes() 74 | { 75 | return array( 76 | array('normal'), 77 | array('custom'), 78 | array('error'), 79 | array('info'), 80 | array('inverse'), 81 | array('success'), 82 | array('warning'), 83 | ); 84 | } 85 | 86 | /** 87 | * @dataProvider classes 88 | */ 89 | public function testButton($class) 90 | { 91 | $button = Button::$class('foo', $this->testAttributes)->__toString(); 92 | $matcher = $this->createMatcher($class); 93 | 94 | $this->assertTag($matcher, $button); 95 | } 96 | 97 | /** 98 | * @dataProvider classes 99 | */ 100 | public function testButtonBlock($class) 101 | { 102 | $button = Button::$class('foo', $this->testAttributes)->block(); 103 | $matcher = $this->createMatcher($class); 104 | $matcher['attributes']['class'] .= ' btn-block'; 105 | $this->assertTag($matcher, $button); 106 | } 107 | 108 | /** 109 | * @dataProvider classes 110 | */ 111 | public function testLink($class) 112 | { 113 | if($class == 'normal') $class = 'link'; 114 | $method = $class.'_link'; 115 | 116 | $button = Button::$method('#', 'foo', $this->testAttributes)->__toString(); 117 | $matcher = $this->createLink($class); 118 | 119 | $this->assertTag($matcher, $button); 120 | } 121 | 122 | /** 123 | * @dataProvider classes 124 | */ 125 | public function testSubmit($class) 126 | { 127 | if($class == 'normal') $class = 'submit'; 128 | $method = $class.'_submit'; 129 | 130 | $button = Button::$method('foo', $this->testAttributes)->__toString(); 131 | $matcher = $this->createSubmit($class); 132 | 133 | $this->assertTag($matcher, $button); 134 | } 135 | 136 | /** 137 | * @dataProvider classes 138 | */ 139 | public function testReset($class) 140 | { 141 | if($class == 'normal') $class = 'reset'; 142 | $method = $class.'_reset'; 143 | 144 | $button = Button::$method('foo', $this->testAttributes)->__toString(); 145 | $matcher = $this->createReset($class); 146 | 147 | $this->assertTag($matcher, $button); 148 | } 149 | 150 | public function testWithIcon() 151 | { 152 | $button1 = Button::info('foo', $this->testAttributes)->with_icon('folder_open')->__toString(); 153 | $button2 = Button::info('foo', $this->testAttributes)->prepend_with_icon('folder_open')->__toString(); 154 | $matcher = $this->createMatcher('info'); 155 | $matcher['child'] = $this->createIcon(); 156 | 157 | $this->assertTag($matcher, $button1); 158 | $this->assertTag($matcher, $button2); 159 | } 160 | 161 | public function testWithIconAppended() 162 | { 163 | $button = Button::info('foo', $this->testAttributes)->append_with_icon('folder_open')->__toString(); 164 | $matcher = $this->createMatcher('info'); 165 | $matcher['child'] = $this->createIcon(); 166 | $exact = 167 | ''; 170 | 171 | $this->assertTag($matcher, $button); 172 | $this->assertEquals($exact, $button); 173 | } 174 | 175 | public function testDropDown() 176 | { 177 | $button = Button::info('foo', $this->testAttributes, true)->__toString(); 178 | $matcher = $this->createMatcher('info'); 179 | $exact = 180 | ''; 183 | 184 | $this->assertTag($matcher, $button); 185 | $this->assertEquals($exact, $button); 186 | } 187 | 188 | public function testMultipleButtons() 189 | { 190 | $buttons = Button::info('foo').Button::success('foo'); 191 | $matcher = ''; 192 | 193 | $this->assertEquals($matcher, $buttons); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/Bootstrapper/Paginator.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Paginator extends \Laravel\Paginator 20 | { 21 | /** 22 | * Paginator types 23 | * @var constant 24 | */ 25 | const ALIGN_LEFT = ''; 26 | const ALIGN_CENTER = ' pagination-centered'; 27 | const ALIGN_RIGHT = ' pagination-right'; 28 | 29 | const SIZE_DEFAULT = ''; 30 | const SIZE_LARGE = ' pagination-large'; 31 | const SIZE_SMALL = ' pagination-small'; 32 | const SIZE_MINI = ' pagination-mini'; 33 | 34 | protected $pager_aligned = false; 35 | 36 | /** 37 | * The "dots" element used in the pagination slider. 38 | * 39 | * @var string 40 | */ 41 | protected $dots = '
  • ...
  • '; 42 | 43 | /** 44 | * Create the HTML pagination links. 45 | * 46 | * @param bool $align align pager 47 | * 48 | * @return string 49 | */ 50 | public function pager($align = false) 51 | { 52 | $this->pager_aligned = $align; 53 | 54 | return '
      '.$this->previous().$this->next().'
    '; 55 | } 56 | 57 | /** 58 | * Create the HTML pagination links. 59 | * 60 | * Typically, an intelligent, "sliding" window of links will be rendered based 61 | * on the total number of pages, the current page, and the number of adjacent 62 | * pages that should rendered. This creates a beautiful paginator similar to 63 | * that of Google's. 64 | * 65 | * Example: 1 2 ... 23 24 25 [26] 27 28 29 ... 51 52 66 | * 67 | * If you wish to render only certain elements of the pagination control, 68 | * explore some of the other public methods available on the instance. 69 | * 70 | * 71 | * // Render the pagination links 72 | * echo $paginator->links(); 73 | * 74 | * // Render the pagination links using a given window size 75 | * echo $paginator->links(5); 76 | * 77 | * 78 | * @param int $adjacent Number of adjacent items 79 | * @param string $alignment Alignment of pagination 80 | * 81 | * @return string 82 | */ 83 | public function links($adjacent = 3, $alignment = self::ALIGN_LEFT, $size = self::SIZE_DEFAULT) 84 | { 85 | if ($this->last <= 1) return ''; 86 | 87 | // The hard-coded seven is to account for all of the constant elements in a 88 | // sliding range, such as the current page, the two ellipses, and the two 89 | // beginning and ending pages. 90 | // 91 | // If there are not enough pages to make the creation of a slider possible 92 | // based on the adjacent pages, we will simply display all of the pages. 93 | // Otherwise, we will create a "truncating" sliding window. 94 | if ($this->last < 7 + ($adjacent * 2)) { 95 | $links = $this->range(1, $this->last); 96 | } else { 97 | $links = $this->slider($adjacent); 98 | } 99 | 100 | $content = $this->previous().' '.$links.' '.$this->next(); 101 | 102 | 103 | $attributes = array("class" => "pagination".$alignment.$size); 104 | 105 | return '
      '.$content.'
    '; 106 | } 107 | 108 | 109 | /** 110 | * Create a chronological pagination element, such as a "previous" or "next" link. 111 | * 112 | * @param string $element Pagination element 113 | * @param int $page Curent page 114 | * @param string $text Text for current element 115 | * @param Closure $disabled function to determine if disabled or not 116 | * 117 | * @return string 118 | */ 119 | protected function element($element, $page, $text, $disabled) 120 | { 121 | $class = $this->pager_aligned ? "{$element}" : ""; 122 | 123 | if (is_null($text)) { 124 | $text = \Lang::line("pagination.{$element}")->get($this->language); 125 | } 126 | 127 | // Each consumer of this method provides a "disabled" Closure which can 128 | // be used to determine if the element should be a span element or an 129 | // actual link. For example, if the current page is the first page, 130 | // the "first" element should be a span instead of a link. 131 | if ($disabled($this->page, $this->last)) { 132 | $class .= " disabled"; 133 | 134 | return ''.HTML::entities($text).''; 135 | } else { 136 | return ''.$this->link($page, $text, null).''; 137 | } 138 | } 139 | 140 | 141 | 142 | /** 143 | * Build a range of numeric pagination links. 144 | * 145 | * For the current page, an HTML span element will be generated instead of a link. 146 | * 147 | * @param int $start starting position 148 | * @param int $end ending position 149 | * 150 | * @return string 151 | */ 152 | protected function range($start, $end) 153 | { 154 | $pages = array(); 155 | 156 | // To generate the range of page links, we will iterate through each page 157 | // and, if the current page matches the page, we will generate a span, 158 | // otherwise we will generate a link for the page. The span elements 159 | // will be assigned the "current" CSS class for convenient styling. 160 | for ($page = $start; $page <= $end; $page++) { 161 | if ($this->page == $page) { 162 | $pages[] = '
  • '.HTML::entities($page).'
  • '; 163 | } else { 164 | $pages[] = '
  • '.$this->link($page, $page, null).'
  • '; 165 | } 166 | } 167 | 168 | return implode(' ', $pages); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /tests/Table.test.php: -------------------------------------------------------------------------------- 1 | 'table', 12 | 'attributes' => array( 13 | 'data-foo' => 'bar', 14 | 'class' => 'foo table' 15 | ), 16 | ); 17 | 18 | private function matchFull($header = false) 19 | { 20 | return array( 21 | 'tag' => 'tr', 22 | 'attributes' => array( 23 | 'class' => 'foo full-row', 24 | 'data-foo' => 'bar', 25 | ), 26 | 'child' => array( 27 | 'tag' => $header ? 'th' : 'td', 28 | 'attributes' => array('colspan' => 4), 29 | 'content' => 'foo', 30 | ), 31 | ); 32 | } 33 | 34 | private $body = array(array('foo' => 'foo', 'bar' => 'bar', 'kal' => 'kal')); 35 | 36 | public function setUp() 37 | { 38 | Table::open(); 39 | } 40 | 41 | public function tearDown() 42 | { 43 | Config::set('table.classes', array()); 44 | Table::close(); 45 | } 46 | 47 | // Tests --------------------------------------------------------- / 48 | 49 | public function testOpen() 50 | { 51 | $table = Table::open($this->testAttributes); 52 | 53 | $this->assertTag($this->matcher, $table); 54 | } 55 | 56 | public function testDefaultOpen() 57 | { 58 | Config::set('table.classes', array('striped', 'foo', 'hover')); 59 | $table = Table::open(); 60 | 61 | $this->assertEquals('', $table); 62 | } 63 | 64 | public function testStaticOpen() 65 | { 66 | $table = Table::bordered_condensed_foobar_open($this->testAttributes); 67 | $matcher = $this->matcher; 68 | $matcher['attributes']['class'] = 'foo table-bordered table-condensed table'; 69 | 70 | $this->assertTag($matcher, $table); 71 | } 72 | 73 | public function testClose() 74 | { 75 | $close = Table::close(); 76 | 77 | $this->assertEquals('
    ', $close); 78 | } 79 | 80 | public function testHeadersSimple() 81 | { 82 | $headers = Table::headers('foo', 'bar', 'tel', 'sub'); 83 | $headers = str_replace(PHP_EOL, null, $headers); 84 | 85 | $matcher = 86 | ''. 87 | 'foo'. 88 | 'bar'. 89 | 'tel'. 90 | 'sub'. 91 | ''; 92 | 93 | $this->assertEquals($matcher, $headers); 94 | } 95 | 96 | public function testHeadersComplex() 97 | { 98 | $headers = Table::headers(array( 99 | 'foo' => $this->testAttributes, 100 | 'bar' => $this->testAttributes)); 101 | $headers = str_replace(PHP_EOL, null, $headers); 102 | 103 | $matcher = 104 | ''. 105 | 'foo'. 106 | 'bar'. 107 | ''; 108 | 109 | $this->assertEquals($matcher, $headers); 110 | } 111 | 112 | public function testFullRow() 113 | { 114 | Table::headers('foo', 'foo', 'foo', 'foo'); 115 | $fullRow = Table::full_row('foo', $this->testAttributes); 116 | $matcher = $this->matchFull(); 117 | 118 | $this->assertTag($matcher, $fullRow); 119 | } 120 | 121 | public function testFullHeader() 122 | { 123 | Table::headers('foo', 'foo', 'foo', 'foo'); 124 | $fullRow = Table::full_header('foo', $this->testAttributes); 125 | $matcher = $this->matchFull(true); 126 | 127 | $this->assertTag($matcher, $fullRow); 128 | } 129 | 130 | public function testBody() 131 | { 132 | $body = Table::body($this->body)->__toString(); 133 | $matcher = 'foobarkal'; 134 | 135 | $this->assertEquals($matcher, $body); 136 | } 137 | 138 | public function testIgnore() 139 | { 140 | $body = Table::body($this->body)->ignore('foo', 'bar')->__toString(); 141 | $matcher = 'kal'; 142 | 143 | $this->assertEquals($matcher, $body); 144 | } 145 | 146 | public function testOrder() 147 | { 148 | $body = Table::body($this->body)->order('kal', 'bar', 'foo')->__toString(); 149 | $matcher = 'kalbarfoo'; 150 | 151 | $this->assertEquals($matcher, $body); 152 | } 153 | 154 | public function testOrderIgnore() 155 | { 156 | $body = Table::body($this->body)->ignore('foo')->order('kal')->__toString(); 157 | $matcher = 'kalbar'; 158 | 159 | $this->assertEquals($matcher, $body); 160 | } 161 | 162 | public function testDynamicColumn() 163 | { 164 | $body = Table::body(array(array('foo' => 'bar')))->fur('var')->__toString(); 165 | $matcher = 'barvar'; 166 | 167 | $this->assertEquals($matcher, $body); 168 | } 169 | 170 | public function testReplaceColumns() 171 | { 172 | $body = Table::body(array(array('foo' => 'foo')))->foo('bar')->__toString(); 173 | $matcher = 'bar'; 174 | 175 | $this->assertEquals($matcher, $body); 176 | } 177 | 178 | public function testUnderscoreReplacement() 179 | { 180 | $body = Table::body(array(array('foo_bar' => 'foo')))->foo_bar('bar')->bar_foo('foo')->__toString(); 181 | $matcher = 'barfoo'; 182 | 183 | $this->assertEquals($matcher, $body); 184 | } 185 | 186 | public function testAlwaysIgnore() 187 | { 188 | Config::set('table.ignore', array('foo', 'bar')); 189 | 190 | $body = Table::body($this->body)->__toString(); 191 | $matcher = 'kal'; 192 | 193 | $this->assertEquals($matcher, $body); 194 | } 195 | 196 | public function testAlwaysIgnoreOverridesManuallyIgnore() 197 | { 198 | Config::set('table.ignore', array('foo')); 199 | 200 | $body = Table::body($this->body)->ignore('bar')->__toString(); 201 | $matcher = 'fookal'; 202 | 203 | $this->assertEquals($matcher, $body); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/Bootstrapper/Navbar.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Navbar 20 | { 21 | /** 22 | * The current Navbar's attributes 23 | * 24 | * @var array 25 | */ 26 | private $attributes = array(); 27 | 28 | /** 29 | * Whether the current Navbar should use automatic routing 30 | * 31 | * @var boolean 32 | */ 33 | private $autoroute = true; 34 | 35 | /** 36 | * Contains the current Navbar's brand (if there is one) 37 | * 38 | * @var array 39 | */ 40 | private $brand = array(); 41 | 42 | /** 43 | * Whether the current Navbar should be collapsible or not 44 | * 45 | * @var boolean 46 | */ 47 | private $collapsible = false; 48 | 49 | /** 50 | * All menus or elements of the current Navbar 51 | * 52 | * @var array 53 | */ 54 | private $menus = array(); 55 | 56 | /** 57 | * The current Navbar's type 58 | * 59 | * @var constant 60 | */ 61 | private $type = Navbar::STATIC_BAR; 62 | 63 | /** 64 | * The Navbar types 65 | * @var constant 66 | */ 67 | const STATIC_BAR = ''; 68 | const FIX_TOP = 'navbar-fixed-top'; 69 | const FIX_BOTTOM = 'navbar-fixed-bottom'; 70 | 71 | /** 72 | * Create a new Navbar instance. 73 | * 74 | * @param array $attributes An array of attributes for the current navbar 75 | * @param const $type The type of Navbar to create 76 | * 77 | * @return Navbar 78 | */ 79 | public static function create($attributes = array(), $type = Navbar::STATIC_BAR) 80 | { 81 | // Fetch current instance 82 | $instance = new Navbar; 83 | 84 | // Save given parameters 85 | $instance->attributes = $attributes; 86 | $instance->type = $type; 87 | 88 | return $instance; 89 | } 90 | 91 | /** 92 | * Set the autoroute to true or false 93 | * 94 | * @param boolean $autoroute The new autoroute value 95 | * 96 | * @return Navbar 97 | */ 98 | public function autoroute($autoroute) 99 | { 100 | $this->autoroute = $autoroute; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * Add menus or strings to the current Navbar 107 | * 108 | * @param mixed $menus An array of items or a string 109 | * @param array $attributes An array of attributes to use 110 | * 111 | * @return Navbar 112 | */ 113 | public function with_menus($menus, $attributes = array()) 114 | { 115 | $this->menus[] = is_string($menus) 116 | ? $menus 117 | : array('attributes' => $attributes, 'items' => $menus); 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Add a brand to the current Navbar 124 | * 125 | * @param string $brand The brand name 126 | * @param string $brand_url The brand URL 127 | * 128 | * @return Navbar 129 | */ 130 | public function with_brand($brand, $brand_url) 131 | { 132 | $this->brand = array( 133 | 'name' => $brand, 134 | 'url' => $brand_url, 135 | ); 136 | 137 | return $this; 138 | } 139 | 140 | /** 141 | * Activates collapsible on the current Navbar 142 | * 143 | * @return Navbar 144 | */ 145 | public function collapsible() 146 | { 147 | $this->collapsible = true; 148 | 149 | return $this; 150 | } 151 | 152 | /** 153 | * Prints out the current Navbar in case it doesn't do it automatically 154 | * 155 | * @return string A Navbar 156 | */ 157 | public function get() 158 | { 159 | return static::__toString(); 160 | } 161 | 162 | /** 163 | * Writes the current Navbar 164 | * 165 | * @return string A Bootstrap navbar 166 | */ 167 | public function __toString() 168 | { 169 | $attributes = Helpers::add_class($this->attributes, 'navbar '.$this->type); 170 | 171 | // Open navbar containers 172 | $html = ''; 173 | $html .= '
    '; 208 | 209 | return $html; 210 | } 211 | 212 | /** 213 | * Allows creation of inverted navbar 214 | * 215 | * @param string $method The method to call 216 | * @param array $parameters An array of parameters 217 | * 218 | * @return Navbar 219 | */ 220 | public static function __callStatic($method, $parameters) 221 | { 222 | if ($method == 'inverse') { 223 | $attributes = array_get($parameters, 0); 224 | $type = array_get($parameters, 1); 225 | $attributes = Helpers::add_class($attributes, 'navbar-inverse'); 226 | 227 | return static::create($attributes, $type); 228 | } else return static::create(); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/Bootstrapper/Progress.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Progress 20 | { 21 | /** 22 | * Progress bar types 23 | * @var constant 24 | */ 25 | const NORMAL = ''; 26 | const DANGER = 'progress-danger'; 27 | const INFO = 'progress-info'; 28 | const SUCCESS = 'progress-success'; 29 | const WARNING = 'progress-warning'; 30 | 31 | /** 32 | * Adds a bar to the current progress bar 33 | * 34 | * @param integer $amounts A progress amount 35 | * @param string $type Type of progress bar 36 | * @param array $attributes array of attributes for progress bar 37 | * 38 | * @return string 39 | */ 40 | protected static function show($amounts = 0, $type = Progress::NORMAL, $attributes = array()) 41 | { 42 | if(is_array($amounts)) $type = Progress::NORMAL; 43 | $attributes = Helpers::add_class($attributes, 'progress '.$type); 44 | 45 | // Create the progress bar(s) 46 | $progress = ''; 47 | if(!is_array($amounts)) $amounts = array((int) $amounts => null); 48 | foreach($amounts as $amount => $style) 49 | $progress .= static::bar($amount, $style); 50 | $progress .= ''; 51 | 52 | return $progress; 53 | } 54 | 55 | /** 56 | * Adds a bar to the current progress bar 57 | * 58 | * @param integer $amount A progress amount 59 | * @param string $style A class to use to style the bar 60 | * 61 | * @return string 62 | */ 63 | protected static function bar($amount = 0, $style = null) 64 | { 65 | // Prepend bar style with 'bar-' 66 | $style = $style ? ' bar-'.$style : null; 67 | 68 | return '
    '; 69 | } 70 | 71 | /** 72 | * Create a new Normal Progress Bar. 73 | * 74 | * @param integer $amount Amount filled 75 | * @param array $attributes array of attributes for progress bar 76 | * 77 | * @return string 78 | */ 79 | public static function normal($amount = 0, $attributes = array()) 80 | { 81 | return static::show($amount, Progress::NORMAL, $attributes); 82 | } 83 | 84 | /** 85 | * Create a new Success Progress Bar. 86 | * 87 | * @param integer $amount Amount filled 88 | * @param array $attributes array of attributes for progress bar 89 | * 90 | * @return string 91 | */ 92 | public static function success($amount = 0, $attributes = array()) 93 | { 94 | return static::show($amount, Progress::SUCCESS, $attributes); 95 | } 96 | 97 | /** 98 | * Create a new Info Progress Bar. 99 | * 100 | * @param integer $amount Amount filled 101 | * @param array $attributes array of attributes for progress bar 102 | * 103 | * @return string 104 | */ 105 | public static function info($amount = 0, $attributes = array()) 106 | { 107 | return static::show($amount, Progress::INFO, $attributes); 108 | } 109 | 110 | /** 111 | * Create a new Warning Progress Bar. 112 | * 113 | * @param integer $amount Amount filled 114 | * @param array $attributes array of attributes for progress bar 115 | * 116 | * @return string 117 | */ 118 | public static function warning($amount = 0, $attributes = array()) 119 | { 120 | return static::show($amount, Progress::WARNING, $attributes); 121 | } 122 | 123 | /** 124 | * Create a new Danger Progress Bar. 125 | * 126 | * @param integer $amount Amount filled 127 | * @param array $attributes array of attributes for progress bar 128 | * 129 | * @return string 130 | */ 131 | public static function danger($amount = 0, $attributes = array()) 132 | { 133 | return static::show($amount, Progress::DANGER, $attributes); 134 | } 135 | 136 | /** 137 | * Automatically computes the progress bar's class according to the amount 138 | * Thus 0 giving it a danger class and 100 giving it a success class 139 | * 140 | * @param integer $amount Amount filled 141 | * @param array $attributes array of attributes for progress bar 142 | * 143 | * @return string 144 | */ 145 | public static function automatic($amount = 0, $attributes = array()) 146 | { 147 | $progress = array(PROGRESS::DANGER, Progress::WARNING, Progress::INFO, Progress::SUCCESS); 148 | $progress = array_get($progress, floor($amount / 25), Progress::SUCCESS); 149 | 150 | return static::show($amount, $progress, $attributes); 151 | } 152 | 153 | /** 154 | * Checks call to see if we can create a progress bar from a magic call (for you wizards). 155 | * normal_striped_active, info_striped, etc... 156 | * 157 | * @param string $method Method name 158 | * @param array $parameters Method parameters 159 | * 160 | * @return mixed 161 | */ 162 | public static function __callStatic($method, $parameters) 163 | { 164 | $method_array = explode('_', strtolower($method)); 165 | 166 | $types = array('normal', 'success', 'info', 'warning', 'danger', 'automatic'); 167 | $type_found = array_intersect($method_array, $types); 168 | 169 | if (count($type_found) > 0) { 170 | $function = $type_found[key($type_found)]; 171 | 172 | // Set default $attributes and check for a set value 173 | $attributes = array(); 174 | if (isset($parameters[1])) { 175 | if (is_array($parameters[1])) { 176 | $attributes = $parameters[1]; 177 | } else { 178 | throw new \InvalidArgumentException("Tabbable attributes parameter should be an array of attributes"); 179 | } 180 | } 181 | 182 | if (in_array('striped', $method_array)) { 183 | $attributes = Helpers::add_class($attributes, 'progress-striped'); 184 | } 185 | 186 | if (in_array('active', $method_array)) { 187 | $attributes = Helpers::add_class($attributes, 'active'); 188 | } 189 | 190 | return static::$function($parameters[0], $attributes); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/Bootstrapper/DropdownButton.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class DropdownButton 20 | { 21 | /** 22 | * The current dropdown instance 23 | * @var DropdownButton 24 | */ 25 | protected static $dropdown = null; 26 | 27 | /** 28 | * The main button's class 29 | * @var string 30 | */ 31 | protected $type = null; 32 | 33 | /** 34 | * The main button's label 35 | * @var string 36 | */ 37 | protected $label = null; 38 | 39 | /** 40 | * The dropdown's links 41 | * @var array 42 | */ 43 | protected $links = array(); 44 | 45 | /** 46 | * The dropdown's attributes 47 | * @var array 48 | */ 49 | protected $attributes = array(); 50 | 51 | /** 52 | * Whether the dropdown should align right 53 | * @var boolean 54 | */ 55 | protected $pullRight = false; 56 | 57 | /** 58 | * Whether button should be a split button or not 59 | * @var boolean 60 | */ 61 | protected $split = false; 62 | 63 | /** 64 | * Whether the dropdown's links should come up or down 65 | * @var boolean 66 | */ 67 | protected $dropup = false; 68 | 69 | /** 70 | * Whether links should be automatically routed or not 71 | * @var boolean 72 | */ 73 | protected $autoroute = true; 74 | 75 | /** 76 | * Checks call to see if we can create a button from a magic call (for you wizards). 77 | * normal, mini_primary, large_warning, danger, etc... 78 | * 79 | * @param string $method Name of missing method 80 | * @param array $parameters array of parameters passed to missing method 81 | * 82 | * @return mixed 83 | */ 84 | public static function __callStatic($method, $parameters) 85 | { 86 | $method_array = explode('_', strtolower($method)); 87 | 88 | // Get the dropdown's button text 89 | $label = array_get($parameters, 0, null); 90 | 91 | // Get the dropdown's links 92 | $links = array_get($parameters, 1, array()); 93 | if(!is_array($links)) throw new \InvalidArgumentException('The dropdown\'s links should be an array'); 94 | 95 | // Get the dropdown's attributes 96 | $attributes = array_get($parameters, 2, array()); 97 | if(!is_array($attributes)) throw new \InvalidArgumentException('Attributes should be an array'); 98 | 99 | // Filter the classes given and concatenate them 100 | $type = ''; 101 | foreach ($method_array as $class) { 102 | if ($class != 'normal') $type .= ' btn-'.$class; 103 | } 104 | 105 | // Create the new dropdown 106 | static::$dropdown = new static($label, $links, $attributes, $type); 107 | 108 | return static::$dropdown; 109 | } 110 | 111 | /** 112 | * Creates a new button dropdown 113 | * 114 | * @param string $label Label Text 115 | * @param array $links dropdown links 116 | * @param array $attributes Attributes to apply the dropdown itself 117 | * @param string $type Type of dropdown 118 | */ 119 | public function __construct($label, $links, $attributes, $type = null) 120 | { 121 | $this->label = $label; 122 | 123 | $this->links = $links; 124 | 125 | $this->attributes = $attributes; 126 | 127 | $this->type .= $type; 128 | } 129 | 130 | /** 131 | * Dynamically set an attribute 132 | * 133 | * @param string $attribute Attributes to apply the dropdown itself 134 | * @param string $value Value of dropdown 135 | * 136 | * @return object dropdownbutton instance 137 | */ 138 | public function __call($attribute, $value) 139 | { 140 | // Replace underscores 141 | $attribute = str_replace('_', '-', $attribute); 142 | 143 | // Get value and set it 144 | $value = array_get($value, 0, 'true'); 145 | $this->attributes[$attribute] = $value; 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * Outputs the current Dropdown in instance 152 | * 153 | * @return string A Dropdown menu 154 | */ 155 | public function __toString() 156 | { 157 | // Base class 158 | $this->attributes = Helpers::add_class($this->attributes, 'btn-group'); 159 | 160 | // Pull right 161 | $listAttributes = $this->pullRight 162 | ? array('class' => 'pull-right') 163 | : array(); 164 | 165 | // Dropup 166 | if ($this->dropup) $this->attributes['class'] .= ' dropup'; 167 | 168 | $html = 'attributes).'>'; 169 | 170 | //If split is false make this button dropdown 171 | $html .= Form::button($this->label, array('class' => $this->type), !$this->split); 172 | 173 | //Add split button if needed 174 | if ($this->split) { 175 | $html .= Form::button('', array('class' => $this->type), true); 176 | } 177 | 178 | $html .= Navigation::dropdown($this->links, $listAttributes, $this->autoroute); 179 | $html .= ''; 180 | 181 | return $html; 182 | } 183 | 184 | // Public methods ---------------------------------------------- / 185 | 186 | /** 187 | * Pull the dropdown's links to the right 188 | * 189 | * @param boolean $pullRight Pull menu to the right 190 | * 191 | * @return object dropdownbutton instance 192 | */ 193 | public function pull_right($pullRight = true) 194 | { 195 | $this->pullRight = $pullRight; 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Drop the menu up or down 202 | * 203 | * @param boolean $dropup Make menu go up 204 | * 205 | * @return object dropdownbutton instance 206 | */ 207 | public function dropup($dropup = true) 208 | { 209 | $this->dropup = $dropup; 210 | 211 | return $this; 212 | } 213 | 214 | /** 215 | * Make button a split dropdown button 216 | * 217 | * @param boolean $split Make split button 218 | * 219 | * @return object dropdownbutton instance 220 | */ 221 | public function split($split = true) 222 | { 223 | $this->split = $split; 224 | 225 | return $this; 226 | } 227 | 228 | /** 229 | * Auto route links or not 230 | * 231 | * @param boolean $autoroute Should auto route links 232 | * 233 | * @return object dropdownbutton instance 234 | */ 235 | public function autoroute($autoroute = true) 236 | { 237 | $this->autoroute = $autoroute; 238 | 239 | return $this; 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/Bootstrapper/MediaObject.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class MediaObject 20 | { 21 | /** 22 | * The current MediaObject instance 23 | * @var MediaObject 24 | */ 25 | public static $object; 26 | 27 | /** 28 | * Whether the MediaObjects should be rendered as a list 29 | * @var boolean 30 | */ 31 | private static $listed = false; 32 | 33 | /** 34 | * An array of nested Media objects 35 | * @var array 36 | */ 37 | public $nested = array(); 38 | 39 | /** 40 | * The body of the media object 41 | * @var string 42 | */ 43 | private $content = null; 44 | 45 | /** 46 | * The title of the media object 47 | * @var string 48 | */ 49 | private $title = null; 50 | 51 | /** 52 | * The media of the media object 53 | * @var string 54 | */ 55 | private $media = null; 56 | 57 | /** 58 | * The media object's attributes 59 | * @var array 60 | */ 61 | private $attributes = array(); 62 | 63 | /** 64 | * Which side the media will be 65 | * @var string 66 | */ 67 | private $pull = 'left'; 68 | 69 | /** 70 | * Statically creates a new MediaObject instance 71 | * 72 | * @param string $content Its content 73 | * @param string $media Its media 74 | * @param array $attributes The media object's attributes 75 | * @return MediaObject 76 | */ 77 | public static function create($content, $media = null, $attributes = array()) 78 | { 79 | static::$object = new static($content); 80 | if($media) static::$object->with_image($media); 81 | if($attributes) static::$object->attributes = $attributes; 82 | 83 | return static::$object; 84 | } 85 | 86 | /** 87 | * Opens a Media Object list 88 | * 89 | * @param array $attributes An array of attributes 90 | * @return string An opening tag 91 | */ 92 | public static function open_list($attributes = array()) 93 | { 94 | static::$listed = true; 95 | $attributes = Helpers::add_class($attributes, 'media-list'); 96 | 97 | return ''; 98 | } 99 | 100 | /** 101 | * Closes an existing Media Objects list 102 | * 103 | * @return string A closing tag 104 | */ 105 | public static function close_list() 106 | { 107 | static::$listed = false; 108 | 109 | return ''; 110 | } 111 | 112 | /** 113 | * Creates a new MediaObject instance 114 | * 115 | * @param string $content Its content 116 | * @param string $media Its media 117 | */ 118 | public function __construct($content, $media = null) 119 | { 120 | $this->content = $content; 121 | } 122 | 123 | /** 124 | * Magic methods for MediaObject 125 | * 126 | * @param string $method The method called 127 | * @param array $parameters Its parameters 128 | * @return MediaObject 129 | */ 130 | public function __call($method, $parameters) 131 | { 132 | // Pull the media to a side 133 | if (starts_with($method, 'pull_')) { 134 | $side = explode('_', $method); 135 | $side = array_get($side, 1); 136 | 137 | return $this->pull($side); 138 | } 139 | 140 | // Add an heading to the media object 141 | if (starts_with($method, 'with_h')) { 142 | $heading = substr($method, -1); 143 | $title = array_get($parameters, 0); 144 | $attributes = array_get($parameters, 1, array()); 145 | $attributes = Helpers::add_class($attributes, 'media-heading'); 146 | $title = ''.$title.''; 147 | 148 | return $this->with_title($title); 149 | } 150 | } 151 | 152 | /** 153 | * Add a media to the MediaObject 154 | * 155 | * @param string $image The path to the image 156 | * @param string $alt Its alt attribute 157 | * @param array $attributes An array of supplementary attributes 158 | * @return MediaObject 159 | */ 160 | public function with_image($image, $alt = null, $attributes = array()) 161 | { 162 | $attributes = Helpers::add_class($attributes, 'media-object'); 163 | $this->media = HTML::image($image, null, $attributes); 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * Add a raw title to the MediaObject 170 | * 171 | * @param string $title The text of the title 172 | * @return MediaObject 173 | */ 174 | public function with_title($title) 175 | { 176 | $this->title = $title; 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * Pull the media to a side 183 | * 184 | * @param string $side Left or right 185 | * @return MediaObject 186 | */ 187 | public function pull($side) 188 | { 189 | if (in_array($side, array('left', 'right'))) { 190 | $this->pull = $side; 191 | } 192 | 193 | return $this; 194 | } 195 | 196 | /** 197 | * Nests a new instance of MediaObject into the existing one 198 | * 199 | * @param MediaObject $mediaObject The new MediaObject to nest 200 | * @return MediaObject 201 | */ 202 | public function nest(MediaObject $mediaObject) 203 | { 204 | $this->nested[] = $mediaObject; 205 | 206 | return $this; 207 | } 208 | 209 | /** 210 | * Prints out the MediaObject in memory 211 | * 212 | * @return string The HTML markup for the media object 213 | */ 214 | public function __toString() 215 | { 216 | // Whether objects should be printed as list elements or divs 217 | $children = static::$listed ? 'li' : 'div'; 218 | 219 | // Open the media object 220 | $attributes = Helpers::add_class($this->attributes, 'media'); 221 | $html = '<' .$children.HTML::attributes($attributes). '>'; 222 | 223 | // Add the media itself 224 | $html .= ''; 225 | $html .= $this->media; 226 | $html .= ''; 227 | 228 | // Add the title and body 229 | $html .= '
    '; 230 | if($this->title) $html .= $this->title; 231 | $html .= $this->content; 232 | 233 | // Render nested media objects (always as divs) 234 | if ($this->nested) { 235 | $listed = static::$listed; 236 | static::$listed = false; 237 | foreach ($this->nested as $mediaObject) { 238 | $html .= $mediaObject; 239 | } 240 | static::$listed = $listed; 241 | } 242 | 243 | // Close body 244 | $html .= '
    '; 245 | 246 | // Close object 247 | $html .=''; 248 | 249 | return $html; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/Bootstrapper/Alert.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Alert 20 | { 21 | /** 22 | * Alert styles 23 | * 24 | * @var constant 25 | */ 26 | const DANGER = 'alert-danger'; 27 | const ERROR = 'alert-error'; 28 | const INFO = 'alert-info'; 29 | const SUCCESS = 'alert-success'; 30 | const WARNING = 'alert-warning'; 31 | 32 | /** 33 | * The type of the alert 34 | * 35 | * @var enum 36 | */ 37 | private $type = Alert::SUCCESS; 38 | 39 | /** 40 | * The message for the alert. 41 | * 42 | * @var string 43 | */ 44 | private $message = false; 45 | 46 | /** 47 | * The current alert's attributes 48 | * 49 | * @var array 50 | */ 51 | private $attributes = array(); 52 | 53 | /** 54 | * Whether the current alert is closeable 55 | * 56 | * @var boolean 57 | */ 58 | private $isCloseable = true; 59 | 60 | /** 61 | * Whether the current alert is block or not. 62 | * 63 | * @var boolean 64 | */ 65 | private $isBlock = false; 66 | 67 | /** 68 | * Create a new Alert. 69 | * 70 | * @param string $type Type of alert 71 | * @param string $message Message in alert 72 | * @param bool $enable_close Is Alert closable 73 | * @param array $attributes Parent div attributes 74 | * 75 | * @return string Alert HTML 76 | */ 77 | protected static function show($type, $message, $attributes = array()) 78 | { 79 | $instance = new Alert; 80 | 81 | // Save given parameters 82 | $instance->type = $type; 83 | $instance->message = $message; 84 | $instance->attributes = $attributes; 85 | 86 | return $instance; 87 | } 88 | 89 | /** 90 | * Create a new Success Alert. 91 | * 92 | * @param string $message Message in alert 93 | * @param array $attributes Parent div attributes 94 | * 95 | * @return string Alert HTML 96 | */ 97 | public static function success($message, $attributes = array()) 98 | { 99 | return static::show(Alert::SUCCESS, $message, $attributes); 100 | } 101 | 102 | /** 103 | * Create a new Info Alert. 104 | * 105 | * @param string $message Message in alert 106 | * @param array $attributes Parent div attributes 107 | * 108 | * @return string Alert HTML 109 | */ 110 | public static function info($message, $attributes = array()) 111 | { 112 | return static::show(Alert::INFO, $message, $attributes); 113 | } 114 | 115 | /** 116 | * Create a new Warning Alert. 117 | * 118 | * @param string $message Message in alert 119 | * @param array $attributes Parent div attributes 120 | * 121 | * @return string Alert HTML 122 | */ 123 | public static function warning($message, $attributes = array()) 124 | { 125 | return static::show(Alert::WARNING, $message, $attributes); 126 | } 127 | 128 | /** 129 | * Create a new Error Alert. 130 | * 131 | * @param string $message Message in alert 132 | * @param array $attributes Parent div attributes 133 | * 134 | * @return string Alert HTML 135 | */ 136 | public static function error($message, $attributes = array()) 137 | { 138 | return static::show(Alert::ERROR, $message, $attributes); 139 | } 140 | 141 | /** 142 | * Create a new Danger Alert. 143 | * 144 | * @param string $message Message in alert 145 | * @param array $attributes Parent div attributes 146 | * 147 | * @return string Alert HTML 148 | */ 149 | public static function danger($message, $attributes = array()) 150 | { 151 | return static::show(Alert::DANGER, $message, $attributes); 152 | } 153 | 154 | /** 155 | * Create a new custom Alert. 156 | * This assumes you have created the appropriate css class for the alert type. 157 | * 158 | * @param string $type Type of alert 159 | * @param string $message Message in alert 160 | * @param array $attributes Parent div attributes 161 | * 162 | * @return string Alert HTML 163 | */ 164 | public static function custom($type, $message, $attributes = array()) 165 | { 166 | $type = 'alert-'.(string) $type; 167 | 168 | return static::show($type, $message, $attributes); 169 | } 170 | 171 | /** 172 | * Force the alert to be open 173 | * 174 | * @param bool $closeable If the alert should be closeable or not 175 | * 176 | * @return Alert 177 | */ 178 | public function open($closeable = false) 179 | { 180 | $this->isCloseable = $closeable; 181 | 182 | return $this; 183 | } 184 | 185 | 186 | /** 187 | * Make the alert block 188 | * 189 | * @param bool $block If the alert should be block or not 190 | * 191 | * @return Alert 192 | */ 193 | public function block($block = true) 194 | { 195 | $this->isBlock = $block; 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Prints out the current Alert in case it doesn't do it automatically 202 | * 203 | * @return string A Alert 204 | */ 205 | public function get() 206 | { 207 | return static::__toString(); 208 | } 209 | 210 | /** 211 | * Writes the current Alert 212 | * 213 | * @return string A Bootstrap Alert 214 | */ 215 | public function __toString() 216 | { 217 | $attr = Helpers::add_class($this->attributes, 'alert '.$this->type); 218 | 219 | if ($this->isBlock) { 220 | $attr = Helpers::add_class($attr, 'alert-block'); 221 | } 222 | 223 | $html = ''; 224 | 225 | // Add close icon if necessary 226 | if ($this->isCloseable) { 227 | $html .= HTML::link('#', '×', array('class' => 'close', 'data-dismiss' => 'alert')); 228 | } 229 | 230 | $html .= $this->message.''; 231 | 232 | return $html; 233 | } 234 | 235 | /** 236 | * Check to see if we're calling an informative alert 237 | * 238 | * @param string $method The function called 239 | * @param array $parameters Its parameters 240 | * 241 | * @return Alert 242 | */ 243 | public static function __callStatic($method, $parameters) 244 | { 245 | // Extract real method and type of alert 246 | $method = explode('_', $method); 247 | 248 | $instance = new Alert; 249 | 250 | // Search for "open_type" method 251 | $open = array_search('open', $method); 252 | if ($open !== false) { 253 | $instance->isCloseable = false; 254 | unset($method[$open]); 255 | } 256 | 257 | // Search for "block_type" method 258 | $block = array_search('block', $method); 259 | if ($block !== false) { 260 | $instance->isBlock = true; 261 | unset($method[$block]); 262 | } 263 | 264 | // Create Alert class 265 | $type = 'alert-'.implode("-", $method); 266 | 267 | // Save given parameters 268 | $instance->type = $type; 269 | $instance->message = array_get($parameters, 0); 270 | $instance->attributes = array_get($parameters, 1); 271 | 272 | return $instance; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /tests/Navigation.test.php: -------------------------------------------------------------------------------- 1 | rootMater('nav'.$class.$extraClass); 18 | } 19 | 20 | private function createDropdownMatcher($class = '') 21 | { 22 | $class = $class != '' ? ' '.$class : ''; 23 | 24 | return $this->rootMater('dropdown-menu'.$class); 25 | } 26 | 27 | private function rootMater($class) 28 | { 29 | return array( 30 | 'tag' => 'ul', 31 | 'attributes' => array( 32 | 'class' => $class 33 | ), 34 | 'children' => array( 35 | 'count' => 2, 36 | 'only' => array('tag' => 'li', 'child' => array('tag' => 'a')), 37 | ) 38 | ); 39 | } 40 | 41 | // Data providers ----------------------------------------------- / 42 | 43 | public function classes() 44 | { 45 | return array( 46 | array('lists'), 47 | array('pills'), 48 | array('tabs'), 49 | array('unstyled'), 50 | ); 51 | } 52 | 53 | // Tests --------------------------------------------------------- / 54 | 55 | public function testDivider() 56 | { 57 | $links = Navigation::links(array( 58 | array(Navigation::DIVIDER) 59 | )); 60 | 61 | $tabs = Navigation::tabs($links); 62 | $match = ''; 63 | $this->assertEquals($match, $tabs); 64 | } 65 | 66 | public function testVerticalDivider() 67 | { 68 | $links = Navigation::links(array( 69 | array(Navigation::VERTICAL_DIVIDER) 70 | )); 71 | 72 | $tabs = Navigation::tabs($links); 73 | $match = ''; 74 | $this->assertEquals($match, $tabs); 75 | } 76 | 77 | public function testHeader() 78 | { 79 | $links = Navigation::links(array( 80 | array(Navigation::HEADER, 'Test') 81 | )); 82 | 83 | $tabs = Navigation::tabs($links); 84 | $match = ''; 85 | $this->assertEquals($match, $tabs); 86 | } 87 | 88 | public function testSubMenu() 89 | { 90 | $matcher = array( 91 | 'tag' => 'ul', 92 | 'attributes' => array( 93 | 'class' => 'nav nav-tabs' 94 | ), 95 | 'child' => array( 96 | 'tag' => 'li', 97 | 'attributes' => array('class' => 'dropdown active'), 98 | 'descendant' => array( 99 | 'tag' => 'a', 100 | 'attributes' => array('class' => 'dropdown-toggle', 'data-toggle' => 'dropdown'), 101 | 'content' => 'Dropdown', 102 | 'child' => array( 103 | 'tag' => 'b', 104 | 'attributes' => array('class' => 'caret'), 105 | ) 106 | ), 107 | 'child' => array( 108 | 'tag' => 'ul', 109 | 'attributes' => array('class' => 'dropdown-menu'), 110 | 'child' => array( 111 | 'tag' => 'li', 112 | 'attributes' => array('class' => 'dropdown-submenu'), 113 | 'descendant' => array( 114 | 'tag' => 'a', 115 | 'content' => 'Action', 116 | ), 117 | 'child' => array( 118 | 'tag' => 'ul', 119 | 'attributes' => array('class' => 'dropdown-menu'), 120 | 'child' => array( 121 | 'tag' => 'li', 122 | 'child' => array( 123 | 'tag' => 'a', 124 | 'content' => 'Sub Action' 125 | ) 126 | ) 127 | ) 128 | ), 129 | ), 130 | ) 131 | ); 132 | 133 | $links = Navigation::links(array( 134 | array('Dropdown', '#', true, false, 135 | array( 136 | array('Action', '#', false, false, 137 | array( 138 | array('Sub Action', '#') 139 | ) 140 | ), 141 | ) 142 | ) 143 | )); 144 | 145 | $tabs = Navigation::tabs($links); 146 | 147 | $this->assertTag($matcher, $tabs); 148 | 149 | } 150 | 151 | public function testLinkBasic() 152 | { 153 | $link = Navigation::link('foo', '#'); 154 | $match = array('label'=> 'foo', 'url' => '#', 'active' => false, 'disabled' => false, 'items' => null, 'icon' => null); 155 | $this->assertEquals($match, $link); 156 | } 157 | 158 | public function testLinkAll() 159 | { 160 | $link = Navigation::link('foo', '#', true, false, array('label' => 'bar', 'url' => '#1')); 161 | $match = array('label'=> 'foo', 'url' => '#', 'active' => true, 'disabled' => false, 'items' => array('label' => 'bar', 'url' => '#1'), 'icon' => null); 162 | $this->assertEquals($match, $link); 163 | } 164 | 165 | public function testLinksBasic() 166 | { 167 | $link = Navigation::links(array( 168 | array('foo', '#'), 169 | array('bar', '#') 170 | )); 171 | $match = array( 172 | array('label'=> 'foo', 'url' => '#', 'active' => false, 'disabled' => false, 'items' => null, 'icon' => null), 173 | array('label'=> 'bar', 'url' => '#', 'active' => false, 'disabled' => false, 'items' => null, 'icon' => null), 174 | ); 175 | $this->assertEquals($match, $link); 176 | } 177 | 178 | public function testLinksAll() 179 | { 180 | $link = Navigation::links(array( 181 | array('foo', '#', true, false, 182 | array( 183 | array('foo1', '#foo1'), 184 | array('foo2', '#foo2') 185 | ) 186 | ), 187 | array('bar', '#', false, true) 188 | )); 189 | 190 | $match = array( 191 | array('label'=> 'foo', 'url' => '#', 'active' => true, 'disabled' => false, 'items' => 192 | array( 193 | array('label'=> 'foo1', 'url' => '#foo1', 'active' => false, 'disabled' => false, 'items' => null, 'icon' => null), 194 | array('label'=> 'foo2', 'url' => '#foo2', 'active' => false, 'disabled' => false, 'items' => null, 'icon' => null), 195 | ), 'icon' => null 196 | ), 197 | array('label'=> 'bar', 'url' => '#', 'active' => false, 'disabled' => true, 'items' => null, 'icon' => null), 198 | ); 199 | 200 | $this->assertEquals($match, $link); 201 | } 202 | 203 | public function testDropdownBasic() 204 | { 205 | $links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 206 | $dropdown = Navigation::dropdown($links); 207 | 208 | $matcher = $this->createDropdownMatcher(); 209 | 210 | $this->assertTag($matcher, $dropdown); 211 | } 212 | 213 | public function testDropdownAll() 214 | { 215 | $links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 216 | $dropdown = Navigation::dropdown($links, array('class' => 'bar', 'data-foo' => 'bar')); 217 | 218 | $matcher = $this->createDropdownMatcher('bar'); 219 | $matcher['attributes']['data-foo'] = 'bar'; 220 | 221 | $this->assertTag($matcher, $dropdown); 222 | } 223 | 224 | /** 225 | * @dataProvider classes 226 | */ 227 | public function testStylesBasic($class) 228 | { 229 | $links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 230 | 231 | $menu = Navigation::$class($links); 232 | $match = $this->createNavMatcher($class); 233 | 234 | $this->assertTag($match, $menu); 235 | } 236 | 237 | /** 238 | * @dataProvider classes 239 | */ 240 | public function testStylesStacked($class) 241 | { 242 | $links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 243 | 244 | $menu = Navigation::$class($links, true); 245 | $match = $this->createNavMatcher($class, '', true); 246 | 247 | $this->assertTag($match, $menu); 248 | } 249 | 250 | /** 251 | * @dataProvider classes 252 | */ 253 | public function testStylesAll($class) 254 | { 255 | $links = Navigation::links(array(array('foo', '#'),array('bar','#'))); 256 | 257 | $menu = Navigation::$class($links, true, array('class' => 'bar', 'data-foo' => 'bar')); 258 | $match = $this->createNavMatcher($class, 'bar', true); 259 | $match['attributes']['data-foo'] = 'bar'; 260 | 261 | $this->assertTag($match, $menu); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/Bootstrapper/Carousel.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Carousel 20 | { 21 | /** 22 | * The current Carousel instance 23 | * @var Carousel 24 | */ 25 | private static $carousel; 26 | 27 | /** 28 | * How data will be fetched from each object/entry 29 | * @var array 30 | */ 31 | private $schema = array( 32 | 'key' => 'id', 33 | 'alt' => 'alt_text', 34 | 'attributes' => 'attributes', 35 | 'caption' => 'caption', 36 | 'label' => 'label', 37 | 'image' => 'image', 38 | ); 39 | 40 | /** 41 | * The carousel's items 42 | * @var array 43 | */ 44 | private $items = array(); 45 | 46 | /** 47 | * The carousel's attributes 48 | * @var array 49 | */ 50 | private $attributes = array(); 51 | 52 | /** 53 | * The previous button content 54 | * @var string 55 | */ 56 | private $prev = '‹'; 57 | 58 | /** 59 | * The next button content 60 | * @var string 61 | */ 62 | private $next = '›'; 63 | 64 | /** 65 | * The current carousel's hash 66 | * @var string 67 | */ 68 | private $hash = null; 69 | 70 | /** 71 | * The current active element in the carousel 72 | * @var integer 73 | */ 74 | private $active = null; 75 | 76 | /** 77 | * Create a Bootstrap carousel. Returns the HTML for the carousel. 78 | * 79 | * @param array $items An array of carousel items 80 | * @param array $attributes Attributes to apply the carousel itself 81 | * 82 | * @return Carousel 83 | */ 84 | public static function create($items, $attributes = array()) 85 | { 86 | static::$carousel = new static($items, $attributes); 87 | 88 | return static::$carousel; 89 | } 90 | 91 | /** 92 | * Renders a Carousel navigation for custom carousels 93 | * 94 | * @param string $id The Carousel ID 95 | * @param string $prev The previous link text 96 | * @param string $next The next link text 97 | * @return string A Carousel navigation 98 | */ 99 | public static function navigation($id, $prev, $next) 100 | { 101 | $navigation = HTML::link($id, $prev, array('class' => 'carousel-control left', 'data-slide' => 'prev')); 102 | $navigation .= HTML::link($id, $next, array('class' => 'carousel-control right', 'data-slide' => 'next')); 103 | 104 | return $navigation; 105 | } 106 | 107 | /** 108 | * Creates a new Carousel instance 109 | * 110 | * @param array $items The items to use as pictures 111 | * @param array $attributes Its attributes 112 | */ 113 | public function __construct($items, $attributes = array()) 114 | { 115 | $this->items = $items; 116 | $this->attributes = Helpers::add_class($attributes, 'carousel slide'); 117 | 118 | // Set default active item 119 | $this->active = key($items); 120 | 121 | // Calculate the Carousel ID 122 | $this->hash = '#'.array_get($attributes, 'id', 'carousel_'.Helpers::rand_string(5)); 123 | } 124 | 125 | /** 126 | * Magic methods for the Carousel class 127 | * 128 | * @param string $method The method 129 | * @param array $parameters Its parameters 130 | * @return Carousel 131 | */ 132 | public function __call($method, $parameters) 133 | { 134 | // Dynamic schema editing 135 | // Example : ->as_label('name') and $item->name/$item['name'] will be used as label 136 | if (starts_with($method, 'as_')) { 137 | $use = substr($method, 3); 138 | $as = array_get($parameters, 0); 139 | $this->schema[$as] = $use; 140 | } 141 | 142 | return $this; 143 | } 144 | 145 | /** 146 | * Changes the text for the prev link 147 | * 148 | * @param string $prev The new text 149 | * @return Carousel 150 | */ 151 | public function prev($next) 152 | { 153 | $this->prev = $prev; 154 | 155 | return $this; 156 | } 157 | 158 | /** 159 | * Changes the text for the next link 160 | * 161 | * @param string $next The new text 162 | * @return Carousel 163 | */ 164 | public function next($next) 165 | { 166 | $this->next = $next; 167 | 168 | return $this; 169 | } 170 | 171 | /** 172 | * Set which element will be the active one 173 | * 174 | * @param integer $key A key 175 | * @return Carousel 176 | */ 177 | public function active($key) 178 | { 179 | $this->active = $key; 180 | 181 | return $this; 182 | } 183 | 184 | /** 185 | * Set the current Carousel's #id 186 | * 187 | * @param string $id The new id 188 | * @return Carousel 189 | */ 190 | public function id($id) 191 | { 192 | $this->hash = '#'.$id; 193 | 194 | return $this; 195 | } 196 | 197 | /** 198 | * Use a custom object schema for the images passed 199 | * 200 | * @param array $schema A schema array 201 | * @return Carousel 202 | */ 203 | public function with_schema($schema) 204 | { 205 | $this->schema = (array) array_merge($this->schema, $schema); 206 | 207 | return $this; 208 | } 209 | 210 | /** 211 | * Prints out the current Carousel instance 212 | * 213 | * @return string A carousel 214 | */ 215 | public function __toString() 216 | { 217 | // Render main wrapper 218 | $this->attributes['id'] = substr($this->hash, 1); 219 | $html = 'attributes).'>'; 220 | 221 | // Render items 222 | $html .= ''; 227 | 228 | // Render navigation 229 | $html .= Carousel::navigation($this->hash, $this->prev, $this->next); 230 | $html .= ''; 231 | 232 | return $html; 233 | } 234 | 235 | ////////////////////////////////////////////////////////////////// 236 | ///////////////////////////// HELPERS //////////////////////////// 237 | ////////////////////////////////////////////////////////////////// 238 | 239 | /** 240 | * Create a carousel item. Returns a HTML element for one slide. 241 | * 242 | * @param array $item A carousel item to render 243 | * @param bool $key A fallback key as the item's position in the array 244 | * @return string 245 | */ 246 | protected function createItem($item, $key) 247 | { 248 | // Gather necessary variables 249 | $key = $this->getFromItem($item, 'key', $key); 250 | $altText = $this->getFromItem($item, 'alt'); 251 | $attributes = $this->getFromItem($item, 'attributes', array()); 252 | $caption = $this->getFromItem($item, 'caption'); 253 | $label = $this->getFromItem($item, 'label'); 254 | $image = $this->getFromItem($item, 'image'); 255 | 256 | // If we were given an array of image paths instead of arrays 257 | if (!$image and is_string($item)) $image = $item; 258 | 259 | // Build HTML 260 | $active = $this->active == $key ? ' active' : null; 261 | $html = '
    '; 262 | 263 | // Render the image 264 | $html .= HTML::image($image, $altText, $attributes); 265 | 266 | // If we have a caption, render it 267 | if ($caption or $label) { 268 | $html .= ''; 272 | } 273 | 274 | $html .= '
    '; 275 | 276 | return $html; 277 | } 278 | 279 | /** 280 | * Get a piece of data from an item 281 | * 282 | * @param mixed $item The item 283 | * @param string $key The key to fetch 284 | * @param string $fallback A fallback to use 285 | * @return string A data from the item 286 | */ 287 | private function getFromItem($item, $key, $fallback = null) 288 | { 289 | $key = $this->schema[$key]; 290 | 291 | if (is_object($item)) { 292 | return isset($item->$key) ? $item->$key : $fallback; 293 | } else { 294 | return array_get($item, $key, $fallback); 295 | } 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/Bootstrapper/Button.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Button 20 | { 21 | /** 22 | * The current instance of Button being used 23 | * @var Button 24 | */ 25 | private static $instance = null; 26 | 27 | /** 28 | * The current button in memory 29 | * @var array 30 | */ 31 | private $currentButton = array(); 32 | 33 | /** 34 | * Stores the current button for future output 35 | * 36 | * @param string $type A button type 37 | * @param string $value Its text value 38 | * @param array $attributes An array of attributes 39 | * @param boolean $hasDropdown Whether the button has a dropdown 40 | * 41 | * @return object Button instance 42 | */ 43 | private static function storeButton($type, $value, $attributes, $hasDropdown) 44 | { 45 | // If we don't have an instance stored, create a new one 46 | $currentInstance = self::$instance ?: new Button; 47 | 48 | // Define new button 49 | $currentInstance->currentButton = array( 50 | 'type' => $type, 51 | 'value' => $value, 52 | 'attributes' => $attributes, 53 | 'hasDropdown' => $hasDropdown, 54 | ); 55 | 56 | return $currentInstance; 57 | } 58 | 59 | /** 60 | * Create a HTML submit input element. 61 | * Overriding the default input submit button from Laravel\Form 62 | * 63 | * @param string $value Text value of button 64 | * @param array $attributes array of attributes 65 | * @param bool $hasDropdown Whether the button has a dropdown 66 | * 67 | * @return object Button instance 68 | */ 69 | public static function submit($value, $attributes = array(), $hasDropdown = false) 70 | { 71 | $attributes['type'] = 'submit'; 72 | 73 | return static::storeButton('normal', $value, $attributes, $hasDropdown); 74 | } 75 | 76 | /** 77 | * Create a HTML reset input element. 78 | * Overriding the default input reset button from Laravel\Form 79 | * 80 | * @param string $value Text value of button 81 | * @param array $attributes array of attributes 82 | * @param bool $hasDropdown Whether the button has a dropdown 83 | * 84 | * @return object Button instance 85 | */ 86 | public static function reset($value, $attributes = array(), $hasDropdown = false) 87 | { 88 | $attributes['type'] = 'reset'; 89 | 90 | return static::storeButton('normal', $value, $attributes, $hasDropdown); 91 | } 92 | 93 | /** 94 | * Create a HTML button element. 95 | * Overriding the default button to add the correct class from Laravel\Form 96 | * 97 | * @param string $value Text value of button 98 | * @param array $attributes array of attributes 99 | * @param bool $hasDropdown Whether the button has a dropdown 100 | * 101 | * @return object Button instance 102 | */ 103 | public static function normal($value, $attributes = array(), $hasDropdown = false) 104 | { 105 | return static::storeButton('normal', $value, $attributes, $hasDropdown); 106 | } 107 | 108 | /** 109 | * Create a HTML anchor tag styled like a button element. 110 | * 111 | * @param string $url Url of the link 112 | * @param string $value Text value of button 113 | * @param array $attributes array of attributes 114 | * @param bool $hasDropdown Whether the button has a dropdown 115 | * 116 | * @return object Button instance 117 | */ 118 | public static function link($url, $value, $attributes = array(), $hasDropdown = false) 119 | { 120 | $attributes['href'] = \URL::to($url); 121 | 122 | return static::storeButton('link', $value, $attributes, $hasDropdown); 123 | } 124 | 125 | /** 126 | * Adds an icon to the next button 127 | * 128 | * @param string $icon The name of the icon to call 129 | * @param array $attributes Attributes to pass to the generated icon 130 | * @param boolean $prependIcon Whether we should prepend the icon, or append it 131 | * 132 | * @return object Button instance 133 | */ 134 | public function with_icon($icon, $attributes = array(), $prependIcon = true) 135 | { 136 | // Call Icon to create the icon 137 | $icon = Icon::make($icon, $attributes); 138 | 139 | // If there was no text, just use the icon, else put a space between 140 | $value = $this->currentButton['value']; 141 | if(empty($value)) $value = $icon; 142 | else { 143 | $value = $prependIcon 144 | ? $icon. ' ' .$value 145 | : $value. ' ' .$icon; 146 | } 147 | 148 | // Store modified value 149 | $this->currentButton['value'] = $value; 150 | 151 | return $this; 152 | } 153 | 154 | /** 155 | * Alias for with_icon 156 | * 157 | * @param string $icon The name of the icon to call 158 | * @param array $attributes Attributes to pass to the generated icon 159 | * 160 | * @return object Button instance 161 | */ 162 | public function prepend_with_icon($icon, $attributes = array()) 163 | { 164 | return $this->with_icon($icon, $attributes); 165 | } 166 | 167 | /** 168 | * Alias for with_icon with $prependIcon to false 169 | * 170 | * @param string $icon The name of the icon to call 171 | * @param array $attributes Attributes to pass to the generated icon 172 | * 173 | * @return object Button instance 174 | */ 175 | public function append_with_icon($icon, $attributes = array()) 176 | { 177 | return $this->with_icon($icon, $attributes, false); 178 | } 179 | 180 | /** 181 | * Add class to deemphasize the button to look more like an anchor tag 182 | * 183 | * @return object Button instance 184 | */ 185 | public function deemphasize() 186 | { 187 | // Add class to attributes array 188 | $this->currentButton['attributes'] = Helpers::add_class($this->currentButton['attributes'], 'btn-link'); 189 | 190 | return $this; 191 | } 192 | 193 | /** 194 | * Add class to make button block 195 | * 196 | * @return object Button instance 197 | */ 198 | public function block() 199 | { 200 | // Add class to attributes array 201 | $this->currentButton['attributes'] = Helpers::add_class($this->currentButton['attributes'], 'btn-block'); 202 | 203 | return $this; 204 | } 205 | 206 | /** 207 | * Checks call to see if we can create a button from a magic call (for you wizards). 208 | * success_button, mini_primary_button, large_warning_submit, danger_reset, etc... 209 | * 210 | * @param string $method Name of missing method 211 | * @param array $parameters array of parameters passed to missing method 212 | * 213 | * @return mixed 214 | */ 215 | public static function __callStatic($method, $parameters) 216 | { 217 | $method_array = explode('_', strtolower($method)); 218 | 219 | $btn_types = array('normal', 'submit', 'reset', 'link'); 220 | $type_found = array_intersect($method_array, $btn_types); 221 | if(!$type_found) $type_found = (array) 'normal'; 222 | 223 | if (count($type_found) > 0) { 224 | $function = $type_found[key($type_found)]; 225 | 226 | // Set default attributes index 227 | $attr_index = $function != 'link' ? 1 : 2; 228 | 229 | $parameters = Helpers::set_multi_class_attributes($function, $method_array, $parameters, $attr_index, 'btn-', 'disabled'); 230 | if(in_array('disabled', $method_array)) $parameters[$attr_index]['disabled'] = 'disabled'; 231 | 232 | return call_user_func_array('static::'.$function, $parameters); 233 | } 234 | } 235 | 236 | /** 237 | * Prints the current button in memory 238 | * 239 | * @return string A button 240 | */ 241 | public function __toString() 242 | { 243 | // Gather variables 244 | extract($this->currentButton); 245 | 246 | // Add btn to classes and fallback type 247 | if(!isset($attributes['type'])) $attributes['type'] = 'button'; 248 | $attributes = Helpers::add_class($attributes, 'btn'); 249 | 250 | // Modify output if we have a dropdown 251 | $caret = null; 252 | if ($hasDropdown) { 253 | $attributes = Helpers::add_class($attributes, 'dropdown-toggle'); 254 | $caret = ' '; 255 | $attributes['data-toggle'] = 'dropdown'; 256 | } 257 | 258 | // Write output according to tag 259 | $tag = 'button'; 260 | if ($type === 'link') { 261 | $tag = 'a'; 262 | unset($attributes['type']); 263 | } 264 | 265 | return '<'.$tag.HTML::attributes($attributes).'>'.(string) $value.$caret.''; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/Bootstrapper/Tabbable.php: -------------------------------------------------------------------------------- 1 | 14 | * @author Maxime Fabre - 15 | * @license MIT License 16 | * @link http://laravelbootstrapper.phpfogapp.com/ 17 | * 18 | * @see http://twitter.github.com/bootstrap/ 19 | */ 20 | class Tabbable 21 | { 22 | /** 23 | * All menu or elements of the current Tabbable 24 | * 25 | * @var array 26 | */ 27 | private $menu = array(); 28 | 29 | /** 30 | * The placement of the current Tabble item 31 | * 32 | * @var enum 33 | */ 34 | private $placement = Tabbable::PLACEMENT_ABOVE; 35 | 36 | /** 37 | * The style of the current Tabble item 38 | * 39 | * @var enum 40 | */ 41 | private $style = Navigation::TYPE_TABS; 42 | 43 | /** 44 | * Whether the current Tabble item should stacked or not 45 | * 46 | * @var boolean 47 | */ 48 | private $stacked = false; 49 | 50 | /** 51 | * The current Tabbable's attributes 52 | * 53 | * @var array 54 | */ 55 | private $attributes = array(); 56 | 57 | /** 58 | * Set the current Tabbables menu attributes 59 | * 60 | * @var array 61 | */ 62 | private $menu_attributes = array(); 63 | 64 | 65 | /** 66 | * Set the current Tabbables content attributes 67 | * 68 | * @var array 69 | */ 70 | private $content_attributes = array(); 71 | 72 | /** 73 | * Whether the current Tabble item should use automatic routing 74 | * 75 | * @var boolean 76 | */ 77 | private $autoroute = true; 78 | 79 | /** 80 | * Tabs placements 81 | * @var constant 82 | */ 83 | const PLACEMENT_ABOVE = 'tabs-above'; 84 | const PLACEMENT_BELOW = 'tabs-below'; 85 | const PLACEMENT_LEFT = 'tabs-left'; 86 | const PLACEMENT_RIGHT = 'tabs-right'; 87 | 88 | 89 | /** 90 | * Generate a Bootstrap tabbable object. 91 | * 92 | * @param array $menu Tab items 93 | * @param array $attributes Attributes for the tabs 94 | * 95 | * @return string 96 | */ 97 | public static function create($menu, $attributes = array()) 98 | { 99 | // Fetch current instance 100 | $instance = new Tabbable; 101 | 102 | // Save given parameters 103 | $instance->menu = $menu; 104 | $instance->attributes = $attributes; 105 | 106 | return $instance; 107 | } 108 | 109 | /** 110 | * Set the placement to Tabbable enum 111 | * 112 | * @param string $placement The new placement value 113 | * 114 | * @return Tabbable 115 | */ 116 | public function placement($placement) 117 | { 118 | $this->placement = $placement; 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * Set the menu style to Navigation enum 125 | * 126 | * @param string $style The new menu style value 127 | * 128 | * @return Tabbable 129 | */ 130 | public function style($style) 131 | { 132 | $this->style = $style; 133 | 134 | return $this; 135 | } 136 | 137 | /** 138 | * Set the stacked value to true or false 139 | * 140 | * @param boolean $stacked The new stacked value 141 | * 142 | * @return Tabbable 143 | */ 144 | public function stacked($stacked = true) 145 | { 146 | $this->stacked = $stacked; 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * Add menus or strings to the current Tabbable 153 | * 154 | * @param array $attributes An array of attributes to use 155 | * 156 | * @return Tabbable 157 | */ 158 | public function menu_attributes($attributes = array()) 159 | { 160 | $this->menu_attributes = $attributes; 161 | 162 | return $this; 163 | } 164 | 165 | /** 166 | * Add attributes to the content of the current Tabbable 167 | * 168 | * @param array $attributes An array of attributes to use 169 | * 170 | * @return Tabbable 171 | */ 172 | public function content_attributes($attributes) 173 | { 174 | $this->content_attributes = $attributes; 175 | 176 | return $this; 177 | } 178 | 179 | /** 180 | * Set the autoroute to true or false 181 | * 182 | * @param boolean $autoroute The new autoroute value 183 | * 184 | * @return Tabbable 185 | */ 186 | public function autoroute($autoroute) 187 | { 188 | $this->autoroute = $autoroute; 189 | 190 | return $this; 191 | } 192 | 193 | /** 194 | * Prints out the current Tabbable in case it doesn't do it automatically 195 | * 196 | * @return string A Tabbable 197 | */ 198 | public function get() 199 | { 200 | return static::__toString(); 201 | } 202 | 203 | /** 204 | * Writes the current Tabbable 205 | * 206 | * @return string A Bootstrap Tabbable 207 | */ 208 | public function __toString() 209 | { 210 | $content = array(); 211 | $list = static::normalize($this->menu, $content); 212 | 213 | $tabs = Navigation::menu($list, $this->style, $this->stacked, $this->menu_attributes, $this->autoroute); 214 | 215 | // Tab content container 216 | if (!isset($this->content_attributes['class'])) { 217 | $this->content_attributes['class'] = 'tab-content'; 218 | } else { 219 | $this->content_attributes['class'] .= ' tab-content'; 220 | } 221 | 222 | $content = '
    content_attributes).'>'. implode('', $content).'
    '; 223 | 224 | $html = '
    attributes).'>'; 225 | $html .= $this->placement === self::PLACEMENT_BELOW ? $content.$tabs : $tabs.$content; 226 | $html .= '
    '; 227 | 228 | return $html; 229 | } 230 | 231 | /** 232 | * Normalizes the items list and correct urls if any are set. 233 | * 234 | * @param array $items Tab items 235 | * @param array &$panes array of panes 236 | * @param int &$i index 237 | * 238 | * @return array 239 | */ 240 | protected static function normalize($items, &$panes, &$i = 0) 241 | { 242 | $id = Helpers::rand_string(5); 243 | $tabs = array(); 244 | 245 | if (!is_array($items)) return false; 246 | 247 | foreach ($items as $key => $tab) { 248 | $url = '#'; 249 | if (isset($tab['items'])) { 250 | 251 | $tab['items'] = static::normalize($tab['items'], $panes, $i); 252 | } else { 253 | if (!isset($tab['url'])) { 254 | $tab['url'] = ''; 255 | } 256 | 257 | $tabId = 'tab_'.$id.'_'.$i; 258 | 259 | //if not disabled set toggle and url 260 | if (!isset($tab['disabled']) || !$tab['disabled']) { 261 | $tab['attributes'] = array('data-toggle' => 'tab'); 262 | $url .= $tabId; 263 | } 264 | 265 | $class = 'tab-pane'; 266 | if (isset($tab['active']) && $tab['active']) { 267 | $class .= ' active'; 268 | } 269 | 270 | $panes[] = '
    '.$tab['url'].'
    '; 271 | 272 | $tab['url'] = $url; 273 | $i++; 274 | } 275 | $tabs[] = $tab; 276 | } 277 | 278 | return $tabs; 279 | } 280 | 281 | /** 282 | * Checks call to see if we can create a tabbable from a magic call (for you wizards). 283 | * tabs_above, tabs_left, pills, lists, etc... 284 | * 285 | * @param string $method Method name 286 | * @param array $parameters Method parameters 287 | * 288 | * @return mixed 289 | */ 290 | public static function __callStatic($method, $parameters) 291 | { 292 | $method_array = explode('_', strtolower($method)); 293 | 294 | $list_styles = array('tabs', 'pills', 'lists'); 295 | $style_found = array_intersect($method_array, $list_styles); 296 | 297 | // Check for placment 298 | $list_placement = array('above', 'below', 'left', 'right'); 299 | $placement_found = array_intersect($method_array, $list_placement); 300 | 301 | if (count($style_found) > 0) { 302 | // Check list parameters 303 | $menu = array_get($parameters, 0); 304 | if (!(isset($menu) && is_array($menu))) { 305 | throw new \Exception("Tabbable requires an array of menu items"); 306 | } 307 | 308 | $attributes = array_get($parameters, 1); 309 | if (isset($attributes) && !is_array($attributes)) { 310 | throw new \Exception("Tabbable attributes parameter should be an array of attributes"); 311 | } 312 | 313 | $inst = static::create($menu, $attributes); 314 | 315 | //Set placement 316 | if (count($placement_found) > 0 ) { 317 | $placement = $placement_found[key($placement_found)]; 318 | $inst->placement('tabs-'.$placement); 319 | } 320 | 321 | //Set Style 322 | if (count($style_found) > 0 ) { 323 | $style = $style_found[key($style_found)]; 324 | 325 | // Hack to get around dynamic list call 326 | if ($style === 'lists') { 327 | $style = 'list'; 328 | } 329 | 330 | $inst->style('nav-'.$style); 331 | } 332 | 333 | return $inst; 334 | } 335 | 336 | throw new \Exception("Method [$method] does not exist."); 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/Bootstrapper/Navigation.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Navigation 20 | { 21 | /** 22 | * Menu types 23 | * @var constant 24 | */ 25 | const TYPE_UNSTYLED = ''; 26 | const TYPE_LIST = 'nav-list'; 27 | const TYPE_PILLS = 'nav-pills'; 28 | const TYPE_TABS = 'nav-tabs'; 29 | 30 | const HEADER = '-HEADER-'; 31 | const DIVIDER = '---'; 32 | const VERTICAL_DIVIDER = '|||'; 33 | 34 | /** 35 | * Generates a nav menu and any dropdown if the $list array contains any dropdown objects. 36 | * 37 | * @param array $list Menu items 38 | * @param string $type Menu Type 39 | * @param bool $stacked Should menu be stacked 40 | * @param array $attributes attributes to apply the nav 41 | * @param bool $autoroute Autoroute links 42 | * 43 | * @return string 44 | */ 45 | public static function menu($list, $type = Navigation::TYPE_UNSTYLED, $stacked = false, $attributes = array(), $autoroute = true, $isDropdown = false) 46 | { 47 | $html = ''; 48 | 49 | if (isset($type)) { 50 | $type = $type != '' ? ' '.$type : ''; 51 | $attributes = Helpers::add_class($attributes, 'nav'.$type); 52 | } 53 | 54 | if ($type !== Navigation::TYPE_LIST && $stacked) { 55 | $attributes = Helpers::add_class($attributes, 'nav-stacked'); 56 | } 57 | 58 | if (count($list) == 0) { 59 | return $html; 60 | } 61 | 62 | foreach ($list as $item) { 63 | $icon = isset($item['icon']) ? $item['icon'] : null; 64 | 65 | // Set vertical dividers 66 | if ($item['label'] === Navigation::VERTICAL_DIVIDER) { 67 | $html .= '
  • '; 68 | 69 | // Set normal divider 70 | } elseif ($item['label'] === Navigation::DIVIDER) { 71 | $html .= '
  • '; 72 | 73 | // Set Header if Label Equals HEADER const 74 | } elseif ($item['label'] === Navigation::HEADER) { 75 | $iconStr = ""; 76 | if ($icon !== null) { 77 | $iconStr = Icon::$icon().' '; 78 | } 79 | 80 | $html .= ''; 81 | 82 | // Set dropdown style 83 | } elseif (isset($item['items'])) { 84 | $dropClass = 'dropdown'; 85 | $att = array('class' => 'dropdown-toggle', 'data-toggle' => 'dropdown'); 86 | $extraCaret = ' '; 87 | 88 | if ($isDropdown) { 89 | $dropClass = 'dropdown-submenu'; 90 | $att = array(); 91 | $extraCaret = ''; 92 | } 93 | 94 | $html .= '
  • '; 95 | $html .= static::linkItem($item['url'], $item['label'].$extraCaret, $att, false, $icon); 96 | $html .= static::dropdown($item['items'], array(), $autoroute); 97 | $html .= '
  • '; 98 | 99 | // Must be basic link 100 | } else { 101 | if (!isset($item['attributes'])) { 102 | $item['attributes'] = array(); 103 | } 104 | 105 | $html .= '
  • '.static::linkItem($item['url'], $item['label'], $item['attributes'], true, $icon).'
  • '; 106 | } 107 | } 108 | 109 | return ''.$html.''; 110 | } 111 | 112 | /** 113 | * Creates a Bootstrap plan unstyled menu. 114 | * 115 | * @param array $list Menu items 116 | * @param bool $stacked Should it be stacked 117 | * @param array $attributes attributes to apply the nav 118 | * @param bool $autoroute Autoroute links 119 | * 120 | * @return string 121 | */ 122 | public static function unstyled($list, $stacked = false, $attributes = array(), $autoroute = true) 123 | { 124 | return static::menu($list, Navigation::TYPE_UNSTYLED, $stacked, $attributes, $autoroute); 125 | } 126 | 127 | /** 128 | * Creates a Bootstrap Tabs menu. 129 | * 130 | * @param array $list Menu items 131 | * @param bool $stacked Should it be stacked 132 | * @param array $attributes attributes to apply the nav 133 | * @param bool $autoroute Autoroute links 134 | * 135 | * @return string 136 | */ 137 | public static function tabs($list, $stacked = false, $attributes = array(), $autoroute = true) 138 | { 139 | return static::menu($list, Navigation::TYPE_TABS, $stacked, $attributes, $autoroute); 140 | } 141 | 142 | /** 143 | * Creates a Bootstrap Pills menu. 144 | * 145 | * @param array $list Menu items 146 | * @param bool $stacked Should it be stacked 147 | * @param array $attributes attributes to apply the nav 148 | * @param bool $autoroute Autoroute links 149 | * 150 | * @return string 151 | */ 152 | public static function pills($list, $stacked = false, $attributes = array(), $autoroute = true) 153 | { 154 | return static::menu($list, Navigation::TYPE_PILLS, $stacked, $attributes, $autoroute); 155 | } 156 | 157 | /** 158 | * Creates a Bootstrap Lists menu. 159 | * 160 | * @param array $list Menu items 161 | * @param bool $stacked Should it be stacked 162 | * @param array $attributes attributes to apply the nav 163 | * @param bool $autoroute Autoroute links 164 | * 165 | * @return string 166 | */ 167 | public static function lists($list, $stacked = false, $attributes = array(), $autoroute = true) 168 | { 169 | return static::menu($list, Navigation::TYPE_LIST, $stacked, $attributes, $autoroute); 170 | } 171 | 172 | /** 173 | * Creates a Bootstrap Dropdown menu. 174 | * 175 | * @param array $list Menu items 176 | * @param array $attributes attributes to apply the nav 177 | * @param bool $autoroute Autoroute links 178 | * 179 | * @return string 180 | */ 181 | public static function dropdown($list, $attributes = array(), $autoroute = true) 182 | { 183 | $attributes = Helpers::add_class($attributes, 'dropdown-menu'); 184 | 185 | return static::menu($list, null, false, $attributes, $autoroute, true); 186 | } 187 | 188 | /** 189 | * Creates the class element for the menu item. 190 | * 191 | * @param array $item item array 192 | * @param bool $with_class with class 193 | * @param bool $autoroute Autoroute links 194 | * 195 | * @return string 196 | */ 197 | protected static function getClasses($item, $with_class = true, $autoroute = true) 198 | { 199 | $class = ''; 200 | if ((isset($item['active']) && $item['active']) || ($autoroute && \URL::current() == $item['url'])) { 201 | $class = 'active'; 202 | } 203 | 204 | if (isset($item['disabled']) && $item['disabled']) { 205 | $class = $class == '' ? '' : ' '; 206 | $class .= 'disabled'; 207 | } 208 | 209 | $class .= isset($item['align']) ? ' '.$item['align'] : ''; 210 | 211 | if (strlen($class) > 0 && $with_class) { 212 | $class = 'class="'.$class.'"'; 213 | } 214 | 215 | return $class; 216 | } 217 | 218 | /** 219 | * Generates a link without doing a getting the full url from Laravel 220 | * 221 | * @param string $url Url for the link 222 | * @param string $title Title for thel ink 223 | * @param array $attributes Attributes to apply to the link 224 | * @param bool $encode Encode title 225 | * @param string $icon Icon for the link 226 | * 227 | * @return string 228 | */ 229 | protected static function linkItem($url, $title, $attributes = array(), $encode = true, $icon = null) 230 | { 231 | if ($encode) { 232 | $title = HTML::entities($title); 233 | } 234 | 235 | if (isset($icon)) { 236 | $title = Icon::$icon().' '.$title; 237 | } 238 | 239 | return ''.$title.''; 240 | } 241 | 242 | /** 243 | * A simple clean way to create a single link array. 244 | * 245 | * @param string $label Link name 246 | * @param bool $active Set current tab as active 247 | * @param bool $disabled Disabled the current tab 248 | * @param array $items Array of for dropdown items 249 | * 250 | * @return mixed 251 | */ 252 | public static function link($label, $url, $active = false, $disabled = false, $items = null, $icon = null) 253 | { 254 | return array('label'=> $label, 'url' => $url, 'active' => $active, 'disabled' => $disabled, 'items' => $items, 'icon' => $icon); 255 | } 256 | 257 | /** 258 | * A simple clean way to create the associative array required for a Navigation item 259 | * 260 | * @param array $links array of links 261 | * 262 | * @return mixed 263 | */ 264 | public static function links($links) 265 | { 266 | if ($links == null) { 267 | return $links; 268 | } 269 | 270 | $l = array(); 271 | foreach ($links as $key => $link) { 272 | $label = array_get($link, 0); 273 | $url = array_get($link, 1); 274 | $active = array_get($link, 2); 275 | $disabled = array_get($link, 3); 276 | $items = array_get($link, 4); 277 | $icon = array_get($link, 5); 278 | $l[] = static::link($label, $url, $active, $disabled, static::links($items), $icon); 279 | } 280 | 281 | return $l; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/Bootstrapper/Table.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Maxime Fabre - 14 | * @license MIT License 15 | * @link http://laravelbootstrapper.phpfogapp.com/ 16 | * 17 | * @see http://twitter.github.com/bootstrap/ 18 | */ 19 | class Table 20 | { 21 | /** 22 | * The current Table instance 23 | * @var Table 24 | */ 25 | private static $table = null; 26 | 27 | /** 28 | * The availables classes for a Table 29 | * @var array 30 | */ 31 | private static $classes = array('striped', 'bordered', 'hover', 'condensed'); 32 | 33 | // Current table ----------------------------------------------- / 34 | 35 | /** 36 | * The current table's number of columns 37 | * @var integer 38 | */ 39 | private $numberColumns = 50; 40 | 41 | /** 42 | * The current table body in memory 43 | * @var string 44 | */ 45 | private $tbody = array(); 46 | 47 | /** 48 | * The rows to be ignored in the next body to come 49 | * @var array 50 | */ 51 | private $ignore = array(); 52 | 53 | /** 54 | * The order in which the columns are to be printed out 55 | * @var array 56 | */ 57 | private $order = array(); 58 | 59 | /** 60 | * Columns to append/replace in the current body 61 | * @var array 62 | */ 63 | private $columns = array(); 64 | 65 | /** 66 | * The table's attributes 67 | * @var array 68 | */ 69 | private $attributes = array(); 70 | 71 | ////////////////////////////////////////////////////////////////// 72 | ////////////////////////// STATIC FUNCTIONS ////////////////////// 73 | ////////////////////////////////////////////////////////////////// 74 | 75 | /** 76 | * Checks call to see if we can create a table from a magic call (for you wizards). 77 | * hover_striped, bordered_condensed, etc. 78 | * 79 | * @param string $method Method name 80 | * @param array $parameters Method parameters 81 | * 82 | * @return mixed 83 | */ 84 | public static function __callStatic($method, $parameters) 85 | { 86 | // Opening a table 87 | if (str_contains($method, 'open') or $method == 'open') { 88 | $method = strtolower($method); 89 | $classes = explode('_', $method); 90 | $method = array_pop($classes); 91 | 92 | // Fallback to default type if defined 93 | if(sizeof($classes) == 0) $classes = Config::get('table.classes'); 94 | 95 | // Filter table classes 96 | $classes = array_intersect($classes, static::$classes); 97 | $attributes = Helpers::set_multi_class_attributes($method, $classes, $parameters, 0, 'table-'); 98 | $attributes = array_get($attributes, 0); 99 | 100 | static::$table = new static($attributes); 101 | 102 | return static::$table->open(); 103 | } 104 | 105 | // Set default function 106 | if(!$method) $method = 'table'; 107 | 108 | // Use cases 109 | switch ($method) { 110 | case 'close': 111 | $close = static::table()->close(); 112 | static::$table = null; 113 | 114 | return $close; 115 | break; 116 | default: 117 | return call_user_func_array(array(static::table(), $method), $parameters); 118 | break; 119 | } 120 | } 121 | 122 | /** 123 | * Pass a method to the Table instance 124 | * 125 | * @param string $method The method to call 126 | * @param array $parameters Its parameters 127 | * @return Table A Table instance 128 | */ 129 | public function __call($method, $parameters) 130 | { 131 | // If trying to set a column 132 | if (!method_exists(static::$table, $method)) { 133 | $this->$method = $parameters[0]; 134 | 135 | return $this; 136 | } 137 | 138 | // Else, call the available method 139 | return call_user_func_array(array(static::$table, $method), $parameters); 140 | } 141 | 142 | /** 143 | * Dynamically set a column's content 144 | * 145 | * @param string $column The column's name and classes 146 | * @param mixed $content Its content 147 | */ 148 | public function __set($column, $content) 149 | { 150 | // List known keys 151 | $columns = array_get($this->tbody, key($this->tbody), array()); 152 | $columns = array_keys(is_object($columns) ? $columns->attributes : $columns); 153 | 154 | // If we're not replacing something, we're creating, assume classes 155 | if (!in_array($column, $columns)) { 156 | $column = str_replace('_', ' ', $column); 157 | } 158 | 159 | // Store Closure/content 160 | $this->columns[$column] = $content; 161 | } 162 | 163 | public static function table() 164 | { 165 | return static::$table ?: new static; 166 | } 167 | 168 | ////////////////////////////////////////////////////////////////// 169 | ////////////////////////// TABLE INSTANCE //////////////////////// 170 | ////////////////////////////////////////////////////////////////// 171 | 172 | /** 173 | * Creates a Table instance 174 | * 175 | * @param array $attributes An array of attributes to create for the table 176 | */ 177 | private function __construct($attributes = array()) 178 | { 179 | $this->attributes = Helpers::add_class($attributes, 'table'); 180 | } 181 | 182 | /** 183 | * Creates a table opening tag 184 | * 185 | * @param array $attributes An array of attributes 186 | * @return string A table opening tag 187 | */ 188 | private function open() 189 | { 190 | return 'attributes).'>'; 191 | } 192 | 193 | /** 194 | * Creates a table tag 195 | * 196 | * @return string A tag prefilled with rows 197 | */ 198 | private function headers() 199 | { 200 | $headers = func_get_args(); 201 | if(sizeof($headers) == 1 and is_array($headers[0])) $headers = $headers[0]; 202 | 203 | // Open headers 204 | $thead = ''.PHP_EOL; 205 | 206 | // Store the number of columns in this table 207 | $this->numberColumns = sizeof($headers); 208 | 209 | // Add each header with its attributes 210 | foreach ($headers as $header => $attributes) { 211 | 212 | // Allows to not specify an attributes array for leaner syntax 213 | if (is_string($attributes) and is_numeric($header)) { 214 | $header = $attributes; 215 | $attributes = array(); 216 | } 217 | 218 | $thead .= '' .$header. ''.PHP_EOL; 219 | } 220 | 221 | $thead .= ''.PHP_EOL; 222 | 223 | return $thead; 224 | } 225 | 226 | /** 227 | * Set the content to be used for the next body 228 | * 229 | * @param mixed $content Can be results from a Query or a bare array 230 | * @return Table The current table instance 231 | */ 232 | private function body($content) 233 | { 234 | if(!$content) return false; 235 | 236 | $this->tbody = $content; 237 | 238 | return $this; 239 | } 240 | 241 | /** 242 | * Ignore certains rows in the body to come 243 | * 244 | * @return Table The current table instance 245 | */ 246 | private function ignore() 247 | { 248 | $this->ignore = func_get_args(); 249 | 250 | return $this; 251 | } 252 | 253 | /** 254 | * Iterate the columns in a certain order in the body to come 255 | */ 256 | private function order() 257 | { 258 | $this->order = func_get_args(); 259 | 260 | return $this; 261 | } 262 | 263 | /** 264 | * Outputs the current body in memory 265 | * 266 | * @return string A with content 267 | */ 268 | public function __toString() 269 | { 270 | if(!$this->tbody) return false; 271 | 272 | // Fetch ignored columns 273 | if (!$this->ignore) $this->ignore = Config::get('table.ignore'); 274 | 275 | // Fetch variables 276 | $content = $this->tbody; 277 | 278 | // Open table body 279 | $html = ''; 280 | 281 | // Iterate through the data 282 | foreach ($content as $row) { 283 | 284 | $html .= ''; 285 | $columnCount = 0; 286 | $data = is_object($row) ? $row->attributes : $row; 287 | 288 | // Reorder columns if necessary 289 | if ($this->order) { 290 | $data = array_merge(array_flip($this->order), $data); 291 | } 292 | 293 | // Read the data row with ignored keys 294 | foreach ($data as $column => $value) { 295 | if(in_array($column, (array) $this->ignore)) continue; 296 | 297 | // Check for replacing columns 298 | $replace = array_get($this->columns, $column); 299 | if ($replace) { 300 | $value = is_callable($replace) ? $replace($row) : $replace; 301 | $value = static::replace_keywords($value, $data); 302 | } 303 | 304 | $columnCount++; 305 | $html .= static::appendColumn($column, $value); 306 | } 307 | 308 | // Add supplementary columns 309 | if($this->columns) 310 | foreach ($this->columns as $class => $column) { 311 | 312 | // Check for replacing columns 313 | if(array_key_exists($class, $data)) continue; 314 | 315 | // Calculate closures 316 | if(is_callable($column)) $column = $column($row); 317 | 318 | // Parse and decode content 319 | $column = static::replace_keywords($column, $data); 320 | $column = HTML::decode($column); 321 | 322 | // Wrap content in a tag if necessary 323 | $columnCount++; 324 | $html .= static::appendColumn($class, $column); 325 | } 326 | $html .= ''; 327 | 328 | // Save new number of columns 329 | if($columnCount > $this->numberColumns) $this->numberColumns = $columnCount; 330 | } 331 | 332 | $html .= ''; 333 | 334 | // Empty data from this body 335 | $this->ignore = array(); 336 | $this->columns = array(); 337 | $this->tbody = null; 338 | 339 | return $html; 340 | } 341 | 342 | /** 343 | * Render a full_row with tags 344 | * 345 | * @param string $content The content to display 346 | * @param array $attributes An array of attributes 347 | * 348 | * @return string A table opening tag 349 | */ 350 | private function full_header($content, $attributes = array()) 351 | { 352 | return static::table()->full_row($content, $attributes, true); 353 | } 354 | 355 | /** 356 | * Creates a table-wide row to display content 357 | * 358 | * @param string $content The content to display 359 | * @param array $attributes The rows's attributes 360 | * @param bool $asHeaders Draw row as header 361 | * 362 | * @return string A single-column row spanning all table 363 | */ 364 | private function full_row($content, $attributes = array(), $asHeaders = false) 365 | { 366 | // Add a class for easy styling 367 | $attributes = Helpers::add_class($attributes, 'full-row'); 368 | $tag = $asHeaders ? 'th' : 'td'; 369 | 370 | return 371 | ' 372 | <' .$tag. ' colspan="' .$this->numberColumns. '">' .$content. ' 373 | '; 374 | } 375 | 376 | /** 377 | * Closes current table 378 | * 379 | * @return string A closing tag 380 | */ 381 | private function close() 382 | { 383 | return ''; 384 | } 385 | 386 | ////////////////////////////////////////////////////////////////// 387 | ////////////////////////////// HELPERS /////////////////////////// 388 | ////////////////////////////////////////////////////////////////// 389 | 390 | /** 391 | * Wrap a supplementary column in a column if it isn't 392 | * 393 | * @param string $name The column's name 394 | * @param string $value Its value 395 | * @return string A tag 396 | */ 397 | private static function appendColumn($name, $value) 398 | { 399 | return starts_with($value, '' .$value. ''; 402 | } 403 | 404 | /** 405 | * Replace keywords with data in a string 406 | * 407 | * @param string $string A string with Laravel patterns (:key) 408 | * @param array $data An array of data to fetch from 409 | * 410 | * @return string The modified string 411 | */ 412 | private static function replace_keywords($string, $data) 413 | { 414 | // Gather used patterns 415 | preg_match_all('/\(:(.+)\)/', $string, $matches); 416 | 417 | // Replace patterns with data 418 | foreach ($matches[0] as $key => $replace) { 419 | $with = array_get($matches, '1.'.$key); 420 | $with = array_get($data, $with); 421 | $string = str_replace($replace, $with, $string); 422 | } 423 | 424 | return $string; 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /public/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.0 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | --------------------------------------------------------------------------------