From 6493f7abe3bd59f55b7b572af03fae8abde1d4a3 Mon Sep 17 00:00:00 2001 From: Antonio Ramirez Date: Sun, 12 May 2013 20:21:44 +0200 Subject: [PATCH] #20 proposed architecture for bootstrap --- yii/assets.php | 17 ++ yii/bootstrap/enum/AlertEnum.php | 26 +++ yii/bootstrap/enum/BootstrapEnum.php | 26 +++ yii/bootstrap/enum/ButtonEnum.php | 33 +++ yii/bootstrap/enum/IconEnum.php | 158 +++++++++++++ yii/bootstrap/enum/ProgressEnum.php | 19 ++ yii/bootstrap/helpers/Alert.php | 19 ++ yii/bootstrap/helpers/Assets.php | 19 ++ yii/bootstrap/helpers/Button.php | 19 ++ yii/bootstrap/helpers/Icon.php | 43 ++++ yii/bootstrap/helpers/Progress.php | 19 ++ yii/bootstrap/helpers/base/Alert.php | 46 ++++ yii/bootstrap/helpers/base/Assets.php | 25 ++ yii/bootstrap/helpers/base/Button.php | 69 ++++++ yii/bootstrap/helpers/base/Icon.php | 21 ++ yii/bootstrap/helpers/base/Progress.php | 21 ++ yii/bootstrap/widgets/Modal.php | 303 +++++++++++++++++++++++++ yii/bootstrap/widgets/base/BootstrapWidget.php | 139 ++++++++++++ 18 files changed, 1022 insertions(+) create mode 100644 yii/bootstrap/enum/AlertEnum.php create mode 100644 yii/bootstrap/enum/BootstrapEnum.php create mode 100644 yii/bootstrap/enum/ButtonEnum.php create mode 100644 yii/bootstrap/enum/IconEnum.php create mode 100644 yii/bootstrap/enum/ProgressEnum.php create mode 100644 yii/bootstrap/helpers/Alert.php create mode 100644 yii/bootstrap/helpers/Assets.php create mode 100644 yii/bootstrap/helpers/Button.php create mode 100644 yii/bootstrap/helpers/Icon.php create mode 100644 yii/bootstrap/helpers/Progress.php create mode 100644 yii/bootstrap/helpers/base/Alert.php create mode 100644 yii/bootstrap/helpers/base/Assets.php create mode 100644 yii/bootstrap/helpers/base/Button.php create mode 100644 yii/bootstrap/helpers/base/Icon.php create mode 100644 yii/bootstrap/helpers/base/Progress.php create mode 100644 yii/bootstrap/widgets/Modal.php create mode 100644 yii/bootstrap/widgets/base/BootstrapWidget.php diff --git a/yii/assets.php b/yii/assets.php index 7ee177d..6c32b83 100644 --- a/yii/assets.php +++ b/yii/assets.php @@ -42,4 +42,21 @@ return array( ), 'depends' => array('yii'), ), + 'yii/bootstrap' => array( + 'sourcePath' => __DIR__ . '/assets/bootstrap', + 'js' => array( + '/js/bootstrap.min.js', + ), + 'css' => array( + 'css/bootstrap.css' + ), + 'depends' => array('yii'), + ), + 'yii/bootstrap-responsive' => array( + 'sourcePath' => __DIR__ . '/assets/bootstrap', + 'css' => array( + 'css/bootstrap-responsive.css' + ), + 'depends' => array('yii/bootstrap'), + ) ); diff --git a/yii/bootstrap/enum/AlertEnum.php b/yii/bootstrap/enum/AlertEnum.php new file mode 100644 index 0000000..d0096fb --- /dev/null +++ b/yii/bootstrap/enum/AlertEnum.php @@ -0,0 +1,26 @@ + + * @since 2.0 + */ +class AlertEnum +{ + const CLASS_NAME = 'alert'; + + const TYPE_DEFAULT = ''; + const TYPE_SUCCESS = 'alert-success'; + const TYPE_INFORMATION = 'alert-info'; + const TYPE_ERROR = 'alert-error'; + + const SIZE_BLOCK = 'alert-block'; +} \ No newline at end of file diff --git a/yii/bootstrap/enum/BootstrapEnum.php b/yii/bootstrap/enum/BootstrapEnum.php new file mode 100644 index 0000000..ad1d0a8 --- /dev/null +++ b/yii/bootstrap/enum/BootstrapEnum.php @@ -0,0 +1,26 @@ + + * @since 2.0 + */ +class BootstrapEnum +{ + const FADE = 'fade'; + const IN = 'in'; + const CLOSE = 'close'; + const DISABLED = 'disabled'; + const ACTIVE = 'active'; + const MODAL = 'modal'; + const HIDE = 'hide'; + const DIALOG = 'dialog'; + const ALERT = 'alert'; +} \ No newline at end of file diff --git a/yii/bootstrap/enum/ButtonEnum.php b/yii/bootstrap/enum/ButtonEnum.php new file mode 100644 index 0000000..68454e4 --- /dev/null +++ b/yii/bootstrap/enum/ButtonEnum.php @@ -0,0 +1,33 @@ + + * @since 2.0 + */ +class ButtonEnum +{ + const TYPE_DEFAULT = 'btn'; + const TYPE_PRIMARY = 'btn-primary'; + const TYPE_INFO = 'btn-info'; + const TYPE_SUCCESS = 'btn-success'; + const TYPE_WARNING = 'btn-warning'; + const TYPE_DANGER = 'btn-danger'; + const TYPE_INVERSE = 'btn-inverse'; + const TYPE_LINK = 'btn-link'; + + const SIZE_DEFAULT = ''; + const SIZE_LARGE = 'btn-large'; + const SIZE_SMALL = 'btn-small'; + const SIZE_MINI = 'btn-mini'; + const SIZE_BLOCK = 'btn-block'; + +} \ No newline at end of file diff --git a/yii/bootstrap/enum/IconEnum.php b/yii/bootstrap/enum/IconEnum.php new file mode 100644 index 0000000..bebd8a3 --- /dev/null +++ b/yii/bootstrap/enum/IconEnum.php @@ -0,0 +1,158 @@ + + * @since 2.0 + */ +class IconEnum +{ + const ICON_GLASS = 'icon-glass'; + const ICON_MUSIC = 'icon-music'; + const ICON_SEARCH = 'icon-search'; + const ICON_ENVELOPE = 'icon-envelope'; + const ICON_HEART = 'icon-heart'; + const ICON_STAR = 'icon-star'; + const ICON_STAR_EMPTY = 'icon-star-empty'; + const ICON_USER = 'icon-user'; + const ICON_FILM = 'icon-film'; + const ICON_TH_LARGE = 'icon-th-large'; + const ICON_TH = 'icon-th'; + const ICON_TH_LIST = 'icon-th-list'; + const ICON_OK = 'icon-ok'; + const ICON_REMOVE = 'icon-remove'; + const ICON_ZOOM_IN = 'icon-zoom-in'; + const ICON_ZOOM_OUT = 'icon-zoom-out'; + const ICON_OFF = 'icon-off'; + const ICON_SIGNAL = 'icon-signal'; + const ICON_COG = 'icon-cog'; + const ICON_TRASH = 'icon-trash'; + const ICON_HOME = 'icon-home'; + const ICON_FILE = 'icon-file'; + const ICON_TIME = 'icon-time'; + const ICON_ROAD = 'icon-road'; + const ICON_DOWNLOAD_ALT = 'icon-download-alt'; + const ICON_DOWNLOAD = 'icon-download'; + const ICON_UPLOAD = 'icon-upload'; + const ICON_INBOX = 'icon-inbox'; + const ICON_PLAY_CIRCLE = 'icon-play-circle'; + const ICON_REPEAT = 'icon-repeat'; + const ICON_REFRESH = 'icon-refresh'; + const ICON_LIST_ALT = 'icon-list-alt'; + const ICON_LOCK = 'icon-lock'; + const ICON_FLAG = 'icon-flag'; + const ICON_HEADPHONES = 'icon-headphones'; + const ICON_VOLUME_OFF = 'icon-volume-off'; + const ICON_VOLUME_DOWN = 'icon-volume-down'; + const ICON_VOLUME_UP = 'icon-volume-up'; + const ICON_QRCODE = 'icon-qrcode'; + const ICON_BARCODE = 'icon-barcode'; + const ICON_TAG = 'icon-tag'; + const ICON_TAGS = 'icon-tags'; + const ICON_BOOK = 'icon-book'; + const ICON_BOOKMARK = 'icon-bookmark'; + const ICON_PRINT = 'icon-print'; + const ICON_CAMERA = 'icon-camera'; + const ICON_FONT = 'icon-font'; + const ICON_BOLD = 'icon-bold'; + const ICON_ITALIC = 'icon-italic'; + const ICON_TEXT_HEIGHT = 'icon-text-height'; + const ICON_TEXT_WIDTH = 'icon-text-width'; + const ICON_ALIGN_LEFT = 'icon-align-left'; + const ICON_ALIGN_CENTER = 'icon-align-center'; + const ICON_ALIGN_RIGHT = 'icon-align-right'; + const ICON_ALIGN_JUSTIFY = 'icon-align-justify'; + const ICON_LIST = 'icon-list'; + const ICON_INDENT_LEFT = 'icon-indent-left'; + const ICON_INDENT_RIGHT = 'icon-indent-right'; + const ICON_FACETIME_VIDEO = 'icon-facetime-video'; + const ICON_PICTURE = 'icon-picture'; + const ICON_PENCIL = 'icon-pencil'; + const ICON_MAP_MARKER = 'icon-map-marker'; + const ICON_ADJUST = 'icon-adjust'; + const ICON_TINT = 'icon-tint'; + const ICON_EDIT = 'icon-edit'; + const ICON_SHARE = 'icon-share'; + const ICON_CHECK = 'icon-check'; + const ICON_MOVE = 'icon-move'; + const ICON_STEP_BACKWARD = 'icon-step-backward'; + const ICON_FAST_BACKWARD = 'icon-fast-backward'; + const ICON_BACKWARD = 'icon-backward'; + const ICON_PLAY = 'icon-play'; + const ICON_PAUSE = 'icon-pause'; + const ICON_STOP = 'icon-pause'; + const ICON_FORWARD = 'icon-forward'; + const ICON_FAST_FORWARD = 'icon-fast-forward'; + const ICON_STEP_FORWARD = 'icon-step-forward'; + const ICON_EJECT = 'icon-eject'; + const ICON_CHEVRON_LEFT = 'icon-chevron-left'; + const ICON_CHEVRON_RIGHT = 'icon-chevron-right'; + const ICON_PLUS_SIGN = 'icon-plus-sign'; + const ICON_MINUS_SIGN = 'icon-minus-sign'; + const ICON_REMOVE_SIGN = 'icon-remove-sign'; + const ICON_OK_SIGN = 'icon-ok-sign'; + const ICON_QUESTION_SIGN = 'icon-question-sign'; + const ICON_INFO_SIGN = 'icon-info-sign'; + const ICON_SCREENSHOT = 'icon-screenshot'; + const ICON_REMOVE_CIRCLE = 'icon-remove-circle'; + const ICON_OK_CIRCLE = 'icon-ok-circle'; + const ICON_BAN_CIRCLE = 'icon-ban-circle'; + const ICON_ARROW_LEFT = 'icon-arrow-left'; + const ICON_ARROW_RIGHT = 'icon-arrow-right'; + const ICON_ARROW_UP = 'icon-arrow-up'; + const ICON_ARROW_DOWN = 'icon-arrow-down'; + const ICON_SHARE_ALT = 'icon-share-alt'; + const ICON_RESIZE_FULL = 'icon-resize-full'; + const ICON_RESIZE_SMALL = 'icon-resize-small'; + const ICON_PLUS = 'icon-plus'; + const ICON_MINUS = 'icon-minus'; + const ICON_ASTERISK = 'icon-asterisk'; + const ICON_EXCLAMATION_SIGN = 'icon-exclamation-sign'; + const ICON_GIFT = 'icon-gift'; + const ICON_LEAF = 'icon-leaf'; + const ICON_FIRE = 'icon-fire'; + const ICON_EYE_OPEN = 'icon-eye-open'; + const ICON_EYE_CLOSE = 'icon-eye-close'; + const ICON_WARNING_SIGN = 'icon-warning-sign'; + const ICON_PLANE = 'icon-plane'; + const ICON_CALENDAR = 'icon-calendar'; + const ICON_RANDOM = 'icon-random'; + const ICON_COMMENT = 'icon-comment'; + const ICON_MAGNET = 'icon-magnet'; + const ICON_CHEVRON_UP = 'icon-chevron-up'; + const ICON_CHEVRON_DOWN = 'icon-chevron-down'; + const ICON_RETWEET = 'icon-retweet'; + const ICON_SHOPPING_CART = 'icon-shopping-cart'; + const ICON_FOLDER_CLOSE = 'icon-folder-close'; + const ICON_FOLDER_OPEN = 'icon-folder-open'; + const ICON_RESIZE_VERTICAL = 'icon-resize-vertical'; + const ICON_RESIZE_HORIZONTAL = 'icon-resize-horizontal'; + const ICON_HDD = 'icon-hdd'; + const ICON_BULLHORN = 'icon-bullhorn'; + const ICON_BELL = 'icon-bell'; + const ICON_CERTFICATE = 'icon-certificate'; + const ICON_THUMBS_UP = 'icon-thumbs-up'; + const ICON_THUMBS_DOWN = 'icon-thumbs-down'; + const ICON_HAND_RIGHT = 'icon-hand-right'; + const ICON_HAND_LEFT = 'icon-hand-left'; + const ICON_HAND_UP = 'icon-hand-up'; + const ICON_HAND_DOWN = 'icon-hand-down'; + const ICON_CIRCLE_ARROW_RIGHT = 'icon-circle-arrow-right'; + const ICON_CIRCLE_ARROW_LEFT = 'icon-circle-arrow-left'; + const ICON_CIRCLE_ARROW_UP = 'icon-circle-arrow-up'; + const ICON_CIRCLE_ARROW_DOWN = 'icon-circle-arrow-down'; + const ICON_GLOBE = 'icon-globe'; + const ICON_WRENCH = 'icon-wrench'; + const ICON_TASKS = 'icon-tasks'; + const ICON_FILTER = 'icon-filter'; + const ICON_BRIEFCASE = 'icon-briefcase'; + const ICON_FULLSCREEN = 'icon-fullscreen'; +} \ No newline at end of file diff --git a/yii/bootstrap/enum/ProgressEnum.php b/yii/bootstrap/enum/ProgressEnum.php new file mode 100644 index 0000000..44a8b51 --- /dev/null +++ b/yii/bootstrap/enum/ProgressEnum.php @@ -0,0 +1,19 @@ + + * @since 2.0 + */ +class ProgressEnum +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/Alert.php b/yii/bootstrap/helpers/Alert.php new file mode 100644 index 0000000..58139bd --- /dev/null +++ b/yii/bootstrap/helpers/Alert.php @@ -0,0 +1,19 @@ + + * @since 2.0 + */ +class Alert extends base\Alert +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/Assets.php b/yii/bootstrap/helpers/Assets.php new file mode 100644 index 0000000..e03b04f --- /dev/null +++ b/yii/bootstrap/helpers/Assets.php @@ -0,0 +1,19 @@ + + * @since 2.0 + */ +class Assets extends base\Assets +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/Button.php b/yii/bootstrap/helpers/Button.php new file mode 100644 index 0000000..1448838 --- /dev/null +++ b/yii/bootstrap/helpers/Button.php @@ -0,0 +1,19 @@ + + * @since 2.0 + */ +class Button extends base\Button +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/Icon.php b/yii/bootstrap/helpers/Icon.php new file mode 100644 index 0000000..41eb0b9 --- /dev/null +++ b/yii/bootstrap/helpers/Icon.php @@ -0,0 +1,43 @@ + + * @since 2.0 + */ +class Icon extends base\Icon +{ + /** + * Generates an icon. + * @param string $icon the icon type. + * @param array $htmlOptions additional HTML attributes. + * @return string the generated icon. + */ + public static function i($icon, $htmlOptions = array()) + { + if (is_string($icon)) + { + if (strpos($icon, 'icon-') === false) + $icon = 'icon-' . implode(' icon-', explode(' ', $icon)); + + // TODO: this method may should be added to ArrayHelper::add or ArrayHelper::append? + if (isset($htmlOptions['class'])) + $htmlOptions['class'] .= ' ' . $icon; + else + $htmlOptions['class'] = $icon; + + return Html::tag('i', '', $htmlOptions); + } + return ''; + } +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/Progress.php b/yii/bootstrap/helpers/Progress.php new file mode 100644 index 0000000..4e5bc7f --- /dev/null +++ b/yii/bootstrap/helpers/Progress.php @@ -0,0 +1,19 @@ + + * @since 2.0 + */ +class Progress extends base\Progress +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/base/Alert.php b/yii/bootstrap/helpers/base/Alert.php new file mode 100644 index 0000000..bc6f899 --- /dev/null +++ b/yii/bootstrap/helpers/base/Alert.php @@ -0,0 +1,46 @@ + + * @since 2.0 + */ +class Alert +{ + + /** + * Generates an alert box + * @param $message + * @param array $htmlOptions + * @param bool $dismiss whether to display dismissal link or not + * @return string + */ + public static function create($message, $htmlOptions = array(), $dismiss = true) + { + // TODO: this method may should be added to ArrayHelper::add or ArrayHelper::append? + if (isset($htmlOptions['class'])) + $htmlOptions['class'] .= ' ' . AlertEnum::CLASS_NAME; + else + $htmlOptions['class'] = AlertEnum::CLASS_NAME; + + ob_start(); + echo Html::beginTag('div', $htmlOptions); + if ($dismiss) + echo Button::closeLink('×', BootstrapEnum::ALERT); + echo $message; + echo Html::endTag('div'); + return ob_get_clean(); + } +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/base/Assets.php b/yii/bootstrap/helpers/base/Assets.php new file mode 100644 index 0000000..30cd8ae --- /dev/null +++ b/yii/bootstrap/helpers/base/Assets.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class Assets +{ + public static function registerBundle($responsive = false) + { + $bundle = $responsive ? 'yii/bootstrap' : 'yii/bootstrap-responsive'; + + Yii::$app->getView()->registerAssetBundle($bundle); + } +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/base/Button.php b/yii/bootstrap/helpers/base/Button.php new file mode 100644 index 0000000..2ae9da5 --- /dev/null +++ b/yii/bootstrap/helpers/base/Button.php @@ -0,0 +1,69 @@ + + * @since 2.0 + */ +class Button +{ + /** + * Returns a dismissal alert link + * @param string $text + * @param string $dismiss what to dismiss (alert or modal) + * @return string the dismissal alert link + */ + public static function closeLink($text = '×', $dismiss = null) + { + $options = array('class' => BootstrapEnum::CLOSE); + if(null !== $dismiss) + $options['data-dismiss'] = $dismiss; + return Html::a($text, '#', $options); + } + + /** + * Returns a dismissal button + * @param string $text the text to use for the close button + * @param string $dismiss what to dismiss (alert or modal) + * @return string the dismissal button + */ + public static function closeButton($text = '×', $dismiss = null) + { + $options = array('type' => 'button', 'class' => BootstrapEnum::CLOSE); + if(null !== $dismiss) + $options['data-dismiss'] = $dismiss; + + return Html::button($text, null, null, $options); + } + + + /** + * Returns a link button + * @param string $label the button label + * @param array $htmlOptions the HTML attributes of the button + * @return string the generated button + */ + public static function link($label, $htmlOptions = array()) + { + // TODO: consider method add or append to ArrayHelper class + if (isset($htmlOptions['class'])) + $htmlOptions['class'] .= ' ' . ButtonEnum::TYPE_LINK; + else + $htmlOptions['class'] = ButtonEnum::TYPE_LINK; + + return Html::a($label, '#', $htmlOptions); + } +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/base/Icon.php b/yii/bootstrap/helpers/base/Icon.php new file mode 100644 index 0000000..47b0b05 --- /dev/null +++ b/yii/bootstrap/helpers/base/Icon.php @@ -0,0 +1,21 @@ + + * @since 2.0 + */ +class Icon +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/helpers/base/Progress.php b/yii/bootstrap/helpers/base/Progress.php new file mode 100644 index 0000000..a13a44f --- /dev/null +++ b/yii/bootstrap/helpers/base/Progress.php @@ -0,0 +1,21 @@ + + * @since 2.0 + */ +class Progress +{ + +} \ No newline at end of file diff --git a/yii/bootstrap/widgets/Modal.php b/yii/bootstrap/widgets/Modal.php new file mode 100644 index 0000000..c591944 --- /dev/null +++ b/yii/bootstrap/widgets/Modal.php @@ -0,0 +1,303 @@ +widget(Modal::className(), array( + * 'id' => 'myModal', + * 'header' => 'Modal Heading', + * 'content' => '

