Example #1
0
 /**
  * Renders the sort links.
  * @return string the rendering result
  */
 protected function renderSortLinks()
 {
     $attributes = empty($this->attributes) ? array_keys($this->sort->attributes) : $this->attributes;
     $links = [];
     foreach ($attributes as $name) {
         $links[] = $this->sort->link($name, $this->linkOptions);
     }
     return Html::ul($links, array_merge($this->options, ['encode' => false]));
 }
 /**
  * @inheritdoc
  */
 public function clientValidateAttribute($model, $attribute, $view)
 {
     $pattern = Html::escapeJsRegularExpression($this->pattern);
     $options = ['pattern' => new JsExpression($pattern), 'not' => $this->not, 'message' => Leaps::$app->getI18n()->format($this->message, ['attribute' => $model->getAttributeLabel($attribute)], Leaps::$app->language)];
     if ($this->skipOnEmpty) {
         $options['skipOnEmpty'] = 1;
     }
     ValidationAsset::register($view);
     return 'leaps.validation.regularExpression(value, messages, ' . Json::htmlEncode($options) . ');';
 }
Example #3
0
 /**
  * Initializes the widget.
  * If you override this method, make sure you call the parent implementation first.
  */
 public function init()
 {
     if ($this->name === null && !$this->hasModel()) {
         throw new InvalidConfigException("Either 'name', or 'model' and 'attribute' properties must be specified.");
     }
     if (!isset($this->options['id'])) {
         $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId();
     }
     parent::init();
 }
Example #4
0
 /**
  * Initializes the default button rendering callbacks.
  */
 protected function initDefaultButtons()
 {
     if (!isset($this->buttons['view'])) {
         $this->buttons['view'] = function ($url, $model, $key) {
             $options = array_merge(['title' => Leaps::t('leaps', 'View'), 'aria-label' => Leaps::t('leaps', 'View'), 'data-pjax' => '0'], $this->buttonOptions);
             return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, $options);
         };
     }
     if (!isset($this->buttons['update'])) {
         $this->buttons['update'] = function ($url, $model, $key) {
             $options = array_merge(['title' => Leaps::t('leaps', 'Update'), 'aria-label' => Leaps::t('leaps', 'Update'), 'data-pjax' => '0'], $this->buttonOptions);
             return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, $options);
         };
     }
     if (!isset($this->buttons['delete'])) {
         $this->buttons['delete'] = function ($url, $model, $key) {
             $options = array_merge(['title' => Leaps::t('leaps', 'Delete'), 'aria-label' => Leaps::t('leaps', 'Delete'), 'data-confirm' => Leaps::t('leaps', 'Are you sure you want to delete this item?'), 'data-method' => 'post', 'data-pjax' => '0'], $this->buttonOptions);
             return Html::a('<span class="glyphicon glyphicon-trash"></span>', $url, $options);
         };
     }
 }
Example #5
0
 /**
  * Renders a single breadcrumb item.
  * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional.
  * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the link.
  * @return string the rendering result
  * @throws InvalidConfigException if `$link` does not have "label" element.
  */
 protected function renderItem($link, $template)
 {
     $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
     if (array_key_exists('label', $link)) {
         $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
     } else {
         throw new InvalidConfigException('The "label" element is required for each link.');
     }
     if (isset($link['template'])) {
         $template = $link['template'];
     }
     if (isset($link['url'])) {
         $options = $link;
         unset($options['template'], $options['label'], $options['url']);
         $link = Html::a($label, $link['url'], $options);
     } else {
         $link = $label;
     }
     return strtr($template, ['{link}' => $link]);
 }
Example #6
0
 /**
  * Renders the detail view.
  * This is the main entry of the whole detail view rendering.
  */
 public function run()
 {
     $rows = [];
     $i = 0;
     foreach ($this->attributes as $attribute) {
         $rows[] = $this->renderAttribute($attribute, $i++);
     }
     $options = $this->options;
     $tag = ArrayHelper::remove($options, 'tag', 'table');
     echo Html::tag($tag, implode("\n", $rows), $options);
 }
