├── webroot └── empty ├── Test ├── Fixture │ └── empty └── Case │ ├── Model │ └── Behavior │ │ └── empty │ ├── Controller │ └── Component │ │ └── empty │ └── View │ └── Helper │ ├── BootstrapHtmlHelperTest.php │ ├── BootstrapPaginatorHelperTest.php │ └── BootstrapFormHelperTest.php ├── .gitignore ├── .gitmodules ├── View ├── Elements │ ├── alert.ctp │ └── modal.ctp ├── Layouts │ └── default.ctp ├── Helper │ ├── BootstrapHtmlHelper.php │ ├── BootstrapPaginatorHelper.php │ └── BootstrapFormHelper.php └── TwitterBootstrap │ └── index.ctp ├── Console ├── Command │ ├── MakeShell.php │ ├── TwitterBootstrapAppShell.php │ └── CopyShell.php └── Templates │ └── bootstrap │ ├── classes │ └── controller.ctp │ ├── views │ ├── form.ctp │ ├── index.ctp │ └── view.ctp │ └── actions │ └── controller_actions.ctp ├── composer.json ├── Config └── html5_tags.php ├── Controller └── TwitterBootstrapController.php └── README.md /webroot/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Test/Fixture/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | webroot/* -------------------------------------------------------------------------------- /Test/Case/Model/Behavior/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Test/Case/Controller/Component/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Vendor/bootstrap"] 2 | path = Vendor/bootstrap 3 | url = https://github.com/twbs/bootstrap.git 4 | -------------------------------------------------------------------------------- /View/Elements/alert.ctp: -------------------------------------------------------------------------------- 1 | 9 |
10 | 11 | × 12 | 13 | 14 |
-------------------------------------------------------------------------------- /View/Elements/modal.ctp: -------------------------------------------------------------------------------- 1 | fetch('modalId'); 3 | $title = $this->fetch('modalTitle'); 4 | $footer = $this->fetch('modalFooter'); 5 | ?> 6 | -------------------------------------------------------------------------------- /Console/Command/MakeShell.php: -------------------------------------------------------------------------------- 1 | bootstrapPath} && "; 15 | $command .= "make bootstrap BOOTSTRAP_LESS='{$bootstrapLess}' BOOTSTRAP_RESPONSIVE_LESS='{$responsiveLess}' && "; 16 | $command .= "cp -R bootstrap/* " . WWW_ROOT . " && "; 17 | $command .= "rm -rf bootstrap"; 18 | 19 | exec($command, $output); 20 | $this->out($output); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slywalker/twitter_bootstrap", 3 | "type": "cakephp-plugin", 4 | "description": "CakePHP Bootstrap (for Twitter) Plugin", 5 | "keywords": [ 6 | "cakephp", 7 | "bootstrap", 8 | "twitter" 9 | ], 10 | "homepage": "https://github.com/slywalker/TwitterBootstrap", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Yasuo Harada", 15 | "email": "slywalker.net@gmail.com" 16 | } 17 | ], 18 | "support": { 19 | "issues": "https://github.com/slywalker/TwitterBootstrap/issues", 20 | "source": "https://github.com/slywalker/TwitterBootstrap" 21 | }, 22 | "require": { 23 | "php": ">=5.3.0", 24 | "composer/installers": "*" 25 | }, 26 | "suggest": { 27 | "twitter/bootstrap": "Bootstrap for Twitter" 28 | } 29 | } -------------------------------------------------------------------------------- /Config/html5_tags.php: -------------------------------------------------------------------------------- 1 | array( 3 | 'meta' => '', 4 | 'metalink' => '', 5 | 'input' => '', 6 | 'hidden' => '', 7 | 'checkbox' => '', 8 | 'checkboxmultiple' => '', 9 | 'radio' => '%s', 10 | 'password' => '', 11 | 'file' => '', 12 | 'file_no_model' => '', 13 | 'submit' => '', 14 | 'submitimage' => '', 15 | 'image' => '', 16 | 'tagselfclosing' => '<%s%s>', 17 | 'css' => '', 18 | 'style' => '%s', 19 | 'charset' => '', 20 | 'javascriptblock' => '%s', 21 | 'javascriptstart' => '', 23 | 'javascriptend' => '' 24 | )); 25 | ?> -------------------------------------------------------------------------------- /Controller/TwitterBootstrapController.php: -------------------------------------------------------------------------------- 1 | array('className' => 'TwitterBootstrap.BootstrapHtml'), 12 | 'Form' => array('className' => 'TwitterBootstrap.BootstrapForm'), 13 | 'Paginator' => array('className' => 'TwitterBootstrap.BootstrapPaginator'), 14 | ); 15 | 16 | public function beforeFilter() { 17 | if (Configure::read('debug') < 1) { 18 | throw new MethodNotAllowedException(__('Debug setting does not allow access to this url.')); 19 | } 20 | parent::beforeFilter(); 21 | } 22 | 23 | public function index() { 24 | $this->Session->setFlash(__('Alert notice message testing...'), 'alert', array( 25 | 'plugin' => 'TwitterBootstrap', 26 | ), 'notice'); 27 | $this->Session->setFlash(__('Alert success message testing...'), 'alert', array( 28 | 'plugin' => 'TwitterBootstrap', 29 | 'class' => 'alert-success' 30 | ), 'success'); 31 | $this->Session->setFlash(__('Alert error message testing...'), 'alert', array( 32 | 'plugin' => 'TwitterBootstrap', 33 | 'class' => 'alert-error' 34 | ), 'error'); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /Console/Command/TwitterBootstrapAppShell.php: -------------------------------------------------------------------------------- 1 | _welcome(); 27 | $this->out('TwitterBootstrap Shell'); 28 | $this->hr(); 29 | 30 | $this->pluginPath = App::pluginPath($this->pluginName); 31 | 32 | $paths = array_unique( 33 | array_merge( 34 | App::path('Vendor', $this->pluginName), 35 | App::path('Vendor') 36 | ) 37 | ); 38 | 39 | foreach ($paths as $path) { 40 | $dir = 'twitter' . DS . 'bootstrap' . DS; 41 | if ( 42 | is_dir($path . $dir . self::IMG_DIR) && 43 | is_dir($path . $dir . self::JS_DIR) && 44 | is_dir($path . $dir . self::LESS_DIR) 45 | ) { 46 | $this->bootstrapPath = $path . $dir; 47 | break; 48 | } 49 | 50 | $dir = 'bootstrap' . DS; 51 | if ( 52 | is_dir($path . $dir . self::IMG_DIR) && 53 | is_dir($path . $dir . self::JS_DIR) && 54 | is_dir($path . $dir . self::LESS_DIR) 55 | ) { 56 | $this->bootstrapPath = $path . $dir; 57 | break; 58 | } 59 | } 60 | if (!$this->bootstrapPath) { 61 | $this->out('Bootstrap files were not found.'); 62 | exit(0); 63 | } 64 | 65 | $this->Folder = new Folder($this->bootstrapPath); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /Test/Case/View/Helper/BootstrapHtmlHelperTest.php: -------------------------------------------------------------------------------- 1 | BootstrapHtml = new BootstrapHtmlHelper($View); 11 | } 12 | 13 | public function tearDown() { 14 | unset($this->BootstrapHtml); 15 | } 16 | 17 | public function testIcon() { 18 | $class = 'glass'; 19 | $expected = ''; 20 | $this->assertSame($expected, $this->BootstrapHtml->icon($class)); 21 | 22 | $class = 'glass white'; 23 | $expected = ''; 24 | $this->assertSame($expected, $this->BootstrapHtml->icon($class)); 25 | } 26 | 27 | public function testLinkWithIcon() { 28 | $title = 'test'; 29 | $url = '/'; 30 | // single 31 | $icon = 'glass'; 32 | $result = $this->BootstrapHtml->link($title, $url, compact('icon')); 33 | $expected = ' <b>test</b>'; 34 | $this->assertSame($expected, $result, 'normal icon link with escape string'); 35 | // white icon 36 | $icon = 'glass white'; 37 | $result = $this->BootstrapHtml->link($title, $url, compact('icon')); 38 | $expected = ' <b>test</b>'; 39 | $this->assertSame($expected, $result, 'white icon link with escape string'); 40 | // white icon without escape 41 | $icon = 'glass white'; 42 | $escape = false; 43 | $result = $this->BootstrapHtml->link($title, $url, compact('icon', 'escape')); 44 | $expected = ' test'; 45 | $this->assertSame($expected, $result, 'white icon link without escape'); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Console/Templates/bootstrap/classes/controller.ctp: -------------------------------------------------------------------------------- 1 | 5 | /** 6 | * Controller 7 | * 8 | 19 | */ 20 | class Controller extends AppController { 21 | 22 | /** 23 | * Layout 24 | * 25 | * @var string 26 | */ 27 | public $layout = 'bootstrap'; 28 | 29 | 30 | /** 31 | * Scaffold 32 | * 33 | * @var mixed 34 | */ 35 | public $scaffold; 36 | 37 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /View/Layouts/default.ctp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <?php echo __('CakePHP: the rapid development php framework:'); ?> 7 | <?php echo $title_for_layout; ?> 8 | 9 | 10 | 11 | 12 | 13 | 14 | Html->css('bootstrap.min'); ?> 15 | 20 | Html->css('bootstrap-responsive.min'); ?> 21 | 22 | 23 | 26 | 27 | 28 | 35 | fetch('meta'); 37 | echo $this->fetch('css'); 38 | ?> 39 | 40 | 41 | 42 | 43 | 62 | 63 |
64 | 65 |

Bootstrap starter template

66 | 67 | Session->flash(); ?> 68 | 69 | fetch('content'); ?> 70 | 71 |
72 | 73 | 75 | 76 | 77 | Html->script('bootstrap.min'); ?> 78 | fetch('script'); ?> 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Console/Templates/bootstrap/views/form.ctp: -------------------------------------------------------------------------------- 1 |
2 |
3 | BootstrapForm->create('{$modelClass}', array('class' => 'form-horizontal'));?>\n";?> 4 |
5 | "; ?> 6 | BootstrapForm->hidden('{$field}');\n"; 15 | } else { 16 | if($this->templateVars['schema'][$field]['null'] == false){ 17 | $required = ", array(\n\t\t\t\t\t'required' => 'required',\n\t\t\t\t\t'helpInline' => '' . __('Required') . ' ')\n\t\t\t\t"; 18 | } else { 19 | $required = null; 20 | } 21 | echo "\t\t\t\techo \$this->BootstrapForm->input('{$field}'{$required});\n"; 22 | } 23 | } 24 | } 25 | echo $id; 26 | unset($id); 27 | if (!empty($associations['hasAndBelongsToMany'])) { 28 | foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) { 29 | echo "\t\t\t\techo \$this->BootstrapForm->input('{$assocName}');\n"; 30 | } 31 | } 32 | echo "\t\t\t\t?>\n"; 33 | echo "\t\t\t\tBootstrapForm->submit(__('Submit'));?>\n"; 34 | ?> 35 |
36 | BootstrapForm->end();?>\n"; 38 | ?> 39 |
40 |
41 |
42 | 61 |
62 |
63 |
-------------------------------------------------------------------------------- /View/Helper/BootstrapHtmlHelper.php: -------------------------------------------------------------------------------- 1 | loadConfig($settings['configFile']); 13 | } else { 14 | $this->loadConfig('TwitterBootstrap.html5_tags'); 15 | } 16 | } 17 | 18 | public function icon($class) { 19 | $class = explode(' ', $class); 20 | foreach ($class as &$_class) { 21 | if ($_class) { 22 | $_class = self::ICON_PREFIX . $_class; 23 | } else { 24 | unset($_class); 25 | } 26 | } 27 | return ''; 28 | } 29 | 30 | public function link($title, $url = null, $options = array(), $confirmMessage = false) { 31 | $default = array('icon' => null, 'escape' => true); 32 | $options = array_merge($default, (array)$options); 33 | if ($options['icon']) { 34 | if ($options['escape']) { 35 | $title = h($title); 36 | } 37 | $title = $this->icon($options['icon']) . ' ' . $title; 38 | $options['escape'] = false; 39 | unset($options['icon']); 40 | } 41 | return parent::link($title, $url, $options, $confirmMessage); 42 | } 43 | 44 | public function css($url = null, $rel = null, $options = array()) { 45 | if (empty($url)) { 46 | $url = 'bootstrap.min.css'; 47 | $pluginRoot = dirname(dirname(DIRNAME(__FILE__))); 48 | $pluginName = end(explode(DS, $pluginRoot)); 49 | $url = '/' . Inflector::underscore($pluginName) . '/css/' . $url; 50 | } 51 | return parent::css($url, $rel, $options); 52 | } 53 | 54 | public function bootstrapCss($url = 'bootstrap.min.css', $rel = null, $options = array()) { 55 | $pluginRoot = dirname(dirname(DIRNAME(__FILE__))); 56 | $pluginName = end(explode(DS, $pluginRoot)); 57 | 58 | $url = '/' . Inflector::underscore($pluginName) . '/css/' . $url; 59 | return parent::css($url, $rel, $options); 60 | } 61 | 62 | public function script($url = null, $options = array()) { 63 | if (empty($url)) { 64 | $url = 'bootstrap.min.js'; 65 | $pluginRoot = dirname(dirname(DIRNAME(__FILE__))); 66 | $pluginName = end(explode(DS, $pluginRoot)); 67 | $url = '/' . Inflector::underscore($pluginName) . '/js/' . $url; 68 | } 69 | return parent::script($url, $options); 70 | } 71 | 72 | public function bootstrapScript($url = 'bootstrap.min.js', $options = array()) { 73 | $pluginRoot = dirname(dirname(DIRNAME(__FILE__))); 74 | $pluginName = end(explode(DS, $pluginRoot)); 75 | 76 | $url = '/' . Inflector::underscore($pluginName) . '/js/' . $url; 77 | return parent::script($url, $options); 78 | } 79 | 80 | public function breadcrumb($items, $options = array()) { 81 | $default = array( 82 | 'class' => 'breadcrumb', 83 | ); 84 | $options = array_merge($default, (array)$options); 85 | 86 | $count = count($items); 87 | $li = array(); 88 | for ($i = 0; $i < $count - 1; $i++) { 89 | $text = $items[$i]; 90 | $text .= ' /'; 91 | $li[] = parent::tag('li', $text); 92 | } 93 | $li[] = parent::tag('li', end($items), array('class' => 'active')); 94 | return parent::tag('ul', implode("\n", $li), $options); 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /Console/Templates/bootstrap/views/index.ctp: -------------------------------------------------------------------------------- 1 |
2 |
3 |

";?>

4 | 5 |

6 | BootstrapPaginator->counter(array('format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')));?>\n";?> 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | \n"; 18 | echo "\t\t\t\n"; 19 | foreach ($fields as $field) { 20 | $isKey = false; 21 | if (!empty($associations['belongsTo'])) { 22 | foreach ($associations['belongsTo'] as $alias => $details) { 23 | if ($field === $details['foreignKey']) { 24 | $isKey = true; 25 | echo "\t\t\t\t\n"; 26 | break; 27 | } 28 | } 29 | } 30 | if ($isKey !== true) { 31 | echo "\t\t\t\t\n"; 32 | } 33 | } 34 | 35 | echo "\t\t\t\t\n"; 40 | echo "\t\t\t\n"; 41 | 42 | echo "\t\t\n"; 43 | ?> 44 |
BootstrapPaginator->sort('{$field}');?>";?>";?>
\n\t\t\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t\t \n"; 36 | echo "\t\t\t\t\tHtml->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; 37 | echo "\t\t\t\t\tHtml->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; 38 | echo "\t\t\t\t\tForm->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; 39 | echo "\t\t\t\t
45 | 46 | BootstrapPaginator->pagination(); ?>\n"; ?> 47 |
48 |
49 |
50 | 66 |
67 |
68 |
-------------------------------------------------------------------------------- /Test/Case/View/Helper/BootstrapPaginatorHelperTest.php: -------------------------------------------------------------------------------- 1 | BootstrapPaginator = new BootstrapPaginatorHelper($View); 21 | } 22 | 23 | /** 24 | * tearDown method 25 | * 26 | * @return void 27 | */ 28 | public function tearDown() { 29 | unset($this->BootstrapPaginator); 30 | 31 | parent::tearDown(); 32 | } 33 | 34 | /** 35 | * testNumbersEmpty 36 | * 37 | * @return void 38 | */ 39 | public function testNumbersEmpty() { 40 | $this->BootstrapPaginator->request->params['paging']['Post'] = array( 41 | 'page' => 1, 42 | 'current' => 0, 43 | 'count' => 0, 44 | 'prevPage' => false, 45 | 'nextPage' => false, 46 | 'pageCount' => 1, 47 | 'order' => null, 48 | 'limit' => 20, 49 | 'options' => array( 50 | 'page' => 1, 51 | 'conditions' => array() 52 | ), 53 | 'paramType' => 'named' 54 | ); 55 | $numbers = $this->BootstrapPaginator->numbers(array('model' => 'Post')); 56 | $this->assertSame('', $numbers); 57 | } 58 | 59 | /** 60 | * testNumbersSimple 61 | * 62 | * @return void 63 | */ 64 | public function testNumbersSimple() { 65 | $this->BootstrapPaginator->request->params['paging']['Post'] = array( 66 | 'page' => 1, 67 | 'current' => 20, 68 | 'count' => 100, 69 | 'prevPage' => false, 70 | 'nextPage' => true, 71 | 'pageCount' => 5, 72 | 'order' => null, 73 | 'limit' => 20, 74 | 'options' => array( 75 | 'page' => 1, 76 | 'conditions' => array() 77 | ), 78 | 'paramType' => 'named' 79 | ); 80 | 81 | $expected = '
  • 1
  • ' . 82 | '
  • 2
  • ' . 83 | '
  • 3
  • ' . 84 | '
  • 4
  • ' . 85 | '
  • 5
  • '; 86 | 87 | $numbers = $this->BootstrapPaginator->numbers(array('model' => 'Post')); 88 | $this->assertSame($expected, $numbers); 89 | } 90 | 91 | /** 92 | * testNumbersElipsis 93 | * 94 | * @return void 95 | */ 96 | public function testNumbersElipsis() { 97 | $this->BootstrapPaginator->request->params['paging']['Post'] = array( 98 | 'page' => 10, 99 | 'current' => 20, 100 | 'count' => 1000, 101 | 'prevPage' => true, 102 | 'nextPage' => true, 103 | 'pageCount' => 200, 104 | 'order' => null, 105 | 'limit' => 20, 106 | 'options' => array( 107 | 'page' => 1, 108 | 'conditions' => array() 109 | ), 110 | 'paramType' => 'named' 111 | ); 112 | 113 | $expected = '
  • 1
  • ' . 114 | '
  • ' . 115 | '
  • 6
  • ' . 116 | '
  • 7
  • ' . 117 | '
  • 8
  • ' . 118 | '
  • 9
  • ' . 119 | '
  • 10
  • ' . 120 | '
  • 11
  • ' . 121 | '
  • 12
  • ' . 122 | '
  • 13
  • ' . 123 | '
  • 14
  • ' . 124 | '
  • ' . 125 | '
  • 200
  • '; 126 | 127 | $numbers = $this->BootstrapPaginator->numbers(array( 128 | 'model' => 'Post', 129 | 'modulus' => 8, 130 | 'first' => 1, 131 | 'last' => 1, 132 | )); 133 | $this->assertSame($expected, $numbers); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /Console/Command/CopyShell.php: -------------------------------------------------------------------------------- 1 | array( 9 | 'short' => 't', 10 | 'help' => __('Set theme to place Bootstrap files in.'), 11 | 'boolean' => false 12 | ), 13 | 'webroot' => array( 14 | 'short' => 'w', 15 | 'help' => __('Set file output to webroot Theme dir (use with theme option).'), 16 | 'boolean' => true 17 | ) 18 | ); 19 | 20 | return ConsoleOptionParser::buildFromArray(array( 21 | 'command' => 'copy', 22 | 'description' => __('TwitterBootstrap Copy Shell Help.'), 23 | 'options' => array( 24 | 'theme' => $options['theme'], 25 | 'webroot' => $options['webroot'] 26 | ), 27 | 'subcommands' => array( 28 | 'all' => array( 29 | 'help' => __('Copies Less, Js & Img source from Bootstrap submodule in plugin Vendor dir'), 30 | 'parser' => array( 31 | 'description' => array(__('files will be placed in webroot of App or named Theme')), 32 | 'options' => array( 33 | 'theme' => $options['theme'], 34 | 'webroot' => $options['webroot'] 35 | ), 36 | ) 37 | ), 38 | 'less' => array( 39 | 'help' => __('Copies Less source from Bootstrap submodule in plugin Vendor dir'), 40 | 'parser' => array( 41 | 'description' => array(__('files will be placed in webroot/css/lib/ of App or named Theme')), 42 | 'options' => array( 43 | 'theme' => $options['theme'], 44 | 'webroot' => $options['webroot'] 45 | ), 46 | ) 47 | ), 48 | 'img' => array( 49 | 'help' => __('Copies Img source from Bootstrap submodule in plugin Vendor dir'), 50 | 'parser' => array( 51 | 'description' => array(__('files will be placed in webroot/img/ of App or named Theme')), 52 | 'options' => array( 53 | 'theme' => $options['theme'], 54 | 'webroot' => $options['webroot'] 55 | ), 56 | ) 57 | ), 58 | 'js' => array( 59 | 'help' => __('Copies Js source from Bootstrap submodule in plugin Vendor dir'), 60 | 'parser' => array( 61 | 'description' => array(__('files will be placed in webroot/js/lib of App or named Theme')), 62 | 'options' => array( 63 | 'theme' => $options['theme'], 64 | 'webroot' => $options['webroot'] 65 | ), 66 | ) 67 | ) 68 | ) 69 | )); 70 | } 71 | 72 | public function main() { 73 | if (isset($this->params['theme'])) { 74 | $this->_Theme = $this->params['theme']; 75 | } 76 | 77 | $this->_Action = isset($this->args[0]) ? $this->args[0] : 'all'; 78 | switch ($this->_Action) { 79 | case 'js': 80 | $this->copyJs(); 81 | break; 82 | case 'less': 83 | $this->copyLess(); 84 | break; 85 | case 'img': 86 | $this->copyImg(); 87 | break; 88 | default: 89 | $this->copyLess(); 90 | $this->copyImg(); 91 | $this->copyJs(); 92 | break; 93 | } 94 | } 95 | 96 | protected function _copy($options) { 97 | $default = array( 98 | 'from' => null, 99 | 'to' => null, 100 | 'skip' => array('tests', 'README.md'), 101 | ); 102 | $options += $default; 103 | 104 | $this->out('From: ' . str_replace(APP, '', $options['from']) . "\n" . 105 | 'To: ' . str_replace(APP, '', $options['to']) . '', 1, Shell::VERBOSE); 106 | 107 | if ($this->Folder->copy($options)) { 108 | $this->out('' . __('Success.', 'TwitterBootstrap') . ''); 109 | } else { 110 | $this->out('' . __('Error!', 'TwitterBootstrap') . ''); 111 | } 112 | } 113 | 114 | public function copyLess() { 115 | $from = $this->bootstrapPath . self::LESS_DIR; 116 | $to = ''; 117 | if ($this->_Theme && !isset($this->params['webroot'])) { 118 | $to = APP . 'View' . DS . 'Themed' . DS . $this->_Theme . DS . 'webroot' . DS . 'css' . DS . 'lib'; 119 | } elseif ($this->_Theme && isset($this->params['webroot'])) { 120 | $to = WWW_ROOT . 'theme' . DS . $this->_Theme . DS . 'css' . DS . 'lib'; 121 | } else { 122 | $to = WWW_ROOT . 'css' . DS . 'less'; 123 | } 124 | $this->out('Copying Less'); 125 | $this->_copy(compact('from', 'to')); 126 | } 127 | 128 | public function copyImg() { 129 | $from = $this->bootstrapPath . self::IMG_DIR; 130 | $to = ''; 131 | if ($this->_Theme && !isset($this->params['webroot'])) { 132 | $to = APP . 'View' . DS . 'Themed' . DS . $this->_Theme . DS . 'webroot' . DS . 'img'; 133 | } elseif ($this->_Theme && isset($this->params['webroot'])) { 134 | $to = WWW_ROOT . 'theme' . DS . $this->_Theme . DS . 'img'; 135 | } else { 136 | $to = WWW_ROOT . 'img'; 137 | } 138 | $this->out('Copying Images'); 139 | $this->_copy(compact('from', 'to')); 140 | } 141 | 142 | public function copyJs() { 143 | $from = $this->bootstrapPath . self::JS_DIR; 144 | $to = ''; 145 | if ($this->_Theme && !isset($this->params['webroot'])) { 146 | $to = APP . 'View' . DS . 'Themed' . DS . $this->_Theme . DS . 'webroot' . DS . 'js' . DS . 'lib'; 147 | } elseif ($this->_Theme && isset($this->params['webroot'])) { 148 | $to = WWW_ROOT . 'theme' . DS . $this->_Theme . DS . 'js' . DS . 'lib'; 149 | } else { 150 | $to = WWW_ROOT . 'js' . DS . 'lib'; 151 | } 152 | $this->out('Copying Javascript'); 153 | $this->_copy(compact('from', 'to')); 154 | } 155 | 156 | } -------------------------------------------------------------------------------- /Test/Case/View/Helper/BootstrapFormHelperTest.php: -------------------------------------------------------------------------------- 1 | BootstrapForm = new BootstrapFormHelper($View); 21 | } 22 | 23 | /** 24 | * tearDown method 25 | * 26 | * @return void 27 | */ 28 | public function tearDown() { 29 | unset($this->BootstrapForm); 30 | 31 | parent::tearDown(); 32 | } 33 | 34 | /** 35 | * testCreate 36 | * 37 | * @return void 38 | */ 39 | public function testCreate() { 40 | $form = $this->BootstrapForm->create(); 41 | $expected = '
    ' . 42 | '
    '; 43 | $this->assertSame($expected, $form); 44 | } 45 | 46 | /** 47 | * testSubmit 48 | * 49 | * @return void 50 | */ 51 | public function testSubmit() { 52 | $form = $this->BootstrapForm->submit('Submit'); 53 | $expected = '
    ' . 54 | '
    '; 55 | $this->assertSame($expected, $form); 56 | } 57 | 58 | /** 59 | * testInput 60 | * 61 | * @return void 62 | */ 63 | public function testInput() { 64 | $form = $this->BootstrapForm->input('foo'); 65 | $expected = '
    ' . 66 | '
    ' . 67 | '
    '; 68 | $this->assertSame($expected, $form); 69 | } 70 | 71 | /** 72 | * testInputHelpInline 73 | * 74 | * @return void 75 | */ 76 | public function testInputHelpInline() { 77 | $form = $this->BootstrapForm->input('foo', array('helpInline' => 'help inline text')); 78 | $expected = '
    ' . 79 | '
    ' . 80 | 'help inline text
    '; 81 | $this->assertSame($expected, $form); 82 | 83 | $form = $this->BootstrapForm->input('foo', array('helpInline' => array( 84 | 'help inline 1', 85 | 'help inline 2' 86 | ))); 87 | $expected = '
    ' . 88 | '
    ' . 89 | 'help inline 1 ' . 90 | 'help inline 2
    '; 91 | $this->assertSame($expected, $form); 92 | } 93 | 94 | /** 95 | * testInputHelpBlock 96 | * 97 | * @return void 98 | */ 99 | public function testInputHelpBlock() { 100 | $form = $this->BootstrapForm->input('foo', array('helpBlock' => 'help block text')); 101 | $expected = '
    ' . 102 | '
    ' . 103 | '

    help block text

    '; 104 | $this->assertSame($expected, $form); 105 | 106 | $form = $this->BootstrapForm->input('foo', array('helpBlock' => array( 107 | 'help block 1', 108 | 'help block 2' 109 | ))); 110 | $expected = '
    ' . 111 | '
    ' . 112 | '

    help block 1

    ' . 113 | '

    help block 2

    '; 114 | $this->assertSame($expected, $form); 115 | } 116 | 117 | /** 118 | * testInputCheckbox 119 | * 120 | * @return void 121 | */ 122 | public function testInputCheckbox() { 123 | $form = $this->BootstrapForm->input('foo', array('type' => 'checkbox', 'label' => 'Foo')); 124 | $expected = '
    ' . 125 | '
    '; 127 | $this->assertSame($expected, $form); 128 | } 129 | 130 | /** 131 | * testInputRadio 132 | * 133 | * @return void 134 | */ 135 | public function testInputRadio() { 136 | $form = $this->BootstrapForm->input('foo', array( 137 | 'type' => 'radio', 138 | 'label' => 'Foo', 139 | 'options' => array(1 => 'One', 2 => 'Two', 3 => 'Three') 140 | )); 141 | $expected = '
    ' . 142 | '
    ' . 143 | '' . "\n" . 144 | '' . "\n" . 145 | '' . 146 | '
    '; 147 | $this->assertSame($expected, $form); 148 | } 149 | 150 | /** 151 | * testInputSelect 152 | * 153 | * @return void 154 | */ 155 | public function testInputSelect() { 156 | $form = $this->BootstrapForm->input('foo', array( 157 | 'type' => 'select', 158 | 'label' => 'Foo', 159 | 'options' => array(1 => 'One', 2 => 'Two', 3 => 'Three') 160 | )); 161 | $expected = '
    ' . 162 | '
    '; 167 | $this->assertSame($expected, $form); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /View/Helper/BootstrapPaginatorHelper.php: -------------------------------------------------------------------------------- 1 | 'pagination pagination-centered' 9 | ); 10 | 11 | $model = (empty($options['model'])) ? $this->defaultModel() : $options['model']; 12 | 13 | $pagingParams = $this->request->params['paging'][$model]; 14 | $pageCount = $pagingParams['pageCount']; 15 | 16 | if ($pageCount < 2) { 17 | // Don't display pagination if there is only one page 18 | return ''; 19 | } else if ($pageCount == 2) { 20 | // If only two pages, don't show duplicate prev/next buttons 21 | $default['units'] = array('prev', 'numbers', 'next'); 22 | } else { 23 | $default['units'] = array('first', 'prev', 'numbers', 'next', 'last'); 24 | } 25 | 26 | $options += $default; 27 | 28 | $units = $options['units']; 29 | unset($options['units']); 30 | $class = $options['div']; 31 | unset($options['div']); 32 | 33 | $out = array(); 34 | foreach ($units as $unit) { 35 | if ($unit === 'numbers') { 36 | $out[] = $this->{$unit}($options); 37 | } else { 38 | $out[] = $this->{$unit}(null, $options); 39 | } 40 | } 41 | return $this->Html->div($class, $this->Html->tag('ul', implode("\n", $out))); 42 | } 43 | 44 | public function pager($options = array()) { 45 | $default = array( 46 | 'ul' => 'pager', 47 | 'prev' => 'Previous', 48 | 'next' => 'Next', 49 | 'disabled' => 'hide', 50 | ); 51 | $options += $default; 52 | 53 | $class = $options['ul']; 54 | unset($options['ul']); 55 | $prev = $options['prev']; 56 | unset($options['prev']); 57 | $next = $options['next']; 58 | unset($options['next']); 59 | 60 | $out = array(); 61 | $out[] = $this->prev($prev, array_merge($options, array('class' => 'previous'))); 62 | $out[] = $this->next($next, array_merge($options, array('class' => 'next'))); 63 | 64 | return $this->Html->tag('ul', implode("\n", $out), compact('class')); 65 | } 66 | 67 | public function prev($title = null, $options = array(), $disabledTitle = null, $disabledOptions = array()) { 68 | $default = array( 69 | 'title' => '<', 70 | 'tag' => 'li', 71 | 'model' => $this->defaultModel(), 72 | 'class' => null, 73 | 'disabled' => 'disabled', 74 | ); 75 | $options += $default; 76 | if (empty($title)) { 77 | $title = $options['title']; 78 | } 79 | unset($options['title']); 80 | 81 | $disabled = $options['disabled']; 82 | $params = (array)$this->params($options['model']); 83 | if ($disabled === 'hide' && !$params['prevPage']) { 84 | return null; 85 | } 86 | unset($options['disabled']); 87 | 88 | return parent::prev($title, $options, $this->link($title), array_merge($options, array( 89 | 'escape' => false, 90 | 'class' => $disabled, 91 | ))); 92 | } 93 | 94 | public function next($title = null, $options = array(), $disabledTitle = null, $disabledOptions = array()) { 95 | $default = array( 96 | 'title' => '>', 97 | 'tag' => 'li', 98 | 'model' => $this->defaultModel(), 99 | 'class' => null, 100 | 'disabled' => 'disabled', 101 | ); 102 | $options += $default; 103 | if (empty($title)) { 104 | $title = $options['title']; 105 | } 106 | unset($options['title']); 107 | 108 | $disabled = $options['disabled']; 109 | $params = (array)$this->params($options['model']); 110 | if ($disabled === 'hide' && !$params['nextPage']) { 111 | return null; 112 | } 113 | unset($options['disabled']); 114 | 115 | return parent::next($title, $options, $this->link($title), array_merge($options, array( 116 | 'escape' => false, 117 | 'class' => $disabled, 118 | ))); 119 | } 120 | 121 | public function numbers($options = array()) { 122 | $defaults = array( 123 | 'tag' => 'li', 124 | 'before' => null, 125 | 'after' => null, 126 | 'model' => $this->defaultModel(), 127 | 'class' => null, 128 | 'modulus' => 11, 129 | 'separator' => false, 130 | 'first' => null, 131 | 'last' => null, 132 | 'ellipsis' => '
  • ', 133 | 'currentClass' => 'current' 134 | ); 135 | $options += $defaults; 136 | $return = parent::numbers($options); 137 | return preg_replace('@
  • (.*?)
  • @', '
  • \1
  • ', $return); 138 | } 139 | 140 | public function first($title = null, $options = array()) { 141 | $default = array( 142 | 'title' => '<<', 143 | 'tag' => 'li', 144 | 'after' => null, 145 | 'model' => $this->defaultModel(), 146 | 'separator' => null, 147 | 'ellipsis' => null, 148 | 'class' => null, 149 | ); 150 | $options += $default; 151 | if (empty($title)) { 152 | $title = $options['title']; 153 | } 154 | unset($options['title']); 155 | 156 | return (parent::first($title, $options)) ? (parent::first($title, $options)) : $this->Html->tag( 157 | $options['tag'], 158 | $this->link($title, array(), $options), 159 | array('class' => 'disabled') 160 | ); 161 | } 162 | 163 | public function last($title = null, $options = array()) { 164 | $default = array( 165 | 'title' => '>>', 166 | 'tag' => 'li', 167 | 'after' => null, 168 | 'model' => $this->defaultModel(), 169 | 'separator' => null, 170 | 'ellipsis' => null, 171 | 'class' => null, 172 | ); 173 | $options += $default; 174 | if (empty($title)) { 175 | $title = $options['title']; 176 | } 177 | unset($options['title']); 178 | 179 | $params = (array)$this->params($options['model']); 180 | 181 | return (parent::last($title, $options)) ? (parent::last($title, $options)) : $this->Html->tag( 182 | $options['tag'], 183 | $this->link($title, array(), $options), 184 | array('class' => 'disabled') 185 | ); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /Console/Templates/bootstrap/views/view.ctp: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    ";?>

    4 |
    5 | $details) { 10 | if ($field === $details['foreignKey']) { 11 | $isKey = true; 12 | echo "\t\t\t
    \n"; 13 | echo "\t\t\t
    \n\t\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t\t \n\t\t\t
    \n"; 14 | break; 15 | } 16 | } 17 | } 18 | if ($isKey !== true) { 19 | echo "\t\t\t
    \n"; 20 | echo "\t\t\t
    \n\t\t\t\t\n\t\t\t\t \n\t\t\t
    \n"; 21 | } 22 | } 23 | ?> 24 |
    25 |
    26 |
    27 |
    28 | 48 |
    49 |
    50 |
    51 | 52 | $details): ?> 55 |
    56 |
    57 |

    ";?>

    58 | \n";?> 59 |
    60 | \n"; 63 | echo "\t\t\t
    \n\t\t\t\t\n\t\t\t\t \n\t\t\t
    \n"; 64 | } 65 | ?> 66 |
    67 | \n";?> 68 |
    69 |
    70 | 73 |
    74 |
    75 | 76 | $details): 88 | $otherSingularVar = Inflector::variable($alias); 89 | $otherPluralHumanName = Inflector::humanize($details['controller']); 90 | ?> 91 |
    92 |
    93 |

    ";?>

    94 | \n";?> 95 | 96 | 97 | \n"; 100 | } 101 | ?> 102 | 103 | 104 | \n"; 106 | echo "\t\t\t\n"; 107 | foreach ($details['fields'] as $field) { 108 | echo "\t\t\t\t\n"; 109 | } 110 | 111 | echo "\t\t\t\t\n"; 116 | echo "\t\t\t\n"; 117 | 118 | echo "\t\t\n"; 119 | ?> 120 |
    ";?>
    \n"; 112 | echo "\t\t\t\t\tHtml->link(__('View'), array('controller' => '{$details['controller']}', 'action' => 'view', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n"; 113 | echo "\t\t\t\t\tHtml->link(__('Edit'), array('controller' => '{$details['controller']}', 'action' => 'edit', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n"; 114 | echo "\t\t\t\t\tForm->postLink(__('Delete'), array('controller' => '{$details['controller']}', 'action' => 'delete', \${$otherSingularVar}['{$details['primaryKey']}']), null, __('Are you sure you want to delete # %s?', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n"; 115 | echo "\t\t\t\t
    121 | \n\n";?> 122 |
    123 |
    124 | 127 |
    128 |
    129 | 130 | -------------------------------------------------------------------------------- /Console/Templates/bootstrap/actions/controller_actions.ctp: -------------------------------------------------------------------------------- 1 | /** 2 | * index method 3 | * 4 | * @return void 5 | */ 6 | public function index() { 7 | $this->->recursive = 0; 8 | $this->set('', $this->Paginator->paginate()); 9 | } 10 | 11 | /** 12 | * view method 13 | * 14 | * @param string $id 15 | * @return void 16 | */ 17 | public function view($id = null) { 18 | $this->->id = $id; 19 | if (!$this->->exists()) { 20 | throw new NotFoundException(__('Invalid %s', __(''))); 21 | } 22 | $this->set('', $this->->read(null, $id)); 23 | } 24 | 25 | 26 | /** 27 | * add method 28 | * 29 | * @return void 30 | */ 31 | public function add() { 32 | if ($this->request->is('post')) { 33 | $this->->create(); 34 | if ($this->->save($this->request->data)) { 35 | 36 | $this->Session->setFlash( 37 | __('The %s has been saved', __('')), 38 | 'alert', 39 | array( 40 | 'plugin' => 'TwitterBootstrap', 41 | 'class' => 'alert-success' 42 | ) 43 | ); 44 | $this->redirect(array('action' => 'index')); 45 | 46 | $this->flash(__('%s saved.', __('')), array('action' => 'index')); 47 | 48 | } else { 49 | 50 | $this->Session->setFlash( 51 | __('The %s could not be saved. Please, try again.', __('')), 52 | 'alert', 53 | array( 54 | 'plugin' => 'TwitterBootstrap', 55 | 'class' => 'alert-error' 56 | ) 57 | ); 58 | 59 | } 60 | } 61 | {$assoc} as $associationName => $relation): 64 | if (!empty($associationName)): 65 | $otherModelName = $this->_modelName($associationName); 66 | $otherPluralName = $this->_pluralName($associationName); 67 | echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n"; 68 | $compact[] = "'{$otherPluralName}'"; 69 | endif; 70 | endforeach; 71 | endforeach; 72 | if (!empty($compact)): 73 | echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n"; 74 | endif; 75 | ?> 76 | } 77 | 78 | 79 | /** 80 | * edit method 81 | * 82 | * @param string $id 83 | * @return void 84 | */ 85 | public function edit($id = null) { 86 | $this->->id = $id; 87 | if (!$this->->exists()) { 88 | throw new NotFoundException(__('Invalid %s', __(''))); 89 | } 90 | if ($this->request->is('post') || $this->request->is('put')) { 91 | if ($this->->save($this->request->data)) { 92 | 93 | $this->Session->setFlash( 94 | __('The %s has been saved', __('')), 95 | 'alert', 96 | array( 97 | 'plugin' => 'TwitterBootstrap', 98 | 'class' => 'alert-success' 99 | ) 100 | ); 101 | $this->redirect(array('action' => 'index')); 102 | 103 | $this->flash(__('The %s has been saved.', __('')), array('action' => 'index')); 104 | 105 | } else { 106 | 107 | $this->Session->setFlash( 108 | __('The %s could not be saved. Please, try again.', __('')), 109 | 'alert', 110 | array( 111 | 'plugin' => 'TwitterBootstrap', 112 | 'class' => 'alert-error' 113 | ) 114 | ); 115 | 116 | } 117 | } else { 118 | $this->request->data = $this->->read(null, $id); 119 | } 120 | {$assoc} as $associationName => $relation): 123 | if (!empty($associationName)): 124 | $otherModelName = $this->_modelName($associationName); 125 | $otherPluralName = $this->_pluralName($associationName); 126 | echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n"; 127 | $compact[] = "'{$otherPluralName}'"; 128 | endif; 129 | endforeach; 130 | endforeach; 131 | if (!empty($compact)): 132 | echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n"; 133 | endif; 134 | ?> 135 | } 136 | 137 | /** 138 | * delete method 139 | * 140 | * @param string $id 141 | * @return void 142 | */ 143 | public function delete($id = null) { 144 | if (!$this->request->is('post')) { 145 | throw new MethodNotAllowedException(); 146 | } 147 | $this->->id = $id; 148 | if (!$this->->exists()) { 149 | throw new NotFoundException(__('Invalid %s', __(''))); 150 | } 151 | if ($this->->delete()) { 152 | 153 | $this->Session->setFlash( 154 | __('The %s deleted', __('')), 155 | 'alert', 156 | array( 157 | 'plugin' => 'TwitterBootstrap', 158 | 'class' => 'alert-success' 159 | ) 160 | ); 161 | $this->redirect(array('action' => 'index')); 162 | 163 | $this->flash(__('%s deleted', __('')), array('action' => 'index')); 164 | 165 | } 166 | 167 | $this->Session->setFlash( 168 | __('The %s was not deleted', __('')), 169 | 'alert', 170 | array( 171 | 'plugin' => 'TwitterBootstrap', 172 | 'class' => 'alert-error' 173 | ) 174 | ); 175 | 176 | $this->flash(__('%s was not deleted', __('')), array('action' => 'index')); 177 | 178 | $this->redirect(array('action' => 'index')); 179 | } 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Development of this plugin has moved [BoostCake](https://github.com/slywalker/cakephp-plugin-boost_cake). 2 | 3 | #TwitterBootstrap Plugin for CakePHP2.x 4 | The TwitterBootstrap Plugin provides an easy-to-use feature Bootstrap in CakePHP2.x 5 | 6 | [Bootstrap, from Twitter](http://twitter.github.com/bootstrap/) 7 | 8 | This v1.5.7 supports Bootstrap v2.2.2 9 | 10 | ##Installation 11 | ###This plugin 12 | 13 | Composer 14 | 15 | { 16 | "repositories": [ 17 | { 18 | "type": "package", 19 | "package": { 20 | "name": "twitter/bootstrap", 21 | "version": "dev-master", 22 | "source": { 23 | "url": "git://github.com/twitter/bootstrap", 24 | "type": "git", 25 | "reference": "master" 26 | }, 27 | "require": { 28 | "composer/installers": "*" 29 | } 30 | }, 31 | "packagist": false 32 | } 33 | ], 34 | "require": { 35 | "twitter/bootstrap": "dev-master", 36 | "slywalker/twitter_bootstrap": "dev-master" 37 | }, 38 | "config": { 39 | "vendor-dir": "Vendor" 40 | } 41 | } 42 | 43 | Submodule 44 | 45 | $ cd /your_app_path 46 | $ git submodule add git://github.com/slywalker/TwitterBootstrap.git Plugin/TwitterBootstrap 47 | $ git submodule update --init --recursive 48 | 49 | Clone 50 | 51 | $ cd /your_app_path/Plugin 52 | $ git clone git://github.com/slywalker/TwitterBootstrap.git 53 | $ cd TwitterBootstrap 54 | $ git submodule update --init 55 | 56 | ###Enable plugin 57 | You need to enable the plugin your app/Config/bootstrap.php file: 58 | 59 | CakePlugin::load('TwitterBootstrap'); 60 | 61 | If you are already using `CakePlugin::loadAll();`, then this is not necessary. 62 | 63 | ###bootstrap 64 | Manual 65 | 66 | - Download bootstrap: [Bootstrap, from Twitter](http://twitter.github.com/bootstrap/) 67 | - Unzip that download. 68 | - Copy folders(css, img, js) in the resulting folder to `app/webroot` 69 | 70 | Shell Command (need `recess` and `uglifyjs`) 71 | 72 | (Copy less, js, img files to webroot and make css, js files) 73 | 74 | $ cd /your_app 75 | $ Console/cake TwitterBootstrap.copy 76 | $ Console/cake TwitterBootstrap.make 77 | 78 | ##Usage 79 | Controller/AppController.php: 80 | 81 | array('className' => 'TwitterBootstrap.BootstrapHtml'), 87 | 'Form' => array('className' => 'TwitterBootstrap.BootstrapForm'), 88 | 'Paginator' => array('className' => 'TwitterBootstrap.BootstrapPaginator'), 89 | ); 90 | 91 | } 92 | 93 | View/Layout/default.ctp: 94 | 95 | Html->css('bootstrap.min'); ?> 96 | Html->css('bootstrap-responsive.min'); ?> 97 | Html->script('bootstrap.min'); ?> 98 | 99 | Output form input as Bootstrap format 100 | 101 | Form->create('Sample', array('class' => 'form-horizontal')); ?> 102 |
    103 | Extending form controls 104 | Form->input('field1', array( 105 | 'label' => 'Prepended text', 106 | 'type' => 'text', 107 | 'class' => 'span2', 108 | 'prepend' => '@', 109 | 'helpBlock' => 'Here\'s some help text', 110 | )); ?> 111 | Form->input('field2', array( 112 | 'label' => 'Appended text', 113 | 'type' => 'text', 114 | 'class' => 'span2', 115 | 'append' => '.00', 116 | 'helpInline' => 'Here\'s more help text', 117 | )); ?> 118 | Form->input('field3', array( 119 | 'label' => 'Append and prepend', 120 | 'type' => 'text', 121 | 'class' => 'span2', 122 | 'prepend' => '$', 123 | 'append' => '.00', 124 | )); ?> 125 | Form->input('field4', array( 126 | 'label' => 'Append with button', 127 | 'type' => 'text', 128 | 'class' => 'span2', 129 | 'append' => array('Go!', array('wrap' => 'button', 'class' => 'btn')), 130 | )); ?> 131 | Form->input('field5', array( 132 | 'label' => 'Inline checkboxes', 133 | 'type' => 'select', 134 | 'multiple' => 'checkbox inline', 135 | 'options' => array('1', '2', '3'), 136 | )); ?> 137 | Form->input('field6', array( 138 | 'label' => 'Checkboxes', 139 | 'type' => 'select', 140 | 'multiple' => 'checkbox', 141 | 'options' => array( 142 | '1' => 'Option one is this and that¡ªbe sure to include why it\'s great', 143 | '2' => 'Option two can also be checked and included in form results', 144 | '3' => 'Option three can¡ªyes, you guessed it¡ªalso be checked and included in form results', 145 | ), 146 | 'helpBlock' => 'Note: Labels surround all the options for much larger click areas and a more usable form.', 147 | )); ?> 148 | Form->input('field7', array( 149 | 'label' => 'Radio buttons', 150 | 'type' => 'radio', 151 | 'options' => array( 152 | '1' => 'Option one is this and that¡ªbe sure to include why it\'s great', 153 | '2' => 'Option two can is something else and selecting it will deselect option one', 154 | ), 155 | )); ?> 156 |
    157 | Form->submit('Save changes', array( 158 | 'div' => false, 159 | 'class' => 'btn btn-primary', 160 | )); ?> 161 | 162 |
    163 |
    164 | Form->end(); ?> 165 | 166 | Output SessionHelper::flash as Bootstrap format 167 | 168 | // SomethingsController 169 | $this->Session->setFlash(__('The something has been saved'), 'alert', array( 170 | 'plugin' => 'TwitterBootstrap', 171 | 'class' => 'alert-success' 172 | )); 173 | $this->Session->setFlash(__('The something could not be saved. Please, try again.'), 'alert', array( 174 | 'plugin' => 'TwitterBootstrap', 175 | 'class' => 'alert-error' 176 | )); 177 | 178 | // View 179 | Session->flash(); ?> 180 | 181 | // Auth 182 | Session->flash('auth', array( 183 | 'element' => 'alert', 184 | 'params' => array('plugin' => 'TwitterBootstrap'), 185 | )); ?> 186 | 187 | Output Paginate as Bootstrap format 188 | 189 | // div.pagination.pagination-centered 190 | Paginator->pagination(); ?> 191 | // ul.pager 192 | Paginator->pager(); ?> 193 | 194 | Breadcrumb 195 | 196 | Html->breadcrumb(array( 197 | $this->Html->link('one', '/one'), 198 | $this->Html->link('two', '/two'), 199 | 'three', 200 | )); ?> 201 | 202 | You can see more sample. access http://{webroot}/twitter_bootstrap 203 | 204 | ##License 205 | 206 | The MIT License (MIT) 207 | 208 | Copyright (c) 2012 Yasuo Harada 209 | 210 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 211 | 212 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 213 | 214 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 215 | -------------------------------------------------------------------------------- /View/Helper/BootstrapFormHelper.php: -------------------------------------------------------------------------------- 1 | array('className' => 'TwitterBootstrap.BootstrapHtml')); 24 | 25 | protected $_isHorizontal = false; 26 | 27 | protected $_Opts = array(); 28 | 29 | public function uneditable($fieldName, $options = array(), $before = false) { 30 | if ($before) { 31 | $class = explode(' ', $this->_extractOption('class', $options)); 32 | if (in_array('uneditable-input', $class)) { 33 | $this->_Opts[$fieldName] = $options; 34 | $options['type'] = 'uneditable'; 35 | } 36 | return $options; 37 | } else { 38 | return $this->Html->tag('span', $options['value'], $options); 39 | } 40 | } 41 | 42 | public function addon($fieldName, $options = array(), $before = false) { 43 | if ($before) { 44 | $prepend = $this->_extractOption('prepend', $options); 45 | $append = $this->_extractOption('append', $options); 46 | if ($prepend || $append) { 47 | $this->_Opts[$fieldName] = $options; 48 | $options['type'] = 'addon'; 49 | } 50 | return $options; 51 | } else { 52 | $type = $this->_extractOption('type', $this->_Opts[$fieldName]); 53 | 54 | $default = array('wrap' => 'span', 'class' => 'add-on'); 55 | $divOptions = array(); 56 | foreach (array('prepend', 'append') as $addon) { 57 | $$addon = null; 58 | $option = (array)$this->_extractOption($addon, $options); 59 | if ($option) { 60 | if (!is_array($option[0])) { 61 | $option = array($option); 62 | } 63 | foreach ($option as $_option) { 64 | array_push($_option, array()); 65 | list($text, $addonOptions) = $_option; 66 | $addonOptions += $default; 67 | 68 | $wrap = $addonOptions['wrap']; 69 | unset($addonOptions['wrap']); 70 | 71 | $$addon .= $this->Html->tag($wrap, $text, $addonOptions); 72 | } 73 | 74 | unset($options[$addon]); 75 | $divOptions = $this->addClass($divOptions, 'input-' . $addon); 76 | } 77 | } 78 | $out = $prepend . $this->{$type}($fieldName, $options) . $append; 79 | return $this->Html->tag('div', $out, $divOptions); 80 | } 81 | } 82 | 83 | public function checkbox($fieldName, $options = array()) { 84 | $label = $this->_extractOption('label', $this->_Opts[$fieldName]); 85 | if (!is_array($label)) { 86 | $label = array('text' => $label); 87 | } 88 | $after = $this->_extractOption('after', $this->_Opts[$fieldName]); 89 | 90 | if ($this->_isHorizontal) { 91 | $label['text'] = $after; 92 | $label['class'] = null; 93 | } 94 | 95 | $label = $this->addClass($label, 'checkbox'); 96 | $text = $label['text']; 97 | unset($label['text']); 98 | $out = parent::checkbox($fieldName, $options) . $text; 99 | return $this->label($fieldName, $out, $label); 100 | } 101 | 102 | protected function _setOptions($fieldName, $options) { 103 | if ('textarea' === $options['type']) { 104 | $options += array('cols' => false, 'rows' => '3'); 105 | } 106 | if ('checkbox' === $options['type']) { 107 | if ($this->_isHorizontal) { 108 | $options['after'] = null; 109 | } else { 110 | $options['label'] = false; 111 | } 112 | } 113 | return $options; 114 | } 115 | 116 | public function radio($fieldName, $radioOptions = array(), $options = array()) { 117 | $options['legend'] = false; 118 | $options['separator'] = "\n"; 119 | $out = parent::radio($fieldName, $radioOptions, $options); 120 | $out = $this->_restructureLabel($out, array('class' => 'radio')); 121 | return $out; 122 | } 123 | 124 | public function select($fieldName, $options = array(), $attributes = array()) { 125 | $multiple = $this->_extractOption('multiple', $attributes); 126 | $checkbox = explode(' ', $multiple); 127 | $attributes['multiple'] = $checkbox[0]; 128 | $out = parent::select($fieldName, $options, $attributes); 129 | if ('checkbox' === $checkbox[0]) { 130 | $out = $this->_restructureLabel($out, array('class' => $multiple)); 131 | } 132 | return $out; 133 | } 134 | 135 | protected function _restructureLabel($out, $options = array()) { 136 | $out = explode("\n", $out); 137 | foreach ($out as $key => &$_out) { 138 | $input = strip_tags($_out, '