One fine body...

', + * 'footer' => '//modal/_footer', // we can also use view paths + * 'buttonOptions' => array( + * 'label' => 'Show Modal', + * 'class' => \yii\bootstrap\enum\ButtonEnum::TYPE_DEFAULT + * ) + * )); + * ``` + * @see http://twitter.github.io/bootstrap/javascript.html#modals + * @author Antonio Ramirez + * @since 2.0 + */ +class Modal extends base\BootstrapWidget +{ + /** + * @var array The additional HTML attributes of the button that will show the modal. If empty array, only + * the markup of the modal will be rendered on the page, so users can easily call the modal manually with their own + * scripts. The following special attributes are available: + * + * + * For available options of the button trigger, see http://twitter.github.com/bootstrap/javascript.html#modals. + */ + public $buttonOptions = array(); + + /** + * @var boolean indicates whether the modal should use transitions. Defaults to 'true'. + */ + public $fade = true; + + /** + * @var bool $keyboard, closes the modal when escape key is pressed. + */ + public $keyboard = true; + + /** + * @var bool $show, shows the modal when initialized. + */ + public $show = false; + + /** + * @var mixed includes a modal-backdrop element. Alternatively, specify `static` for a backdrop which doesn't close + * the modal on click. + */ + public $backdrop = true; + + /** + * @var mixed the remote url. If a remote url is provided, content will be loaded via jQuery's load method and + * injected into the .modal-body of the modal. + */ + public $remote; + + /** + * @var string a javascript function that will be invoked immediately when the `show` instance method is called. + */ + public $onShow; + + /** + * @var string a javascript function that will be invoked when the modal has been made visible to the user + * (will wait for css transitions to complete). + */ + public $onShown; + + /** + * @var string a javascript function that will be invoked immediately when the hide instance method has been called. + */ + public $onHide; + + /** + * @var string a javascript function that will be invoked when the modal has finished being hidden from the user + * (will wait for css transitions to complete). + */ + public $onHidden; + + /** + * @var string[] the Javascript event handlers. + */ + protected $events = array(); + + /** + * @var array $pluginOptions the plugin options. + */ + protected $pluginOptions = array(); + + /** + * @var string + */ + public $closeText = '×'; + + /** + * @var string header content. Header can also be a path to a view file. + */ + public $header; + + /** + * @var string body of modal. Body can also be a path to a view file. + */ + public $content; + + /** + * @var string footer content. Content can also be a path to a view file. + */ + public $footer; + + /** + * Widget's init method + */ + public function init() + { + parent::init(); + + $this->name = 'modal'; + + $this->defaultOption('id', $this->getId()); + $this->selector = '#' . ArrayHelper::getValue($this->options, 'id'); + + $this->defaultOption('role', BootstrapEnum::DIALOG); + $this->defaultOption('tabindex', '-1'); + + $this->addOption('class', BootstrapEnum::MODAL); + $this->addOption('class', BootstrapEnum::HIDE); + + if ($this->fade) + $this->addOption('class', BootstrapEnum::FADE); + + $this->initPluginOptions(); + $this->initPluginEvents(); + } + + /** + * Initialize plugin events if any + */ + public function initPluginEvents() + { + foreach (array('onShow', 'onShown', 'onHide', 'onHidden') as $event) { + if ($this->{$event} !== null) { + $modalEvent = strtolower(substr($event, 2)); + if ($this->{$event} instanceof JsExpression) + $this->events[$modalEvent] = $this->$event; + else + $this->events[$modalEvent] = new JsExpression($this->{$event}); + } + } + } + + /** + * Initialize plugin options. + * ***Important***: The display of the button overrides the initialization of the modal bootstrap widget. + */ + public function initPluginOptions() + { + if (null !== $this->remote) + $this->pluginOptions['remote'] = Html::url($this->remote); + + foreach (array('backdrop', 'keyboard', 'show') as $option) { + $this->pluginOptions[$option] = isset($this->pluginOptions[$option]) + ? $this->pluginOptions[$option] + : $this->{$option}; + } + } + + /** + * Widget's run method + */ + public function run() + { + $this->renderModal(); + $this->renderButton(); + $this->registerScript(); + } + + /** + * Renders the button that will open the modal if its options have been configured + */ + public function renderButton() + { + if (!empty($this->buttonOptions)) { + + $this->buttonOptions['data-toggle'] = isset($this->buttonOptions['data-toggle']) + ? $this->buttonOptions['data-toggle'] + : BootstrapEnum::MODAL; + + if ($this->remote !== null && !isset($this->buttonOptions['data-remote'])) + $this->buttonOptions['data-remote'] = Html::url($this->remote); + + $label = ArrayHelper::remove($this->buttonOptions, 'label', 'Button'); + $name = ArrayHelper::remove($this->buttonOptions, 'name'); + $value = ArrayHelper::remove($this->buttonOptions, 'value'); + + $attr = isset($this->buttonOptions['data-remote']) + ? 'data-target' + : 'href'; + + $this->buttonOptions[$attr] = isset($this->buttonOptions[$attr]) + ? $this->buttonOptions[$attr] + : $this->selector; + + echo Html::button($label, $name, $value, $this->buttonOptions); + } + } + + /** + * Renders the modal markup + */ + public function renderModal() + { + echo Html::beginTag('div', $this->options) . PHP_EOL; + + $this->renderModalHeader(); + $this->renderModalBody(); + $this->renderModalFooter(); + + echo Html::endTag('div') . PHP_EOL; + } + + /** + * Renders the header HTML markup of the modal + */ + public function renderModalHeader() + { + echo '' . PHP_EOL; + } + + /** + * Renders the HTML markup for the body of the modal + */ + public function renderModalBody() + { + echo '' . PHP_EOL; + } + + /** + * Renders the HTML markup for the footer of the modal + */ + public function renderModalFooter() + { + + echo '' . PHP_EOL; + } + + /** + * Renders a section. If the section is a view file, the returned string will be the contents of the view file, + * otherwise, it will return the string in the $section variable. + * @param string $section + * @return string + */ + public function renderSection($section) + { + $viewFile = Yii::getAlias($section); + if (is_file($viewFile)) + return $this->view->renderFile($viewFile, array(), $this); + return $section; + } + + /** + * Registers client scripts + */ + public function registerScript() + { + // do we render a button? If so, bootstrap will handle its behavior through its + // mark-up, otherwise, register the plugin. + if(empty($this->buttonOptions)) + $this->registerPlugin($this->selector, $this->pluginOptions); + + // register events + $this->registerEvents($this->selector, $this->events); + } + +} \ No newline at end of file diff --git a/yii/bootstrap/widgets/base/BootstrapWidget.php b/yii/bootstrap/widgets/base/BootstrapWidget.php new file mode 100644 index 0000000..042f6f9 --- /dev/null +++ b/yii/bootstrap/widgets/base/BootstrapWidget.php @@ -0,0 +1,139 @@ + + * @since 2.0 + */ +class BootstrapWidget extends Widget +{ + + /** + * @var bool whether to register the asset + */ + public $responsive = true; + + /** + * @var array the HTML attributes for the widget container tag. + */ + public $options = array(); + + /** + * @var string the widget name + */ + protected $name; + + /** + * @var string the jQuery selector of the widget + */ + protected $selector; + + /** + * Initializes the widget. + */ + public function init() + { + $this->view->registerAssetBundle(($this->responsive ? 'yii/bootstrap' : 'yii/bootstrap-responsive')); + } + + /** + * Registers plugin events with the API. + * @param string $selector the CSS selector. + * @param string[] $events the JavaScript event configuration (name=>handler). + * @param int $position the position of the JavaScript code. + * @return boolean whether the events were registered. + */ + protected function registerEvents($selector, $events = array(), $position = View::POS_END) + { + if (empty($events)) + return; + + $script = ''; + foreach ($events as $name => $handler) { + $handler = ($handler instanceof JsExpression) + ? $handler + : new JsExpression($handler); + + $script .= ";jQuery(document).ready(function (){jQuery('{$selector}').on('{$name}', {$handler});});"; + } + if (!empty($script)) + $this->view->registerJs($script, array('position' => $position), $this->getUniqueScriptId()); + } + + /** + * Registers a specific Bootstrap plugin using the given selector and options. + * @param string $selector the CSS selector. + * @param array $options the JavaScript options for the plugin. + * @param int $position the position of the JavaScript code. + * @throws \yii\base\InvalidCallException + */ + public function registerPlugin($selector, $options = array(), $position = View::POS_END) + { + if(null === $this->name) + throw new InvalidCallException(); + + $options = !empty($options) ? Json::encode($options) : ''; + $script = ";jQuery(document).ready(function (){jQuery('{$selector}').{$this->name}({$options});});"; + $this->view->registerJs($script, array('position'=>$position)); + } + + /** + * Generates a "somewhat" random id string. + * @return string the id. + * @todo not sure it should be here or + */ + protected function getUniqueScriptId() + { + return uniqid(time() . '#', true); + } + + /** + * Adds a new option. If the key does not exists, it will create one, if it exists it will append the value + * and also makes sure the uniqueness of them. + * + * @param string $key + * @param mixed $value + * @param string $glue + * @return array + */ + protected function addOption($key, $value, $glue = ' ') + { + if (isset($this->options[$key])) { + if (!is_array($this->options[$key])) + $this->options[$key] = explode($glue, $this->options[$key]); + $this->options[$key][] = $value; + $this->options[$key] = array_unique($this->options[$key]); + $this->options[$key] = implode($glue, $this->options[$key]); + } else + $this->options[$key] = $value; + return $this->options; + } + + /** + * Sets the default value for an item if not set. + * @param string $key the name of the item. + * @param mixed $value the default value. + * @return array + */ + protected function defaultOption($key, $value) + { + if (!isset($this->options[$key])) + $this->options[$key] = $value; + return $this->options; + } +} \ No newline at end of file