Example #7
0
 /**
  * Normalizes the [[items]] property to remove invisible items and activate certain items.
  * @param array $items the items to be normalized.
  * @param boolean $active whether there is an active child menu item.
  * @return array the normalized menu items
  */
 protected function normalizeItems($items, &$active)
 {
     foreach ($items as $i => $item) {
         if (isset($item['visible']) && !$item['visible']) {
             unset($items[$i]);
             continue;
         }
         if (!isset($item['label'])) {
             $item['label'] = '';
         }
         $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
         $items[$i]['label'] = $encodeLabel ? Html::encode($item['label']) : $item['label'];
         $hasActiveChild = false;
         if (isset($item['items'])) {
             $items[$i]['items'] = $this->normalizeItems($item['items'], $hasActiveChild);
             if (empty($items[$i]['items']) && $this->hideEmptyItems) {
                 unset($items[$i]['items']);
                 if (!isset($item['url'])) {
                     unset($items[$i]);
                     continue;
                 }
             }
         }
         if (!isset($item['active'])) {
             if ($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item)) {
                 $active = $items[$i]['active'] = true;
             } else {
                 $items[$i]['active'] = false;
             }
         } elseif ($item['active']) {
             $active = true;
         }
     }
     return array_values($items);
 }
Example #8
0
 /**
  * @inheritdoc
  */
 protected function renderFilterCellContent()
 {
     if (is_string($this->filter)) {
         return $this->filter;
     }
     $model = $this->grid->filterModel;
     if ($this->filter !== false && $model instanceof Model && $this->attribute !== null && $model->isAttributeActive($this->attribute)) {
         if ($model->hasErrors($this->attribute)) {
             Html::addCssClass($this->filterOptions, 'has-error');
             $error = ' ' . Html::error($model, $this->attribute, $this->grid->filterErrorOptions);
         } else {
             $error = '';
         }
         if (is_array($this->filter)) {
             $options = array_merge(['prompt' => ''], $this->filterInputOptions);
             return Html::activeDropDownList($model, $this->attribute, $this->filter, $options) . $error;
         } else {
             return Html::activeTextInput($model, $this->attribute, $this->filterInputOptions) . $error;
         }
     } else {
         return parent::renderFilterCellContent();
     }
 }
 /**
  * @inheritdoc
  */
 public function clientValidateAttribute($model, $attribute, $view)
 {
     $options = ['operator' => $this->operator, 'type' => $this->type];
     if ($this->compareValue !== null) {
         $options['compareValue'] = $this->compareValue;
         $compareValue = $this->compareValue;
     } else {
         $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute;
         $compareValue = $model->getAttributeLabel($compareAttribute);
         $options['compareAttribute'] = Html::getInputId($model, $compareAttribute);
     }
     if ($this->skipOnEmpty) {
         $options['skipOnEmpty'] = 1;
     }
     $options['message'] = Leaps::$app->getI18n()->format($this->message, ['attribute' => $model->getAttributeLabel($attribute), 'compareAttribute' => $compareValue, 'compareValue' => $compareValue], Leaps::$app->language);
     ValidationAsset::register($view);
     return 'leaps.validation.compare(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
 }
Example #10
0
 /**
  * Returns the JS options for the field.
  * @return array the JS options
  */
 protected function getClientOptions()
 {
     $attribute = Html::getAttributeName($this->attribute);
     if (!in_array($attribute, $this->model->activeAttributes(), true)) {
         return [];
     }
     $enableClientValidation = $this->enableClientValidation || $this->enableClientValidation === null && $this->form->enableClientValidation;
     $enableAjaxValidation = $this->enableAjaxValidation || $this->enableAjaxValidation === null && $this->form->enableAjaxValidation;
     if ($enableClientValidation) {
         $validators = [];
         foreach ($this->model->getActiveValidators($attribute) as $validator) {
             /* @var $validator \Leaps\Validator\Validator */
             $js = $validator->clientValidateAttribute($this->model, $attribute, $this->form->getView());
             if ($validator->enableClientValidation && $js != '') {
                 if ($validator->whenClient !== null) {
                     $js = "if (({$validator->whenClient})(attribute, value)) { {$js} }";
                 }
                 $validators[] = $js;
             }
         }
     }
     if (!$enableAjaxValidation && (!$enableClientValidation || empty($validators))) {
         return [];
     }
     $options = [];
     $inputID = Html::getInputId($this->model, $this->attribute);
     $options['id'] = $inputID;
     $options['name'] = $this->attribute;
     $options['container'] = isset($this->selectors['container']) ? $this->selectors['container'] : ".field-{$inputID}";
     $options['input'] = isset($this->selectors['input']) ? $this->selectors['input'] : "#{$inputID}";
     if (isset($this->selectors['error'])) {
         $options['error'] = $this->selectors['error'];
     } elseif (isset($this->errorOptions['class'])) {
         $options['error'] = '.' . implode('.', preg_split('/\\s+/', $this->errorOptions['class'], -1, PREG_SPLIT_NO_EMPTY));
     } else {
         $options['error'] = isset($this->errorOptions['tag']) ? $this->errorOptions['tag'] : 'span';
     }
     $options['encodeError'] = !isset($this->errorOptions['encode']) || $this->errorOptions['encode'];
     if ($enableAjaxValidation) {
         $options['enableAjaxValidation'] = true;
     }
     foreach (['validateOnChange', 'validateOnBlur', 'validateOnType', 'validationDelay'] as $name) {
         $options[$name] = $this->{$name} === null ? $this->form->{$name} : $this->{$name};
     }
     if (!empty($validators)) {
         $options['validate'] = new JsExpression("function (attribute, value, messages, deferred, \$form) {" . implode('', $validators) . '}');
     }
     // only get the options that are different from the default ones (set in leaps.activeForm.js)
     return array_diff_assoc($options, ['validateOnChange' => true, 'validateOnBlur' => true, 'validateOnType' => false, 'validationDelay' => 500, 'encodeError' => true, 'error' => '.help-block']);
 }
Example #11
0
 /**
  * Renders the widget.
  */
 public function run()
 {
     $this->registerClientScript();
     if ($this->hasModel()) {
         $input = Html::activeTextInput($this->model, $this->attribute, $this->options);
     } else {
         $input = Html::textInput($this->name, $this->value, $this->options);
     }
     $route = $this->captchaAction;
     if (is_array($route)) {
         $route['v'] = uniqid();
     } else {
         $route = [$route, 'v' => uniqid()];
     }
     $image = Html::img($route, $this->imageOptions);
     echo strtr($this->template, ['{input}' => $input, '{image}' => $image]);
 }
Example #12
0
 /**
  * Validates an array of model instances and returns an error message array indexed by the attribute IDs.
  * This is a helper method that simplifies the way of writing AJAX validation code for tabular input.
  *
  * For example, you may use the following code in a controller action to respond
  * to an AJAX validation request:
  *
  * ~~~
  * // ... load $models ...
  * if (Leaps::$app->request->isAjax) {
  *     Leaps::$app->response->format = Response::FORMAT_JSON;
  *     return ActiveForm::validateMultiple($models);
  * }
  * // ... respond to non-AJAX request ...
  * ~~~
  *
  * @param array $models an array of models to be validated.
  * @param mixed $attributes list of attributes that should be validated.
  * If this parameter is empty, it means any attribute listed in the applicable
  * validation rules should be validated.
  * @return array the error message array indexed by the attribute IDs.
  */
 public static function validateMultiple($models, $attributes = null)
 {
     $result = [];
     /* @var $model Model */
     foreach ($models as $i => $model) {
         $model->validate($attributes);
         foreach ($model->getErrors() as $attribute => $errors) {
             $result[Html::getInputId($model, "[{$i}]" . $attribute)] = $errors;
         }
     }
     return $result;
 }
Example #13
0
?>
</head>
<body>
<?php 
$this->beginBody();
?>

<div class="wrap">
    <?php 
NavBar::begin(['brandLabel' => 'CodeForge', 'brandUrl' => Leaps::$app->homeUrl, 'options' => ['class' => 'navbar-inverse navbar-fixed-top']]);
$menuItems = [['label' => '威客', 'url' => ['/site/index']], ['label' => '源代码', 'url' => ['/site/code']], ['label' => '活动', 'url' => ['/event']], ['label' => 'CF币', 'url' => ['/site/cfcoin']], ['label' => '关于我们', 'url' => ['/site/about']], ['label' => '联系我们', 'url' => ['/site/contact']]];
if (Leaps::$app->user->isGuest) {
    $menuItems[] = ['label' => '注册', 'url' => ['/site/signup']];
    $menuItems[] = ['label' => '登陆', 'url' => ['/site/login']];
} else {
    $menuItems[] = '<li>' . Html::beginForm(['/site/logout'], 'post') . Html::submitButton('Logout (' . Leaps::$app->user->identity->username . ')', ['class' => 'btn btn-link']) . Html::endForm() . '</li>';
}
echo Nav::widget(['options' => ['class' => 'navbar-nav navbar-right'], 'items' => $menuItems]);
NavBar::end();
?>

    <div class="container">
        <?php 
echo Breadcrumbs::widget(['links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : []]);
?>
        <?php 
echo '';
?>
        <?php 
echo $content;
?>
 /**
  * @inheritdoc
  */
 protected function renderDataCellContent($model, $key, $index)
 {
     if ($this->checkboxOptions instanceof Closure) {
         $options = call_user_func($this->checkboxOptions, $model, $key, $index, $this);
     } else {
         $options = $this->checkboxOptions;
         if (!isset($options['value'])) {
             $options['value'] = is_array($key) ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : $key;
         }
     }
     return Html::checkbox($this->name, !empty($options['checked']), $options);
 }
Example #15
0
 /**
  * Formats the value as a hyperlink.
  * @param mixed $value the value to be formatted.
  * @param array $options the tag options in terms of name-value pairs. See [[Html::a()]].
  * @return string the formatted result.
  */
 public function asUrl($value, $options = [])
 {
     if ($value === null) {
         return $this->nullDisplay;
     }
     $url = $value;
     if (strpos($url, '://') === false) {
         $url = 'http://' . $url;
     }
     return Html::a(Html::encode($value), $url, $options);
 }
Example #16
0
 /**
  * Renders the filter cell.
  */
 public function renderFilterCell()
 {
     return Html::tag('td', $this->renderFilterCellContent(), $this->filterOptions);
 }
Example #17
0
 /**
  * Renders a single data model.
  * @param mixed $model the data model to be rendered
  * @param mixed $key the key value associated with the data model
  * @param integer $index the zero-based index of the data model in the model array returned by [[dataProvider]].
  * @return string the rendering result
  */
 public function renderItem($model, $key, $index)
 {
     if ($this->itemView === null) {
         $content = $key;
     } elseif (is_string($this->itemView)) {
         $content = $this->getView()->render($this->itemView, array_merge(['model' => $model, 'key' => $key, 'index' => $index, 'widget' => $this], $this->viewParams));
     } else {
         $content = call_user_func($this->itemView, $model, $key, $index, $this);
     }
     $options = $this->itemOptions;
     $tag = ArrayHelper::remove($options, 'tag', 'div');
     if ($tag !== false) {
         $options['data-key'] = is_array($key) ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : (string) $key;
         return Html::tag($tag, $content, $options);
     } else {
         return $content;
     }
 }
Example #18
0
 /**
  * Renders a table row with the given data model and key.
  * @param mixed $model the data model to be rendered
  * @param mixed $key the key associated with the data model
  * @param integer $index the zero-based index of the data model among the model array returned by [[dataProvider]].
  * @return string the rendering result
  */
 public function renderTableRow($model, $key, $index)
 {
     $cells = [];
     /* @var $column Column */
     foreach ($this->columns as $column) {
         $cells[] = $column->renderDataCell($model, $key, $index);
     }
     if ($this->rowOptions instanceof Closure) {
         $options = call_user_func($this->rowOptions, $model, $key, $index, $this);
     } else {
         $options = $this->rowOptions;
     }
     $options['data-key'] = is_array($key) ? json_encode($key) : (string) $key;
     return Html::tag('tr', implode('', $cells), $options);
 }
Example #19
0
 /**
  * @inheritdoc
  */
 public function run()
 {
     $this->registerClientScript();
     if ($this->hasModel()) {
         echo Html::activeInput($this->type, $this->model, $this->attribute, $this->options);
     } else {
         echo Html::input($this->type, $this->name, $this->value, $this->options);
     }
 }
Example #20
0
 /**
  * Renders a page button.
  * You may override this method to customize the generation of page buttons.
  * @param string $label the text label for the button
  * @param integer $page the page number
  * @param string $class the CSS class for the page button.
  * @param boolean $disabled whether this page button is disabled
  * @param boolean $active whether this page button is active
  * @return string the rendering result
  */
 protected function renderPageButton($label, $page, $class, $disabled, $active)
 {
     $options = ['class' => $class === '' ? null : $class];
     if ($active) {
         Html::addCssClass($options, $this->activePageCssClass);
     }
     if ($disabled) {
         Html::addCssClass($options, $this->disabledPageCssClass);
         return Html::tag('li', Html::tag('span', $label), $options);
     }
     $linkOptions = $this->linkOptions;
     $linkOptions['data-page'] = $page;
     return Html::tag('li', Html::a($label, $this->pagination->createUrl($page), $linkOptions), $options);
 }
Example #21
0
?>


<?php 
echo $form->field($model, 'username')->icon('fa-user')->tooltip('lalala');
?>

                <?php 
echo $form->field($model, 'password')->passwordInput();
?>

                <div style="color: #999; margin: 1em 0">
                    If you forgot your password you can <?php 
echo Html::a('reset it', ['site/request-password-reset']);
?>
.
                </div>

			<div class="form-group">
                    <?php 
echo Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']);
?>
                </div>

            <?php 
ActiveForm::end();
?>
        </div>
	</div>
</div>
Example #22
0
 /**
  * Renders the content to be inserted at the end of the body section.
  * The content is rendered using the registered JS code blocks and files.
  * @param boolean $ajaxMode whether the view is rendering in AJAX mode.
  * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
  * will be rendered at the end of the view like normal scripts.
  * @return string the rendered content
  */
 protected function renderBodyEndHtml($ajaxMode)
 {
     $lines = [];
     if (!empty($this->jsFiles[self::POS_END])) {
         $lines[] = implode("\n", $this->jsFiles[self::POS_END]);
     }
     if ($ajaxMode) {
         $scripts = [];
         if (!empty($this->js[self::POS_END])) {
             $scripts[] = implode("\n", $this->js[self::POS_END]);
         }
         if (!empty($this->js[self::POS_READY])) {
             $scripts[] = implode("\n", $this->js[self::POS_READY]);
         }
         if (!empty($this->js[self::POS_LOAD])) {
             $scripts[] = implode("\n", $this->js[self::POS_LOAD]);
         }
         if (!empty($scripts)) {
             $lines[] = Html::script(implode("\n", $scripts), ['type' => 'text/javascript']);
         }
     } else {
         if (!empty($this->js[self::POS_END])) {
             $lines[] = Html::script(implode("\n", $this->js[self::POS_END]), ['type' => 'text/javascript']);
         }
         if (!empty($this->js[self::POS_READY])) {
             $js = "jQuery(document).ready(function () {\n" . implode("\n", $this->js[self::POS_READY]) . "\n});";
             $lines[] = Html::script($js, ['type' => 'text/javascript']);
         }
         if (!empty($this->js[self::POS_LOAD])) {
             $js = "jQuery(window).load(function () {\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});";
             $lines[] = Html::script($js, ['type' => 'text/javascript']);
         }
     }
     return empty($lines) ? '' : implode("\n", $lines);
 }
Example #23
0
 /**
  * Renders the summary text.
  */
 public function renderSummary()
 {
     $count = $this->dataProvider->getCount();
     if ($count <= 0) {
         return '';
     }
     $summaryOptions = $this->summaryOptions;
     $tag = ArrayHelper::remove($summaryOptions, 'tag', 'div');
     if (($pagination = $this->dataProvider->getPagination()) !== false) {
         $totalCount = $this->dataProvider->getTotalCount();
         $begin = $pagination->getPage() * $pagination->pageSize + 1;
         $end = $begin + $count - 1;
         if ($begin > $end) {
             $begin = $end;
         }
         $page = $pagination->getPage() + 1;
         $pageCount = $pagination->pageCount;
         if (($summaryContent = $this->summary) === null) {
             return Html::tag($tag, Leaps::t('leaps', 'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', ['begin' => $begin, 'end' => $end, 'count' => $count, 'totalCount' => $totalCount, 'page' => $page, 'pageCount' => $pageCount]), $summaryOptions);
         }
     } else {
         $begin = $page = $pageCount = 1;
         $end = $totalCount = $count;
         if (($summaryContent = $this->summary) === null) {
             return Html::tag($tag, Leaps::t('leaps', 'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', ['begin' => $begin, 'end' => $end, 'count' => $count, 'totalCount' => $totalCount, 'page' => $page, 'pageCount' => $pageCount]), $summaryOptions);
         }
     }
     return Leaps::$app->getI18n()->format($summaryContent, ['begin' => $begin, 'end' => $end, 'count' => $count, 'totalCount' => $totalCount, 'page' => $page, 'pageCount' => $pageCount], Leaps::$app->language);
 }
Example #24
0
 /**
  * @inheritdoc
  */
 public function run()
 {
     if (!$this->requiresPjax()) {
         echo Html::endTag('div');
         $this->registerClientScript();
         return;
     }
     $view = $this->getView();
     $view->endBody();
     // Do not re-send css files as it may override the css files that were loaded after them.
     // It should be removed once pjax supports loading only missing css files
     $view->cssFiles = null;
     $view->endPage(true);
     $content = ob_get_clean();
     // only need the content enclosed within this widget
     $response = Leaps::$app->getResponse();
     $response->clearOutputBuffers();
     $response->setStatusCode(200);
     $response->format = Response::FORMAT_HTML;
     $response->content = $content;
     $response->send();
     Leaps::$app->end();
 }
Example #25
0
 /**
  * Returns all uploaded files for the given model attribute.
  * @param \Leaps\Base\Model $model the data model
  * @param string $attribute the attribute name. The attribute name may contain array indexes
  * for tabular file uploading, e.g. '[1]file'.
  * @return UploadedFile[] array of UploadedFile objects.
  * Empty array is returned if no available file was found for the given attribute.
  */
 public static function getInstances($model, $attribute)
 {
     $name = Html::getInputName($model, $attribute);
     return static::getInstancesByName($name);
 }
Example #26
0
 /**
  * Generates a hyperlink that links to the sort action to sort by the specified attribute.
  * Based on the sort direction, the CSS class of the generated hyperlink will be appended
  * with "asc" or "desc".
  * 
  * @param string $attribute the attribute name by which the data should be sorted by.
  * @param array $options additional HTML attributes for the hyperlink tag.
  *        There is one special attribute `label` which will be used as the label of the hyperlink.
  *        If this is not set, the label defined in [[attributes]] will be used.
  *        If no label is defined, [[\Leaps\Helper\Inflector::camel2words()]] will be called to get a label.
  *        Note that it will not be HTML-encoded.
  * @return string the generated hyperlink
  * @throws InvalidConfigException if the attribute is unknown
  */
 public function link($attribute, $options = [])
 {
     if (($direction = $this->getAttributeOrder($attribute)) !== null) {
         $class = $direction === SORT_DESC ? 'desc' : 'asc';
         if (isset($options['class'])) {
             $options['class'] .= ' ' . $class;
         } else {
             $options['class'] = $class;
         }
     }
     $url = $this->createUrl($attribute);
     $options['data-sort'] = $this->createSortParam($attribute);
     if (isset($options['label'])) {
         $label = $options['label'];
         unset($options['label']);
     } else {
         if (isset($this->attributes[$attribute]['label'])) {
             $label = $this->attributes[$attribute]['label'];
         } else {
             $label = Inflector::camel2words($attribute);
         }
     }
     return Html::a($label, $url, $options);
 }